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	"testing"
21	"time"
22
23	"cloud.google.com/go/civil"
24	proto3 "github.com/golang/protobuf/ptypes/struct"
25	sppb "google.golang.org/genproto/googleapis/spanner/v1"
26)
27
28// Test Key.String() and Key.proto().
29func TestKey(t *testing.T) {
30	tm, _ := time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z")
31	dt, _ := civil.ParseDate("2016-11-15")
32	for _, test := range []struct {
33		k         Key
34		wantProto *proto3.ListValue
35		wantStr   string
36	}{
37		{
38			k:         Key{int(1)},
39			wantProto: listValueProto(stringProto("1")),
40			wantStr:   "(1)",
41		},
42		{
43			k:         Key{int8(1)},
44			wantProto: listValueProto(stringProto("1")),
45			wantStr:   "(1)",
46		},
47		{
48			k:         Key{int16(1)},
49			wantProto: listValueProto(stringProto("1")),
50			wantStr:   "(1)",
51		},
52		{
53			k:         Key{int32(1)},
54			wantProto: listValueProto(stringProto("1")),
55			wantStr:   "(1)",
56		},
57		{
58			k:         Key{int64(1)},
59			wantProto: listValueProto(stringProto("1")),
60			wantStr:   "(1)",
61		},
62		{
63			k:         Key{uint8(1)},
64			wantProto: listValueProto(stringProto("1")),
65			wantStr:   "(1)",
66		},
67		{
68			k:         Key{uint16(1)},
69			wantProto: listValueProto(stringProto("1")),
70			wantStr:   "(1)",
71		},
72		{
73			k:         Key{uint32(1)},
74			wantProto: listValueProto(stringProto("1")),
75			wantStr:   "(1)",
76		},
77		{
78			k:         Key{true},
79			wantProto: listValueProto(boolProto(true)),
80			wantStr:   "(true)",
81		},
82		{
83			k:         Key{float32(1.5)},
84			wantProto: listValueProto(floatProto(1.5)),
85			wantStr:   "(1.5)",
86		},
87		{
88			k:         Key{float64(1.5)},
89			wantProto: listValueProto(floatProto(1.5)),
90			wantStr:   "(1.5)",
91		},
92		{
93			k:         Key{"value"},
94			wantProto: listValueProto(stringProto("value")),
95			wantStr:   `("value")`,
96		},
97		{
98			k:         Key{[]byte(nil)},
99			wantProto: listValueProto(nullProto()),
100			wantStr:   "(<null>)",
101		},
102		{
103			k:         Key{[]byte{}},
104			wantProto: listValueProto(stringProto("")),
105			wantStr:   `("")`,
106		},
107		{
108			k:         Key{tm},
109			wantProto: listValueProto(stringProto("2016-11-15T15:04:05.999999999Z")),
110			wantStr:   `("2016-11-15T15:04:05.999999999Z")`,
111		},
112		{k: Key{dt},
113			wantProto: listValueProto(stringProto("2016-11-15")),
114			wantStr:   `("2016-11-15")`,
115		},
116		{
117			k:         Key{[]byte("value")},
118			wantProto: listValueProto(bytesProto([]byte("value"))),
119			wantStr:   `("value")`,
120		},
121		{
122			k:         Key{NullInt64{1, true}},
123			wantProto: listValueProto(stringProto("1")),
124			wantStr:   "(1)",
125		},
126		{
127			k:         Key{NullInt64{2, false}},
128			wantProto: listValueProto(nullProto()),
129			wantStr:   "(<null>)",
130		},
131		{
132			k:         Key{NullFloat64{1.5, true}},
133			wantProto: listValueProto(floatProto(1.5)),
134			wantStr:   "(1.5)",
135		},
136		{
137			k:         Key{NullFloat64{2.0, false}},
138			wantProto: listValueProto(nullProto()),
139			wantStr:   "(<null>)",
140		},
141		{
142			k:         Key{NullBool{true, true}},
143			wantProto: listValueProto(boolProto(true)),
144			wantStr:   "(true)",
145		},
146		{
147			k:         Key{NullBool{true, false}},
148			wantProto: listValueProto(nullProto()),
149			wantStr:   "(<null>)",
150		},
151		{
152			k:         Key{NullString{"value", true}},
153			wantProto: listValueProto(stringProto("value")),
154			wantStr:   `("value")`,
155		},
156		{
157			k:         Key{NullString{"value", false}},
158			wantProto: listValueProto(nullProto()),
159			wantStr:   "(<null>)",
160		},
161		{
162			k:         Key{NullTime{tm, true}},
163			wantProto: listValueProto(timeProto(tm)),
164			wantStr:   `("2016-11-15T15:04:05.999999999Z")`,
165		},
166
167		{
168			k:         Key{NullTime{time.Now(), false}},
169			wantProto: listValueProto(nullProto()),
170			wantStr:   "(<null>)",
171		},
172		{
173			k:         Key{NullDate{dt, true}},
174			wantProto: listValueProto(dateProto(dt)),
175			wantStr:   `("2016-11-15")`,
176		},
177		{
178			k:         Key{NullDate{civil.Date{}, false}},
179			wantProto: listValueProto(nullProto()),
180			wantStr:   "(<null>)",
181		},
182		{
183			k:         Key{int(1), NullString{"value", false}, "value", 1.5, true},
184			wantProto: listValueProto(stringProto("1"), nullProto(), stringProto("value"), floatProto(1.5), boolProto(true)),
185			wantStr:   `(1,<null>,"value",1.5,true)`,
186		},
187	} {
188		if got := test.k.String(); got != test.wantStr {
189			t.Errorf("%v.String() = %v, want %v", test.k, got, test.wantStr)
190		}
191		gotProto, err := test.k.proto()
192		if err != nil {
193			t.Errorf("%v.proto() returns error %v; want nil error", test.k, err)
194		}
195		if !testEqual(gotProto, test.wantProto) {
196			t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.k, gotProto, test.wantProto)
197		}
198	}
199}
200
201// Test KeyRange.String() and KeyRange.proto().
202func TestKeyRange(t *testing.T) {
203	for _, test := range []struct {
204		kr        KeyRange
205		wantProto *sppb.KeyRange
206		wantStr   string
207	}{
208		{
209			kr: KeyRange{Key{"A"}, Key{"D"}, OpenOpen},
210			wantProto: &sppb.KeyRange{
211				StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("A"))},
212				EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(stringProto("D"))},
213			},
214			wantStr: `(("A"),("D"))`,
215		},
216		{
217			kr: KeyRange{Key{1}, Key{10}, OpenClosed},
218			wantProto: &sppb.KeyRange{
219				StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("1"))},
220				EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))},
221			},
222			wantStr: "((1),(10)]",
223		},
224		{
225			kr: KeyRange{Key{1.5, 2.1, 0.2}, Key{1.9, 0.7}, ClosedOpen},
226			wantProto: &sppb.KeyRange{
227				StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(floatProto(1.5), floatProto(2.1), floatProto(0.2))},
228				EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(floatProto(1.9), floatProto(0.7))},
229			},
230			wantStr: "[(1.5,2.1,0.2),(1.9,0.7))",
231		},
232		{
233			kr: KeyRange{Key{NullInt64{1, true}}, Key{10}, ClosedClosed},
234			wantProto: &sppb.KeyRange{
235				StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(stringProto("1"))},
236				EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))},
237			},
238			wantStr: "[(1),(10)]",
239		},
240	} {
241		if got := test.kr.String(); got != test.wantStr {
242			t.Errorf("%v.String() = %v, want %v", test.kr, got, test.wantStr)
243		}
244		gotProto, err := test.kr.proto()
245		if err != nil {
246			t.Errorf("%v.proto() returns error %v; want nil error", test.kr, err)
247		}
248		if !testEqual(gotProto, test.wantProto) {
249			t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.kr, gotProto.String(), test.wantProto.String())
250		}
251	}
252}
253
254func TestPrefixRange(t *testing.T) {
255	got := Key{1}.AsPrefix()
256	want := KeyRange{Start: Key{1}, End: Key{1}, Kind: ClosedClosed}
257	if !testEqual(got, want) {
258		t.Errorf("got %v, want %v", got, want)
259	}
260}
261
262func TestKeySets(t *testing.T) {
263	int1 := intProto(1)
264	int2 := intProto(2)
265	int3 := intProto(3)
266	int4 := intProto(4)
267	for i, test := range []struct {
268		ks        KeySet
269		wantProto *sppb.KeySet
270	}{
271		{
272			KeySets(),
273			&sppb.KeySet{},
274		},
275		{
276			Key{4},
277			&sppb.KeySet{
278				Keys: []*proto3.ListValue{listValueProto(int4)},
279			},
280		},
281		{
282			AllKeys(),
283			&sppb.KeySet{All: true},
284		},
285		{
286			KeySets(Key{1, 2}, Key{3, 4}),
287			&sppb.KeySet{
288				Keys: []*proto3.ListValue{
289					listValueProto(int1, int2),
290					listValueProto(int3, int4),
291				},
292			},
293		},
294		{
295			KeyRange{Key{1}, Key{2}, ClosedOpen},
296			&sppb.KeySet{Ranges: []*sppb.KeyRange{
297				{
298					StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)},
299					EndKeyType:   &sppb.KeyRange_EndOpen{EndOpen: listValueProto(int2)},
300				},
301			}},
302		},
303		{
304			Key{2}.AsPrefix(),
305			&sppb.KeySet{Ranges: []*sppb.KeyRange{
306				{
307					StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)},
308					EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)},
309				},
310			}},
311		},
312		{
313			KeySets(
314				KeyRange{Key{1}, Key{2}, ClosedClosed},
315				KeyRange{Key{3}, Key{4}, OpenClosed},
316			),
317			&sppb.KeySet{
318				Ranges: []*sppb.KeyRange{
319					{
320						StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)},
321						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)},
322					},
323					{
324						StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int3)},
325						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int4)},
326					},
327				},
328			},
329		},
330		{
331			KeySets(
332				Key{1},
333				KeyRange{Key{2}, Key{3}, ClosedClosed},
334				KeyRange{Key{4}, Key{5}, OpenClosed},
335				KeySets(),
336				Key{6}),
337			&sppb.KeySet{
338				Keys: []*proto3.ListValue{
339					listValueProto(int1),
340					listValueProto(intProto(6)),
341				},
342				Ranges: []*sppb.KeyRange{
343					{
344						StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)},
345						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int3)},
346					},
347					{
348						StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int4)},
349						EndKeyType:   &sppb.KeyRange_EndClosed{EndClosed: listValueProto(intProto(5))},
350					},
351				},
352			},
353		},
354		{
355			KeySets(
356				Key{1},
357				KeyRange{Key{2}, Key{3}, ClosedClosed},
358				AllKeys(),
359				KeyRange{Key{4}, Key{5}, OpenClosed},
360				Key{6}),
361			&sppb.KeySet{All: true},
362		},
363	} {
364		gotProto, err := test.ks.keySetProto()
365		if err != nil {
366			t.Errorf("#%d: %v.proto() returns error %v; want nil error", i, test.ks, err)
367		}
368		if !testEqual(gotProto, test.wantProto) {
369			t.Errorf("#%d: %v.proto() = \n%v\nwant:\n%v", i, test.ks, gotProto.String(), test.wantProto.String())
370		}
371	}
372}
373