diff --git a/validator/rules/overlapping_fields_can_be_merged.go b/validator/rules/overlapping_fields_can_be_merged.go index 5cd028df..cc0a66d8 100644 --- a/validator/rules/overlapping_fields_can_be_merged.go +++ b/validator/rules/overlapping_fields_can_be_merged.go @@ -478,14 +478,16 @@ func sameArguments(args1 []*ast.Argument, args2 []*ast.Argument) bool { return false } for _, arg1 := range args1 { + var matched bool for _, arg2 := range args2 { - if arg1.Name != arg2.Name { - return false - } - if !sameValue(arg1.Value, arg2.Value) { - return false + if arg1.Name == arg2.Name && sameValue(arg1.Value, arg2.Value) { + matched = true + break } } + if !matched { + return false + } } return true } diff --git a/validator/rules/overlapping_fields_can_be_merged_test.go b/validator/rules/overlapping_fields_can_be_merged_test.go new file mode 100644 index 00000000..d7bdb0d6 --- /dev/null +++ b/validator/rules/overlapping_fields_can_be_merged_test.go @@ -0,0 +1,143 @@ +package validator + +import ( + "testing" + + "github.com/vektah/gqlparser/v2/ast" +) + +func Test_sameArguments(t *testing.T) { + tests := map[string]struct { + args func() (args1, args2 []*ast.Argument) + result bool + }{ + "both argument lists empty": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return nil, nil + }, + result: true, + }, + "args 1 empty, args 2 not": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return nil, []*ast.Argument{ + { + Name: "thing", + Value: &ast.Value{Raw: "a thing"}, + Position: &ast.Position{}, + }, + } + }, + result: false, + }, + "args 2 empty, args 1 not": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return []*ast.Argument{ + { + Name: "thing", + Value: &ast.Value{Raw: "a thing"}, + Position: &ast.Position{}, + }, + }, nil + }, + result: false, + }, + "args 1 mismatches args 2 names": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + }, + []*ast.Argument{ + { + Name: "thing2", + Value: &ast.Value{Raw: "2 thing"}, + Position: &ast.Position{}, + }, + } + }, + result: false, + }, + "args 1 mismatches args 2 values": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + }, + []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "2 thing"}, + Position: &ast.Position{}, + }, + } + }, + result: false, + }, + "args 1 matches args 2 names and values": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + }, + []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + } + }, + result: true, + }, + "args 1 matches args 2 names and values where multiple exist in various orders": { + args: func() (args1 []*ast.Argument, args2 []*ast.Argument) { + return []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + { + Name: "thing2", + Value: &ast.Value{Raw: "2 thing"}, + Position: &ast.Position{}, + }, + }, + []*ast.Argument{ + { + Name: "thing1", + Value: &ast.Value{Raw: "1 thing"}, + Position: &ast.Position{}, + }, + { + Name: "thing2", + Value: &ast.Value{Raw: "2 thing"}, + Position: &ast.Position{}, + }, + } + }, + result: true, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + args1, args2 := tc.args() + + resp := sameArguments(args1, args2) + + if resp != tc.result { + t.Fatalf("Expected %t got %t", tc.result, resp) + } + }) + } +}