1 package testing
2
3 import (
4 "bytes"
5 "io"
6 "io/ioutil"
7 "math"
8 "strings"
9 "testing"
10
11 "github.com/aws/smithy-go/middleware"
12 "github.com/aws/smithy-go/ptr"
13 )
14
15 func TestCompareValues(t *testing.T) {
16 const float64NaN = 0x7fffffff_ffffffff
17
18 cases := map[string]struct {
19 A, B interface{}
20 ExpectErr string
21 }{
22 "totally different types": {
23 A: 1,
24 B: struct {
25 Foo string
26 Bar int
27 }{
28 Foo: "abc",
29 Bar: 123,
30 },
31 ExpectErr: "<root>: kind int != struct",
32 },
33 "simple match": {
34 A: struct {
35 Foo string
36 Bar int
37 Metadata middleware.Metadata
38 }{
39 Foo: "abc",
40 Bar: 123,
41 Metadata: func() middleware.Metadata {
42 var md middleware.Metadata
43 md.Set(1, 1)
44 return md
45 }(),
46 },
47 B: struct {
48 Foo string
49 Bar int
50 Metadata middleware.Metadata
51 }{
52 Foo: "abc",
53 Bar: 123,
54 Metadata: middleware.Metadata{},
55 },
56 },
57 "simple diff": {
58 A: struct {
59 Foo string
60 Bar int
61 }{
62 Foo: "abc",
63 Bar: 123,
64 },
65 B: struct {
66 Foo string
67 Bar int
68 }{
69 Foo: "abc",
70 Bar: 456,
71 },
72 ExpectErr: "<root>.Bar: 123 != 456",
73 },
74 "reader match": {
75 A: struct {
76 Foo io.Reader
77 Bar int
78 }{
79 Foo: bytes.NewBuffer([]byte("abc123")),
80 Bar: 123,
81 },
82 B: struct {
83 Foo io.Reader
84 Bar int
85 }{
86 Foo: ioutil.NopCloser(strings.NewReader("abc123")),
87 Bar: 123,
88 },
89 },
90 "reader diff": {
91 A: struct {
92 Foo io.Reader
93 Bar int
94 }{
95 Foo: bytes.NewBuffer([]byte("abc123")),
96 Bar: 123,
97 },
98 B: struct {
99 Foo io.Reader
100 Bar int
101 }{
102 Foo: ioutil.NopCloser(strings.NewReader("123abc")),
103 Bar: 123,
104 },
105 ExpectErr: "<root>.Foo: bytes do not match",
106 },
107 "float match": {
108 A: struct {
109 Foo float64
110 Bar int
111 }{
112 Foo: math.Float64frombits(float64NaN),
113 Bar: 123,
114 },
115 B: struct {
116 Foo float64
117 Bar int
118 }{
119 Foo: math.Float64frombits(float64NaN),
120 Bar: 123,
121 },
122 },
123 "float diff": {
124 A: struct {
125 Foo float64
126 Bar int
127 }{
128 Foo: math.Float64frombits(float64NaN),
129 Bar: 123,
130 },
131 B: struct {
132 Foo float64
133 Bar int
134 }{
135 Foo: math.Float64frombits(float64NaN - 1),
136 Bar: 123,
137 },
138 ExpectErr: "<root>.Foo: float 0x7fffffffffffffff != 0x7ffffffffffffffe",
139 },
140 "document equal": {
141 A: &mockDocumentMarshaler{[]byte("123"), nil},
142 B: &mockDocumentMarshaler{[]byte("123"), nil},
143 },
144 "document unequal": {
145 A: &mockDocumentMarshaler{[]byte("123"), nil},
146 B: &mockDocumentMarshaler{[]byte("124"), nil},
147 ExpectErr: "<root>: document values unequal",
148 },
149 "slice equal": {
150 A: []struct {
151 Bar int
152 }{{0}, {1}},
153 B: []struct {
154 Bar int
155 }{{0}, {1}},
156 },
157 "slice length unequal": {
158 A: []struct {
159 Bar int
160 }{{0}},
161 B: []struct {
162 Bar int
163 }{{0}, {1}},
164 ExpectErr: "slice length unequal",
165 },
166 "slice value unequal": {
167 A: []struct {
168 Bar int
169 }{{2}, {1}, {0}},
170 B: []struct {
171 Bar int
172 }{{2}, {0}, {1}},
173 ExpectErr: "<root>[1].Bar: 1 != 0",
174 },
175 "map equal": {
176 A: map[string]struct {
177 Bar int
178 }{
179 "foo": {0},
180 "bar": {1},
181 },
182 B: map[string]struct {
183 Bar int
184 }{
185 "bar": {1},
186 "foo": {0},
187 },
188 },
189 "map length unequal": {
190 A: map[string]struct {
191 Bar int
192 }{
193 "foo": {0},
194 "bar": {1},
195 },
196 B: map[string]struct {
197 Bar int
198 }{
199 "foo": {0},
200 },
201 ExpectErr: "map length unequal",
202 },
203 "map value unequal": {
204 A: map[string]struct {
205 IntField int
206 }{
207 "foo": {0},
208 "bar": {1},
209 },
210 B: map[string]struct {
211 IntField int
212 }{
213 "bar": {1},
214 "foo": {1},
215 },
216 ExpectErr: `<root>["foo"].IntField: 0 != 1`,
217 },
218 "handles deref, nil equal": {
219 A: struct {
220 Int *int
221 }{nil},
222 B: struct {
223 Int *int
224 }{nil},
225 },
226 "handles deref, value equal": {
227 A: struct {
228 Int *int
229 }{ptr.Int(12)},
230 B: struct {
231 Int *int
232 }{ptr.Int(12)},
233 },
234 "handles deref, different types are unequal": {
235 A: struct {
236 Int *int
237 }{nil},
238 B: struct {
239 Int *string
240 }{nil},
241 ExpectErr: "<root>.Int: type mismatch",
242 },
243 "handles deref, unequal": {
244 A: struct {
245 Int *int
246 }{ptr.Int(12)},
247 B: struct {
248 Int *int
249 }{nil},
250 ExpectErr: "<root>.Int: non-nil != nil",
251 },
252 "handles deref, unequal switched": {
253 A: struct {
254 Int *int
255 }{nil},
256 B: struct {
257 Int *int
258 }{ptr.Int(12)},
259 ExpectErr: "<root>.Int: nil != non-nil",
260 },
261 }
262
263 for name, c := range cases {
264 t.Run(name, func(t *testing.T) {
265 err := CompareValues(c.A, c.B)
266
267 if len(c.ExpectErr) != 0 {
268 if err == nil {
269 t.Fatalf("expect error, got none")
270 }
271 if e, a := c.ExpectErr, err.Error(); !strings.Contains(a, e) {
272 t.Fatalf("expect error to contain %v, got %v", e, a)
273 }
274 return
275 }
276 if err != nil {
277 t.Fatalf("expect no error, got %v", err)
278 }
279 })
280 }
281 }
282
283 func TestCompareValues_Document(t *testing.T) {
284 cases := map[string]struct {
285 A, B interface{}
286 ExpectErr string
287 }{
288 "equal": {
289 A: &mockDocumentMarshaler{[]byte("123"), nil},
290 B: &mockDocumentMarshaler{[]byte("123"), nil},
291 },
292 "unequal": {
293 A: &mockDocumentMarshaler{[]byte("123"), nil},
294 B: &mockDocumentMarshaler{[]byte("124"), nil},
295 ExpectErr: "<root>: document values unequal",
296 },
297 }
298 for name, c := range cases {
299 t.Run(name, func(t *testing.T) {
300 err := CompareValues(c.A, c.B)
301
302 if len(c.ExpectErr) != 0 {
303 if err == nil {
304 t.Errorf("expect error, got none")
305 }
306 if e, a := c.ExpectErr, err.Error(); !strings.Contains(a, e) {
307 t.Errorf("expect error to contain %v, got %v", e, a)
308 }
309 return
310 }
311 if err != nil {
312 t.Errorf("expect no error, got %v", err)
313 }
314 })
315 }
316 }
317
318 type mockDocumentMarshaler struct {
319 p []byte
320 err error
321 }
322
323 var _ documentInterface = (*mockDocumentMarshaler)(nil)
324
325 func (m *mockDocumentMarshaler) MarshalSmithyDocument() ([]byte, error) { return m.p, m.err }
326 func (m *mockDocumentMarshaler) UnmarshalSmithyDocument(v interface{}) error { return nil }
327
View as plain text