Chromium Code Reviews| Index: go/src/infra/gae/libs/gae/helper/datastore_test.go |
| diff --git a/go/src/infra/gae/libs/gae/helper/datastore_test.go b/go/src/infra/gae/libs/gae/helper/datastore_test.go |
| index 9fd3b49de82e4d75d2ac26ccb1f6e65ef84ed58d..ea88414e320dd186258284ae25c19a5622cdb378 100644 |
| --- a/go/src/infra/gae/libs/gae/helper/datastore_test.go |
| +++ b/go/src/infra/gae/libs/gae/helper/datastore_test.go |
| @@ -22,18 +22,10 @@ import ( |
| . "github.com/smartystreets/goconvey/convey" |
| ) |
| -func mp(value interface{}, noIndexes ...bool) (ret gae.DSProperty) { |
| - ni := false |
| - if len(noIndexes) > 1 { |
| - panic("YOU FOOL! YOU CANNOT HOPE TO PASS THAT MANY VALUES!") |
| - } else if len(noIndexes) == 1 { |
| - ni = noIndexes[0] |
| - } |
| - if err := ret.SetValue(value, ni); err != nil { |
| - panic(err) |
| - } |
| - return |
| -} |
| +var ( |
| + mp = gae.MkDSProperty |
| + mpNI = gae.MkDSPropertyNI |
|
iannucci
2015/07/14 18:15:44
I made MkDSProperty and MkDSPropertyNI (no index)
|
| +) |
| const testAppID = "testApp" |
| @@ -347,7 +339,7 @@ type MismatchTypes struct { |
| } |
| type BadSpecial struct { |
| - ID int `gae:"$id"` |
| + ID int64 `gae:"$id"` |
| id string `gae:"$id"` |
| } |
| @@ -357,19 +349,17 @@ type Doubler struct { |
| B bool |
| } |
| -func (d *Doubler) Load(props gae.DSPropertyMap) ([]string, error) { |
| - return GetStructPLS(d).Load(props) |
| +func (d *Doubler) Load(props gae.DSPropertyMap) error { |
| + return GetPLS(d).Load(props) |
| } |
| -func (d *Doubler) Save() (gae.DSPropertyMap, error) { |
| +func (d *Doubler) Save(withMeta bool) (gae.DSPropertyMap, error) { |
| // Save the default gae.DSProperty slice to an in-memory buffer (a gae.DSPropertyList). |
| - pls := GetStructPLS(d) |
| - props, err := pls.Save() |
| + pls := GetPLS(d) |
| + propMap, err := pls.Save(withMeta) |
| if err != nil { |
| return nil, err |
| } |
| - var propMap gae.DSPropertyMap |
| - propMap.Load(props) // we know this returns nil/nil |
| // Edit that map and send it on. |
| for _, props := range propMap { |
| @@ -384,16 +374,20 @@ func (d *Doubler) Save() (gae.DSPropertyMap, error) { |
| } |
| } |
| } |
| - return propMap.Save() |
| + return propMap, nil |
| } |
| +func (d *Doubler) GetMeta(string) (interface{}, error) { return nil, gae.ErrDSMetaFieldUnset } |
| +func (d *Doubler) SetMeta(string, interface{}) error { return gae.ErrDSMetaFieldUnset } |
| +func (d *Doubler) Problem() error { return nil } |
| + |
| var _ gae.DSPropertyLoadSaver = (*Doubler)(nil) |
| type Deriver struct { |
| S, Derived, Ignored string |
| } |
| -func (e *Deriver) Load(props gae.DSPropertyMap) ([]string, error) { |
| +func (e *Deriver) Load(props gae.DSPropertyMap) error { |
| for name, p := range props { |
| if name != "S" { |
| continue |
| @@ -401,15 +395,19 @@ func (e *Deriver) Load(props gae.DSPropertyMap) ([]string, error) { |
| e.S = p[0].Value().(string) |
| e.Derived = "derived+" + e.S |
| } |
| - return nil, nil |
| + return nil |
| } |
| -func (e *Deriver) Save() (gae.DSPropertyMap, error) { |
| +func (e *Deriver) Save(withMeta bool) (gae.DSPropertyMap, error) { |
| return map[string][]gae.DSProperty{ |
| "S": {mp(e.S)}, |
| }, nil |
| } |
| +func (d *Deriver) GetMeta(string) (interface{}, error) { return nil, gae.ErrDSMetaFieldUnset } |
| +func (d *Deriver) SetMeta(string, interface{}) error { return gae.ErrDSMetaFieldUnset } |
| +func (d *Deriver) Problem() error { return nil } |
| + |
| var _ gae.DSPropertyLoadSaver = (*Deriver)(nil) |
| type BK struct { |
| @@ -545,7 +543,6 @@ type testCase struct { |
| saveErr string |
| actualNoIndex bool |
| plsLoadErr string |
| - convErr string |
|
iannucci
2015/07/14 18:15:44
this is gone because conversion errors are not mul
|
| loadErr string |
| } |
| @@ -601,7 +598,7 @@ var testCases = []testCase{ |
| { |
| desc: "geopoint as props", |
| src: &G0{G: testGeoPt0}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
|
iannucci
2015/07/14 18:15:44
I simplified the interface to not require pointer-
|
| "G": {mp(testGeoPt0)}, |
| }, |
| }, |
| @@ -639,7 +636,7 @@ var testCases = []testCase{ |
| desc: "overflow", |
| src: &O0{I: 1 << 48}, |
| want: &O1{}, |
| - convErr: "overflow", |
| + loadErr: "overflow", |
| }, |
| { |
| desc: "time", |
| @@ -649,8 +646,8 @@ var testCases = []testCase{ |
| { |
| desc: "time as props", |
| src: &T{T: time.Unix(1e9, 0).UTC()}, |
| - want: &gae.DSPropertyMap{ |
| - "T": {mp(time.Unix(1e9, 0).UTC(), false)}, |
| + want: gae.DSPropertyMap{ |
| + "T": {mp(time.Unix(1e9, 0).UTC())}, |
| }, |
| }, |
| { |
| @@ -683,13 +680,13 @@ var testCases = []testCase{ |
| desc: "missing fields", |
| src: &X0{S: "one", I: 2, i: 3}, |
| want: &X2{}, |
| - convErr: "no such struct field", |
| + loadErr: "no such struct field", |
| }, |
| { |
| desc: "save string load bool", |
| src: &X0{S: "one", I: 2, i: 3}, |
| want: &X3{I: 2}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "basic slice", |
| @@ -700,7 +697,7 @@ var testCases = []testCase{ |
| desc: "save []float64 load float64", |
| src: &Y0{B: true, F: []float64{7, 8, 9}}, |
| want: &Y1{B: true}, |
| - convErr: "requires a slice", |
| + loadErr: "requires a slice", |
| }, |
| { |
| desc: "save single []int64 load int64", |
| @@ -720,15 +717,15 @@ var testCases = []testCase{ |
| { |
| desc: "use convertable slice (to map)", |
| src: &Impossible{[]ImpossibleInner{{Convertable{1, 5, 9}}, {Convertable{2, 4, 6}}}}, |
| - want: &gae.DSPropertyMap{ |
| - "Nested.wot": {mp("1,5,9", true), mp("2,4,6", true)}, |
| + want: gae.DSPropertyMap{ |
| + "Nested.wot": {mpNI("1,5,9"), mpNI("2,4,6")}, |
| }, |
| }, |
| { |
| desc: "convertable slice (bad load)", |
| - src: &gae.DSPropertyMap{"Nested.wot": {mp([]byte("ohai"), true)}}, |
| + src: gae.DSPropertyMap{"Nested.wot": {mpNI([]byte("ohai"))}}, |
| want: &Impossible{[]ImpossibleInner{{}}}, |
| - convErr: "nope", |
| + loadErr: "nope", |
| }, |
| { |
| desc: "use convertable struct", |
| @@ -769,11 +766,10 @@ var testCases = []testCase{ |
| "what": []interface{}{"is", "really", 100}, |
| }, |
| }, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "kewelmap": { |
| - mp([]byte( |
| - `{"epic":"success","no_way!":[true,"story"],"what":["is","really",100]}`), |
| - true)}, |
| + mpNI([]byte( |
| + `{"epic":"success","no_way!":[true,"story"],"what":["is","really",100]}`))}, |
| }, |
| }, |
| { |
| @@ -790,16 +786,16 @@ var testCases = []testCase{ |
| src: &Impossible4{ |
| []Complex{complex(1, 2), complex(3, 4)}, |
| }, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "Values": { |
| mp(gae.DSGeoPoint{Lat: 1, Lng: 2}), mp(gae.DSGeoPoint{Lat: 3, Lng: 4})}, |
| }, |
| }, |
| { |
| desc: "convertable complex slice (bad load)", |
| - src: &gae.DSPropertyMap{"Values": {mp("hello")}}, |
| + src: gae.DSPropertyMap{"Values": {mp("hello")}}, |
| want: &Impossible4{[]Complex(nil)}, |
| - convErr: "nope", |
| + loadErr: "nope", |
| }, |
| { |
| desc: "allow concrete gae.DSKey implementors (save)", |
| @@ -815,7 +811,7 @@ var testCases = []testCase{ |
| desc: "save []float64 load []int64", |
| src: &Y0{B: true, F: []float64{7, 8, 9}}, |
| want: &Y2{B: true}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "single slice is too long", |
| @@ -892,13 +888,13 @@ var testCases = []testCase{ |
| { |
| desc: "short gae.DSByteString as props", |
| src: &B5{B: gae.DSByteString(makeUint8Slice(3))}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "B": {mp(gae.DSByteString(makeUint8Slice(3)))}, |
| }, |
| }, |
| { |
| desc: "[]byte must be noindex", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "B": {mp(makeUint8Slice(3))}, |
| }, |
| actualNoIndex: true, |
| @@ -906,7 +902,7 @@ var testCases = []testCase{ |
| { |
| desc: "save tagged load props", |
| src: &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| // A and B are renamed to a and b; A and C are noindex, I is ignored. |
| // Indexed properties are loaded before raw properties. Thus, the |
| // result is: b, b, b, D, E, a, c. |
| @@ -917,9 +913,9 @@ var testCases = []testCase{ |
| }, |
| "D": {mp(4)}, |
| "E": {mp(5)}, |
| - "a": {mp(1, true)}, |
| - "C": {mp(3, true)}, |
| - "J": {mp(7, true)}, |
| + "a": {mpNI(1)}, |
| + "C": {mpNI(3)}, |
| + "J": {mpNI(7)}, |
| }, |
| }, |
| { |
| @@ -929,12 +925,12 @@ var testCases = []testCase{ |
| }, |
| { |
| desc: "save props load tagged", |
| - src: &gae.DSPropertyMap{ |
| - "A": {mp(11, true)}, |
| - "a": {mp(12, true)}, |
| + src: gae.DSPropertyMap{ |
| + "A": {mpNI(11)}, |
| + "a": {mpNI(12)}, |
| }, |
| want: &Tagged{A: 12}, |
| - convErr: `cannot load field "A"`, |
| + loadErr: `cannot load field "A"`, |
| }, |
| { |
| desc: "invalid tagged1", |
| @@ -970,14 +966,14 @@ var testCases = []testCase{ |
| { |
| desc: "save struct load props", |
| src: &X0{S: "s", I: 1}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "S": {mp("s")}, |
| "I": {mp(1)}, |
| }, |
| }, |
| { |
| desc: "save props load struct", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "S": {mp("s")}, |
| "I": {mp(1)}, |
| }, |
| @@ -985,7 +981,7 @@ var testCases = []testCase{ |
| }, |
| { |
| desc: "nil-value props", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "I": {mp(nil)}, |
| "B": {mp(nil)}, |
| "S": {mp(nil)}, |
| @@ -1026,7 +1022,7 @@ var testCases = []testCase{ |
| Z: true, |
| }, |
| }, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "A": {mp(1)}, |
| "I.W": { |
| mp(10), |
| @@ -1044,7 +1040,7 @@ var testCases = []testCase{ |
| }, |
| { |
| desc: "save props load outer-equivalent", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "A": {mp(1)}, |
| "I.W": { |
| mp(10), |
| @@ -1094,13 +1090,13 @@ var testCases = []testCase{ |
| { |
| desc: "dotted names save", |
| src: &Dotted{A: DottedA{B: DottedB{C: 88}}}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "A0.A1.A2.B3.C4.C5": {mp(88)}, |
| }, |
| }, |
| { |
| desc: "dotted names load", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "A0.A1.A2.B3.C4.C5": {mp(99)}, |
| }, |
| want: &Dotted{A: DottedA{B: DottedB{C: 99}}}, |
| @@ -1180,49 +1176,49 @@ var testCases = []testCase{ |
| }, |
| { |
| desc: "mismatch (string)", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "K": {mp(199)}, |
| "S": {mp([]byte("cats"))}, |
| "F": {mp(gae.DSByteString("nurbs"))}, |
| }, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "mismatch (float)", |
| - src: &gae.DSPropertyMap{"F": {mp(gae.BSKey("wot"))}}, |
| + src: gae.DSPropertyMap{"F": {mp(gae.BSKey("wot"))}}, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "mismatch (float/overflow)", |
| - src: &gae.DSPropertyMap{"F": {mp(math.MaxFloat64)}}, |
| + src: gae.DSPropertyMap{"F": {mp(math.MaxFloat64)}}, |
| want: &MismatchTypes{}, |
| - convErr: "overflows", |
| + loadErr: "overflows", |
| }, |
| { |
| desc: "mismatch (key)", |
| - src: &gae.DSPropertyMap{"K": {mp(false)}}, |
| + src: gae.DSPropertyMap{"K": {mp(false)}}, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "mismatch (bool)", |
| - src: &gae.DSPropertyMap{"B": {mp(testKey0)}}, |
| + src: gae.DSPropertyMap{"B": {mp(testKey0)}}, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "mismatch (time)", |
| - src: &gae.DSPropertyMap{"T": {mp(gae.DSGeoPoint{})}}, |
| + src: gae.DSPropertyMap{"T": {mp(gae.DSGeoPoint{})}}, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "mismatch (geopoint)", |
| - src: &gae.DSPropertyMap{"G": {mp(time.Now().UTC())}}, |
| + src: gae.DSPropertyMap{"G": {mp(time.Now().UTC())}}, |
| want: &MismatchTypes{}, |
| - convErr: "type mismatch", |
| + loadErr: "type mismatch", |
| }, |
| { |
| desc: "slice of structs", |
| @@ -1331,7 +1327,7 @@ var testCases = []testCase{ |
| }, |
| }, |
| }, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "red.S": {mp("rouge")}, |
| "red.I": {mp(0)}, |
| "red.Nonymous.S": {mp("rosso0"), mp("rosso1")}, |
| @@ -1351,7 +1347,7 @@ var testCases = []testCase{ |
| }, |
| { |
| desc: "save props load structs with ragged fields", |
| - src: &gae.DSPropertyMap{ |
| + src: gae.DSPropertyMap{ |
| "red.S": {mp("rot")}, |
| "green.Nonymous.I": {mp(10), mp(11), mp(12), mp(13)}, |
| "Blue.Nonymous.S": {mp("blau0"), mp("blau1"), mp("blau2")}, |
| @@ -1390,11 +1386,11 @@ var testCases = []testCase{ |
| Y string |
| } |
| }{}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "B.Y": {mp("")}, |
| - "A.X": {mp("", true)}, |
| - "A.Y": {mp("", true)}, |
| - "B.X": {mp("", true)}, |
| + "A.X": {mpNI("")}, |
| + "A.Y": {mpNI("")}, |
| + "B.X": {mpNI("")}, |
| }, |
| }, |
| { |
| @@ -1402,7 +1398,7 @@ var testCases = []testCase{ |
| src: &struct { |
| Inner1 `gae:"foo"` |
| }{}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "foo.W": {mp(0)}, |
| "foo.X": {mp("")}, |
| }, |
| @@ -1427,7 +1423,7 @@ var testCases = []testCase{ |
| src: &struct { |
| i, J int64 |
| }{i: 1, J: 2}, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "J": {mp(2)}, |
| }, |
| }, |
| @@ -1438,7 +1434,7 @@ var testCases = []testCase{ |
| }{ |
| J: json.RawMessage("rawr"), |
| }, |
| - want: &gae.DSPropertyMap{ |
| + want: gae.DSPropertyMap{ |
| "J": {mp([]byte("rawr"))}, |
| }, |
| }, |
| @@ -1511,13 +1507,17 @@ func TestRoundTrip(t *testing.T) { |
| for _, tc := range testCases { |
| tc := tc |
| Convey(tc.desc, func() { |
| - pls, err := GetPLS(tc.src) |
| - if checkErr(err, tc.plsErr) { |
| + ok := false |
| + pls := gae.DSPropertyLoadSaver(nil) |
| + if pls, ok = tc.src.(gae.DSPropertyLoadSaver); !ok { |
| + pls = GetPLS(tc.src) |
| + } |
| + if checkErr(pls.Problem(), tc.plsErr) { |
| return |
| } |
| So(pls, ShouldNotBeNil) |
| - savedProps, err := pls.Save() |
| + savedProps, err := pls.Save(false) |
| if checkErr(err, tc.saveErr) { |
| return |
| } |
| @@ -1532,27 +1532,25 @@ func TestRoundTrip(t *testing.T) { |
| } |
| var got interface{} |
| - if _, ok := tc.want.(*gae.DSPropertyMap); ok { |
| - got = &gae.DSPropertyMap{} |
| + if _, ok := tc.want.(gae.DSPropertyMap); ok { |
| + pls = gae.DSPropertyMap{} |
| + got = pls |
| } else { |
| got = reflect.New(reflect.TypeOf(tc.want).Elem()).Interface() |
| + if pls, ok = got.(gae.DSPropertyLoadSaver); !ok { |
| + pls = GetPLS(got) |
| + } |
| } |
| - pls, err = GetPLS(got) |
| - if checkErr(err, tc.plsLoadErr) { |
| + if checkErr(pls.Problem(), tc.plsLoadErr) { |
| return |
| } |
| So(pls, ShouldNotBeNil) |
| - convErrs, err := pls.Load(savedProps) |
| + err = pls.Load(savedProps) |
| if checkErr(err, tc.loadErr) { |
| return |
| } |
| - if len(tc.convErr) == 0 { |
| - So(convErrs, ShouldBeNil) |
| - } else { |
| - So(convErrs[0], ShouldContainSubstring, tc.convErr) |
| - } |
| if tc.want == nil { |
| return |
| } |
| @@ -1575,39 +1573,37 @@ func TestSpecial(t *testing.T) { |
| Convey("Test special fields", t, func() { |
| Convey("Can retrieve from struct", func() { |
| o := &N0{ID: 100} |
| - pls := GetStructPLS(o) |
| - val, current, err := pls.GetSpecial("id") |
| + pls := GetPLS(o) |
| + val, err := pls.GetMeta("id") |
| So(err, ShouldBeNil) |
| - So(val, ShouldEqual, "") |
| - So(current, ShouldEqual, 100) |
| + So(val, ShouldEqual, 100) |
| - val, current, err = pls.GetSpecial("kind") |
| + val, err = pls.GetMeta("kind") |
| So(err, ShouldBeNil) |
| So(val, ShouldEqual, "whatnow") |
| - So(current, ShouldEqual, nil) |
| }) |
| Convey("Getting something not there is an error", func() { |
| o := &N0{ID: 100} |
| - pls := GetStructPLS(o) |
| - _, _, err := pls.GetSpecial("wat") |
| - So(err, ShouldEqual, gae.ErrDSSpecialFieldUnset) |
| + pls := GetPLS(o) |
| + _, err := pls.GetMeta("wat") |
| + So(err, ShouldEqual, gae.ErrDSMetaFieldUnset) |
| }) |
| Convey("getting/setting from a bad struct is an error", func() { |
| o := &Recursive{} |
| - pls := GetStructPLS(o) |
| - _, _, err := pls.GetSpecial("wat") |
| + pls := GetPLS(o) |
| + _, err := pls.GetMeta("wat") |
| So(err, ShouldNotBeNil) |
| - err = pls.SetSpecial("wat", 100) |
| + err = pls.SetMeta("wat", 100) |
| So(err, ShouldNotBeNil) |
| }) |
| Convey("can assign values to exported special fields", func() { |
| o := &N0{ID: 100} |
| - pls := GetStructPLS(o) |
| - err := pls.SetSpecial("id", int64(200)) |
| + pls := GetPLS(o) |
| + err := pls.SetMeta("id", int64(200)) |
| So(err, ShouldBeNil) |
| So(o.ID, ShouldEqual, 200) |
| @@ -1615,74 +1611,111 @@ func TestSpecial(t *testing.T) { |
| Convey("assigning to unsassiagnable fields is a simple error", func() { |
| o := &N0{ID: 100} |
| - pls := GetStructPLS(o) |
| - err := pls.SetSpecial("kind", "hi") |
| + pls := GetPLS(o) |
| + err := pls.SetMeta("kind", "hi") |
| So(err.Error(), ShouldContainSubstring, "unexported field") |
| - err = pls.SetSpecial("noob", "hi") |
| - So(err, ShouldEqual, gae.ErrDSSpecialFieldUnset) |
| + err = pls.SetMeta("noob", "hi") |
| + So(err, ShouldEqual, gae.ErrDSMetaFieldUnset) |
| }) |
| }) |
| Convey("StructPLS Miscellaneous", t, func() { |
| Convey("multiple overlapping fields is an error", func() { |
| o := &BadSpecial{} |
| - pls := GetStructPLS(o) |
| - convErr, err := pls.Load(nil) |
| - So(convErr, ShouldBeNil) |
| + pls := GetPLS(o) |
| + err := pls.Load(nil) |
| So(err, ShouldErrLike, "multiple times") |
| e := pls.Problem() |
| - _, err = pls.Save() |
| + _, err = pls.Save(true) |
| So(err, ShouldEqual, e) |
| - _, err = pls.Load(nil) |
| + err = pls.Load(nil) |
| So(err, ShouldEqual, e) |
| }) |
| - Convey("can transform a list of things into a list of PLSs", func() { |
|
iannucci
2015/07/14 18:15:44
this functionality was dropped since nothing needs
|
| - o := []interface{}{ |
| - &N0{X0: X0{S: "hi", I: 5}}, |
| - &N0{Nonymous: X0{S: "hi", I: 5}}, |
| - &gae.DSPropertyMap{ |
| - "Nerd": {mp(10), mp(false)}, |
| - "What": {mp("is"), mp("up")}, |
| - }, |
| + Convey("empty property names are invalid", func() { |
| + So(validPropertyName(""), ShouldBeFalse) |
| + }) |
| + |
| + Convey("attempting to get a PLS for a non *struct is an error", func() { |
| + pls := GetPLS((*[]string)(nil)) |
| + So(pls.Problem(), ShouldEqual, gae.ErrDSInvalidEntityType) |
| + }) |
| + |
| + Convey("convertible meta default types", func() { |
| + type OKDefaults struct { |
| + When string `gae:"$when,tomorrow"` |
| + Amount int64 `gae:"$amt,100"` |
| } |
| - plss, err := MultiGetPLS(o) |
| + pls := GetPLS(&OKDefaults{}) |
| + So(pls.Problem(), ShouldBeNil) |
| + |
| + v, err := pls.GetMeta("when") |
| So(err, ShouldBeNil) |
| - for i, pls := range plss { |
| - pmap, err := pls.Save() |
| - targ := gae.DSPropertyLoadSaver(&gae.DSPropertyMap{}) |
| - obj := interface{}(targ) |
| - if i < 2 { |
| - obj = &N0{} |
| - targ = GetStructPLS(obj) |
| - } |
| - convErr, err := targ.Load(pmap) |
| - So(err, ShouldBeNil) |
| - So(convErr, ShouldBeNil) |
| - So(obj, ShouldResemble, o[i]) |
| + So(v, ShouldEqual, "tomorrow") |
| + |
| + v, err = pls.GetMeta("amt") |
| + So(err, ShouldBeNil) |
| + So(v, ShouldEqual, int64(100)) |
| + }) |
| + |
| + Convey("meta fields can be saved", func() { |
| + type OKDefaults struct { |
| + When string `gae:"$when,tomorrow"` |
| + Amount int64 `gae:"$amt,100"` |
| } |
| + pls := GetPLS(&OKDefaults{}) |
| + pm, err := pls.Save(true) |
| + So(err, ShouldBeNil) |
| + So(pm, ShouldResemble, gae.DSPropertyMap{ |
| + "$when": {gae.MkDSPropertyNI("tomorrow")}, |
| + "$amt": {gae.MkDSPropertyNI(100)}, |
| + }) |
| + |
| + v, err := pm.GetMeta("when") |
| + So(err, ShouldBeNil) |
| + So(v, ShouldEqual, "tomorrow") |
| + |
| + v, err = pm.GetMeta("amt") |
| + So(err, ShouldBeNil) |
| + So(v, ShouldEqual, int64(100)) |
| }) |
| - Convey("list of DSPropertyLoadSavers is a shortcut", func() { |
| - o := []gae.DSPropertyLoadSaver{&gae.DSPropertyMap{}} |
| - plss, err := MultiGetPLS(o) |
| + Convey("default are optional", func() { |
| + type OverrideDefault struct { |
| + Val int64 `gae:"$val"` |
| + } |
| + o := &OverrideDefault{} |
| + pls := GetPLS(o) |
| + |
| + v, err := pls.GetMeta("val") |
| So(err, ShouldBeNil) |
| - So(&plss[0], ShouldEqual, &o[0]) // identical underlying array |
| + So(v, ShouldEqual, int64(0)) |
| }) |
| - Convey("attempting to transform a bad object is an error", func() { |
| - o := []int{100} |
| - _, err := MultiGetPLS(o) |
| - So(err, ShouldEqual, gae.ErrDSInvalidEntityType) |
| + Convey("overridable defaults", func() { |
| + type OverrideDefault struct { |
| + Val int64 `gae:"$val,100"` |
| + } |
| + o := &OverrideDefault{} |
| + pls := GetPLS(o) |
| + |
| + v, err := pls.GetMeta("val") |
| + So(err, ShouldBeNil) |
| + So(v, ShouldEqual, int64(100)) |
| - f := false |
| - _, err = MultiGetPLS(&f) |
| - So(err, ShouldErrLike, "bad type") |
| + o.Val = 10 |
| + v, err = pls.GetMeta("val") |
| + So(err, ShouldBeNil) |
| + So(v, ShouldEqual, int64(10)) |
| }) |
| - Convey("empty property names are invalid", func() { |
| - So(validPropertyName(""), ShouldBeFalse) |
| + Convey("Bad default meta type", func() { |
| + type BadDefault struct { |
| + Val time.Time `gae:"$meta,tomorrow"` |
| + } |
| + pls := GetPLS(&BadDefault{}) |
| + So(pls.Problem().Error(), ShouldContainSubstring, "bad type") |
| }) |
| }) |
| } |