yangdx commited on
Commit
d60bf1c
·
1 Parent(s): 32943a3

Update graph unit test

Browse files
Files changed (1) hide show
  1. tests/test_graph_storage.py +289 -4
tests/test_graph_storage.py CHANGED
@@ -209,6 +209,21 @@ async def test_graph_basic(storage):
209
  else:
210
  print(f"读取边属性失败: {node1_id} -> {node2_id}")
211
  assert False, f"未能读取边属性: {node1_id} -> {node2_id}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  print("基本测试完成,数据已保留在数据库中")
214
  return True
@@ -293,6 +308,15 @@ async def test_graph_advanced(storage):
293
  node1_degree = await storage.node_degree(node1_id)
294
  print(f"节点 {node1_id} 的度数: {node1_degree}")
295
  assert node1_degree == 1, f"节点 {node1_id} 的度数应为1,实际为 {node1_degree}"
 
 
 
 
 
 
 
 
 
296
 
297
  # 3. 测试 edge_degree - 获取边的度数
298
  print(f"== 测试 edge_degree: {node1_id} -> {node2_id}")
@@ -300,7 +324,14 @@ async def test_graph_advanced(storage):
300
  print(f"边 {node1_id} -> {node2_id} 的度数: {edge_degree}")
301
  assert (
302
  edge_degree == 3
303
- ), f"边 {node1_id} -> {node2_id} 的度数应为2,实际为 {edge_degree}"
 
 
 
 
 
 
 
304
 
305
  # 4. 测试 get_node_edges - 获取节点的所有边
306
  print(f"== 测试 get_node_edges: {node2_id}")
@@ -309,6 +340,23 @@ async def test_graph_advanced(storage):
309
  assert (
310
  len(node2_edges) == 2
311
  ), f"节点 {node2_id} 应有2条边,实际有 {len(node2_edges)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
  # 5. 测试 get_all_labels - 获取所有标签
314
  print("== 测试 get_all_labels")
@@ -345,6 +393,13 @@ async def test_graph_advanced(storage):
345
  edge_props = await storage.get_edge(node2_id, node3_id)
346
  print(f"删除后查询边属性 {node2_id} -> {node3_id}: {edge_props}")
347
  assert edge_props is None, f"边 {node2_id} -> {node3_id} 应已被删除"
 
 
 
 
 
 
 
348
 
349
  # 9. 测试 remove_nodes - 批量删除节点
350
  print(f"== 测试 remove_nodes: [{node2_id}, {node3_id}]")
@@ -602,6 +657,21 @@ async def test_graph_batch_operations(storage):
602
  edges_dict[(node3_id, node4_id)]["relationship"]
603
  == edge5_data["relationship"]
604
  ), f"边 {node3_id} -> {node4_id} 关系不匹配"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
 
606
  # 6. 测试 get_nodes_edges_batch - 批量获取多个节点的所有边
607
  print("== 测试 get_nodes_edges_batch")
@@ -618,6 +688,41 @@ async def test_graph_batch_operations(storage):
618
  assert (
619
  len(nodes_edges[node3_id]) == 3
620
  ), f"{node3_id} 应有3条边,实际有 {len(nodes_edges[node3_id])} 条"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
 
622
  # 7. 清理数据
623
  print("== 测试 drop")
@@ -635,6 +740,179 @@ async def test_graph_batch_operations(storage):
635
  return False
636
 
637
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  async def main():
639
  """主函数"""
640
  # 显示程序标题
@@ -670,9 +948,10 @@ async def main():
670
  ASCIIColors.white("1. 基本测试 (节点和边的插入、读取)")
671
  ASCIIColors.white("2. 高级测试 (度数、标签、知识图谱、删除操作等)")
672
  ASCIIColors.white("3. 批量操作测试 (批量获取节点、边属性和度数等)")
673
- ASCIIColors.white("4. 全部测试")
 
674
 
675
- choice = input("\n请输入选项 (1/2/3/4): ")
676
 
677
  if choice == "1":
678
  await test_graph_basic(storage)
@@ -681,6 +960,8 @@ async def main():
681
  elif choice == "3":
682
  await test_graph_batch_operations(storage)
683
  elif choice == "4":
 
 
684
  ASCIIColors.cyan("\n=== 开始基本测试 ===")
685
  basic_result = await test_graph_basic(storage)
