Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: service/datastore/pls_test.go

Issue 1292913002: Split off serialization and key functions to their own packages. (Closed) Base URL: https://github.com/luci/gae.git@make_queries_better
Patch Set: rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « service/datastore/key_test.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 datastore 7 package datastore
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/service/blobstore" 20 "github.com/luci/gae/service/blobstore"
21 . "github.com/luci/luci-go/common/testing/assertions"
21 . "github.com/smartystreets/goconvey/convey" 22 . "github.com/smartystreets/goconvey/convey"
22 ) 23 )
23 24
24 var ( 25 var (
25 mp = MkProperty 26 mp = MkProperty
26 mpNI = MkPropertyNI 27 mpNI = MkPropertyNI
27 ) 28 )
28 29
29 const testAppID = "testApp" 30 const testAppID = "testApp"
30 31
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 *c = Complex(complex(gval.Lat, gval.Lng)) 521 *c = Complex(complex(gval.Lat, gval.Lng))
521 return nil 522 return nil
522 } 523 }
523 return fmt.Errorf("nope") 524 return fmt.Errorf("nope")
524 } 525 }
525 526
526 type Impossible4 struct { 527 type Impossible4 struct {
527 Values []Complex 528 Values []Complex
528 } 529 }
529 530
531 // TODO(riannucci): see if there's a way to NOT have this be a duplicate of
532 // key.Generic. I couldn't figure out the package interdependency, and this
533 // allows things to be in separate packages.
534 type genericKey struct {
535 kind string
536 sid string
537 iid int64
538
539 aid string
540 ns string
541
542 parent *genericKey
543 }
544
545 func (g *genericKey) Kind() string { return g.kind }
546 func (g *genericKey) StringID() string { return g.sid }
547 func (g *genericKey) IntID() int64 { return g.iid }
548 func (g *genericKey) AppID() string { return g.aid }
549 func (g *genericKey) Namespace() string { return g.ns }
550 func (g *genericKey) Parent() Key { return g.parent }
551
552 func marshalDSKey(b *bytes.Buffer, k *genericKey) {
553 if k.parent != nil {
554 marshalDSKey(b, k.parent)
555 }
556 b.WriteByte('/')
557 b.WriteString(k.kind)
558 b.WriteByte(',')
559 if k.sid != "" {
560 b.WriteString(k.sid)
561 } else {
562 b.WriteString(strconv.FormatInt(k.iid, 10))
563 }
564 }
565
566 func (g *genericKey) String() string {
567 if g == nil {
568 return ""
569 }
570 b := bytes.NewBuffer(make([]byte, 0, 512))
571 marshalDSKey(b, g)
572 return b.String()
573 }
574
575 func (g *genericKey) Incomplete() bool {
576 return g.iid == 0 && g.sid == ""
577 }
578
579 func (g *genericKey) Valid(allowSpecial bool, aid, ns string) bool {
580 if g == nil {
581 return false
582 }
583 if aid != g.AppID() || ns != g.Namespace() {
584 return false
585 }
586 for ; g != nil; g = g.parent {
587 if !allowSpecial && len(g.Kind()) >= 2 && g.Kind()[:2] == "__" {
588 return false
589 }
590 if g.Kind() == "" || g.AppID() == "" {
591 return false
592 }
593 if g.StringID() != "" && g.IntID() != 0 {
594 return false
595 }
596 if g.parent != nil {
597 if g.parent.Incomplete() {
598 return false
599 }
600 if g.parent.AppID() != g.AppID() || g.parent.Namespace() != g.Namespace() {
601 return false
602 }
603 }
604 }
605 return true
606 }
607
608 func (g *genericKey) PartialValid(aid, ns string) bool {
609 if g.Incomplete() {
610 g = mkKey(g.AppID(), g.Namespace(), g.Kind(), 1, g.Parent()).(*g enericKey)
611 }
612 return g.Valid(false, aid, ns)
613 }
614
615 var _ Key = (*genericKey)(nil)
616
617 func mkKey(aid, ns string, pairs ...interface{}) Key {
618 ret := (*genericKey)(nil)
619 if len(pairs)%2 != 0 {
620 ret, _ = pairs[len(pairs)-1].(*genericKey)
621 pairs = pairs[:len(pairs)-1]
622 }
623 for i := 0; i < len(pairs); i += 2 {
624 kind := pairs[i].(string)
625 id := pairs[i+1]
626 ret = &genericKey{
627 kind: kind,
628 aid: aid,
629 ns: ns,
630 parent: ret,
631 }
632 ret.sid, _ = id.(string)
633 iid, ok := id.(int)
634 if ok {
635 ret.iid = int64(iid)
636 } else {
637 ret.iid, _ = id.(int64)
638 }
639 }
640 return ret
641 }
642
530 type DerivedKey struct { 643 type DerivedKey struct {
531 » K *GenericKey 644 » K *genericKey
532 } 645 }
533 646
534 type IfaceKey struct { 647 type IfaceKey struct {
535 K Key 648 K Key
536 } 649 }
537 650
538 type testCase struct { 651 type testCase struct {
539 desc string 652 desc string
540 src interface{} 653 src interface{}
541 want interface{} 654 want interface{}
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 }, 905 },
793 }, 906 },
794 { 907 {
795 desc: "convertable complex slice (bad load)", 908 desc: "convertable complex slice (bad load)",
796 src: PropertyMap{"Values": {mp("hello")}}, 909 src: PropertyMap{"Values": {mp("hello")}},
797 want: &Impossible4{[]Complex(nil)}, 910 want: &Impossible4{[]Complex(nil)},
798 loadErr: "nope", 911 loadErr: "nope",
799 }, 912 },
800 { 913 {
801 desc: "allow concrete Key implementors (save)", 914 desc: "allow concrete Key implementors (save)",
802 » » src: &DerivedKey{testKey2a.(*GenericKey)}, 915 » » src: &DerivedKey{testKey2a.(*genericKey)},
803 want: &IfaceKey{testKey2b}, 916 want: &IfaceKey{testKey2b},
804 }, 917 },
805 { 918 {
806 desc: "allow concrete Key implementors (load)", 919 desc: "allow concrete Key implementors (load)",
807 src: &IfaceKey{testKey2b}, 920 src: &IfaceKey{testKey2b},
808 » » want: &DerivedKey{testKey2a.(*GenericKey)}, 921 » » want: &DerivedKey{testKey2a.(*genericKey)},
809 }, 922 },
810 { 923 {
811 desc: "save []float64 load []int64", 924 desc: "save []float64 load []int64",
812 src: &Y0{B: true, F: []float64{7, 8, 9}}, 925 src: &Y0{B: true, F: []float64{7, 8, 9}},
813 want: &Y2{B: true}, 926 want: &Y2{B: true},
814 loadErr: "type mismatch", 927 loadErr: "type mismatch",
815 }, 928 },
816 { 929 {
817 desc: "single slice is too long", 930 desc: "single slice is too long",
818 src: &Y0{F: make([]float64, maxIndexedProperties+1)}, 931 src: &Y0{F: make([]float64, maxIndexedProperties+1)},
(...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after
1456 got := err.Error() 1569 got := err.Error()
1457 if want == "" || strings.Index(got, want) == -1 { 1570 if want == "" || strings.Index(got, want) == -1 {
1458 return got 1571 return got
1459 } 1572 }
1460 } else if want != "" { 1573 } else if want != "" {
1461 return fmt.Sprintf("want error %q", want) 1574 return fmt.Sprintf("want error %q", want)
1462 } 1575 }
1463 return "" 1576 return ""
1464 } 1577 }
1465 1578
1466 func ShouldErrLike(actual interface{}, expected ...interface{}) string {
1467 e2s := func(o interface{}) (string, bool) {
1468 switch x := o.(type) {
1469 case nil:
1470 return "", true
1471 case string:
1472 return x, true
1473 case error:
1474 if x != nil {
1475 return x.Error(), true
1476 }
1477 return "", true
1478 }
1479 return fmt.Sprintf("unknown argument type %T, expected string, e rror or nil", actual), false
1480 }
1481
1482 as, ok := e2s(actual)
1483 if !ok {
1484 return as
1485 }
1486
1487 if len(expected) != 1 {
1488 return fmt.Sprintf("Assertion requires 1 expected value, got %d" , len(expected))
1489 }
1490
1491 err, ok := e2s(expected[0])
1492 if !ok {
1493 return err
1494 }
1495 return ShouldContainSubstring(as, err)
1496 }
1497
1498 func TestRoundTrip(t *testing.T) { 1579 func TestRoundTrip(t *testing.T) {
1499 t.Parallel() 1580 t.Parallel()
1500 1581
1501 checkErr := func(actual interface{}, expected string) bool { 1582 checkErr := func(actual interface{}, expected string) bool {
1502 » » So(actual, ShouldErrLike, expected) 1583 » » if expected == "" {
1584 » » » So(actual, ShouldErrLike, nil)
1585 » » } else {
1586 » » » So(actual, ShouldErrLike, expected)
1587 » » }
1503 return expected != "" 1588 return expected != ""
1504 } 1589 }
1505 1590
1506 Convey("Test round-trip", t, func() { 1591 Convey("Test round-trip", t, func() {
1507 for _, tc := range testCases { 1592 for _, tc := range testCases {
1508 tc := tc 1593 tc := tc
1509 Convey(tc.desc, func() { 1594 Convey(tc.desc, func() {
1510 pls, ok := tc.src.(PropertyLoadSaver) 1595 pls, ok := tc.src.(PropertyLoadSaver)
1511 if !ok { 1596 if !ok {
1512 pls = GetPLS(tc.src) 1597 pls = GetPLS(tc.src)
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1756 1841
1757 Convey("Bad default meta type", func() { 1842 Convey("Bad default meta type", func() {
1758 type BadDefault struct { 1843 type BadDefault struct {
1759 Val time.Time `gae:"$meta,tomorrow"` 1844 Val time.Time `gae:"$meta,tomorrow"`
1760 } 1845 }
1761 pls := GetPLS(&BadDefault{}) 1846 pls := GetPLS(&BadDefault{})
1762 So(pls.Problem().Error(), ShouldContainSubstring, "bad t ype") 1847 So(pls.Problem().Error(), ShouldContainSubstring, "bad t ype")
1763 }) 1848 })
1764 }) 1849 })
1765 } 1850 }
OLDNEW
« no previous file with comments | « service/datastore/key_test.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698