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