| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // adapted from github.com/golang/appengine/datastore | 5 // adapted from github.com/golang/appengine/datastore |
| 6 | 6 |
| 7 package helper | 7 package rawdatastore |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "bytes" | 10 "bytes" |
| 11 "encoding/json" | 11 "encoding/json" |
| 12 "fmt" | 12 "fmt" |
| 13 "math" | 13 "math" |
| 14 "reflect" | 14 "reflect" |
| 15 "strconv" | 15 "strconv" |
| 16 "strings" | 16 "strings" |
| 17 "testing" | 17 "testing" |
| 18 "time" | 18 "time" |
| 19 | 19 |
| 20 » "github.com/luci/gae" | 20 » "github.com/luci/gae/service/blobstore" |
| 21 . "github.com/smartystreets/goconvey/convey" | 21 . "github.com/smartystreets/goconvey/convey" |
| 22 ) | 22 ) |
| 23 | 23 |
| 24 var ( | 24 var ( |
| 25 » mp = gae.MkDSProperty | 25 » mp = MkProperty |
| 26 » mpNI = gae.MkDSPropertyNI | 26 » mpNI = MkPropertyNI |
| 27 ) | 27 ) |
| 28 | 28 |
| 29 const testAppID = "testApp" | 29 const testAppID = "testApp" |
| 30 | 30 |
| 31 type ( | 31 type ( |
| 32 myBlob []byte | 32 myBlob []byte |
| 33 myByte byte | 33 myByte byte |
| 34 myString string | 34 myString string |
| 35 ) | 35 ) |
| 36 | 36 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 57 } | 57 } |
| 58 return b | 58 return b |
| 59 } | 59 } |
| 60 | 60 |
| 61 var ( | 61 var ( |
| 62 testKey0 = mkKey("aid", "", "kind", "name0") | 62 testKey0 = mkKey("aid", "", "kind", "name0") |
| 63 testKey1a = mkKey("aid", "", "kind", "name1") | 63 testKey1a = mkKey("aid", "", "kind", "name1") |
| 64 testKey1b = mkKey("aid", "", "kind", "name1") | 64 testKey1b = mkKey("aid", "", "kind", "name1") |
| 65 testKey2a = mkKey("aid", "", "kind", "name0", "kind", "name2") | 65 testKey2a = mkKey("aid", "", "kind", "name0", "kind", "name2") |
| 66 testKey2b = mkKey("aid", "", "kind", "name0", "kind", "name2") | 66 testKey2b = mkKey("aid", "", "kind", "name0", "kind", "name2") |
| 67 » testGeoPt0 = gae.DSGeoPoint{Lat: 1.2, Lng: 3.4} | 67 » testGeoPt0 = GeoPoint{Lat: 1.2, Lng: 3.4} |
| 68 » testGeoPt1 = gae.DSGeoPoint{Lat: 5, Lng: 10} | 68 » testGeoPt1 = GeoPoint{Lat: 5, Lng: 10} |
| 69 » testBadGeoPt = gae.DSGeoPoint{Lat: 1000, Lng: 34} | 69 » testBadGeoPt = GeoPoint{Lat: 1000, Lng: 34} |
| 70 ) | 70 ) |
| 71 | 71 |
| 72 type B0 struct { | 72 type B0 struct { |
| 73 B []byte | 73 B []byte |
| 74 } | 74 } |
| 75 | 75 |
| 76 type B1 struct { | 76 type B1 struct { |
| 77 B []int8 | 77 B []int8 |
| 78 } | 78 } |
| 79 | 79 |
| 80 type B2 struct { | 80 type B2 struct { |
| 81 B myBlob | 81 B myBlob |
| 82 } | 82 } |
| 83 | 83 |
| 84 type B3 struct { | 84 type B3 struct { |
| 85 B []myByte | 85 B []myByte |
| 86 } | 86 } |
| 87 | 87 |
| 88 type B4 struct { | 88 type B4 struct { |
| 89 B [][]byte | 89 B [][]byte |
| 90 } | 90 } |
| 91 | 91 |
| 92 type B5 struct { | 92 type B5 struct { |
| 93 » B gae.DSByteString | 93 » B ByteString |
| 94 } | 94 } |
| 95 | 95 |
| 96 type C0 struct { | 96 type C0 struct { |
| 97 I int | 97 I int |
| 98 C chan int | 98 C chan int |
| 99 } | 99 } |
| 100 | 100 |
| 101 type C1 struct { | 101 type C1 struct { |
| 102 I int | 102 I int |
| 103 C *chan int | 103 C *chan int |
| 104 } | 104 } |
| 105 | 105 |
| 106 type C2 struct { | 106 type C2 struct { |
| 107 I int | 107 I int |
| 108 C []chan int | 108 C []chan int |
| 109 } | 109 } |
| 110 | 110 |
| 111 type C3 struct { | 111 type C3 struct { |
| 112 C string | 112 C string |
| 113 } | 113 } |
| 114 | 114 |
| 115 type E struct{} | 115 type E struct{} |
| 116 | 116 |
| 117 type G0 struct { | 117 type G0 struct { |
| 118 » G gae.DSGeoPoint | 118 » G GeoPoint |
| 119 } | 119 } |
| 120 | 120 |
| 121 type G1 struct { | 121 type G1 struct { |
| 122 » G []gae.DSGeoPoint | 122 » G []GeoPoint |
| 123 } | 123 } |
| 124 | 124 |
| 125 type K0 struct { | 125 type K0 struct { |
| 126 » K gae.DSKey | 126 » K Key |
| 127 } | 127 } |
| 128 | 128 |
| 129 type K1 struct { | 129 type K1 struct { |
| 130 » K []gae.DSKey | 130 » K []Key |
| 131 } | 131 } |
| 132 | 132 |
| 133 type N0 struct { | 133 type N0 struct { |
| 134 X0 | 134 X0 |
| 135 ID int64 `gae:"$id"` | 135 ID int64 `gae:"$id"` |
| 136 _kind string `gae:"$kind,whatnow"` | 136 _kind string `gae:"$kind,whatnow"` |
| 137 Nonymous X0 | 137 Nonymous X0 |
| 138 Ignore string `gae:"-"` | 138 Ignore string `gae:"-"` |
| 139 Other string | 139 Other string |
| 140 } | 140 } |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 I int | 312 I int |
| 313 R []MutuallyRecursive1 | 313 R []MutuallyRecursive1 |
| 314 } | 314 } |
| 315 | 315 |
| 316 type MutuallyRecursive1 struct { | 316 type MutuallyRecursive1 struct { |
| 317 I int | 317 I int |
| 318 R []MutuallyRecursive0 | 318 R []MutuallyRecursive0 |
| 319 } | 319 } |
| 320 | 320 |
| 321 type ExoticTypes struct { | 321 type ExoticTypes struct { |
| 322 » BS gae.BSKey | 322 » BS blobstore.Key |
| 323 » DSBS gae.DSByteString | 323 » DSBS ByteString |
| 324 } | 324 } |
| 325 | 325 |
| 326 type Underspecified struct { | 326 type Underspecified struct { |
| 327 » Iface gae.DSPropertyConverter | 327 » Iface PropertyConverter |
| 328 } | 328 } |
| 329 | 329 |
| 330 type MismatchTypes struct { | 330 type MismatchTypes struct { |
| 331 S string | 331 S string |
| 332 B bool | 332 B bool |
| 333 F float32 | 333 F float32 |
| 334 » K gae.DSKey | 334 » K Key |
| 335 T time.Time | 335 T time.Time |
| 336 » G gae.DSGeoPoint | 336 » G GeoPoint |
| 337 IS []int | 337 IS []int |
| 338 } | 338 } |
| 339 | 339 |
| 340 type BadSpecial struct { | 340 type BadSpecial struct { |
| 341 ID int64 `gae:"$id"` | 341 ID int64 `gae:"$id"` |
| 342 id string `gae:"$id"` | 342 id string `gae:"$id"` |
| 343 } | 343 } |
| 344 | 344 |
| 345 type Doubler struct { | 345 type Doubler struct { |
| 346 S string | 346 S string |
| 347 I int64 | 347 I int64 |
| 348 B bool | 348 B bool |
| 349 } | 349 } |
| 350 | 350 |
| 351 func (d *Doubler) Load(props gae.DSPropertyMap) error { | 351 func (d *Doubler) Load(props PropertyMap) error { |
| 352 return GetPLS(d).Load(props) | 352 return GetPLS(d).Load(props) |
| 353 } | 353 } |
| 354 | 354 |
| 355 func (d *Doubler) Save(withMeta bool) (gae.DSPropertyMap, error) { | 355 func (d *Doubler) Save(withMeta bool) (PropertyMap, error) { |
| 356 pls := GetPLS(d) | 356 pls := GetPLS(d) |
| 357 propMap, err := pls.Save(withMeta) | 357 propMap, err := pls.Save(withMeta) |
| 358 if err != nil { | 358 if err != nil { |
| 359 return nil, err | 359 return nil, err |
| 360 } | 360 } |
| 361 | 361 |
| 362 // Edit that map and send it on. | 362 // Edit that map and send it on. |
| 363 for _, props := range propMap { | 363 for _, props := range propMap { |
| 364 for i := range props { | 364 for i := range props { |
| 365 switch v := props[i].Value().(type) { | 365 switch v := props[i].Value().(type) { |
| 366 case string: | 366 case string: |
| 367 // + means string concatenation. | 367 // + means string concatenation. |
| 368 props[i].SetValue(v+v, props[i].IndexSetting()) | 368 props[i].SetValue(v+v, props[i].IndexSetting()) |
| 369 case int64: | 369 case int64: |
| 370 // + means integer addition. | 370 // + means integer addition. |
| 371 props[i].SetValue(v+v, props[i].IndexSetting()) | 371 props[i].SetValue(v+v, props[i].IndexSetting()) |
| 372 } | 372 } |
| 373 } | 373 } |
| 374 } | 374 } |
| 375 return propMap, nil | 375 return propMap, nil |
| 376 } | 376 } |
| 377 | 377 |
| 378 func (d *Doubler) GetMeta(string) (interface{}, error) { return nil, gae.ErrDSMe
taFieldUnset } | 378 func (d *Doubler) GetMeta(string) (interface{}, error) { return nil, ErrMetaFiel
dUnset } |
| 379 func (d *Doubler) SetMeta(string, interface{}) error { return gae.ErrDSMetaFie
ldUnset } | 379 func (d *Doubler) SetMeta(string, interface{}) error { return ErrMetaFieldUnse
t } |
| 380 func (d *Doubler) Problem() error { return nil } | 380 func (d *Doubler) Problem() error { return nil } |
| 381 | 381 |
| 382 var _ gae.DSPropertyLoadSaver = (*Doubler)(nil) | 382 var _ PropertyLoadSaver = (*Doubler)(nil) |
| 383 | 383 |
| 384 type Deriver struct { | 384 type Deriver struct { |
| 385 S, Derived, Ignored string | 385 S, Derived, Ignored string |
| 386 } | 386 } |
| 387 | 387 |
| 388 func (d *Deriver) Load(props gae.DSPropertyMap) error { | 388 func (d *Deriver) Load(props PropertyMap) error { |
| 389 for name, p := range props { | 389 for name, p := range props { |
| 390 if name != "S" { | 390 if name != "S" { |
| 391 continue | 391 continue |
| 392 } | 392 } |
| 393 d.S = p[0].Value().(string) | 393 d.S = p[0].Value().(string) |
| 394 d.Derived = "derived+" + d.S | 394 d.Derived = "derived+" + d.S |
| 395 } | 395 } |
| 396 return nil | 396 return nil |
| 397 } | 397 } |
| 398 | 398 |
| 399 func (d *Deriver) Save(withMeta bool) (gae.DSPropertyMap, error) { | 399 func (d *Deriver) Save(withMeta bool) (PropertyMap, error) { |
| 400 » return map[string][]gae.DSProperty{ | 400 » return map[string][]Property{ |
| 401 "S": {mp(d.S)}, | 401 "S": {mp(d.S)}, |
| 402 }, nil | 402 }, nil |
| 403 } | 403 } |
| 404 | 404 |
| 405 func (d *Deriver) GetMeta(string) (interface{}, error) { return nil, gae.ErrDSMe
taFieldUnset } | 405 func (d *Deriver) GetMeta(string) (interface{}, error) { return nil, ErrMetaFiel
dUnset } |
| 406 func (d *Deriver) SetMeta(string, interface{}) error { return gae.ErrDSMetaFie
ldUnset } | 406 func (d *Deriver) SetMeta(string, interface{}) error { return ErrMetaFieldUnse
t } |
| 407 func (d *Deriver) Problem() error { return nil } | 407 func (d *Deriver) Problem() error { return nil } |
| 408 | 408 |
| 409 var _ gae.DSPropertyLoadSaver = (*Deriver)(nil) | 409 var _ PropertyLoadSaver = (*Deriver)(nil) |
| 410 | 410 |
| 411 type BK struct { | 411 type BK struct { |
| 412 » Key gae.BSKey | 412 » Key blobstore.Key |
| 413 } | 413 } |
| 414 | 414 |
| 415 type Convertable []int64 | 415 type Convertable []int64 |
| 416 | 416 |
| 417 var _ gae.DSPropertyConverter = (*Convertable)(nil) | 417 var _ PropertyConverter = (*Convertable)(nil) |
| 418 | 418 |
| 419 func (c *Convertable) ToDSProperty() (ret gae.DSProperty, err error) { | 419 func (c *Convertable) ToProperty() (ret Property, err error) { |
| 420 buf := make([]string, len(*c)) | 420 buf := make([]string, len(*c)) |
| 421 for i, v := range *c { | 421 for i, v := range *c { |
| 422 buf[i] = strconv.FormatInt(v, 10) | 422 buf[i] = strconv.FormatInt(v, 10) |
| 423 } | 423 } |
| 424 » err = ret.SetValue(strings.Join(buf, ","), gae.NoIndex) | 424 » err = ret.SetValue(strings.Join(buf, ","), NoIndex) |
| 425 return | 425 return |
| 426 } | 426 } |
| 427 | 427 |
| 428 func (c *Convertable) FromDSProperty(pv gae.DSProperty) error { | 428 func (c *Convertable) FromProperty(pv Property) error { |
| 429 if sval, ok := pv.Value().(string); ok { | 429 if sval, ok := pv.Value().(string); ok { |
| 430 for _, t := range strings.Split(sval, ",") { | 430 for _, t := range strings.Split(sval, ",") { |
| 431 ival, err := strconv.ParseInt(t, 10, 64) | 431 ival, err := strconv.ParseInt(t, 10, 64) |
| 432 if err != nil { | 432 if err != nil { |
| 433 return err | 433 return err |
| 434 } | 434 } |
| 435 *c = append(*c, ival) | 435 *c = append(*c, ival) |
| 436 } | 436 } |
| 437 return nil | 437 return nil |
| 438 } | 438 } |
| 439 return fmt.Errorf("nope") | 439 return fmt.Errorf("nope") |
| 440 } | 440 } |
| 441 | 441 |
| 442 type Impossible struct { | 442 type Impossible struct { |
| 443 Nested []ImpossibleInner | 443 Nested []ImpossibleInner |
| 444 } | 444 } |
| 445 | 445 |
| 446 type ImpossibleInner struct { | 446 type ImpossibleInner struct { |
| 447 Ints Convertable `gae:"wot"` | 447 Ints Convertable `gae:"wot"` |
| 448 } | 448 } |
| 449 | 449 |
| 450 type Convertable2 struct { | 450 type Convertable2 struct { |
| 451 Data string | 451 Data string |
| 452 Exploded []string | 452 Exploded []string |
| 453 } | 453 } |
| 454 | 454 |
| 455 func (c *Convertable2) ToDSProperty() (ret gae.DSProperty, err error) { | 455 func (c *Convertable2) ToProperty() (ret Property, err error) { |
| 456 » err = ret.SetValue(c.Data, gae.ShouldIndex) | 456 » err = ret.SetValue(c.Data, ShouldIndex) |
| 457 return | 457 return |
| 458 } | 458 } |
| 459 | 459 |
| 460 func (c *Convertable2) FromDSProperty(pv gae.DSProperty) error { | 460 func (c *Convertable2) FromProperty(pv Property) error { |
| 461 if sval, ok := pv.Value().(string); ok { | 461 if sval, ok := pv.Value().(string); ok { |
| 462 c.Data = sval | 462 c.Data = sval |
| 463 c.Exploded = []string{"turn", "down", "for", "what"} | 463 c.Exploded = []string{"turn", "down", "for", "what"} |
| 464 return nil | 464 return nil |
| 465 } | 465 } |
| 466 return fmt.Errorf("nope") | 466 return fmt.Errorf("nope") |
| 467 } | 467 } |
| 468 | 468 |
| 469 type Impossible2 struct { | 469 type Impossible2 struct { |
| 470 Nested []ImpossibleInner2 | 470 Nested []ImpossibleInner2 |
| 471 } | 471 } |
| 472 | 472 |
| 473 type ImpossibleInner2 struct { | 473 type ImpossibleInner2 struct { |
| 474 Thingy Convertable2 `gae:"nerb"` | 474 Thingy Convertable2 `gae:"nerb"` |
| 475 } | 475 } |
| 476 | 476 |
| 477 type JSONKVProp map[string]interface{} | 477 type JSONKVProp map[string]interface{} |
| 478 | 478 |
| 479 var _ gae.DSPropertyConverter = (*JSONKVProp)(nil) | 479 var _ PropertyConverter = (*JSONKVProp)(nil) |
| 480 | 480 |
| 481 func (j *JSONKVProp) ToDSProperty() (ret gae.DSProperty, err error) { | 481 func (j *JSONKVProp) ToProperty() (ret Property, err error) { |
| 482 data, err := json.Marshal(map[string]interface{}(*j)) | 482 data, err := json.Marshal(map[string]interface{}(*j)) |
| 483 if err != nil { | 483 if err != nil { |
| 484 return | 484 return |
| 485 } | 485 } |
| 486 » err = ret.SetValue(data, gae.NoIndex) | 486 » err = ret.SetValue(data, NoIndex) |
| 487 return | 487 return |
| 488 } | 488 } |
| 489 | 489 |
| 490 func (j *JSONKVProp) FromDSProperty(pv gae.DSProperty) error { | 490 func (j *JSONKVProp) FromProperty(pv Property) error { |
| 491 if bval, ok := pv.Value().([]byte); ok { | 491 if bval, ok := pv.Value().([]byte); ok { |
| 492 dec := json.NewDecoder(bytes.NewBuffer(bval)) | 492 dec := json.NewDecoder(bytes.NewBuffer(bval)) |
| 493 dec.UseNumber() | 493 dec.UseNumber() |
| 494 return dec.Decode((*map[string]interface{})(j)) | 494 return dec.Decode((*map[string]interface{})(j)) |
| 495 } | 495 } |
| 496 return fmt.Errorf("nope") | 496 return fmt.Errorf("nope") |
| 497 } | 497 } |
| 498 | 498 |
| 499 type Impossible3 struct { | 499 type Impossible3 struct { |
| 500 KMap JSONKVProp `gae:"kewelmap"` | 500 KMap JSONKVProp `gae:"kewelmap"` |
| 501 } | 501 } |
| 502 | 502 |
| 503 type Complex complex128 | 503 type Complex complex128 |
| 504 | 504 |
| 505 var _ gae.DSPropertyConverter = (*Complex)(nil) | 505 var _ PropertyConverter = (*Complex)(nil) |
| 506 | 506 |
| 507 func (c *Complex) ToDSProperty() (ret gae.DSProperty, err error) { | 507 func (c *Complex) ToProperty() (ret Property, err error) { |
| 508 // cheat hardkore and usurp GeoPoint so datastore will index these sucke
rs | 508 // cheat hardkore and usurp GeoPoint so datastore will index these sucke
rs |
| 509 // (note that this won't REALLY work, since GeoPoints are limited to a v
ery | 509 // (note that this won't REALLY work, since GeoPoints are limited to a v
ery |
| 510 // limited range of values, but it's nice to pretend ;)). You'd probably | 510 // limited range of values, but it's nice to pretend ;)). You'd probably |
| 511 // really end up with a packed binary representation. | 511 // really end up with a packed binary representation. |
| 512 » err = ret.SetValue(gae.DSGeoPoint{Lat: real(*c), Lng: imag(*c)}, gae.Sho
uldIndex) | 512 » err = ret.SetValue(GeoPoint{Lat: real(*c), Lng: imag(*c)}, ShouldIndex) |
| 513 return | 513 return |
| 514 } | 514 } |
| 515 | 515 |
| 516 func (c *Complex) FromDSProperty(p gae.DSProperty) error { | 516 func (c *Complex) FromProperty(p Property) error { |
| 517 » if gval, ok := p.Value().(gae.DSGeoPoint); ok { | 517 » if gval, ok := p.Value().(GeoPoint); ok { |
| 518 *c = Complex(complex(gval.Lat, gval.Lng)) | 518 *c = Complex(complex(gval.Lat, gval.Lng)) |
| 519 return nil | 519 return nil |
| 520 } | 520 } |
| 521 return fmt.Errorf("nope") | 521 return fmt.Errorf("nope") |
| 522 } | 522 } |
| 523 | 523 |
| 524 type Impossible4 struct { | 524 type Impossible4 struct { |
| 525 Values []Complex | 525 Values []Complex |
| 526 } | 526 } |
| 527 | 527 |
| 528 type DerivedKey struct { | 528 type DerivedKey struct { |
| 529 » K *GenericDSKey | 529 » K *GenericKey |
| 530 } | 530 } |
| 531 | 531 |
| 532 type IfaceKey struct { | 532 type IfaceKey struct { |
| 533 » K gae.DSKey | 533 » K Key |
| 534 } | 534 } |
| 535 | 535 |
| 536 type testCase struct { | 536 type testCase struct { |
| 537 desc string | 537 desc string |
| 538 src interface{} | 538 src interface{} |
| 539 want interface{} | 539 want interface{} |
| 540 plsErr string | 540 plsErr string |
| 541 saveErr string | 541 saveErr string |
| 542 actualNoIndex bool | 542 actualNoIndex bool |
| 543 plsLoadErr string | 543 plsLoadErr string |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 want: &G0{G: testGeoPt0}, | 589 want: &G0{G: testGeoPt0}, |
| 590 }, | 590 }, |
| 591 { | 591 { |
| 592 desc: "geopoint invalid", | 592 desc: "geopoint invalid", |
| 593 src: &G0{G: testBadGeoPt}, | 593 src: &G0{G: testBadGeoPt}, |
| 594 saveErr: "invalid GeoPoint value", | 594 saveErr: "invalid GeoPoint value", |
| 595 }, | 595 }, |
| 596 { | 596 { |
| 597 desc: "geopoint as props", | 597 desc: "geopoint as props", |
| 598 src: &G0{G: testGeoPt0}, | 598 src: &G0{G: testGeoPt0}, |
| 599 » » want: gae.DSPropertyMap{ | 599 » » want: PropertyMap{ |
| 600 "G": {mp(testGeoPt0)}, | 600 "G": {mp(testGeoPt0)}, |
| 601 }, | 601 }, |
| 602 }, | 602 }, |
| 603 { | 603 { |
| 604 desc: "geopoint slice", | 604 desc: "geopoint slice", |
| 605 » » src: &G1{G: []gae.DSGeoPoint{testGeoPt0, testGeoPt1}}, | 605 » » src: &G1{G: []GeoPoint{testGeoPt0, testGeoPt1}}, |
| 606 » » want: &G1{G: []gae.DSGeoPoint{testGeoPt0, testGeoPt1}}, | 606 » » want: &G1{G: []GeoPoint{testGeoPt0, testGeoPt1}}, |
| 607 }, | 607 }, |
| 608 { | 608 { |
| 609 desc: "key", | 609 desc: "key", |
| 610 src: &K0{K: testKey1a}, | 610 src: &K0{K: testKey1a}, |
| 611 want: &K0{K: testKey1b}, | 611 want: &K0{K: testKey1b}, |
| 612 }, | 612 }, |
| 613 { | 613 { |
| 614 desc: "key with parent", | 614 desc: "key with parent", |
| 615 src: &K0{K: testKey2a}, | 615 src: &K0{K: testKey2a}, |
| 616 want: &K0{K: testKey2b}, | 616 want: &K0{K: testKey2b}, |
| 617 }, | 617 }, |
| 618 { | 618 { |
| 619 desc: "nil key", | 619 desc: "nil key", |
| 620 src: &K0{}, | 620 src: &K0{}, |
| 621 want: &K0{}, | 621 want: &K0{}, |
| 622 }, | 622 }, |
| 623 { | 623 { |
| 624 desc: "all nil keys in slice", | 624 desc: "all nil keys in slice", |
| 625 » » src: &K1{[]gae.DSKey{nil, nil}}, | 625 » » src: &K1{[]Key{nil, nil}}, |
| 626 » » want: &K1{[]gae.DSKey{nil, nil}}, | 626 » » want: &K1{[]Key{nil, nil}}, |
| 627 }, | 627 }, |
| 628 { | 628 { |
| 629 desc: "some nil keys in slice", | 629 desc: "some nil keys in slice", |
| 630 » » src: &K1{[]gae.DSKey{testKey1a, nil, testKey2a}}, | 630 » » src: &K1{[]Key{testKey1a, nil, testKey2a}}, |
| 631 » » want: &K1{[]gae.DSKey{testKey1b, nil, testKey2b}}, | 631 » » want: &K1{[]Key{testKey1b, nil, testKey2b}}, |
| 632 }, | 632 }, |
| 633 { | 633 { |
| 634 desc: "overflow", | 634 desc: "overflow", |
| 635 src: &O0{I: 1 << 48}, | 635 src: &O0{I: 1 << 48}, |
| 636 want: &O1{}, | 636 want: &O1{}, |
| 637 loadErr: "overflow", | 637 loadErr: "overflow", |
| 638 }, | 638 }, |
| 639 { | 639 { |
| 640 desc: "time", | 640 desc: "time", |
| 641 src: &T{T: time.Unix(1e9, 0).UTC()}, | 641 src: &T{T: time.Unix(1e9, 0).UTC()}, |
| 642 want: &T{T: time.Unix(1e9, 0).UTC()}, | 642 want: &T{T: time.Unix(1e9, 0).UTC()}, |
| 643 }, | 643 }, |
| 644 { | 644 { |
| 645 desc: "time as props", | 645 desc: "time as props", |
| 646 src: &T{T: time.Unix(1e9, 0).UTC()}, | 646 src: &T{T: time.Unix(1e9, 0).UTC()}, |
| 647 » » want: gae.DSPropertyMap{ | 647 » » want: PropertyMap{ |
| 648 "T": {mp(time.Unix(1e9, 0).UTC())}, | 648 "T": {mp(time.Unix(1e9, 0).UTC())}, |
| 649 }, | 649 }, |
| 650 }, | 650 }, |
| 651 { | 651 { |
| 652 desc: "uint save", | 652 desc: "uint save", |
| 653 src: &U0{U: 1}, | 653 src: &U0{U: 1}, |
| 654 plsErr: `field "U" has invalid type: uint`, | 654 plsErr: `field "U" has invalid type: uint`, |
| 655 }, | 655 }, |
| 656 { | 656 { |
| 657 desc: "uint load", | 657 desc: "uint load", |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 want: &Y2{B: true, F: []int64{7}}, | 708 want: &Y2{B: true, F: []int64{7}}, |
| 709 }, | 709 }, |
| 710 { | 710 { |
| 711 desc: "use convertable slice", | 711 desc: "use convertable slice", |
| 712 src: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, | 712 src: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, |
| 713 want: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, | 713 want: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, |
| 714 }, | 714 }, |
| 715 { | 715 { |
| 716 desc: "use convertable slice (to map)", | 716 desc: "use convertable slice (to map)", |
| 717 src: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, | 717 src: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Con
vertable{2, 4, 6}}}}, |
| 718 » » want: gae.DSPropertyMap{ | 718 » » want: PropertyMap{ |
| 719 "Nested.wot": {mpNI("1,5,9"), mpNI("2,4,6")}, | 719 "Nested.wot": {mpNI("1,5,9"), mpNI("2,4,6")}, |
| 720 }, | 720 }, |
| 721 }, | 721 }, |
| 722 { | 722 { |
| 723 desc: "convertable slice (bad load)", | 723 desc: "convertable slice (bad load)", |
| 724 » » src: gae.DSPropertyMap{"Nested.wot": {mpNI([]byte("ohai"))}}
, | 724 » » src: PropertyMap{"Nested.wot": {mpNI([]byte("ohai"))}}, |
| 725 want: &Impossible{[]ImpossibleInner{{}}}, | 725 want: &Impossible{[]ImpossibleInner{{}}}, |
| 726 loadErr: "nope", | 726 loadErr: "nope", |
| 727 }, | 727 }, |
| 728 { | 728 { |
| 729 desc: "use convertable struct", | 729 desc: "use convertable struct", |
| 730 src: &Impossible2{ | 730 src: &Impossible2{ |
| 731 []ImpossibleInner2{ | 731 []ImpossibleInner2{ |
| 732 {Convertable2{"nerb", nil}}, | 732 {Convertable2{"nerb", nil}}, |
| 733 }, | 733 }, |
| 734 }, | 734 }, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 757 }, | 757 }, |
| 758 { | 758 { |
| 759 desc: "convertable json KVMap (to map)", | 759 desc: "convertable json KVMap (to map)", |
| 760 src: &Impossible3{ | 760 src: &Impossible3{ |
| 761 JSONKVProp{ | 761 JSONKVProp{ |
| 762 "epic": "success", | 762 "epic": "success", |
| 763 "no_way!": []interface{}{true, "story"}, | 763 "no_way!": []interface{}{true, "story"}, |
| 764 "what": []interface{}{"is", "really", 100}, | 764 "what": []interface{}{"is", "really", 100}, |
| 765 }, | 765 }, |
| 766 }, | 766 }, |
| 767 » » want: gae.DSPropertyMap{ | 767 » » want: PropertyMap{ |
| 768 "kewelmap": { | 768 "kewelmap": { |
| 769 mpNI([]byte( | 769 mpNI([]byte( |
| 770 `{"epic":"success","no_way!":[true,"stor
y"],"what":["is","really",100]}`))}, | 770 `{"epic":"success","no_way!":[true,"stor
y"],"what":["is","really",100]}`))}, |
| 771 }, | 771 }, |
| 772 }, | 772 }, |
| 773 { | 773 { |
| 774 desc: "convertable complex slice", | 774 desc: "convertable complex slice", |
| 775 src: &Impossible4{ | 775 src: &Impossible4{ |
| 776 []Complex{complex(1, 2), complex(3, 4)}, | 776 []Complex{complex(1, 2), complex(3, 4)}, |
| 777 }, | 777 }, |
| 778 want: &Impossible4{ | 778 want: &Impossible4{ |
| 779 []Complex{complex(1, 2), complex(3, 4)}, | 779 []Complex{complex(1, 2), complex(3, 4)}, |
| 780 }, | 780 }, |
| 781 }, | 781 }, |
| 782 { | 782 { |
| 783 desc: "convertable complex slice (to map)", | 783 desc: "convertable complex slice (to map)", |
| 784 src: &Impossible4{ | 784 src: &Impossible4{ |
| 785 []Complex{complex(1, 2), complex(3, 4)}, | 785 []Complex{complex(1, 2), complex(3, 4)}, |
| 786 }, | 786 }, |
| 787 » » want: gae.DSPropertyMap{ | 787 » » want: PropertyMap{ |
| 788 "Values": { | 788 "Values": { |
| 789 » » » » mp(gae.DSGeoPoint{Lat: 1, Lng: 2}), mp(gae.DSGeo
Point{Lat: 3, Lng: 4})}, | 789 » » » » mp(GeoPoint{Lat: 1, Lng: 2}), mp(GeoPoint{Lat: 3
, Lng: 4})}, |
| 790 }, | 790 }, |
| 791 }, | 791 }, |
| 792 { | 792 { |
| 793 desc: "convertable complex slice (bad load)", | 793 desc: "convertable complex slice (bad load)", |
| 794 » » src: gae.DSPropertyMap{"Values": {mp("hello")}}, | 794 » » src: PropertyMap{"Values": {mp("hello")}}, |
| 795 want: &Impossible4{[]Complex(nil)}, | 795 want: &Impossible4{[]Complex(nil)}, |
| 796 loadErr: "nope", | 796 loadErr: "nope", |
| 797 }, | 797 }, |
| 798 { | 798 { |
| 799 » » desc: "allow concrete gae.DSKey implementors (save)", | 799 » » desc: "allow concrete Key implementors (save)", |
| 800 » » src: &DerivedKey{testKey2a.(*GenericDSKey)}, | 800 » » src: &DerivedKey{testKey2a.(*GenericKey)}, |
| 801 want: &IfaceKey{testKey2b}, | 801 want: &IfaceKey{testKey2b}, |
| 802 }, | 802 }, |
| 803 { | 803 { |
| 804 » » desc: "allow concrete gae.DSKey implementors (load)", | 804 » » desc: "allow concrete Key implementors (load)", |
| 805 src: &IfaceKey{testKey2b}, | 805 src: &IfaceKey{testKey2b}, |
| 806 » » want: &DerivedKey{testKey2a.(*GenericDSKey)}, | 806 » » want: &DerivedKey{testKey2a.(*GenericKey)}, |
| 807 }, | 807 }, |
| 808 { | 808 { |
| 809 desc: "save []float64 load []int64", | 809 desc: "save []float64 load []int64", |
| 810 src: &Y0{B: true, F: []float64{7, 8, 9}}, | 810 src: &Y0{B: true, F: []float64{7, 8, 9}}, |
| 811 want: &Y2{B: true}, | 811 want: &Y2{B: true}, |
| 812 loadErr: "type mismatch", | 812 loadErr: "type mismatch", |
| 813 }, | 813 }, |
| 814 { | 814 { |
| 815 desc: "single slice is too long", | 815 desc: "single slice is too long", |
| 816 src: &Y0{F: make([]float64, maxIndexedProperties+1)}, | 816 src: &Y0{F: make([]float64, maxIndexedProperties+1)}, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 872 makeUint8Slice(4), | 872 makeUint8Slice(4), |
| 873 makeUint8Slice(5), | 873 makeUint8Slice(5), |
| 874 }}, | 874 }}, |
| 875 want: &B4{B: [][]byte{ | 875 want: &B4{B: [][]byte{ |
| 876 makeUint8Slice(3), | 876 makeUint8Slice(3), |
| 877 makeUint8Slice(4), | 877 makeUint8Slice(4), |
| 878 makeUint8Slice(5), | 878 makeUint8Slice(5), |
| 879 }}, | 879 }}, |
| 880 }, | 880 }, |
| 881 { | 881 { |
| 882 » » desc: "short gae.DSByteString", | 882 » » desc: "short ByteString", |
| 883 » » src: &B5{B: gae.DSByteString(makeUint8Slice(3))}, | 883 » » src: &B5{B: ByteString(makeUint8Slice(3))}, |
| 884 » » want: &B5{B: gae.DSByteString(makeUint8Slice(3))}, | 884 » » want: &B5{B: ByteString(makeUint8Slice(3))}, |
| 885 }, | 885 }, |
| 886 { | 886 { |
| 887 » » desc: "short gae.DSByteString as props", | 887 » » desc: "short ByteString as props", |
| 888 » » src: &B5{B: gae.DSByteString(makeUint8Slice(3))}, | 888 » » src: &B5{B: ByteString(makeUint8Slice(3))}, |
| 889 » » want: gae.DSPropertyMap{ | 889 » » want: PropertyMap{ |
| 890 » » » "B": {mp(gae.DSByteString(makeUint8Slice(3)))}, | 890 » » » "B": {mp(ByteString(makeUint8Slice(3)))}, |
| 891 }, | 891 }, |
| 892 }, | 892 }, |
| 893 { | 893 { |
| 894 desc: "[]byte must be noindex", | 894 desc: "[]byte must be noindex", |
| 895 » » src: gae.DSPropertyMap{ | 895 » » src: PropertyMap{ |
| 896 "B": {mp(makeUint8Slice(3))}, | 896 "B": {mp(makeUint8Slice(3))}, |
| 897 }, | 897 }, |
| 898 actualNoIndex: true, | 898 actualNoIndex: true, |
| 899 }, | 899 }, |
| 900 { | 900 { |
| 901 desc: "save tagged load props", | 901 desc: "save tagged load props", |
| 902 src: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6
, J: 7}, | 902 src: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6
, J: 7}, |
| 903 » » want: gae.DSPropertyMap{ | 903 » » want: PropertyMap{ |
| 904 // A and B are renamed to a and b; A and C are noindex,
I is ignored. | 904 // A and B are renamed to a and b; A and C are noindex,
I is ignored. |
| 905 // Indexed properties are loaded before raw properties.
Thus, the | 905 // Indexed properties are loaded before raw properties.
Thus, the |
| 906 // result is: b, b, b, D, E, a, c. | 906 // result is: b, b, b, D, E, a, c. |
| 907 "b1": { | 907 "b1": { |
| 908 mp(21), | 908 mp(21), |
| 909 mp(22), | 909 mp(22), |
| 910 mp(23), | 910 mp(23), |
| 911 }, | 911 }, |
| 912 "D": {mp(4)}, | 912 "D": {mp(4)}, |
| 913 "E": {mp(5)}, | 913 "E": {mp(5)}, |
| 914 "a": {mpNI(1)}, | 914 "a": {mpNI(1)}, |
| 915 "C": {mpNI(3)}, | 915 "C": {mpNI(3)}, |
| 916 "J": {mpNI(7)}, | 916 "J": {mpNI(7)}, |
| 917 }, | 917 }, |
| 918 }, | 918 }, |
| 919 { | 919 { |
| 920 desc: "save tagged load tagged", | 920 desc: "save tagged load tagged", |
| 921 src: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6
, J: 7}, | 921 src: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6
, J: 7}, |
| 922 want: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7
}, | 922 want: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7
}, |
| 923 }, | 923 }, |
| 924 { | 924 { |
| 925 desc: "save props load tagged", | 925 desc: "save props load tagged", |
| 926 » » src: gae.DSPropertyMap{ | 926 » » src: PropertyMap{ |
| 927 "A": {mpNI(11)}, | 927 "A": {mpNI(11)}, |
| 928 "a": {mpNI(12)}, | 928 "a": {mpNI(12)}, |
| 929 }, | 929 }, |
| 930 want: &Tagged{A: 12}, | 930 want: &Tagged{A: 12}, |
| 931 loadErr: `cannot load field "A"`, | 931 loadErr: `cannot load field "A"`, |
| 932 }, | 932 }, |
| 933 { | 933 { |
| 934 desc: "invalid tagged1", | 934 desc: "invalid tagged1", |
| 935 src: &InvalidTagged1{I: 1}, | 935 src: &InvalidTagged1{I: 1}, |
| 936 plsErr: `struct tag has invalid property name: "\t"`, | 936 plsErr: `struct tag has invalid property name: "\t"`, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 957 plsErr: `struct tag has repeated property name: "V.I"`, | 957 plsErr: `struct tag has repeated property name: "V.I"`, |
| 958 }, | 958 }, |
| 959 { | 959 { |
| 960 desc: "doubler", | 960 desc: "doubler", |
| 961 src: &Doubler{S: "s", I: 1, B: true}, | 961 src: &Doubler{S: "s", I: 1, B: true}, |
| 962 want: &Doubler{S: "ss", I: 2, B: true}, | 962 want: &Doubler{S: "ss", I: 2, B: true}, |
| 963 }, | 963 }, |
| 964 { | 964 { |
| 965 desc: "save struct load props", | 965 desc: "save struct load props", |
| 966 src: &X0{S: "s", I: 1}, | 966 src: &X0{S: "s", I: 1}, |
| 967 » » want: gae.DSPropertyMap{ | 967 » » want: PropertyMap{ |
| 968 "S": {mp("s")}, | 968 "S": {mp("s")}, |
| 969 "I": {mp(1)}, | 969 "I": {mp(1)}, |
| 970 }, | 970 }, |
| 971 }, | 971 }, |
| 972 { | 972 { |
| 973 desc: "save props load struct", | 973 desc: "save props load struct", |
| 974 » » src: gae.DSPropertyMap{ | 974 » » src: PropertyMap{ |
| 975 "S": {mp("s")}, | 975 "S": {mp("s")}, |
| 976 "I": {mp(1)}, | 976 "I": {mp(1)}, |
| 977 }, | 977 }, |
| 978 want: &X0{S: "s", I: 1}, | 978 want: &X0{S: "s", I: 1}, |
| 979 }, | 979 }, |
| 980 { | 980 { |
| 981 desc: "nil-value props", | 981 desc: "nil-value props", |
| 982 » » src: gae.DSPropertyMap{ | 982 » » src: PropertyMap{ |
| 983 "I": {mp(nil)}, | 983 "I": {mp(nil)}, |
| 984 "B": {mp(nil)}, | 984 "B": {mp(nil)}, |
| 985 "S": {mp(nil)}, | 985 "S": {mp(nil)}, |
| 986 "F": {mp(nil)}, | 986 "F": {mp(nil)}, |
| 987 "K": {mp(nil)}, | 987 "K": {mp(nil)}, |
| 988 "T": {mp(nil)}, | 988 "T": {mp(nil)}, |
| 989 "J": { | 989 "J": { |
| 990 mp(nil), | 990 mp(nil), |
| 991 mp(7), | 991 mp(7), |
| 992 mp(nil), | 992 mp(nil), |
| 993 }, | 993 }, |
| 994 }, | 994 }, |
| 995 want: &struct { | 995 want: &struct { |
| 996 I int64 | 996 I int64 |
| 997 B bool | 997 B bool |
| 998 S string | 998 S string |
| 999 F float64 | 999 F float64 |
| 1000 » » » K gae.DSKey | 1000 » » » K Key |
| 1001 T time.Time | 1001 T time.Time |
| 1002 J []int64 | 1002 J []int64 |
| 1003 }{ | 1003 }{ |
| 1004 J: []int64{0, 7, 0}, | 1004 J: []int64{0, 7, 0}, |
| 1005 }, | 1005 }, |
| 1006 }, | 1006 }, |
| 1007 { | 1007 { |
| 1008 desc: "save outer load props", | 1008 desc: "save outer load props", |
| 1009 src: &Outer{ | 1009 src: &Outer{ |
| 1010 A: 1, | 1010 A: 1, |
| 1011 I: []Inner1{ | 1011 I: []Inner1{ |
| 1012 {10, "ten"}, | 1012 {10, "ten"}, |
| 1013 {20, "twenty"}, | 1013 {20, "twenty"}, |
| 1014 {30, "thirty"}, | 1014 {30, "thirty"}, |
| 1015 }, | 1015 }, |
| 1016 J: Inner2{ | 1016 J: Inner2{ |
| 1017 Y: 3.14, | 1017 Y: 3.14, |
| 1018 }, | 1018 }, |
| 1019 Inner3: Inner3{ | 1019 Inner3: Inner3{ |
| 1020 Z: true, | 1020 Z: true, |
| 1021 }, | 1021 }, |
| 1022 }, | 1022 }, |
| 1023 » » want: gae.DSPropertyMap{ | 1023 » » want: PropertyMap{ |
| 1024 "A": {mp(1)}, | 1024 "A": {mp(1)}, |
| 1025 "I.W": { | 1025 "I.W": { |
| 1026 mp(10), | 1026 mp(10), |
| 1027 mp(20), | 1027 mp(20), |
| 1028 mp(30), | 1028 mp(30), |
| 1029 }, | 1029 }, |
| 1030 "I.X": { | 1030 "I.X": { |
| 1031 mp("ten"), | 1031 mp("ten"), |
| 1032 mp("twenty"), | 1032 mp("twenty"), |
| 1033 mp("thirty"), | 1033 mp("thirty"), |
| 1034 }, | 1034 }, |
| 1035 "J.Y": {mp(3.14)}, | 1035 "J.Y": {mp(3.14)}, |
| 1036 "Z": {mp(true)}, | 1036 "Z": {mp(true)}, |
| 1037 }, | 1037 }, |
| 1038 }, | 1038 }, |
| 1039 { | 1039 { |
| 1040 desc: "save props load outer-equivalent", | 1040 desc: "save props load outer-equivalent", |
| 1041 » » src: gae.DSPropertyMap{ | 1041 » » src: PropertyMap{ |
| 1042 "A": {mp(1)}, | 1042 "A": {mp(1)}, |
| 1043 "I.W": { | 1043 "I.W": { |
| 1044 mp(10), | 1044 mp(10), |
| 1045 mp(20), | 1045 mp(20), |
| 1046 mp(30), | 1046 mp(30), |
| 1047 }, | 1047 }, |
| 1048 "I.X": { | 1048 "I.X": { |
| 1049 mp("ten"), | 1049 mp("ten"), |
| 1050 mp("twenty"), | 1050 mp("twenty"), |
| 1051 mp("thirty"), | 1051 mp("thirty"), |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1081 Y: 3.14, | 1081 Y: 3.14, |
| 1082 }, | 1082 }, |
| 1083 Inner3: Inner3{ | 1083 Inner3: Inner3{ |
| 1084 Z: true, | 1084 Z: true, |
| 1085 }, | 1085 }, |
| 1086 }, | 1086 }, |
| 1087 }, | 1087 }, |
| 1088 { | 1088 { |
| 1089 desc: "dotted names save", | 1089 desc: "dotted names save", |
| 1090 src: &Dotted{A: DottedA{B: DottedB{C: 88}}}, | 1090 src: &Dotted{A: DottedA{B: DottedB{C: 88}}}, |
| 1091 » » want: gae.DSPropertyMap{ | 1091 » » want: PropertyMap{ |
| 1092 "A0.A1.A2.B3.C4.C5": {mp(88)}, | 1092 "A0.A1.A2.B3.C4.C5": {mp(88)}, |
| 1093 }, | 1093 }, |
| 1094 }, | 1094 }, |
| 1095 { | 1095 { |
| 1096 desc: "dotted names load", | 1096 desc: "dotted names load", |
| 1097 » » src: gae.DSPropertyMap{ | 1097 » » src: PropertyMap{ |
| 1098 "A0.A1.A2.B3.C4.C5": {mp(99)}, | 1098 "A0.A1.A2.B3.C4.C5": {mp(99)}, |
| 1099 }, | 1099 }, |
| 1100 want: &Dotted{A: DottedA{B: DottedB{C: 99}}}, | 1100 want: &Dotted{A: DottedA{B: DottedB{C: 99}}}, |
| 1101 }, | 1101 }, |
| 1102 { | 1102 { |
| 1103 desc: "save struct load deriver", | 1103 desc: "save struct load deriver", |
| 1104 src: &X0{S: "s", I: 1}, | 1104 src: &X0{S: "s", I: 1}, |
| 1105 want: &Deriver{S: "s", Derived: "derived+s"}, | 1105 want: &Deriver{S: "s", Derived: "derived+s"}, |
| 1106 }, | 1106 }, |
| 1107 { | 1107 { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1153 want: &N0{ | 1153 want: &N0{ |
| 1154 X0: X0{S: "one", I: 2}, | 1154 X0: X0{S: "one", I: 2}, |
| 1155 Nonymous: X0{S: "four", I: 5}, | 1155 Nonymous: X0{S: "four", I: 5}, |
| 1156 Other: "other", | 1156 Other: "other", |
| 1157 }, | 1157 }, |
| 1158 }, | 1158 }, |
| 1159 { | 1159 { |
| 1160 desc: "exotic types", | 1160 desc: "exotic types", |
| 1161 src: &ExoticTypes{ | 1161 src: &ExoticTypes{ |
| 1162 BS: "sup", | 1162 BS: "sup", |
| 1163 » » » DSBS: gae.DSByteString("nerds"), | 1163 » » » DSBS: ByteString("nerds"), |
| 1164 }, | 1164 }, |
| 1165 want: &ExoticTypes{ | 1165 want: &ExoticTypes{ |
| 1166 BS: "sup", | 1166 BS: "sup", |
| 1167 » » » DSBS: gae.DSByteString("nerds"), | 1167 » » » DSBS: ByteString("nerds"), |
| 1168 }, | 1168 }, |
| 1169 }, | 1169 }, |
| 1170 { | 1170 { |
| 1171 desc: "underspecified types", | 1171 desc: "underspecified types", |
| 1172 src: &Underspecified{}, | 1172 src: &Underspecified{}, |
| 1173 plsErr: "non-concrete interface", | 1173 plsErr: "non-concrete interface", |
| 1174 }, | 1174 }, |
| 1175 { | 1175 { |
| 1176 desc: "mismatch (string)", | 1176 desc: "mismatch (string)", |
| 1177 » » src: gae.DSPropertyMap{ | 1177 » » src: PropertyMap{ |
| 1178 "K": {mp(199)}, | 1178 "K": {mp(199)}, |
| 1179 "S": {mp([]byte("cats"))}, | 1179 "S": {mp([]byte("cats"))}, |
| 1180 » » » "F": {mp(gae.DSByteString("nurbs"))}, | 1180 » » » "F": {mp(ByteString("nurbs"))}, |
| 1181 }, | 1181 }, |
| 1182 want: &MismatchTypes{}, | 1182 want: &MismatchTypes{}, |
| 1183 loadErr: "type mismatch", | 1183 loadErr: "type mismatch", |
| 1184 }, | 1184 }, |
| 1185 { | 1185 { |
| 1186 desc: "mismatch (float)", | 1186 desc: "mismatch (float)", |
| 1187 » » src: gae.DSPropertyMap{"F": {mp(gae.BSKey("wot"))}}, | 1187 » » src: PropertyMap{"F": {mp(blobstore.Key("wot"))}}, |
| 1188 want: &MismatchTypes{}, | 1188 want: &MismatchTypes{}, |
| 1189 loadErr: "type mismatch", | 1189 loadErr: "type mismatch", |
| 1190 }, | 1190 }, |
| 1191 { | 1191 { |
| 1192 desc: "mismatch (float/overflow)", | 1192 desc: "mismatch (float/overflow)", |
| 1193 » » src: gae.DSPropertyMap{"F": {mp(math.MaxFloat64)}}, | 1193 » » src: PropertyMap{"F": {mp(math.MaxFloat64)}}, |
| 1194 want: &MismatchTypes{}, | 1194 want: &MismatchTypes{}, |
| 1195 loadErr: "overflows", | 1195 loadErr: "overflows", |
| 1196 }, | 1196 }, |
| 1197 { | 1197 { |
| 1198 desc: "mismatch (key)", | 1198 desc: "mismatch (key)", |
| 1199 » » src: gae.DSPropertyMap{"K": {mp(false)}}, | 1199 » » src: PropertyMap{"K": {mp(false)}}, |
| 1200 want: &MismatchTypes{}, | 1200 want: &MismatchTypes{}, |
| 1201 loadErr: "type mismatch", | 1201 loadErr: "type mismatch", |
| 1202 }, | 1202 }, |
| 1203 { | 1203 { |
| 1204 desc: "mismatch (bool)", | 1204 desc: "mismatch (bool)", |
| 1205 » » src: gae.DSPropertyMap{"B": {mp(testKey0)}}, | 1205 » » src: PropertyMap{"B": {mp(testKey0)}}, |
| 1206 want: &MismatchTypes{}, | 1206 want: &MismatchTypes{}, |
| 1207 loadErr: "type mismatch", | 1207 loadErr: "type mismatch", |
| 1208 }, | 1208 }, |
| 1209 { | 1209 { |
| 1210 desc: "mismatch (time)", | 1210 desc: "mismatch (time)", |
| 1211 » » src: gae.DSPropertyMap{"T": {mp(gae.DSGeoPoint{})}}, | 1211 » » src: PropertyMap{"T": {mp(GeoPoint{})}}, |
| 1212 want: &MismatchTypes{}, | 1212 want: &MismatchTypes{}, |
| 1213 loadErr: "type mismatch", | 1213 loadErr: "type mismatch", |
| 1214 }, | 1214 }, |
| 1215 { | 1215 { |
| 1216 desc: "mismatch (geopoint)", | 1216 desc: "mismatch (geopoint)", |
| 1217 » » src: gae.DSPropertyMap{"G": {mp(time.Now().UTC())}}, | 1217 » » src: PropertyMap{"G": {mp(time.Now().UTC())}}, |
| 1218 want: &MismatchTypes{}, | 1218 want: &MismatchTypes{}, |
| 1219 loadErr: "type mismatch", | 1219 loadErr: "type mismatch", |
| 1220 }, | 1220 }, |
| 1221 { | 1221 { |
| 1222 desc: "slice of structs", | 1222 desc: "slice of structs", |
| 1223 src: &N1{ | 1223 src: &N1{ |
| 1224 X0: X0{S: "one", I: 2, i: 3}, | 1224 X0: X0{S: "one", I: 2, i: 3}, |
| 1225 Nonymous: []X0{ | 1225 Nonymous: []X0{ |
| 1226 {S: "four", I: 5, i: 6}, | 1226 {S: "four", I: 5, i: 6}, |
| 1227 {S: "seven", I: 8, i: 9}, | 1227 {S: "seven", I: 8, i: 9}, |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1318 Blue: N1{ | 1318 Blue: N1{ |
| 1319 X0: X0{S: "bleu"}, | 1319 X0: X0{S: "bleu"}, |
| 1320 Nonymous: []X0{ | 1320 Nonymous: []X0{ |
| 1321 {S: "blu0"}, | 1321 {S: "blu0"}, |
| 1322 {S: "blu1"}, | 1322 {S: "blu1"}, |
| 1323 {S: "blu2"}, | 1323 {S: "blu2"}, |
| 1324 {S: "blu3"}, | 1324 {S: "blu3"}, |
| 1325 }, | 1325 }, |
| 1326 }, | 1326 }, |
| 1327 }, | 1327 }, |
| 1328 » » want: gae.DSPropertyMap{ | 1328 » » want: PropertyMap{ |
| 1329 "red.S": {mp("rouge")}, | 1329 "red.S": {mp("rouge")}, |
| 1330 "red.I": {mp(0)}, | 1330 "red.I": {mp(0)}, |
| 1331 "red.Nonymous.S": {mp("rosso0"), mp("rosso1")}, | 1331 "red.Nonymous.S": {mp("rosso0"), mp("rosso1")}, |
| 1332 "red.Nonymous.I": {mp(0), mp(0)}, | 1332 "red.Nonymous.I": {mp(0), mp(0)}, |
| 1333 "red.Other": {mp("")}, | 1333 "red.Other": {mp("")}, |
| 1334 "green.S": {mp("vert")}, | 1334 "green.S": {mp("vert")}, |
| 1335 "green.I": {mp(0)}, | 1335 "green.I": {mp(0)}, |
| 1336 "green.Nonymous.S": {mp("verde0"), mp("verde1"), mp("ver
de2")}, | 1336 "green.Nonymous.S": {mp("verde0"), mp("verde1"), mp("ver
de2")}, |
| 1337 "green.Nonymous.I": {mp(0), mp(0), mp(0)}, | 1337 "green.Nonymous.I": {mp(0), mp(0), mp(0)}, |
| 1338 "green.Other": {mp("")}, | 1338 "green.Other": {mp("")}, |
| 1339 "Blue.S": {mp("bleu")}, | 1339 "Blue.S": {mp("bleu")}, |
| 1340 "Blue.I": {mp(0)}, | 1340 "Blue.I": {mp(0)}, |
| 1341 "Blue.Nonymous.S": {mp("blu0"), mp("blu1"), mp("blu2"),
mp("blu3")}, | 1341 "Blue.Nonymous.S": {mp("blu0"), mp("blu1"), mp("blu2"),
mp("blu3")}, |
| 1342 "Blue.Nonymous.I": {mp(0), mp(0), mp(0), mp(0)}, | 1342 "Blue.Nonymous.I": {mp(0), mp(0), mp(0), mp(0)}, |
| 1343 "Blue.Other": {mp("")}, | 1343 "Blue.Other": {mp("")}, |
| 1344 }, | 1344 }, |
| 1345 }, | 1345 }, |
| 1346 { | 1346 { |
| 1347 desc: "save props load structs with ragged fields", | 1347 desc: "save props load structs with ragged fields", |
| 1348 » » src: gae.DSPropertyMap{ | 1348 » » src: PropertyMap{ |
| 1349 "red.S": {mp("rot")}, | 1349 "red.S": {mp("rot")}, |
| 1350 "green.Nonymous.I": {mp(10), mp(11), mp(12), mp(13)}, | 1350 "green.Nonymous.I": {mp(10), mp(11), mp(12), mp(13)}, |
| 1351 "Blue.Nonymous.S": {mp("blau0"), mp("blau1"), mp("blau2
")}, | 1351 "Blue.Nonymous.S": {mp("blau0"), mp("blau1"), mp("blau2
")}, |
| 1352 "Blue.Nonymous.I": {mp(20), mp(21)}, | 1352 "Blue.Nonymous.I": {mp(20), mp(21)}, |
| 1353 }, | 1353 }, |
| 1354 want: &N2{ | 1354 want: &N2{ |
| 1355 N1: N1{ | 1355 N1: N1{ |
| 1356 X0: X0{S: "rot"}, | 1356 X0: X0{S: "rot"}, |
| 1357 }, | 1357 }, |
| 1358 Green: N1{ | 1358 Green: N1{ |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1377 src: &struct { | 1377 src: &struct { |
| 1378 A struct { | 1378 A struct { |
| 1379 X string `gae:",noindex"` | 1379 X string `gae:",noindex"` |
| 1380 Y string | 1380 Y string |
| 1381 } `gae:",noindex"` | 1381 } `gae:",noindex"` |
| 1382 B struct { | 1382 B struct { |
| 1383 X string `gae:",noindex"` | 1383 X string `gae:",noindex"` |
| 1384 Y string | 1384 Y string |
| 1385 } | 1385 } |
| 1386 }{}, | 1386 }{}, |
| 1387 » » want: gae.DSPropertyMap{ | 1387 » » want: PropertyMap{ |
| 1388 "B.Y": {mp("")}, | 1388 "B.Y": {mp("")}, |
| 1389 "A.X": {mpNI("")}, | 1389 "A.X": {mpNI("")}, |
| 1390 "A.Y": {mpNI("")}, | 1390 "A.Y": {mpNI("")}, |
| 1391 "B.X": {mpNI("")}, | 1391 "B.X": {mpNI("")}, |
| 1392 }, | 1392 }, |
| 1393 }, | 1393 }, |
| 1394 { | 1394 { |
| 1395 desc: "embedded struct with name override", | 1395 desc: "embedded struct with name override", |
| 1396 src: &struct { | 1396 src: &struct { |
| 1397 Inner1 `gae:"foo"` | 1397 Inner1 `gae:"foo"` |
| 1398 }{}, | 1398 }{}, |
| 1399 » » want: gae.DSPropertyMap{ | 1399 » » want: PropertyMap{ |
| 1400 "foo.W": {mp(0)}, | 1400 "foo.W": {mp(0)}, |
| 1401 "foo.X": {mp("")}, | 1401 "foo.X": {mp("")}, |
| 1402 }, | 1402 }, |
| 1403 }, | 1403 }, |
| 1404 { | 1404 { |
| 1405 desc: "slice of slices", | 1405 desc: "slice of slices", |
| 1406 src: &SliceOfSlices{}, | 1406 src: &SliceOfSlices{}, |
| 1407 plsErr: `flattening nested structs leads to a slice of slices: f
ield "S"`, | 1407 plsErr: `flattening nested structs leads to a slice of slices: f
ield "S"`, |
| 1408 }, | 1408 }, |
| 1409 { | 1409 { |
| 1410 desc: "recursive struct", | 1410 desc: "recursive struct", |
| 1411 src: &Recursive{}, | 1411 src: &Recursive{}, |
| 1412 plsErr: `field "R" is recursively defined`, | 1412 plsErr: `field "R" is recursively defined`, |
| 1413 }, | 1413 }, |
| 1414 { | 1414 { |
| 1415 desc: "mutually recursive struct", | 1415 desc: "mutually recursive struct", |
| 1416 src: &MutuallyRecursive0{}, | 1416 src: &MutuallyRecursive0{}, |
| 1417 plsErr: `field "R" has problem: field "R" is recursively defined
`, | 1417 plsErr: `field "R" has problem: field "R" is recursively defined
`, |
| 1418 }, | 1418 }, |
| 1419 { | 1419 { |
| 1420 desc: "non-exported struct fields", | 1420 desc: "non-exported struct fields", |
| 1421 src: &struct { | 1421 src: &struct { |
| 1422 i, J int64 | 1422 i, J int64 |
| 1423 }{i: 1, J: 2}, | 1423 }{i: 1, J: 2}, |
| 1424 » » want: gae.DSPropertyMap{ | 1424 » » want: PropertyMap{ |
| 1425 "J": {mp(2)}, | 1425 "J": {mp(2)}, |
| 1426 }, | 1426 }, |
| 1427 }, | 1427 }, |
| 1428 { | 1428 { |
| 1429 desc: "json.RawMessage", | 1429 desc: "json.RawMessage", |
| 1430 src: &struct { | 1430 src: &struct { |
| 1431 J json.RawMessage | 1431 J json.RawMessage |
| 1432 }{ | 1432 }{ |
| 1433 J: json.RawMessage("rawr"), | 1433 J: json.RawMessage("rawr"), |
| 1434 }, | 1434 }, |
| 1435 » » want: gae.DSPropertyMap{ | 1435 » » want: PropertyMap{ |
| 1436 "J": {mp([]byte("rawr"))}, | 1436 "J": {mp([]byte("rawr"))}, |
| 1437 }, | 1437 }, |
| 1438 }, | 1438 }, |
| 1439 { | 1439 { |
| 1440 desc: "json.RawMessage to myBlob", | 1440 desc: "json.RawMessage to myBlob", |
| 1441 src: &struct { | 1441 src: &struct { |
| 1442 B json.RawMessage | 1442 B json.RawMessage |
| 1443 }{ | 1443 }{ |
| 1444 B: json.RawMessage("rawr"), | 1444 B: json.RawMessage("rawr"), |
| 1445 }, | 1445 }, |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1498 | 1498 |
| 1499 checkErr := func(actual interface{}, expected string) bool { | 1499 checkErr := func(actual interface{}, expected string) bool { |
| 1500 So(actual, ShouldErrLike, expected) | 1500 So(actual, ShouldErrLike, expected) |
| 1501 return expected != "" | 1501 return expected != "" |
| 1502 } | 1502 } |
| 1503 | 1503 |
| 1504 Convey("Test round-trip", t, func() { | 1504 Convey("Test round-trip", t, func() { |
| 1505 for _, tc := range testCases { | 1505 for _, tc := range testCases { |
| 1506 tc := tc | 1506 tc := tc |
| 1507 Convey(tc.desc, func() { | 1507 Convey(tc.desc, func() { |
| 1508 » » » » pls, ok := tc.src.(gae.DSPropertyLoadSaver) | 1508 » » » » pls, ok := tc.src.(PropertyLoadSaver) |
| 1509 if !ok { | 1509 if !ok { |
| 1510 pls = GetPLS(tc.src) | 1510 pls = GetPLS(tc.src) |
| 1511 } | 1511 } |
| 1512 if checkErr(pls.Problem(), tc.plsErr) { | 1512 if checkErr(pls.Problem(), tc.plsErr) { |
| 1513 return | 1513 return |
| 1514 } | 1514 } |
| 1515 So(pls, ShouldNotBeNil) | 1515 So(pls, ShouldNotBeNil) |
| 1516 | 1516 |
| 1517 savedProps, err := pls.Save(false) | 1517 savedProps, err := pls.Save(false) |
| 1518 if checkErr(err, tc.saveErr) { | 1518 if checkErr(err, tc.saveErr) { |
| 1519 return | 1519 return |
| 1520 } | 1520 } |
| 1521 So(savedProps, ShouldNotBeNil) | 1521 So(savedProps, ShouldNotBeNil) |
| 1522 | 1522 |
| 1523 if tc.actualNoIndex { | 1523 if tc.actualNoIndex { |
| 1524 for _, props := range savedProps { | 1524 for _, props := range savedProps { |
| 1525 » » » » » » So(props[0].IndexSetting(), Shou
ldEqual, gae.NoIndex) | 1525 » » » » » » So(props[0].IndexSetting(), Shou
ldEqual, NoIndex) |
| 1526 return | 1526 return |
| 1527 } | 1527 } |
| 1528 So(true, ShouldBeFalse) // shouldn't get
here | 1528 So(true, ShouldBeFalse) // shouldn't get
here |
| 1529 } | 1529 } |
| 1530 | 1530 |
| 1531 var got interface{} | 1531 var got interface{} |
| 1532 » » » » if _, ok := tc.want.(gae.DSPropertyMap); ok { | 1532 » » » » if _, ok := tc.want.(PropertyMap); ok { |
| 1533 » » » » » pls = gae.DSPropertyMap{} | 1533 » » » » » pls = PropertyMap{} |
| 1534 got = pls | 1534 got = pls |
| 1535 } else { | 1535 } else { |
| 1536 got = reflect.New(reflect.TypeOf(tc.want
).Elem()).Interface() | 1536 got = reflect.New(reflect.TypeOf(tc.want
).Elem()).Interface() |
| 1537 » » » » » if pls, ok = got.(gae.DSPropertyLoadSave
r); !ok { | 1537 » » » » » if pls, ok = got.(PropertyLoadSaver); !o
k { |
| 1538 pls = GetPLS(got) | 1538 pls = GetPLS(got) |
| 1539 } | 1539 } |
| 1540 } | 1540 } |
| 1541 | 1541 |
| 1542 if checkErr(pls.Problem(), tc.plsLoadErr) { | 1542 if checkErr(pls.Problem(), tc.plsLoadErr) { |
| 1543 return | 1543 return |
| 1544 } | 1544 } |
| 1545 So(pls, ShouldNotBeNil) | 1545 So(pls, ShouldNotBeNil) |
| 1546 | 1546 |
| 1547 err = pls.Load(savedProps) | 1547 err = pls.Load(savedProps) |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1577 | 1577 |
| 1578 val, err = pls.GetMeta("kind") | 1578 val, err = pls.GetMeta("kind") |
| 1579 So(err, ShouldBeNil) | 1579 So(err, ShouldBeNil) |
| 1580 So(val, ShouldEqual, "whatnow") | 1580 So(val, ShouldEqual, "whatnow") |
| 1581 }) | 1581 }) |
| 1582 | 1582 |
| 1583 Convey("Getting something not there is an error", func() { | 1583 Convey("Getting something not there is an error", func() { |
| 1584 o := &N0{ID: 100} | 1584 o := &N0{ID: 100} |
| 1585 pls := GetPLS(o) | 1585 pls := GetPLS(o) |
| 1586 _, err := pls.GetMeta("wat") | 1586 _, err := pls.GetMeta("wat") |
| 1587 » » » So(err, ShouldEqual, gae.ErrDSMetaFieldUnset) | 1587 » » » So(err, ShouldEqual, ErrMetaFieldUnset) |
| 1588 }) | 1588 }) |
| 1589 | 1589 |
| 1590 Convey("getting/setting from a bad struct is an error", func() { | 1590 Convey("getting/setting from a bad struct is an error", func() { |
| 1591 o := &Recursive{} | 1591 o := &Recursive{} |
| 1592 pls := GetPLS(o) | 1592 pls := GetPLS(o) |
| 1593 _, err := pls.GetMeta("wat") | 1593 _, err := pls.GetMeta("wat") |
| 1594 So(err, ShouldNotBeNil) | 1594 So(err, ShouldNotBeNil) |
| 1595 | 1595 |
| 1596 err = pls.SetMeta("wat", 100) | 1596 err = pls.SetMeta("wat", 100) |
| 1597 So(err, ShouldNotBeNil) | 1597 So(err, ShouldNotBeNil) |
| 1598 }) | 1598 }) |
| 1599 | 1599 |
| 1600 Convey("can assign values to exported special fields", func() { | 1600 Convey("can assign values to exported special fields", func() { |
| 1601 o := &N0{ID: 100} | 1601 o := &N0{ID: 100} |
| 1602 pls := GetPLS(o) | 1602 pls := GetPLS(o) |
| 1603 err := pls.SetMeta("id", int64(200)) | 1603 err := pls.SetMeta("id", int64(200)) |
| 1604 So(err, ShouldBeNil) | 1604 So(err, ShouldBeNil) |
| 1605 So(o.ID, ShouldEqual, 200) | 1605 So(o.ID, ShouldEqual, 200) |
| 1606 | 1606 |
| 1607 }) | 1607 }) |
| 1608 | 1608 |
| 1609 Convey("assigning to unsassiagnable fields is a simple error", f
unc() { | 1609 Convey("assigning to unsassiagnable fields is a simple error", f
unc() { |
| 1610 o := &N0{ID: 100} | 1610 o := &N0{ID: 100} |
| 1611 pls := GetPLS(o) | 1611 pls := GetPLS(o) |
| 1612 err := pls.SetMeta("kind", "hi") | 1612 err := pls.SetMeta("kind", "hi") |
| 1613 So(err.Error(), ShouldContainSubstring, "unexported fiel
d") | 1613 So(err.Error(), ShouldContainSubstring, "unexported fiel
d") |
| 1614 | 1614 |
| 1615 err = pls.SetMeta("noob", "hi") | 1615 err = pls.SetMeta("noob", "hi") |
| 1616 » » » So(err, ShouldEqual, gae.ErrDSMetaFieldUnset) | 1616 » » » So(err, ShouldEqual, ErrMetaFieldUnset) |
| 1617 }) | 1617 }) |
| 1618 }) | 1618 }) |
| 1619 | 1619 |
| 1620 Convey("StructPLS Miscellaneous", t, func() { | 1620 Convey("StructPLS Miscellaneous", t, func() { |
| 1621 Convey("multiple overlapping fields is an error", func() { | 1621 Convey("multiple overlapping fields is an error", func() { |
| 1622 o := &BadSpecial{} | 1622 o := &BadSpecial{} |
| 1623 pls := GetPLS(o) | 1623 pls := GetPLS(o) |
| 1624 err := pls.Load(nil) | 1624 err := pls.Load(nil) |
| 1625 So(err, ShouldErrLike, "multiple times") | 1625 So(err, ShouldErrLike, "multiple times") |
| 1626 e := pls.Problem() | 1626 e := pls.Problem() |
| 1627 _, err = pls.Save(true) | 1627 _, err = pls.Save(true) |
| 1628 So(err, ShouldEqual, e) | 1628 So(err, ShouldEqual, e) |
| 1629 err = pls.Load(nil) | 1629 err = pls.Load(nil) |
| 1630 So(err, ShouldEqual, e) | 1630 So(err, ShouldEqual, e) |
| 1631 }) | 1631 }) |
| 1632 | 1632 |
| 1633 Convey("empty property names are invalid", func() { | 1633 Convey("empty property names are invalid", func() { |
| 1634 So(validPropertyName(""), ShouldBeFalse) | 1634 So(validPropertyName(""), ShouldBeFalse) |
| 1635 }) | 1635 }) |
| 1636 | 1636 |
| 1637 Convey("attempting to get a PLS for a non *struct is an error",
func() { | 1637 Convey("attempting to get a PLS for a non *struct is an error",
func() { |
| 1638 pls := GetPLS((*[]string)(nil)) | 1638 pls := GetPLS((*[]string)(nil)) |
| 1639 » » » So(pls.Problem(), ShouldEqual, gae.ErrDSInvalidEntityTyp
e) | 1639 » » » So(pls.Problem(), ShouldEqual, ErrInvalidEntityType) |
| 1640 }) | 1640 }) |
| 1641 | 1641 |
| 1642 Convey("convertible meta default types", func() { | 1642 Convey("convertible meta default types", func() { |
| 1643 type OKDefaults struct { | 1643 type OKDefaults struct { |
| 1644 When string `gae:"$when,tomorrow"` | 1644 When string `gae:"$when,tomorrow"` |
| 1645 Amount int64 `gae:"$amt,100"` | 1645 Amount int64 `gae:"$amt,100"` |
| 1646 } | 1646 } |
| 1647 pls := GetPLS(&OKDefaults{}) | 1647 pls := GetPLS(&OKDefaults{}) |
| 1648 So(pls.Problem(), ShouldBeNil) | 1648 So(pls.Problem(), ShouldBeNil) |
| 1649 | 1649 |
| 1650 v, err := pls.GetMeta("when") | 1650 v, err := pls.GetMeta("when") |
| 1651 So(err, ShouldBeNil) | 1651 So(err, ShouldBeNil) |
| 1652 So(v, ShouldEqual, "tomorrow") | 1652 So(v, ShouldEqual, "tomorrow") |
| 1653 | 1653 |
| 1654 v, err = pls.GetMeta("amt") | 1654 v, err = pls.GetMeta("amt") |
| 1655 So(err, ShouldBeNil) | 1655 So(err, ShouldBeNil) |
| 1656 So(v, ShouldEqual, int64(100)) | 1656 So(v, ShouldEqual, int64(100)) |
| 1657 }) | 1657 }) |
| 1658 | 1658 |
| 1659 Convey("meta fields can be saved", func() { | 1659 Convey("meta fields can be saved", func() { |
| 1660 type OKDefaults struct { | 1660 type OKDefaults struct { |
| 1661 When string `gae:"$when,tomorrow"` | 1661 When string `gae:"$when,tomorrow"` |
| 1662 Amount int64 `gae:"$amt,100"` | 1662 Amount int64 `gae:"$amt,100"` |
| 1663 } | 1663 } |
| 1664 pls := GetPLS(&OKDefaults{}) | 1664 pls := GetPLS(&OKDefaults{}) |
| 1665 pm, err := pls.Save(true) | 1665 pm, err := pls.Save(true) |
| 1666 So(err, ShouldBeNil) | 1666 So(err, ShouldBeNil) |
| 1667 » » » So(pm, ShouldResemble, gae.DSPropertyMap{ | 1667 » » » So(pm, ShouldResemble, PropertyMap{ |
| 1668 » » » » "$when": {gae.MkDSPropertyNI("tomorrow")}, | 1668 » » » » "$when": {mpNI("tomorrow")}, |
| 1669 » » » » "$amt": {gae.MkDSPropertyNI(100)}, | 1669 » » » » "$amt": {mpNI(100)}, |
| 1670 }) | 1670 }) |
| 1671 | 1671 |
| 1672 v, err := pm.GetMeta("when") | 1672 v, err := pm.GetMeta("when") |
| 1673 So(err, ShouldBeNil) | 1673 So(err, ShouldBeNil) |
| 1674 So(v, ShouldEqual, "tomorrow") | 1674 So(v, ShouldEqual, "tomorrow") |
| 1675 | 1675 |
| 1676 v, err = pm.GetMeta("amt") | 1676 v, err = pm.GetMeta("amt") |
| 1677 So(err, ShouldBeNil) | 1677 So(err, ShouldBeNil) |
| 1678 So(v, ShouldEqual, int64(100)) | 1678 So(v, ShouldEqual, int64(100)) |
| 1679 }) | 1679 }) |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1709 | 1709 |
| 1710 Convey("Bad default meta type", func() { | 1710 Convey("Bad default meta type", func() { |
| 1711 type BadDefault struct { | 1711 type BadDefault struct { |
| 1712 Val time.Time `gae:"$meta,tomorrow"` | 1712 Val time.Time `gae:"$meta,tomorrow"` |
| 1713 } | 1713 } |
| 1714 pls := GetPLS(&BadDefault{}) | 1714 pls := GetPLS(&BadDefault{}) |
| 1715 So(pls.Problem().Error(), ShouldContainSubstring, "bad t
ype") | 1715 So(pls.Problem().Error(), ShouldContainSubstring, "bad t
ype") |
| 1716 }) | 1716 }) |
| 1717 }) | 1717 }) |
| 1718 } | 1718 } |
| OLD | NEW |