686
 
@@ -690,7 +971,11 @@ async def main():
690
 
691
  if advanced_result:
692
  ASCIIColors.cyan("\n=== 开始批量操作测试 ===")
693
- await test_graph_batch_operations(storage)
 
 
 
 
694
  else:
695
  ASCIIColors.red("无效的选项")
696
 
 
209
  else:
210
  print(f"读取边属性失败: {node1_id} -> {node2_id}")
211
  assert False, f"未能读取边属性: {node1_id} -> {node2_id}"
212
+
213
+ # 5.1 验证无向图特性 - 读取反向边属性
214
+ print(f"读取反向边属性: {node2_id} -> {node1_id}")
215
+ reverse_edge_props = await storage.get_edge(node2_id, node1_id)
216
+ if reverse_edge_props:
217
+ print(f"成功读取反向边属性: {node2_id} -> {node1_id}")
218
+ print(f"反向边关系: {reverse_edge_props.get('relationship', '无关系')}")
219
+ print(f"反向边描述: {reverse_edge_props.get('description', '无描述')}")
220
+ print(f"反向边权重: {reverse_edge_props.get('weight', '无权重')}")
221
+ # 验证正向和反向边属性是否相同
222
+ assert edge_props == reverse_edge_props, "正向和反向边属性不一致,无向图特性验证失败"
223
+ print("无向图特性验证成功:正向和反向边属性一致")
224
+ else:
225
+ print(f"读取反向边属性失败: {node2_id} -> {node1_id}")
226
+ assert False, f"未能读取反向边属性: {node2_id} -> {node1_id},无向图特性验证失败"
227
 
228
  print("基本测试完成,数据已保留在数据库中")
229
  return True
 
308
  node1_degree = await storage.node_degree(node1_id)
309
  print(f"节点 {node1_id} 的度数: {node1_degree}")
310
  assert node1_degree == 1, f"节点 {node1_id} 的度数应为1,实际为 {node1_degree}"
311
+
312
+ # 2.1 测试所有节点的度数
313
+ print("== 测试所有节点的度数")
314
+ node2_degree = await storage.node_degree(node2_id)
315
+ node3_degree = await storage.node_degree(node3_id)
316
+ print(f"节点 {node2_id} 的度数: {node2_degree}")
317
+ print(f"节点 {node3_id} 的度数: {node3_degree}")
318
+ assert node2_degree == 2, f"节点 {node2_id} 的度数应为2,实际为 {node2_degree}"
319
+ assert node3_degree == 1, f"节点 {node3_id} 的度数应为1,实际为 {node3_degree}"
320
 
321
  # 3. 测试 edge_degree - 获取边的度数
322
  print(f"== 测试 edge_degree: {node1_id} -> {node2_id}")
 
324
  print(f"边 {node1_id} -> {node2_id} 的度数: {edge_degree}")
325
  assert (
326
  edge_degree == 3
327
+ ), f"边 {node1_id} -> {node2_id} 的度数应为3,实际为 {edge_degree}"
328
+
329
+ # 3.1 测试反向边的度数 - 验证无向图特性
330
+ print(f"== 测试反向边的度数: {node2_id} -> {node1_id}")
331
+ reverse_edge_degree = await storage.edge_degree(node2_id, node1_id)
332
+ print(f"反向边 {node2_id} -> {node1_id} 的度数: {reverse_edge_degree}")
333
+ assert edge_degree == reverse_edge_degree, f"正向边和反向边的度数不一致,无向图特性验证失败"
334
+ print("无向图特性验证成功:正向边和反向边的度数一致")
335
 
336
  # 4. 测试 get_node_edges - 获取节点的所有边
337
  print(f"== 测试 get_node_edges: {node2_id}")
 
340
  assert (
341
  len(node2_edges) == 2
342
  ), f"节点 {node2_id} 应有2条边,实际有 {len(node2_edges)}"
