1/*
2Copyright 2017 Google LLC
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package spanner
18
19import (
20	"errors"
21	"testing"
22	"time"
23
24	"cloud.google.com/go/civil"
25	proto3 "github.com/golang/protobuf/ptypes/struct"
26	sppb "google.golang.org/genproto/googleapis/spanner/v1"
27)
28
29type customKeyToString string
30
31func (k customKeyToString) EncodeSpanner() (interface{}, error) {
32	return string(k), nil
33}
34
35type customKeyToInt int
36
37func (k customKeyToInt) EncodeSpanner() (interface{}, error) {
38	return int(k), nil
39}
40
41type customKeyToError struct{}
42
43func (k customKeyToError) EncodeSpanner() (interface{}, error) {
44	return nil, errors.New("always error")
45}
46
47// Test Key.String() and Key.proto().
48func TestKey(t *testing.T) {
49	tm, _ := time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z")
50	dt, _ := civil.ParseDate("2016-11-15")
51	for _, test := range []struct {
52		k         Key
53		wantProto *proto3.ListValue
54		wantStr   string
55	}{
56		{
57			k:         Key{int(1)},
58			wantProto: listValueProto(stringProto("1")),
59			wantStr:   "(1)",
60		},
61		{
62			k:         Key{int8(1)},
63			wantProto: listValueProto(stringProto("1")),
64			wantStr:   "(1)",
65		},
66		{
67			k:         Key{int16(1)},
68			wantProto: listValueProto(stringProto("1")),
69			wantStr:   "(1)",
70		},
71		{
72			k:         Key{int32(1)},
73			wantProto: listValueProto(stringProto("1")),
74			wantStr:   "(1)",
75		},
76		{
77			k:         Key{int64(1)},
78			wantProto: listValueProto(stringProto("1")),
79			wantStr:   "(1)",
80		},
81		{
82			k:         Key{uint8(1)},
83			wantProto: listValueProto(stringProto("1")),
84			wantStr:   "(1)",
85		},
86		{
87			k:         Key{uint16(1)},
88			wantProto: listValueProto(stringProto("1")),
89			wantStr:   "(1)",
90		},
91		{
92			k:         Key{uint32(1)},
93			wantProto: listValueProto(stringProto("1")),
94			wantStr:   "(1)",
95		},
96		{
97			k:         Key{true},
98			wantProto: listValueProto(boolProto(true)),
99			wantStr:   "(true)",
100		},
101		{
102			k:         Key{float32(1.5)},
103			wantProto: listValueProto(floatProto(1.5)),
104			wantStr:   "(1.5)",
105		},
106		{
107			k:         Key{float64(1.5)},
108			wantProto: listValueProto(floatProto(1.5)),
109			wantStr:   "(1.5)",
110		},
111		{
112			k:         Key{"value"},
113			wantProto: listValueProto(stringProto("value")),
114			wantStr:   `("value")`,
115		},
116		{
117			k:         Key{[]byte(nil)},
118			wantProto: listValueProto(nullProto()),
119			wantStr:   "(<null>)",
120		},
121		{
122			k:         Key{[]byte{}},
123			wantProto: listValueProto(stringProto("")),
124			wantStr:   `("")`,
125		},
126		{
127			k:         Key{tm},
128			wantProto: listValueProto(stringProto("2016-11-15T15:04:05.999999999Z")),
129			wantStr:   `("2016-11-15T15:04:05.999999999Z")`,
130		},
131		{k: Key{dt},
132			wantProto: listValueProto(stringProto("2016-11-15")),
133			wantStr:   `("2016-11-15")`,
134		},
135		{
136			k:         Key{[]byte("value")},
137			wantProto: listValueProto(bytesProto([]byte("value"))),
138			wantStr:   `("value")`,
139		},
140		{
141			k:         Key{NullInt64{1, true}},
142			wantProto: listValueProto(stringProto("1")),
143			wantStr:   "(1)",
144		},
145		{
146			k:         Key{NullInt64{2, false}},
147			wantProto: listValueProto(nullProto()),
148			wantStr:   "(<null>)",
149		},
150		{
151			k:         Key{NullFloat64{1.5, true}},
152			wantProto: listValueProto(floatProto(1.5)),
153			wantStr:   "(1.5)",
154		},
155		{
156			k:         Key{NullFloat64{2.0, false}},
157			wantProto: listValueProto(nullProto()),
158			wantStr:   "(<null>)",
159		},
160		{
161			k:         Key{NullBool{true, true}},
162			wantProto: listValueProto(boolProto(true)),
163			wantStr:   "(true)",
164		},
165		{
166			k:         Key{NullBool{true, false}},
167			wantProto: listValueProto(nullProto()),
168			wantStr:   "(<null>)",
169		},
170		{
171			k:         Key{NullString{"value", true}},
172			wantProto: listValueProto(stringProto("value")),
173			wantStr:   `("value")`,
174		},
175		{
176			k:         Key{NullString{"value", false}},
177			wantProto: listValueProto(nullProto()),
178			wantStr:   "(<null>)",
179		},
180		{
181			k:         Key{NullTime{tm, true}},
182			wantProto: listValueProto(timeProto(tm)),
183			wantStr:   `("2016-11-15T15:04:05.999999999Z")`,
184		},
185
186		{
187			k:         Key{NullTime{time.Now(), false}},
188			wantProto: listValueProto(nullProto()),
189			wantStr:   "(<null>)",
190		},
191		{
192			k:         Key{NullDate{dt, true}},
193			wantProto: listValueProto(dateProto(dt)),
194			wantStr:   `("2016-11-15")`,
195		},
196		{
197			k:         Key{NullDate{civil.Date{}, false}},
198			wantProto: listValueProto(nullProto()),
199			wantStr:   "(<null>)",
200		},
201		{
202			k:         Key{int(1), NullString{"value", false}, "value", 1.5, true},
203			wantProto: listValueProto(stringProto("1"), nullProto(), stringProto("value"), floatProto(1.5), boolProto(true)),
204			wantStr:   `(1,<null>,"value",1.5,true)`,
205		},
206		{
207			k:         Key{customKeyToString("value")},
208			wantProto: listValueProto(stringProto("value")),
209			wantStr:   `("value")`,
210		},
211		{
212			k:         Key{customKeyToInt(1)},
213			wantProto: listValueProto(intProto(1)),
214			wantStr:   `(1)`,
215		},
216		{
217			k:         Key{customKeyToError{}},
218			wantProto: nil,
219			wantStr:   `(error)`,
220		},
221	} {
222		if got := test.k.String(); got != test.wantStr {
223			t.Errorf("%v.String() = %v, want %v", test.k, got, test.wantStr)
224		}
225		gotProto, err := test.k.proto()
226		if test.wantProto != nil && err != nil {
227			t.Errorf("%v.proto() returns error %v; want nil error", test.k, err)
228		}
229		if !testEqual(gotProto, test.wantProto) {
230			t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.k, gotProto, test.wantProto)
231		}
232	}
233}
234
235// Test KeyRange.String() and KeyRange.proto().
236func TestKeyRange(t *testing.T) {
237	for _, test := range []struct {
238		kr        KeyRange
239		wantProto *sppb.KeyRange
240		wantStr   string
241	}{
242		{
243			kr: KeyRange{Key{"A"}, Key{"D"}, OpenOpen},
244			wantProto: &sppb.KeyRange{
245				StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("A"))},
246				EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(stringProto("D"))},
247			},
248			wantStr: `(("A"),("D"))`,
249		},
250		{
251			kr: KeyRange{Key{1}, Key{10}, OpenClosed},
252			wantProto: &sppb.KeyRange{
253				StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("1"))},
254				EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))},
255			},
256			wantStr: "((1),(10)]",
257		},
258		{
259			kr: KeyRange{Key{1.5, 2.1, 0.2}, Key{1.9, 0.7}, ClosedOpen},
260			wantProto: &sppb.KeyRange{
261				StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(floatProto(1.5), floatProto(2.1), floatProto(0.2))},
262				EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(floatProto(1.9), floatProto(0.7))},
263			},
264			wantStr: "[(1.5,2.1,0.2),(1.9,0.7))",
265		},
266		{
267			kr: KeyRange{Key{NullInt64{1, true}}, Key{10}, ClosedClosed},
268			wantProto: &sppb.KeyRange{
269				StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(stringProto("1"))},
270				EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))},
271			},
272			wantStr: "[(1),(10)]",
273		},
274		{
275			kr: KeyRange{Key{customKeyToString("A")}, Key{customKeyToString("D")}, OpenOpen},
276			wantProto: &sppb.KeyRange{
277				StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("A"))},
278				EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(stringProto("D"))},
279			},
280			wantStr: `(("A"),("D"))`,
281		},
282	} {
283		if got := test.kr.String(); got != test.wantStr {
284			t.Errorf("%v.String() = %v, want %v", test.kr, got, test.wantStr)
285		}
286		gotProto, err := test.kr.proto()
287		if err != nil {
288			t.Errorf("%v.proto() returns error %v; want nil error", test.kr, err)
289		}
290		if !testEqual(gotProto, test.wantProto) {
291			t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.kr, gotProto.String(), test.wantProto.String())
292		}
293	}
294}
295
296func TestPrefixRange(t *testing.T) {
297	got := Key{1}.AsPrefix()
298	want := KeyRange{Start: Key{1}, End: Key{1}, Kind: ClosedClosed}
299	if !testEqual(got, want) {
300		t.Errorf("got %v, want %v", got, want)
301	}
302}
303
304func TestKeySetFromKeys(t *testing.T) {
305	for i, test := range []struct {
306		ks        KeySet
307		wantProto *sppb.KeySet
308	}{
309		{
310			KeySetFromKeys(),
311			&sppb.KeySet{},
312		},
313		{
314			KeySetFromKeys(Key{1}),
315			&sppb.KeySet{
316				Keys: []*proto3.ListValue{
317					listValueProto(intProto(1)),
318				},
319			},
320		},
321		{
322			KeySetFromKeys(Key{1}, Key{2}),
323			&sppb.KeySet{
324				Keys: []*proto3.ListValue{
325					listValueProto(intProto(1)),
326					listValueProto(intProto(2)),
327				},
328			},
329		},
330		{
331			KeySetFromKeys(Key{1, "one"}, Key{2, "two"}),
332			&sppb.KeySet{
333				Keys: []*proto3.ListValue{
334					listValueProto(intProto(1), stringProto("one")),
335					listValueProto(intProto(2), stringProto("two")),
336				},
337			},
338		},
339	} {
340		gotProto, err := test.ks.keySetProto()
341		if err != nil {
342			t.Errorf("#%d: %v.proto() returns error %v; want nil error", i, test.ks, err)
343		}
344		if !testEqual(gotProto, test.wantProto) {
345			t.Errorf("#%d: %v.proto() = \n%v\nwant:\n%v", i, test.ks, gotProto.String(), test.wantProto.String())
346		}
347	}
348}
349
350func TestKeySets(t *testing.T) {
351	int1 := intProto(1)
352	int2 := intProto(2)
353	int3 := intProto(3)
354	int4 := intProto(4)
355	for i, test := range []struct {
356		ks        KeySet
357		wantProto *sppb.KeySet
358	}{
359		{
360			KeySets(),
361			&sppb.KeySet{},
362		},
363		{
364			Key{4},
365			&sppb.KeySet{
366				Keys: []*proto3.ListValue{listValueProto(int4)},
367			},
368		},
369		{
370			AllKeys(),
371			&sppb.KeySet{All: true},
372		},
373		{
374			KeySets(Key{1, 2}, Key{3, 4}),
375			&sppb.KeySet{
376				Keys: []*proto3.ListValue{
377					listValueProto(int1, int2),
378					listValueProto(int3, int4),
379				},
380			},
381		},
382		{
383			KeyRange{Key{1}, Key{2}, ClosedOpen},
384			&sppb.KeySet{Ranges: []*sppb.KeyRange{
385				{
386					StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)},
387					EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(int2)},
388				},
389			}},
390		},
391		{
392			Key{2}.AsPrefix(),
393			&sppb.KeySet{Ranges: []*sppb.KeyRange{
394				{
395					StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)},
396					EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)},
397				},
398			}},
399		},
400		{
401			KeySets(
402				KeyRange{Key{1}, Key{2}, ClosedClosed},
403				KeyRange{Key{3}, Key{4}, OpenClosed},
404			),
405			&sppb.KeySet{
406				Ranges: []*sppb.KeyRange{
407					{
408						StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)},
409						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)},
410					},
411					{
412						StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int3)},
413						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int4)},
414					},
415				},
416			},
417		},
418		{
419			KeySets(
420				Key{1},
421				KeyRange{Key{2}, Key{3}, ClosedClosed},
422				KeyRange{Key{4}, Key{5}, OpenClosed},
423				KeySets(),
424				Key{6}),
425			&sppb.KeySet{
426				Keys: []*proto3.ListValue{
427					listValueProto(int1),
428					listValueProto(intProto(6)),
429				},
430				Ranges: []*sppb.KeyRange{
431					{
432						StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)},
433						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int3)},
434					},
435					{
436						StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int4)},
437						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(intProto(5))},
438					},
439				},
440			},
441		},
442		{
443			KeySets(
444				Key{1},
445				KeyRange{Key{2}, Key{3}, ClosedClosed},
446				AllKeys(),
447				KeyRange{Key{4}, Key{5}, OpenClosed},
448				Key{6}),
449			&sppb.KeySet{All: true},
450		},
451		{
452			KeySets(
453				Key{customKeyToInt(1), customKeyToInt(2)},
454				Key{customKeyToInt(3), customKeyToInt(4)},
455			),
456			&sppb.KeySet{
457				Keys: []*proto3.ListValue{
458					listValueProto(int1, int2),
459					listValueProto(int3, int4),
460				},
461			},
462		},
463	} {
464		gotProto, err := test.ks.keySetProto()
465		if err != nil {
466			t.Errorf("#%d: %v.proto() returns error %v; want nil error", i, test.ks, err)
467		}
468		if !testEqual(gotProto, test.wantProto) {
469			t.Errorf("#%d: %v.proto() = \n%v\nwant:\n%v", i, test.ks, gotProto.String(), test.wantProto.String())
470		}
471	}
472}
473