@@ -1214,3 +1214,54 @@ func TestJSONSchema_GetTopLevelReference(t *testing.T) {
12141214 assert .Equal (t , refTopLevel , entry .Schema )
12151215 })
12161216}
1217+
1218+ // Test GetReferenceChain with circular reference (regression test for infinite loop bug)
1219+ func TestJSONSchema_GetReferenceChain_CircularReference (t * testing.T ) {
1220+ t .Parallel ()
1221+
1222+ t .Run ("circular parent chain terminates without infinite loop" , func (t * testing.T ) {
1223+ t .Parallel ()
1224+ // Create a circular reference: A -> B -> A
1225+ // This simulates a self-referential schema like:
1226+ // Node:
1227+ // properties:
1228+ // next:
1229+ // $ref: "#/components/schemas/Node"
1230+
1231+ schemaA := createSchemaWithRef ("#/components/schemas/Node" )
1232+ schemaB := createSchemaWithRef ("#/components/schemas/Node" )
1233+ childSchema := createSimpleSchema ()
1234+
1235+ // Create circular parent chain: childSchema -> schemaB -> schemaA -> schemaB (circular)
1236+ schemaA .SetParent (schemaB )
1237+ schemaB .SetParent (schemaA )
1238+ childSchema .SetParent (schemaB )
1239+
1240+ // This should NOT hang or infinite loop - it should detect the cycle and return
1241+ chain := childSchema .GetReferenceChain ()
1242+
1243+ // Chain should contain both schemas (visited before cycle detected)
1244+ // The exact length depends on when the cycle is detected, but it should be finite
1245+ assert .NotNil (t , chain , "chain should not be nil even with circular references" )
1246+ assert .LessOrEqual (t , len (chain ), 2 , "chain should be bounded, not infinite" )
1247+ })
1248+
1249+ t .Run ("self-referential parent terminates without infinite loop" , func (t * testing.T ) {
1250+ t .Parallel ()
1251+ // Create a self-referential schema: A -> A
1252+ schemaA := createSchemaWithRef ("#/components/schemas/Self" )
1253+ childSchema := createSimpleSchema ()
1254+
1255+ // Schema A's parent is itself
1256+ schemaA .SetParent (schemaA )
1257+ childSchema .SetParent (schemaA )
1258+
1259+ // This should NOT hang or infinite loop
1260+ chain := childSchema .GetReferenceChain ()
1261+
1262+ // Chain should contain exactly one entry (schemaA visited once before cycle detected)
1263+ assert .NotNil (t , chain , "chain should not be nil even with self-reference" )
1264+ assert .Len (t , chain , 1 , "chain should contain exactly one entry for self-referential parent" )
1265+ assert .Equal (t , "#/components/schemas/Self" , string (chain [0 ].Reference ))
1266+ })
1267+ }
0 commit comments