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