func TestFindTypeCycles(t *testing.T) { tests := []struct { desc string typ TypeSpec msgs []string }{ { desc: "self-referential typedef", typ: withTypedef(func(t *TypedefSpec) { t.Name = "foo" t.Target = t }), msgs: []string{ "found a type reference cycle", " foo", "-> foo", }, }, { desc: "mutually recursive references", typ: withTypedef(func(x *TypedefSpec) { x.Name = "foo" x.Target = &TypedefSpec{ Name: "bar", File: "test.thrift", Target: x, } }), msgs: []string{ "found a type reference cycle", " foo", "-> bar", "-> foo", }, }, { desc: "recurse from map", typ: withTypedef(func(t *TypedefSpec) { t.Name = "foo" t.Target = &MapSpec{ KeySpec: &StringSpec{}, ValueSpec: t, } }), msgs: []string{ "found a type reference cycle", " foo", "-> map<string, foo>", "-> foo", }, }, { desc: "recurse from list", typ: withTypedef(func(t *TypedefSpec) { t.Name = "foo" t.Target = &ListSpec{ValueSpec: t} }), msgs: []string{ "found a type reference cycle", " foo", "-> list<foo>", "-> foo", }, }, { desc: "recurse from set", typ: withTypedef(func(t *TypedefSpec) { t.Name = "foo" t.Target = &SetSpec{ValueSpec: t} }), msgs: []string{ "found a type reference cycle", " foo", "-> set<foo>", "-> foo", }, }, { desc: "recurse from struct", typ: withTypedef(func(t *TypedefSpec) { t.Name = "foo" t.Target = &StructSpec{ Name: "bar", File: "test.thrift", Type: ast.StructType, Fields: FieldGroup{ { ID: 1, Name: "foo", Type: t, Required: true, }, }, } }), }, } for _, tt := range tests { typ := mustLink(t, tt.typ, defaultScope) err := findTypeCycles(typ) if len(tt.msgs) > 0 { if assert.Error(t, err, tt.desc) { for _, msg := range tt.msgs { assert.Contains(t, err.Error(), msg) } } } else { assert.NoError(t, err, tt.desc) } } }