1// +build go1.8,codegen
2
3package api
4
5import (
6	"reflect"
7	"strconv"
8	"strings"
9	"testing"
10)
11
12func TestUniqueInputAndOutputs(t *testing.T) {
13	const serviceName = "FooService"
14
15	shamelist[serviceName] = map[string]persistAPIType{
16		"OpOutputNoRename": {
17			output: true,
18		},
19		"OpInputNoRename": {
20			input: true,
21		},
22		"OpBothNoRename": {
23			input:  true,
24			output: true,
25		},
26	}
27
28	cases := [][]struct {
29		expectedInput  string
30		expectedOutput string
31		operation      string
32		input          string
33		output         string
34	}{
35		{
36			{
37				expectedInput:  "FooOperationInput",
38				expectedOutput: "FooOperationOutput",
39				operation:      "FooOperation",
40				input:          "FooInputShape",
41				output:         "FooOutputShape",
42			},
43			{
44				expectedInput:  "BarOperationInput",
45				expectedOutput: "BarOperationOutput",
46				operation:      "BarOperation",
47				input:          "FooInputShape",
48				output:         "FooOutputShape",
49			},
50		},
51		{
52			{
53				expectedInput:  "FooOperationInput",
54				expectedOutput: "FooOperationOutput",
55				operation:      "FooOperation",
56				input:          "FooInputShape",
57				output:         "FooOutputShape",
58			},
59			{
60				expectedInput:  "OpOutputNoRenameInput",
61				expectedOutput: "OpOutputNoRenameOutputShape",
62				operation:      "OpOutputNoRename",
63				input:          "OpOutputNoRenameInputShape",
64				output:         "OpOutputNoRenameOutputShape",
65			},
66		},
67		{
68			{
69				expectedInput:  "FooOperationInput",
70				expectedOutput: "FooOperationOutput",
71				operation:      "FooOperation",
72				input:          "FooInputShape",
73				output:         "FooOutputShape",
74			},
75			{
76				expectedInput:  "OpInputNoRenameInputShape",
77				expectedOutput: "OpInputNoRenameOutput",
78				operation:      "OpInputNoRename",
79				input:          "OpInputNoRenameInputShape",
80				output:         "OpInputNoRenameOutputShape",
81			},
82		},
83		{
84			{
85				expectedInput:  "FooOperationInput",
86				expectedOutput: "FooOperationOutput",
87				operation:      "FooOperation",
88				input:          "FooInputShape",
89				output:         "FooOutputShape",
90			},
91			{
92				expectedInput:  "OpInputNoRenameInputShape",
93				expectedOutput: "OpInputNoRenameOutputShape",
94				operation:      "OpBothNoRename",
95				input:          "OpInputNoRenameInputShape",
96				output:         "OpInputNoRenameOutputShape",
97			},
98		},
99	}
100
101	for i, c := range cases {
102		t.Run(strconv.Itoa(i), func(t *testing.T) {
103			a := &API{
104				name:       serviceName,
105				Operations: map[string]*Operation{},
106				Shapes:     map[string]*Shape{},
107			}
108
109			expected := map[string][]string{}
110			for _, op := range c {
111				o := &Operation{
112					Name:         op.operation,
113					ExportedName: op.operation,
114					InputRef: ShapeRef{
115						API:       a,
116						ShapeName: op.input,
117						Shape: &Shape{
118							API:       a,
119							ShapeName: op.input,
120						},
121					},
122					OutputRef: ShapeRef{
123						API:       a,
124						ShapeName: op.output,
125						Shape: &Shape{
126							API:       a,
127							ShapeName: op.output,
128						},
129					},
130				}
131				o.InputRef.Shape.refs = append(o.InputRef.Shape.refs, &o.InputRef)
132				o.OutputRef.Shape.refs = append(o.OutputRef.Shape.refs, &o.OutputRef)
133
134				a.Operations[o.Name] = o
135
136				a.Shapes[op.input] = o.InputRef.Shape
137				a.Shapes[op.output] = o.OutputRef.Shape
138
139				expected[op.operation] = append(expected[op.operation],
140					op.expectedInput,
141					op.expectedOutput,
142				)
143			}
144
145			a.fixStutterNames()
146			a.applyShapeNameAliases()
147			a.createInputOutputShapes()
148			for k, v := range expected {
149				if e, ac := v[0], a.Operations[k].InputRef.Shape.ShapeName; e != ac {
150					t.Errorf("Error %s case: Expected %q, but received %q",
151						k, e, ac)
152				}
153				if e, ac := v[1], a.Operations[k].OutputRef.Shape.ShapeName; e != ac {
154					t.Errorf("Error %s case: Expected %q, but received %q",
155						k, e, ac)
156				}
157			}
158		})
159
160	}
161}
162
163func TestCollidingFields(t *testing.T) {
164	cases := map[string]struct {
165		MemberRefs  map[string]*ShapeRef
166		Expect      []string
167		IsException bool
168	}{
169		"SimpleMembers": {
170			MemberRefs: map[string]*ShapeRef{
171				"Code":     {},
172				"Foo":      {},
173				"GoString": {},
174				"Message":  {},
175				"OrigErr":  {},
176				"SetFoo":   {},
177				"String":   {},
178				"Validate": {},
179			},
180			Expect: []string{
181				"Code",
182				"Foo",
183				"GoString_",
184				"Message",
185				"OrigErr",
186				"SetFoo_",
187				"String_",
188				"Validate_",
189			},
190		},
191		"ExceptionShape": {
192			IsException: true,
193			MemberRefs: map[string]*ShapeRef{
194				"Code":    {},
195				"Message": {},
196				"OrigErr": {},
197				"Other":   {},
198				"String":  {},
199			},
200			Expect: []string{
201				"Code_",
202				"Message_",
203				"OrigErr_",
204				"Other",
205				"String_",
206			},
207		},
208	}
209
210	for k, c := range cases {
211		t.Run(k, func(t *testing.T) {
212			a := &API{
213				Shapes: map[string]*Shape{
214					"shapename": {
215						ShapeName:  k,
216						MemberRefs: c.MemberRefs,
217						Exception:  c.IsException,
218					},
219				},
220			}
221
222			a.renameCollidingFields()
223
224			for i, name := range a.Shapes["shapename"].MemberNames() {
225				if e, a := c.Expect[i], name; e != a {
226					t.Errorf("expect %v, got %v", e, a)
227				}
228			}
229		})
230	}
231}
232
233func TestCollidingFields_MaintainOriginalName(t *testing.T) {
234	cases := map[string]struct {
235		MemberRefs map[string]*ShapeRef
236		Expect     map[string]*ShapeRef
237	}{
238		"NoLocationName": {
239			MemberRefs: map[string]*ShapeRef{
240				"String": {},
241			},
242			Expect: map[string]*ShapeRef{
243				"String_": {LocationName: "String"},
244			},
245		},
246		"ExitingLocationName": {
247			MemberRefs: map[string]*ShapeRef{
248				"String": {LocationName: "OtherName"},
249			},
250			Expect: map[string]*ShapeRef{
251				"String_": {LocationName: "OtherName"},
252			},
253		},
254	}
255
256	for k, c := range cases {
257		t.Run(k, func(t *testing.T) {
258			a := &API{
259				Shapes: map[string]*Shape{
260					"shapename": {
261						ShapeName:  k,
262						MemberRefs: c.MemberRefs,
263					},
264				},
265			}
266
267			a.renameCollidingFields()
268
269			if e, a := c.Expect, a.Shapes["shapename"].MemberRefs; !reflect.DeepEqual(e, a) {
270				t.Errorf("expect %v, got %v", e, a)
271			}
272		})
273	}
274}
275
276func TestCreateInputOutputShapes(t *testing.T) {
277	meta := Metadata{
278		APIVersion:          "0000-00-00",
279		EndpointPrefix:      "rpcservice",
280		JSONVersion:         "1.1",
281		Protocol:            "json",
282		ServiceAbbreviation: "RPCService",
283		ServiceFullName:     "RPC Service",
284		ServiceID:           "RPCService",
285		SignatureVersion:    "v4",
286		TargetPrefix:        "RPCService_00000000",
287		UID:                 "RPCService-0000-00-00",
288	}
289
290	type OpExpect struct {
291		Input  string
292		Output string
293	}
294
295	cases := map[string]struct {
296		API          *API
297		ExpectOps    map[string]OpExpect
298		ExpectShapes []string
299	}{
300		"allRename": {
301			API: &API{Metadata: meta,
302				Operations: map[string]*Operation{
303					"FirstOp": {Name: "FirstOp",
304						InputRef:  ShapeRef{ShapeName: "FirstOpRequest"},
305						OutputRef: ShapeRef{ShapeName: "FirstOpResponse"},
306					},
307					"SecondOp": {Name: "SecondOp",
308						InputRef:  ShapeRef{ShapeName: "SecondOpRequest"},
309						OutputRef: ShapeRef{ShapeName: "SecondOpResponse"},
310					},
311				},
312				Shapes: map[string]*Shape{
313					"FirstOpRequest":   {ShapeName: "FirstOpRequest", Type: "structure"},
314					"FirstOpResponse":  {ShapeName: "FirstOpResponse", Type: "structure"},
315					"SecondOpRequest":  {ShapeName: "SecondOpRequest", Type: "structure"},
316					"SecondOpResponse": {ShapeName: "SecondOpResponse", Type: "structure"},
317				},
318			},
319			ExpectOps: map[string]OpExpect{
320				"FirstOp": {
321					Input:  "FirstOpInput",
322					Output: "FirstOpOutput",
323				},
324				"SecondOp": {
325					Input:  "SecondOpInput",
326					Output: "SecondOpOutput",
327				},
328			},
329			ExpectShapes: []string{
330				"FirstOpInput", "FirstOpOutput",
331				"SecondOpInput", "SecondOpOutput",
332			},
333		},
334		"noRename": {
335			API: &API{Metadata: meta,
336				Operations: map[string]*Operation{
337					"FirstOp": {Name: "FirstOp",
338						InputRef:  ShapeRef{ShapeName: "FirstOpInput"},
339						OutputRef: ShapeRef{ShapeName: "FirstOpOutput"},
340					},
341					"SecondOp": {Name: "SecondOp",
342						InputRef:  ShapeRef{ShapeName: "SecondOpInput"},
343						OutputRef: ShapeRef{ShapeName: "SecondOpOutput"},
344					},
345				},
346				Shapes: map[string]*Shape{
347					"FirstOpInput":   {ShapeName: "FirstOpInput", Type: "structure"},
348					"FirstOpOutput":  {ShapeName: "FirstOpOutput", Type: "structure"},
349					"SecondOpInput":  {ShapeName: "SecondOpInput", Type: "structure"},
350					"SecondOpOutput": {ShapeName: "SecondOpOutput", Type: "structure"},
351				},
352			},
353			ExpectOps: map[string]OpExpect{
354				"FirstOp": {
355					Input:  "FirstOpInput",
356					Output: "FirstOpOutput",
357				},
358				"SecondOp": {
359					Input:  "SecondOpInput",
360					Output: "SecondOpOutput",
361				},
362			},
363			ExpectShapes: []string{
364				"FirstOpInput", "FirstOpOutput",
365				"SecondOpInput", "SecondOpOutput",
366			},
367		},
368		"renameWithNested": {
369			API: &API{Metadata: meta,
370				Operations: map[string]*Operation{
371					"FirstOp": {Name: "FirstOp",
372						InputRef:  ShapeRef{ShapeName: "FirstOpWriteMe"},
373						OutputRef: ShapeRef{ShapeName: "FirstOpReadMe"},
374					},
375					"SecondOp": {Name: "SecondOp",
376						InputRef:  ShapeRef{ShapeName: "SecondOpWriteMe"},
377						OutputRef: ShapeRef{ShapeName: "SecondOpReadMe"},
378					},
379				},
380				Shapes: map[string]*Shape{
381					"FirstOpWriteMe": {ShapeName: "FirstOpWriteMe", Type: "structure",
382						MemberRefs: map[string]*ShapeRef{
383							"Foo": {ShapeName: "String"},
384						},
385					},
386					"FirstOpReadMe": {ShapeName: "FirstOpReadMe", Type: "structure",
387						MemberRefs: map[string]*ShapeRef{
388							"Bar":  {ShapeName: "Struct"},
389							"Once": {ShapeName: "Once"},
390						},
391					},
392					"SecondOpWriteMe": {ShapeName: "SecondOpWriteMe", Type: "structure"},
393					"SecondOpReadMe":  {ShapeName: "SecondOpReadMe", Type: "structure"},
394					"Once":            {ShapeName: "Once", Type: "string"},
395					"String":          {ShapeName: "String", Type: "string"},
396					"Struct": {ShapeName: "Struct", Type: "structure",
397						MemberRefs: map[string]*ShapeRef{
398							"Foo": {ShapeName: "String"},
399							"Bar": {ShapeName: "Struct"},
400						},
401					},
402				},
403			},
404			ExpectOps: map[string]OpExpect{
405				"FirstOp": {
406					Input:  "FirstOpInput",
407					Output: "FirstOpOutput",
408				},
409				"SecondOp": {
410					Input:  "SecondOpInput",
411					Output: "SecondOpOutput",
412				},
413			},
414			ExpectShapes: []string{
415				"FirstOpInput", "FirstOpOutput",
416				"Once",
417				"SecondOpInput", "SecondOpOutput",
418				"String", "Struct",
419			},
420		},
421		"aliasedInput": {
422			API: &API{Metadata: meta,
423				Operations: map[string]*Operation{
424					"FirstOp": {Name: "FirstOp",
425						InputRef:  ShapeRef{ShapeName: "FirstOpRequest"},
426						OutputRef: ShapeRef{ShapeName: "FirstOpResponse"},
427					},
428				},
429				Shapes: map[string]*Shape{
430					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure",
431						AliasedShapeName: true,
432					},
433					"FirstOpResponse": {ShapeName: "FirstOpResponse", Type: "structure"},
434				},
435			},
436			ExpectOps: map[string]OpExpect{
437				"FirstOp": {
438					Input:  "FirstOpRequest",
439					Output: "FirstOpOutput",
440				},
441			},
442			ExpectShapes: []string{
443				"FirstOpOutput", "FirstOpRequest",
444			},
445		},
446		"aliasedOutput": {
447			API: &API{Metadata: meta,
448				Operations: map[string]*Operation{
449					"FirstOp": {Name: "FirstOp",
450						InputRef:  ShapeRef{ShapeName: "FirstOpRequest"},
451						OutputRef: ShapeRef{ShapeName: "FirstOpResponse"},
452					},
453				},
454				Shapes: map[string]*Shape{
455					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure"},
456					"FirstOpResponse": {ShapeName: "FirstOpResponse", Type: "structure",
457						AliasedShapeName: true,
458					},
459				},
460			},
461			ExpectOps: map[string]OpExpect{
462				"FirstOp": {
463					Input:  "FirstOpInput",
464					Output: "FirstOpResponse",
465				},
466			},
467			ExpectShapes: []string{
468				"FirstOpInput", "FirstOpResponse",
469			},
470		},
471		"resusedShape": {
472			API: &API{Metadata: meta,
473				Operations: map[string]*Operation{
474					"FirstOp": {Name: "FirstOp",
475						InputRef:  ShapeRef{ShapeName: "FirstOpRequest"},
476						OutputRef: ShapeRef{ShapeName: "ReusedShape"},
477					},
478				},
479				Shapes: map[string]*Shape{
480					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure",
481						MemberRefs: map[string]*ShapeRef{
482							"Foo": {ShapeName: "ReusedShape"},
483							"ooF": {ShapeName: "ReusedShapeList"},
484						},
485					},
486					"ReusedShape": {ShapeName: "ReusedShape", Type: "structure"},
487					"ReusedShapeList": {ShapeName: "ReusedShapeList", Type: "list",
488						MemberRef: ShapeRef{ShapeName: "ReusedShape"},
489					},
490				},
491			},
492			ExpectOps: map[string]OpExpect{
493				"FirstOp": {
494					Input:  "FirstOpInput",
495					Output: "FirstOpOutput",
496				},
497			},
498			ExpectShapes: []string{
499				"FirstOpInput", "FirstOpOutput",
500				"ReusedShape", "ReusedShapeList",
501			},
502		},
503		"aliasedResusedShape": {
504			API: &API{Metadata: meta,
505				Operations: map[string]*Operation{
506					"FirstOp": {Name: "FirstOp",
507						InputRef:  ShapeRef{ShapeName: "FirstOpRequest"},
508						OutputRef: ShapeRef{ShapeName: "ReusedShape"},
509					},
510				},
511				Shapes: map[string]*Shape{
512					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure",
513						MemberRefs: map[string]*ShapeRef{
514							"Foo": {ShapeName: "ReusedShape"},
515							"ooF": {ShapeName: "ReusedShapeList"},
516						},
517					},
518					"ReusedShape": {ShapeName: "ReusedShape", Type: "structure",
519						AliasedShapeName: true,
520					},
521					"ReusedShapeList": {ShapeName: "ReusedShapeList", Type: "list",
522						MemberRef: ShapeRef{ShapeName: "ReusedShape"},
523					},
524				},
525			},
526			ExpectOps: map[string]OpExpect{
527				"FirstOp": {
528					Input:  "FirstOpInput",
529					Output: "ReusedShape",
530				},
531			},
532			ExpectShapes: []string{
533				"FirstOpInput",
534				"ReusedShape", "ReusedShapeList",
535			},
536		},
537		"unsetInput": {
538			API: &API{Metadata: meta,
539				Operations: map[string]*Operation{
540					"FirstOp": {Name: "FirstOp",
541						OutputRef: ShapeRef{ShapeName: "FirstOpResponse"},
542					},
543				},
544				Shapes: map[string]*Shape{
545					"FirstOpResponse": {ShapeName: "FirstOpResponse", Type: "structure"},
546				},
547			},
548			ExpectOps: map[string]OpExpect{
549				"FirstOp": {
550					Input:  "FirstOpInput",
551					Output: "FirstOpOutput",
552				},
553			},
554			ExpectShapes: []string{
555				"FirstOpInput", "FirstOpOutput",
556			},
557		},
558		"unsetOutput": {
559			API: &API{Metadata: meta,
560				Operations: map[string]*Operation{
561					"FirstOp": {Name: "FirstOp",
562						InputRef: ShapeRef{ShapeName: "FirstOpRequest"},
563					},
564				},
565				Shapes: map[string]*Shape{
566					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure"},
567				},
568			},
569			ExpectOps: map[string]OpExpect{
570				"FirstOp": {
571					Input:  "FirstOpInput",
572					Output: "FirstOpOutput",
573				},
574			},
575			ExpectShapes: []string{
576				"FirstOpInput", "FirstOpOutput",
577			},
578		},
579		"collidingShape": {
580			API: &API{
581				name:     "APIClientName",
582				Metadata: meta,
583				Operations: map[string]*Operation{
584					"FirstOp": {Name: "FirstOp",
585						InputRef: ShapeRef{ShapeName: "FirstOpRequest"},
586					},
587				},
588				Shapes: map[string]*Shape{
589					"FirstOpRequest": {ShapeName: "FirstOpRequest", Type: "structure",
590						MemberRefs: map[string]*ShapeRef{
591							"Foo": {ShapeName: "APIClientName"},
592							"ooF": {ShapeName: "APIClientNameList"},
593						},
594					},
595					"APIClientName": {
596						ShapeName: "APIClientName", Type: "structure",
597					},
598					"APIClientNameList": {
599						ShapeName: "APIClientNameList", Type: "list",
600						MemberRef: ShapeRef{ShapeName: "APIClientName"},
601					},
602				},
603			},
604			ExpectOps: map[string]OpExpect{
605				"FirstOp": {
606					Input:  "FirstOpInput",
607					Output: "FirstOpOutput",
608				},
609			},
610			ExpectShapes: []string{
611				"APIClientNameList", "APIClientName_",
612				"FirstOpInput", "FirstOpOutput",
613			},
614		},
615	}
616
617	for name, c := range cases {
618		t.Run(name, func(t *testing.T) {
619			a := c.API
620			a.Setup()
621
622			for opName, op := range a.Operations {
623				if e, a := op.InputRef.ShapeName, op.InputRef.Shape.ShapeName; e != a {
624					t.Errorf("expect input ref and shape names to match, %s, %s", e, a)
625				}
626				if e, a := c.ExpectOps[opName].Input, op.InputRef.ShapeName; e != a {
627					t.Errorf("expect %v input shape, got %v", e, a)
628				}
629
630				if e, a := op.OutputRef.ShapeName, op.OutputRef.Shape.ShapeName; e != a {
631					t.Errorf("expect output ref and shape names to match, %s, %s", e, a)
632				}
633				if e, a := c.ExpectOps[opName].Output, op.OutputRef.ShapeName; e != a {
634					t.Errorf("expect %v output shape, got %v", e, a)
635				}
636			}
637
638			if e, a := c.ExpectShapes, a.ShapeNames(); !reflect.DeepEqual(e, a) {
639				t.Errorf("expect %v shapes, got %v", e, a)
640			}
641		})
642	}
643}
644
645func TestValidateShapeNameMethod(t *testing.T) {
646	cases := map[string]struct {
647		inputShapeName    string
648		shapeType         string
649		expectedShapeName string
650		expectedError     string
651	}{
652		"empty case": {
653			inputShapeName:    "",
654			shapeType:         "structure",
655			expectedShapeName: "",
656			expectedError:     "invalid shape name found",
657		},
658		"No rename": {
659			inputShapeName:    "Sample123Shape",
660			shapeType:         "structure",
661			expectedShapeName: "Sample123Shape",
662		},
663		"starts with underscores": {
664			inputShapeName:    "__Sample123Shape",
665			shapeType:         "structure",
666			expectedShapeName: "Sample123Shape",
667		},
668		"Contains underscores": {
669			inputShapeName:    "__sample_123_shape__",
670			shapeType:         "structure",
671			expectedShapeName: "Sample123Shape",
672		},
673		"Starts with numeric character": {
674			inputShapeName:    "123__sampleShape",
675			shapeType:         "structure",
676			expectedShapeName: "",
677			expectedError:     "invalid shape name found",
678		},
679		"Starts with non alphabetic or non underscore character": {
680			inputShapeName:    "&&SampleShape",
681			shapeType:         "structure",
682			expectedShapeName: "",
683			expectedError:     "invalid shape name found",
684		},
685		"Contains non Alphanumeric or non underscore character": {
686			inputShapeName:    "Sample&__Shape",
687			shapeType:         "structure",
688			expectedShapeName: "",
689			expectedError:     "invalid shape name found",
690		},
691		"Renamed Shape already exists": {
692			inputShapeName:    "__sample_shape",
693			shapeType:         "structure",
694			expectedShapeName: "",
695			expectedError:     "rename would result in shape name collision",
696		},
697		"empty case for enums shape type": {
698			inputShapeName:    "",
699			shapeType:         "string",
700			expectedShapeName: "",
701			expectedError:     "invalid shape name found",
702		},
703		"No rename for enums shape type": {
704			inputShapeName:    "Sample123Shape",
705			shapeType:         "string",
706			expectedShapeName: "Sample123Shape",
707		},
708		"starts with underscores for enums shape type": {
709			inputShapeName:    "__Sample123Shape",
710			shapeType:         "string",
711			expectedShapeName: "Sample123Shape",
712		},
713		"Contains underscores for enums shape type": {
714			inputShapeName:    "__sample_123_shape__",
715			shapeType:         "string",
716			expectedShapeName: "Sample123Shape",
717		},
718		"Starts with numeric character for enums shape type": {
719			inputShapeName:    "123__sampleShape",
720			shapeType:         "string",
721			expectedShapeName: "",
722			expectedError:     "invalid shape name found",
723		},
724		"Starts with non alphabetic or non underscore character for enums shape type": {
725			inputShapeName:    "&&SampleShape",
726			shapeType:         "string",
727			expectedShapeName: "",
728			expectedError:     "invalid shape name found",
729		},
730		"Contains non Alphanumeric or non underscore character for enums shape type": {
731			inputShapeName:    "Sample&__Shape",
732			shapeType:         "string",
733			expectedShapeName: "",
734			expectedError:     "invalid shape name found",
735		},
736		"Renamed Shape already exists for enums shape type": {
737			inputShapeName:    "__sample_shape",
738			shapeType:         "string",
739			expectedShapeName: "",
740			expectedError:     "rename would result in shape name collision",
741		},
742	}
743
744	for name, c := range cases {
745		operation := "FooOperation"
746		t.Run(name, func(t *testing.T) {
747			a := &API{
748				Operations: map[string]*Operation{},
749				Shapes:     map[string]*Shape{},
750			}
751			// add another shape with name SampleShape to check for collision
752			a.Shapes["SampleShape"] = &Shape{ShapeName: "SampleShape"}
753			o := &Operation{
754				Name:         operation,
755				ExportedName: operation,
756				InputRef: ShapeRef{
757					API:       a,
758					ShapeName: c.inputShapeName,
759					Shape: &Shape{
760						API:       a,
761						ShapeName: c.inputShapeName,
762						Type:      c.shapeType,
763						Enum:      []string{"x"},
764					},
765				},
766			}
767			o.InputRef.Shape.refs = append(o.InputRef.Shape.refs, &o.InputRef)
768			a.Operations[o.Name] = o
769			a.Shapes[c.inputShapeName] = o.InputRef.Shape
770
771			err := a.validateShapeNames()
772			if err != nil || c.expectedError != "" {
773				if err == nil {
774					t.Fatalf("Received no error, expected error with log: \n \t %v ", c.expectedError)
775				}
776				if c.expectedError == "" {
777					t.Fatalf("Expected no error, got %v", err.Error())
778				}
779				if e, a := err.Error(), c.expectedError; !strings.Contains(e, a) {
780					t.Fatalf("Expected to receive error containing %v, got %v", e, a)
781				}
782				return
783			}
784
785			if e, a := c.expectedShapeName, o.InputRef.Shape.ShapeName; e != a {
786				t.Fatalf("Expected shape name to be %v, got %v", e, a)
787			}
788		})
789	}
790}
791