343
+
344
+ # 4.1 验证节点边的无向图特性
345
+ print("== 验证节点边的无向图特性")
346
+ # 检查是否包含与node1和node3的连接关系(无论方向)
347
+ has_connection_with_node1 = False
348
+ has_connection_with_node3 = False
349
+ for edge in node2_edges:
350
+ # 检查是否有与node1的连接(无论方向)
351
+ if (edge[0] == node1_id and edge[1] == node2_id) or (edge[0] == node2_id and edge[1] == node1_id):
352
+ has_connection_with_node1 = True
353
+ # 检查是否有与node3的连接(无论方向)
354
+ if (edge[0] == node2_id and edge[1] == node3_id) or (edge[0] == node3_id and edge[1] == node2_id):
355
+ has_connection_with_node3 = True
356
+
357
+ assert has_connection_with_node1, f"节点 {node2_id} 的边列表中应包含与 {node1_id} 的连接"
358
+ assert has_connection_with_node3, f"节点 {node2_id} 的边列表中应包含与 {node3_id} 的连接"
359
+ print(f"无向图特性验证成功:节点 {node2_id} 的边列表包含所有相关的边")
360
 
361
  # 5. 测试 get_all_labels - 获取所有标签
362
  print("== 测试 get_all_labels")
 
393
  edge_props = await storage.get_edge(node2_id, node3_id)
394
  print(f"删除后查询边属性 {node2_id} -> {node3_id}: {edge_props}")
395
  assert edge_props is None, f"边 {node2_id} -> {node3_id} 应已被删除"
396
+
397
+ # 8.1 验证删除边的无向图特性
398
+ print(f"== 验证删��边的无向图特性: {node3_id} -> {node2_id}")
399
+ reverse_edge_props = await storage.get_edge(node3_id, node2_id)
400
+ print(f"删除后查询反向边属性 {node3_id} -> {node2_id}: {reverse_edge_props}")
401
+ assert reverse_edge_props is None, f"反向边 {node3_id} -> {node2_id} 也应被删除,无向图特性验证失败"
402
+ print("无向图特性验证成功:删除一个方向的边后,反向边也被删除")
403
 
404
  # 9. 测试 remove_nodes - 批量删除节点
405
  print(f"== 测试 remove_nodes: [{node2_id}, {node3_id}]")
 
657
  edges_dict[(node3_id, node4_id)]["relationship"]
658
  == edge5_data["relationship"]
659
  ), f"边 {node3_id} -> {node4_id} 关系不匹配"
660
+
661
+ # 5.1 测试反向边的批量获取 - 验证无向图特性
662
+ print("== 测试反向边的批量获取")
663
+ # 创建反向边的字典列表
664
+ reverse_edge_dicts = [{"src": tgt, "tgt": src} for src, tgt in edges]
665
+ reverse_edges_dict = await storage.get_edges_batch(reverse_edge_dicts)
666
+ print(f"批量获取反向边属性结果: {reverse_edges_dict.keys()}")
667
+ assert len(reverse_edges_dict) == 3, f"应返回3条反向边的属性,实际返回 {len(reverse_edges_dict)} 条"
668
+
669
+ # 验证正向和反向边的属性是否一致
670
+ for (src, tgt), props in edges_dict.items():
671
+ assert (tgt, src) in reverse_edges_dict, f"反向边 {tgt} -> {src} 应在返回结果中"
672
+ assert props == reverse_edges_dict[(tgt, src)], f"边 {src} -> {tgt} 和反向边 {tgt} -> {src} 的属性不一致"
673
+
674
+ print("无向图特性验证成功:批量获取的正向和反向边属性一致")
675
 
676
  # 6. 测试 get_nodes_edges_batch - 批量获取多个节点的所有边
677
  print("== 测试 get_nodes_edges_batch")
 
688
  assert (
689
  len(nodes_edges[node3_id]) == 3
690
  ), f"{node3_id} 应有3条边,实际有 {len(nodes_edges[node3_id])} 条"
