@@ -2981,12 +2981,25 @@ def test_class_name_mappings() -> None:
29812981 assert {snm_def .name : snm for snm , snm_def in view .slot_name_mappings ().items ()} == slot_names
29822982
29832983
2984+ """
2985+ Tests of the detect_cycles function, which can identify cyclic relationships between classes, types, and other schema elements.
2986+ """
2987+
2988+
2989+ @pytest .mark .parametrize ("dodgy_input" , [None , [], set (), {}, 12345 , 123.45 , "some string" , ()])
2990+ def test_detect_cycles_input_error (dodgy_input : Any ) -> None :
2991+ """Ensure that `detect_cycles` throws an error if input is not supplied in the appropriate form."""
2992+ with pytest .raises (ValueError , match = "detect_cycles requires a list of values to process" ):
2993+ detect_cycles (lambda x : x , dodgy_input )
2994+
2995+
29842996@pytest .fixture (scope = "module" )
29852997def sv_cycles_schema () -> SchemaView :
29862998 """A schema containing cycles!"""
29872999 return SchemaView (INPUT_DIR_PATH / "cycles.yaml" )
29883000
29893001
3002+ # metadata for elements in the `sv_cycles_schema`
29903003CYCLES = {
29913004 TYPES : {
29923005 # types in cycles, either directly or via ancestors
@@ -3028,8 +3041,8 @@ def sv_cycles_schema() -> SchemaView:
30283041 # key: class name, value: class ancestors
30293042 1 : {
30303043 "BaseClass" : {"BaseClass" },
3031- "MixinA" : {"MixinA" },
3032- "MixinB" : {"MixinB" },
3044+ "MixinA" : {"MixinA" }, # no ID slot
3045+ "MixinB" : {"MixinB" }, # no ID slot
30333046 "NonCycleClassA" : {"NonCycleClassA" , "BaseClass" },
30343047 "NonCycleClassB" : {"MixinA" , "NonCycleClassB" , "NonCycleClassA" , "BaseClass" },
30353048 "NonCycleClassC" : {"MixinB" , "NonCycleClassC" , "NonCycleClassA" , "BaseClass" },
@@ -3048,10 +3061,10 @@ def test_detect_type_cycles_error(sv_cycles_schema: SchemaView, target: str, cyc
30483061 """Test detection of cycles in the types segment of the cycles schema."""
30493062 if fn == "detect_cycles" :
30503063 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
3051- detect_cycles (lambda x : sv_cycles_schema .type_parents ( x ), target )
3064+ detect_cycles (sv_cycles_schema .type_parents , [ target ] )
30523065 elif fn == "graph_closure" :
30533066 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
3054- graph_closure (lambda x : sv_cycles_schema .type_parents ( x ) , target , detect_cycles = True )
3067+ graph_closure (sv_cycles_schema .type_parents , target , detect_cycles = True )
30553068 else :
30563069 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
30573070 sv_cycles_schema .type_ancestors (type_name = target , detect_cycles = True )
@@ -3062,9 +3075,9 @@ def test_detect_type_cycles_error(sv_cycles_schema: SchemaView, target: str, cyc
30623075def test_detect_type_cycles_no_cycles (sv_cycles_schema : SchemaView , target : str , expected : set [str ], fn : str ) -> None :
30633076 """Ensure that types without cycles in their ancestry do not throw an error."""
30643077 if fn == "detect_cycles" :
3065- detect_cycles (lambda x : sv_cycles_schema .type_parents ( x ), target )
3078+ detect_cycles (sv_cycles_schema .type_parents , [ target ] )
30663079 elif fn == "graph_closure" :
3067- got = graph_closure (lambda x : sv_cycles_schema .type_parents ( x ) , target , detect_cycles = True )
3080+ got = graph_closure (sv_cycles_schema .type_parents , target , detect_cycles = True )
30683081 assert set (got ) == expected
30693082 else :
30703083 got = sv_cycles_schema .type_ancestors (target , detect_cycles = True )
@@ -3077,11 +3090,11 @@ def test_detect_class_cycles_error(sv_cycles_schema: SchemaView, target: str, cy
30773090 """Test detection of class cycles in the cycles schema."""
30783091 if fn == "detect_cycles" :
30793092 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
3080- detect_cycles (lambda x : sv_cycles_schema .class_parents ( x ), target )
3093+ detect_cycles (sv_cycles_schema .class_parents , [ target ] )
30813094
30823095 elif fn == "graph_closure" :
30833096 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
3084- graph_closure (lambda x : sv_cycles_schema .class_parents ( x ) , target , detect_cycles = True )
3097+ graph_closure (sv_cycles_schema .class_parents , target , detect_cycles = True )
30853098 else :
30863099 with pytest .raises (ValueError , match = f"Cycle detected at node '{ cycle_start_node } '" ):
30873100 sv_cycles_schema .class_ancestors (target , detect_cycles = True )
@@ -3092,9 +3105,9 @@ def test_detect_class_cycles_error(sv_cycles_schema: SchemaView, target: str, cy
30923105def test_detect_class_cycles_no_cycles (sv_cycles_schema : SchemaView , target : str , expected : set [str ], fn : str ) -> None :
30933106 """Ensure that classes without cycles in their ancestry do not throw an error."""
30943107 if fn == "detect_cycles" :
3095- detect_cycles (lambda x : sv_cycles_schema .class_parents ( x ), target )
3108+ detect_cycles (sv_cycles_schema .class_parents , [ target ] )
30963109 elif fn == "graph_closure" :
3097- got = graph_closure (lambda x : sv_cycles_schema .class_parents ( x ) , target , detect_cycles = True )
3110+ got = graph_closure (sv_cycles_schema .class_parents , target , detect_cycles = True )
30983111 assert set (got ) == expected
30993112 else :
31003113 got = sv_cycles_schema .class_ancestors (target , detect_cycles = True )
@@ -3116,10 +3129,10 @@ def check_recursive_id_slots(class_name: str) -> list[str]:
31163129 # classes with a cycle in the class identifier slot range are cunningly named
31173130 if "IdentifierCycle" in target :
31183131 with pytest .raises (ValueError , match = "Cycle detected at node " ):
3119- detect_cycles (lambda x : check_recursive_id_slots ( x ), target )
3132+ detect_cycles (check_recursive_id_slots , [ target ] )
31203133
31213134 else :
3122- detect_cycles (lambda x : check_recursive_id_slots ( x ), target )
3135+ detect_cycles (check_recursive_id_slots , [ target ] )
31233136
31243137
31253138@pytest .mark .parametrize (
0 commit comments