691
+
692
+ # 6.1 验证批量获取节点边的无向图特性
693
+ print("== 验证批量获取节点边的无向图特性")
694
+
695
+ # 检查节点1的边是否包含所有相关的边(无论方向)
696
+ node1_outgoing_edges = [(src, tgt) for src, tgt in nodes_edges[node1_id] if src == node1_id]
697
+ node1_incoming_edges = [(src, tgt) for src, tgt in nodes_edges[node1_id] if tgt == node1_id]
698
+ print(f"节点 {node1_id} 的出边: {node1_outgoing_edges}")
699
+ print(f"节点 {node1_id} 的入边: {node1_incoming_edges}")
700
+
701
+ # 检查是否包含到机器学习、自然语言处理和计算机视觉的边
702
+ has_edge_to_node2 = any(tgt == node2_id for _, tgt in node1_outgoing_edges)
703
+ has_edge_to_node4 = any(tgt == node4_id for _, tgt in node1_outgoing_edges)
704
+ has_edge_to_node5 = any(tgt == node5_id for _, tgt in node1_outgoing_edges)
705
+
706
+ assert has_edge_to_node2, f"节点 {node1_id} 的边列表中应包含到 {node2_id} 的边"
707
+ assert has_edge_to_node4, f"节点 {node1_id} 的边列表中应包含到 {node4_id} 的边"
708
+ assert has_edge_to_node5, f"节点 {node1_id} 的边列表中应包含到 {node5_id} 的边"
709
+
710
+ # 检查节点3的边是否包含所有相关的边(无论方向)
711
+ node3_outgoing_edges = [(src, tgt) for src, tgt in nodes_edges[node3_id] if src == node3_id]
712
+ node3_incoming_edges = [(src, tgt) for src, tgt in nodes_edges[node3_id] if tgt == node3_id]
713
+ print(f"节点 {node3_id} 的出边: {node3_outgoing_edges}")
714
+ print(f"节点 {node3_id} 的入边: {node3_incoming_edges}")
715
+
716
+ # 检查是否包含从机器学习来的边,以及到自然语言处理和计算机视觉的边
717
+ has_edge_from_node2 = any(src == node2_id for src, _ in node3_incoming_edges)
718
+ has_edge_to_node4 = any(tgt == node4_id for _, tgt in node3_outgoing_edges)
719
+ has_edge_to_node5 = any(tgt == node5_id for _, tgt in node3_outgoing_edges)
720
+
721
+ assert has_edge_from_node2, f"节点 {node3_id} 的边列表中应包含从 {node2_id} 来的边"
722
+ assert has_edge_to_node4, f"节点 {node3_id} 的边列表中应包含到 {node4_id} 的边"
723
+ assert has_edge_to_node5, f"节点 {node3_id} 的边列表中应包含到 {node5_id} 的边"
724
+
725
+ print("无向图特性验证成功:批量获取的节点边包含所有相关的边(无论方向)")
726
 
727
  # 7. 清理数据
728
  print("== 测试 drop")
 
740
  return False
741
 
742
 
743
+ async def test_graph_undirected_property(storage):
744
+ """
745
+ 专门测试图存储的无向图特性:
746
+ 1. 验证插入一个方向的边后,反向查询是否能获得相同的结果
747
+ 2. 验证边的属性在正向和反向查询中是否一致
748
+ 3. 验证删除一个方向的边后��另一个方向的边是否也被删除
749
+ 4. 验证批量操作中的无向图特性
750
+ """
751
+ try:
752
+ # 清理之前的测试数据
753
+ print("清理之前的测试数据...\n")
754
+ await storage.drop()
755
+
756
+ # 1. 插入测试数据
757
+ # 插入节点1: 计算机科学
758
+ node1_id = "计算机科学"
759
+ node1_data = {
760
+ "entity_id": node1_id,
761
+ "description": "计算机科学是研究计算机及其应用的科学。",
762
+ "keywords": "计算机,科学,技术",
763
+ "entity_type": "学科",
764
+ }
765
+ print(f"插入节点1: {node1_id}")
766
+ await storage.upsert_node(node1_id, node1_data)
767
+
768
+ # 插入节点2: 数据结构
769
+ node2_id = "数据结构"
770
+ node2_data = {
771
+ "entity_id": node2_id,
772
+ "description": "数据结构是计算机科学中的一个基础概念,用于组织和存储数据。",
773
+ "keywords": "数据,结构,组织",
774
+ "entity_type": "概念",
775
+ }
776
+ print(f"插入节点2: {node2_id}")
777
+ await storage.upsert_node(node2_id, node2_data)
778
+
779
+ # 插入节点3: 算法
780
+ node3_id = "算法"
781
+ node3_data = {
782
+ "entity_id": node3_id,
783
+ "description": "算法是解决问题的步骤和方法。",
784
+ "keywords": "算法,步骤,方法",
785
+ "entity_type": "概念",
786
+ }
787
+ print(f"插入节点3: {node3_id}")
788
+ await storage.upsert_node(node3_id, node3_data)
789
+
790
+ # 2. 测试插入边后的无向图特性
791
+ print("\n== 测试插入边后的无向图特性")
792
+
793
+ # 插入边1: 计算机科学 -> 数据结构
794
+ edge1_data = {
795
+ "relationship": "包含",
796
+ "weight": 1.0,
797
+ "description": "计算机科学包含数据结构这个概念",
798
+ }
799
+ print(f"插入边1: {node1_id} -> {node2_id}")
800
+ await storage.upsert_edge(node1_id, node2_id, edge1_data)
801
+
802
+ # 验证正向查询
803
+ forward_edge = await storage.get_edge(node1_id, node2_id)
804
+ print(f"正向边属性: {forward_edge}")
805
+ assert forward_edge is not None, f"未能读取正向边属性: {node1_id} -> {node2_id}"
806
+
807
+ # 验证反向查询
808
+ reverse_edge = await storage.get_edge(node2_id, node1_id)
809
+ print(f"反向边属性: {reverse_edge}")
810
+ assert reverse_edge is not None, f"未能读取反向边属性: {node2_id} -> {node1_id}"
811
+
812
+ # 验证正向和反向边属性是否一致
813
+ assert forward_edge == reverse_edge, "正向和反向边属性不一致,无向图特性验证失败"
814
+ print("无向图特性验证成功:正向和反向边属性一致")
815
+
816
+ # 3. 测试边的度数的无向图特性
817
+ print("\n== 测试边的度数的无向图特性")
818
+
819
+ # 插入边2: 计算机科学 -> 算法
820
+ edge2_data = {
821
+ "relationship": "包含",
822
+ "weight": 1.0,
823
+ "description": "计算机科学包含算法这个概念",
824
+ }
825
+ print(f"插入边2: {node1_id} -> {node3_id}")
826
+ await storage.upsert_edge(node1_id, node3_id, edge2_data)
827
+
828
+ # 验证正向和反向边的度数
829
+ forward_degree = await storage.edge_degree(node1_id, node2_id)
830
+ reverse_degree = await storage.edge_degree(node2_id, node1_id)
831
+ print(f"正向边 {node1_id} -> {node2_id} 的度数: {forward_degree}")
832
+ print(f"反向边 {node2_id} -> {node1_id} 的度数: {reverse_degree}")
833
+ assert forward_degree == reverse_degree, "正向和反向边的度数不一致,无向图特性验证失败"
834
+ print("无向图特性验证成功:正向和反向边的度数一致")
835
+
836
+ # 4. 测试删除边的无向图特性
837
+ print("\n== 测试删除边的无向图特性")
838
+
839
+ # 删除正向边
840
+ print(f"删除边: {node1_id} -> {node2_id}")
841
+ await storage.remove_edges([(node1_id, node2_id)])
842
+
843
+ # 验证正向边是否被删除
844
+ forward_edge = await storage.get_edge(node1_id, node2_id)
845
+ print(f"删除后查询正向边属性 {node1_id} -> {node2_id}: {forward_edge}")
846
+ assert forward_edge is None, f"边 {node1_id} -> {node2_id} 应已被删除"
847
+
848
+ # 验证反向边是否也被删除
849
+ reverse_edge = await storage.get_edge(node2_id, node1_id)
850
+ print(f"删除后查询反向边属性 {node2_id} -> {node1_id}: {reverse_edge}")
851
+ assert reverse_edge is None, f"反向边 {node2_id} -> {node1_id} 也应被删除,无向图特性验证失败"
852
+ print("无向图特性验证成功:删除一个方向的边后,反向边也被删除")
853
+
854
+ # 5. 测试批量操作中的无向图特性
855
+ print("\n== 测试批量操作中的无向图特性")
856
+
857
+ # 重新插入边
858
+ await storage.upsert_edge(node1_id, node2_id, edge1_data)
859
+
860
+ # 批量获取边属性
861
+ edge_dicts = [{"src": node1_id, "tgt": node2_id}, {"src": node1_id, "tgt": node3_id}]
862
+ reverse_edge_dicts = [{"src": node2_id, "tgt": node1_id}, {"src": node3_id, "tgt": node1_id}]
863
+
864
+ edges_dict = await storage.get_edges_batch(edge_dicts)
865
+ reverse_edges_dict = await storage.get_edges_batch(reverse_edge_dicts)
866
+
867
+ print(f"批量获取正向边属性结果: {edges_dict.keys()}")
868
+ print(f"批量获取反向边属性结果: {reverse_edges_dict.keys()}")
869
+
870
+ # 验证正向和反向边的属性是否一致
871
+ for (src, tgt), props in edges_dict.items():
872
+ assert (tgt, src) in reverse_edges_dict, f"反向边 {tgt} -> {src} 应在返回结果中"
873
+ assert props == reverse_edges_dict[(tgt, src)], f"边 {src} -> {tgt} 和反向边 {tgt} -> {src} 的属性不一致"
874
+
875
+ print("无向图特性验证成功:批量获取的正向和反向边属性一致")
876
+
877
+ # 6. 测试批量获取节点边的无向图特性
878
+ print("\n== 测试批量获取节点边的无向图特性")
879
+
880
+ nodes_edges = await storage.get_nodes_edges_batch([node1_id, node2_id])
881
+ print(f"批量获取节点边结果: {nodes_edges.keys()}")
882
+
883
+ # 检查节点1的边是否包含所有相关的边(无论方向)
884
+ node1_edges = nodes_edges[node1_id]
885
+ node2_edges = nodes_edges[node2_id]
886
+
887
+ # 检查节点1是否有到节点2和节点3的边
888
+ has_edge_to_node2 = any((src == node1_id and tgt == node2_id) for src, tgt in node1_edges)
889
+ has_edge_to_node3 = any((src == node1_id and tgt == node3_id) for src, tgt in node1_edges)
890
+
891
+ assert has_edge_to_node2, f"节点 {node1_id} 的边列表中应包含到 {node2_id} 的边"
892
+ assert has_edge_to_node3, f"节点 {node1_id} 的边列表中应包含到 {node3_id} 的边"
893
+
894
+ # 检查节点2是否有到节点1的边
895
+ has_edge_to_node1 = any((src == node2_id and tgt == node1_id) or (src == node1_id and tgt == node2_id) for src, tgt in node2_edges)
896
+ assert has_edge_to_node1, f"节点 {node2_id} 的边列表中应包含与 {node1_id} 的连接"
897
+
898
+ print("无向图特性验证成功:批量获取的节点边包含所有相关的边(无论方向)")
899
+
900
+ # 7. 清理数据
901
+ print("== 测试 drop")
902
+ result = await storage.drop()
903
+ print(f"清理结果: {result}")
904
+ assert (
905
+ result["status"] == "success"
906
+ ), f"清理应成功,实际状态为 {result['status']}"
907
+
908
+ print("\n无向图特性测试完成")
909
+ return True
910
+
911
+ except Exception as e:
912
+ ASCIIColors.red(f"测试过程中发生错误: {str(e)}")
913
+ return False
914
+
915
+
916
  async def main():
917
  """主函数"""
918
  # 显示程序标题
 
948
  ASCIIColors.white("1. 基本测试 (节点和边的插入、读取)")
949
  ASCIIColors.white("2. 高级测试 (度数、标签、知识图谱、删除操作等)")
950
  ASCIIColors.white("3. 批量操作测试 (批量获取节点、边属性和度数等)")
951
+ ASCIIColors.white("4. 无向图特性测试 (验证存储的无向图特性)")
952
+ ASCIIColors.white("5. 全部测试")
953
 
954
+ choice = input("\n请输入选项 (1/2/3/4/5): ")
955
 
956
  if choice == "1":
957
  await test_graph_basic(storage)
 
960
  elif choice == "3":
961
  await test_graph_batch_operations(storage)
962
  elif choice == "4":
963
+ await test_graph_undirected_property(storage)
964
+ elif choice == "5":
965
  ASCIIColors.cyan("\n=== 开始基本测试 ===")
966
  basic_result = await test_graph_basic(storage)
967
 
 
971
 
972
  if advanced_result:
973
  ASCIIColors.cyan("\n=== 开始批量操作测试 ===")
974
+ batch_result = await test_graph_batch_operations(storage)
975
+
976
+ if batch_result:
977
+ ASCIIColors.cyan("\n=== 开始无向图特性测试 ===")
978
+ await test_graph_undirected_property(storage)
979
  else:
980
  ASCIIColors.red("无效的选项")
981