| 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 package datastore | 5 package serialize |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "fmt" |
| 9 "io" | 10 "io" |
| 10 "testing" | 11 "testing" |
| 11 "time" | 12 "time" |
| 12 | 13 |
| 13 "github.com/luci/gae/service/blobstore" | 14 "github.com/luci/gae/service/blobstore" |
| 15 ds "github.com/luci/gae/service/datastore" |
| 16 "github.com/luci/gae/service/datastore/dskey" |
| 14 "github.com/luci/luci-go/common/cmpbin" | 17 "github.com/luci/luci-go/common/cmpbin" |
| 18 . "github.com/luci/luci-go/common/testing/assertions" |
| 15 . "github.com/smartystreets/goconvey/convey" | 19 . "github.com/smartystreets/goconvey/convey" |
| 16 ) | 20 ) |
| 17 | 21 |
| 18 func init() { | 22 func init() { |
| 19 WritePropertyMapDeterministic = true | 23 WritePropertyMapDeterministic = true |
| 20 } | 24 } |
| 21 | 25 |
| 26 var ( |
| 27 mp = ds.MkProperty |
| 28 mpNI = ds.MkPropertyNI |
| 29 ) |
| 30 |
| 22 type dspmapTC struct { | 31 type dspmapTC struct { |
| 23 name string | 32 name string |
| 24 » props PropertyMap | 33 » props ds.PropertyMap |
| 34 } |
| 35 |
| 36 // TODO(riannucci): dedup with datastore/key testing file. |
| 37 func mkKey(aid, ns string, elems ...interface{}) ds.Key { |
| 38 » if len(elems)%2 != 0 { |
| 39 » » panic("odd number of tokens") |
| 40 » } |
| 41 » toks := make([]ds.KeyTok, len(elems)/2) |
| 42 » for i := 0; i < len(elems); i += 2 { |
| 43 » » toks[i/2].Kind = elems[i].(string) |
| 44 » » switch x := elems[i+1].(type) { |
| 45 » » case string: |
| 46 » » » toks[i/2].StringID = x |
| 47 » » case int: |
| 48 » » » toks[i/2].IntID = int64(x) |
| 49 » » default: |
| 50 » » » panic("bad token id") |
| 51 » » } |
| 52 » } |
| 53 » return dskey.NewToks(aid, ns, toks) |
| 54 } |
| 55 |
| 56 func mkBuf(data []byte) Buffer { |
| 57 » return Invertible(bytes.NewBuffer(data)) |
| 58 } |
| 59 |
| 60 // TODO(riannucci): dedup with datastore/key testing file |
| 61 func ShouldEqualKey(actual interface{}, expected ...interface{}) string { |
| 62 » if len(expected) != 1 { |
| 63 » » return fmt.Sprintf("Assertion requires 1 expected value, got %d"
, len(expected)) |
| 64 » } |
| 65 » if dskey.Equal(actual.(ds.Key), expected[0].(ds.Key)) { |
| 66 » » return "" |
| 67 » } |
| 68 » return fmt.Sprintf("Expected: %q\nActual: %q", actual, expected[0]) |
| 25 } | 69 } |
| 26 | 70 |
| 27 func TestPropertyMapSerialization(t *testing.T) { | 71 func TestPropertyMapSerialization(t *testing.T) { |
| 28 t.Parallel() | 72 t.Parallel() |
| 29 | 73 |
| 30 tests := []dspmapTC{ | 74 tests := []dspmapTC{ |
| 31 { | 75 { |
| 32 "basic", | 76 "basic", |
| 33 » » » PropertyMap{ | 77 » » » ds.PropertyMap{ |
| 34 "R": {mp(false), mp(2.1), mpNI(3)}, | 78 "R": {mp(false), mp(2.1), mpNI(3)}, |
| 35 "S": {mp("hello"), mp("world")}, | 79 "S": {mp("hello"), mp("world")}, |
| 36 }, | 80 }, |
| 37 }, | 81 }, |
| 38 { | 82 { |
| 39 "keys", | 83 "keys", |
| 40 » » » PropertyMap{ | 84 » » » ds.PropertyMap{ |
| 41 "DS": {mp(mkKey("appy", "ns", "Foo", 7)),
mp(mkKey("other", "", "Yot", "wheeep"))}, | 85 "DS": {mp(mkKey("appy", "ns", "Foo", 7)),
mp(mkKey("other", "", "Yot", "wheeep"))}, |
| 42 "blobstore": {mp(blobstore.Key("sup")), mp(blobs
tore.Key("nerds"))}, | 86 "blobstore": {mp(blobstore.Key("sup")), mp(blobs
tore.Key("nerds"))}, |
| 43 }, | 87 }, |
| 44 }, | 88 }, |
| 45 { | 89 { |
| 46 "geo", | 90 "geo", |
| 47 » » » PropertyMap{ | 91 » » » ds.PropertyMap{ |
| 48 » » » » "G": {mp(GeoPoint{Lat: 1, Lng: 2})}, | 92 » » » » "G": {mp(ds.GeoPoint{Lat: 1, Lng: 2})}, |
| 49 }, | 93 }, |
| 50 }, | 94 }, |
| 51 { | 95 { |
| 52 "data", | 96 "data", |
| 53 » » » PropertyMap{ | 97 » » » ds.PropertyMap{ |
| 54 "S": {mp("sup"), mp("fool"), mp("nerd")
}, | 98 "S": {mp("sup"), mp("fool"), mp("nerd")
}, |
| 55 "D.Foo.Nerd": {mp([]byte("sup")), mp([]byte("foo
l"))}, | 99 "D.Foo.Nerd": {mp([]byte("sup")), mp([]byte("foo
l"))}, |
| 56 » » » » "B": {mp(ByteString("sup")), mp(ByteStr
ing("fool"))}, | 100 » » » » "B": {mp(ds.ByteString("sup")), mp(ds.B
yteString("fool"))}, |
| 57 }, | 101 }, |
| 58 }, | 102 }, |
| 59 { | 103 { |
| 60 "time", | 104 "time", |
| 61 » » » PropertyMap{ | 105 » » » ds.PropertyMap{ |
| 62 "T": { | 106 "T": { |
| 63 mp(time.Now().UTC()), | 107 mp(time.Now().UTC()), |
| 64 mp(time.Now().Add(time.Second).UTC())}, | 108 mp(time.Now().Add(time.Second).UTC())}, |
| 65 }, | 109 }, |
| 66 }, | 110 }, |
| 67 { | 111 { |
| 68 "empty vals", | 112 "empty vals", |
| 69 » » » PropertyMap{ | 113 » » » ds.PropertyMap{ |
| 70 "T": {mp(true), mp(true)}, | 114 "T": {mp(true), mp(true)}, |
| 71 "F": {mp(false), mp(false)}, | 115 "F": {mp(false), mp(false)}, |
| 72 "N": {mp(nil), mp(nil)}, | 116 "N": {mp(nil), mp(nil)}, |
| 73 "E": {}, | 117 "E": {}, |
| 74 }, | 118 }, |
| 75 }, | 119 }, |
| 76 } | 120 } |
| 77 | 121 |
| 78 Convey("PropertyMap serialization", t, func() { | 122 Convey("PropertyMap serialization", t, func() { |
| 79 Convey("round trip", func() { | 123 Convey("round trip", func() { |
| 80 for _, tc := range tests { | 124 for _, tc := range tests { |
| 81 tc := tc | 125 tc := tc |
| 82 Convey(tc.name, func() { | 126 Convey(tc.name, func() { |
| 83 » » » » » buf := &bytes.Buffer{} | 127 » » » » » data := ToBytesWithContext(tc.props) |
| 84 » » » » » tc.props.Write(buf, WithContext) | 128 » » » » » dec, err := ReadPropertyMap(mkBuf(data),
WithContext, "", "") |
| 85 » » » » » dec := PropertyMap{} | |
| 86 » » » » » err := dec.Read(buf, WithContext, "", ""
) | |
| 87 So(err, ShouldBeNil) | 129 So(err, ShouldBeNil) |
| 88 So(dec, ShouldResemble, tc.props) | 130 So(dec, ShouldResemble, tc.props) |
| 89 }) | 131 }) |
| 90 } | 132 } |
| 91 }) | 133 }) |
| 92 }) | 134 }) |
| 93 } | 135 } |
| 94 | 136 |
| 95 func TestSerializationReadMisc(t *testing.T) { | 137 func TestSerializationReadMisc(t *testing.T) { |
| 96 t.Parallel() | 138 t.Parallel() |
| 97 | 139 |
| 98 Convey("Misc Serialization tests", t, func() { | 140 Convey("Misc Serialization tests", t, func() { |
| 99 » » buf := &bytes.Buffer{} | 141 » » Convey("GeoPoint", func() { |
| 142 » » » buf := mkBuf(nil) |
| 143 » » » cmpbin.WriteFloat64(buf, 10) |
| 144 » » » cmpbin.WriteFloat64(buf, 20) |
| 145 » » » So(string(ToBytes(ds.GeoPoint{Lat: 10, Lng: 20})), Shoul
dEqual, buf.String()) |
| 146 » » }) |
| 147 |
| 148 » » Convey("IndexColumn", func() { |
| 149 » » » buf := mkBuf(nil) |
| 150 » » » buf.WriteByte(1) |
| 151 » » » cmpbin.WriteString(buf, "hi") |
| 152 » » » So(string(ToBytes(ds.IndexColumn{Property: "hi", Directi
on: ds.DESCENDING})), |
| 153 » » » » ShouldEqual, buf.String()) |
| 154 » » }) |
| 155 |
| 156 » » Convey("KeyTok", func() { |
| 157 » » » buf := mkBuf(nil) |
| 158 » » » cmpbin.WriteString(buf, "foo") |
| 159 » » » buf.WriteByte(byte(ds.PTInt)) |
| 160 » » » cmpbin.WriteInt(buf, 20) |
| 161 » » » So(string(ToBytes(ds.KeyTok{Kind: "foo", IntID: 20})), |
| 162 » » » » ShouldEqual, buf.String()) |
| 163 » » }) |
| 164 |
| 165 » » Convey("Property", func() { |
| 166 » » » buf := mkBuf(nil) |
| 167 » » » buf.WriteByte(byte(ds.PTString)) |
| 168 » » » cmpbin.WriteString(buf, "nerp") |
| 169 » » » So(string(ToBytes(mp("nerp"))), |
| 170 » » » » ShouldEqual, buf.String()) |
| 171 » » }) |
| 172 |
| 173 » » Convey("Time", func() { |
| 174 » » » tp := mp(time.Now().UTC()) |
| 175 » » » So(string(ToBytes(tp.Value())), ShouldEqual, string(ToBy
tes(tp)[1:])) |
| 176 » » }) |
| 177 |
| 178 » » Convey("Bad ToBytes", func() { |
| 179 » » » So(func() { ToBytes(100.7) }, ShouldPanic) |
| 180 » » » So(func() { ToBytesWithContext(100.7) }, ShouldPanic) |
| 181 » » }) |
| 182 |
| 100 Convey("ReadKey", func() { | 183 Convey("ReadKey", func() { |
| 101 Convey("good cases", func() { | 184 Convey("good cases", func() { |
| 102 Convey("w/ ctx decodes normally w/ ctx", func()
{ | 185 Convey("w/ ctx decodes normally w/ ctx", func()
{ |
| 103 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | 186 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) |
| 104 » » » » » WriteKey(buf, WithContext, k) | 187 » » » » » data := ToBytesWithContext(k) |
| 105 » » » » » dk, err := ReadKey(buf, WithContext, "",
"") | 188 » » » » » dk, err := ReadKey(mkBuf(data), WithCont
ext, "", "") |
| 106 So(err, ShouldBeNil) | 189 So(err, ShouldBeNil) |
| 107 So(dk, ShouldEqualKey, k) | 190 So(dk, ShouldEqualKey, k) |
| 108 }) | 191 }) |
| 109 Convey("w/ ctx decodes normally w/o ctx", func()
{ | 192 Convey("w/ ctx decodes normally w/o ctx", func()
{ |
| 110 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | 193 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) |
| 111 » » » » » WriteKey(buf, WithContext, k) | 194 » » » » » data := ToBytesWithContext(k) |
| 112 » » » » » dk, err := ReadKey(buf, WithoutContext,
"spam", "nerd") | 195 » » » » » dk, err := ReadKey(mkBuf(data), WithoutC
ontext, "spam", "nerd") |
| 113 So(err, ShouldBeNil) | 196 So(err, ShouldBeNil) |
| 114 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) | 197 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) |
| 115 }) | 198 }) |
| 116 Convey("w/o ctx decodes normally w/ ctx", func()
{ | 199 Convey("w/o ctx decodes normally w/ ctx", func()
{ |
| 117 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | 200 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) |
| 118 » » » » » WriteKey(buf, WithoutContext, k) | 201 » » » » » data := ToBytes(k) |
| 119 » » » » » dk, err := ReadKey(buf, WithContext, "sp
am", "nerd") | 202 » » » » » dk, err := ReadKey(mkBuf(data), WithCont
ext, "spam", "nerd") |
| 120 So(err, ShouldBeNil) | 203 So(err, ShouldBeNil) |
| 121 So(dk, ShouldEqualKey, mkKey("", "", "kn
d", "yo", "other", 10)) | 204 So(dk, ShouldEqualKey, mkKey("", "", "kn
d", "yo", "other", 10)) |
| 122 }) | 205 }) |
| 123 Convey("w/o ctx decodes normally w/o ctx", func(
) { | 206 Convey("w/o ctx decodes normally w/o ctx", func(
) { |
| 124 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | 207 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) |
| 125 » » » » » WriteKey(buf, WithoutContext, k) | 208 » » » » » data := ToBytes(k) |
| 126 » » » » » dk, err := ReadKey(buf, WithoutContext,
"spam", "nerd") | 209 » » » » » dk, err := ReadKey(mkBuf(data), WithoutC
ontext, "spam", "nerd") |
| 127 So(err, ShouldBeNil) | 210 So(err, ShouldBeNil) |
| 128 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) | 211 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) |
| 129 }) | 212 }) |
| 130 Convey("IntIDs always sort before StringIDs", fu
nc() { | 213 Convey("IntIDs always sort before StringIDs", fu
nc() { |
| 131 // -1 writes as almost all 1's in the fi
rst byte under cmpbin, even | 214 // -1 writes as almost all 1's in the fi
rst byte under cmpbin, even |
| 132 // though it's technically not a valid k
ey. | 215 // though it's technically not a valid k
ey. |
| 133 k := mkKey("aid", "ns", "knd", -1) | 216 k := mkKey("aid", "ns", "knd", -1) |
| 134 » » » » » WriteKey(buf, WithoutContext, k) | 217 » » » » » data := ToBytes(k) |
| 135 | 218 |
| 136 k = mkKey("aid", "ns", "knd", "hat") | 219 k = mkKey("aid", "ns", "knd", "hat") |
| 137 » » » » » buf2 := &bytes.Buffer{} | 220 » » » » » data2 := ToBytes(k) |
| 138 » » » » » WriteKey(buf2, WithoutContext, k) | |
| 139 | 221 |
| 140 » » » » » So(bytes.Compare(buf.Bytes(), buf2.Bytes
()), ShouldBeLessThan, 0) | 222 » » » » » So(string(data), ShouldBeLessThan, strin
g(data2)) |
| 141 }) | 223 }) |
| 142 }) | 224 }) |
| 143 | 225 |
| 144 Convey("err cases", func() { | 226 Convey("err cases", func() { |
| 227 buf := mkBuf(nil) |
| 145 Convey("nil", func() { | 228 Convey("nil", func() { |
| 146 _, err := ReadKey(buf, WithContext, "",
"") | 229 _, err := ReadKey(buf, WithContext, "",
"") |
| 147 So(err, ShouldEqual, io.EOF) | 230 So(err, ShouldEqual, io.EOF) |
| 148 }) | 231 }) |
| 149 Convey("str", func() { | 232 Convey("str", func() { |
| 150 buf.WriteString("sup") | 233 buf.WriteString("sup") |
| 151 _, err := ReadKey(buf, WithContext, "",
"") | 234 _, err := ReadKey(buf, WithContext, "",
"") |
| 152 So(err, ShouldErrLike, "expected actualC
tx") | 235 So(err, ShouldErrLike, "expected actualC
tx") |
| 153 }) | 236 }) |
| 154 Convey("truncated 1", func() { | 237 Convey("truncated 1", func() { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 cmpbin.WriteString(buf, "hi") | 276 cmpbin.WriteString(buf, "hi") |
| 194 _, err := ReadKey(buf, WithContext, "",
"") | 277 _, err := ReadKey(buf, WithContext, "",
"") |
| 195 So(err, ShouldEqual, io.EOF) | 278 So(err, ShouldEqual, io.EOF) |
| 196 }) | 279 }) |
| 197 Convey("partial token 2", func() { | 280 Convey("partial token 2", func() { |
| 198 buf.WriteByte(1) // actualCtx == 1 | 281 buf.WriteByte(1) // actualCtx == 1 |
| 199 cmpbin.WriteString(buf, "aid") | 282 cmpbin.WriteString(buf, "aid") |
| 200 cmpbin.WriteString(buf, "ns") | 283 cmpbin.WriteString(buf, "ns") |
| 201 cmpbin.WriteUint(buf, 2) | 284 cmpbin.WriteUint(buf, 2) |
| 202 cmpbin.WriteString(buf, "hi") | 285 cmpbin.WriteString(buf, "hi") |
| 203 » » » » » buf.WriteByte(byte(PTString)) | 286 » » » » » buf.WriteByte(byte(ds.PTString)) |
| 204 _, err := ReadKey(buf, WithContext, "",
"") | 287 _, err := ReadKey(buf, WithContext, "",
"") |
| 205 So(err, ShouldEqual, io.EOF) | 288 So(err, ShouldEqual, io.EOF) |
| 206 }) | 289 }) |
| 207 Convey("bad token (invalid type)", func() { | 290 Convey("bad token (invalid type)", func() { |
| 208 buf.WriteByte(1) // actualCtx == 1 | 291 buf.WriteByte(1) // actualCtx == 1 |
| 209 cmpbin.WriteString(buf, "aid") | 292 cmpbin.WriteString(buf, "aid") |
| 210 cmpbin.WriteString(buf, "ns") | 293 cmpbin.WriteString(buf, "ns") |
| 211 cmpbin.WriteUint(buf, 2) | 294 cmpbin.WriteUint(buf, 2) |
| 212 cmpbin.WriteString(buf, "hi") | 295 cmpbin.WriteString(buf, "hi") |
| 213 » » » » » buf.WriteByte(byte(PTBlobKey)) | 296 » » » » » buf.WriteByte(byte(ds.PTBlobKey)) |
| 214 _, err := ReadKey(buf, WithContext, "",
"") | 297 _, err := ReadKey(buf, WithContext, "",
"") |
| 215 So(err, ShouldErrLike, "invalid type PTB
lobKey") | 298 So(err, ShouldErrLike, "invalid type PTB
lobKey") |
| 216 }) | 299 }) |
| 217 Convey("bad token (invalid IntID)", func() { | 300 Convey("bad token (invalid IntID)", func() { |
| 218 buf.WriteByte(1) // actualCtx == 1 | 301 buf.WriteByte(1) // actualCtx == 1 |
| 219 cmpbin.WriteString(buf, "aid") | 302 cmpbin.WriteString(buf, "aid") |
| 220 cmpbin.WriteString(buf, "ns") | 303 cmpbin.WriteString(buf, "ns") |
| 221 cmpbin.WriteUint(buf, 2) | 304 cmpbin.WriteUint(buf, 2) |
| 222 cmpbin.WriteString(buf, "hi") | 305 cmpbin.WriteString(buf, "hi") |
| 223 » » » » » buf.WriteByte(byte(PTInt)) | 306 » » » » » buf.WriteByte(byte(ds.PTInt)) |
| 224 cmpbin.WriteInt(buf, -2) | 307 cmpbin.WriteInt(buf, -2) |
| 225 _, err := ReadKey(buf, WithContext, "",
"") | 308 _, err := ReadKey(buf, WithContext, "",
"") |
| 226 So(err, ShouldErrLike, "zero/negative") | 309 So(err, ShouldErrLike, "zero/negative") |
| 227 }) | 310 }) |
| 228 }) | 311 }) |
| 229 }) | 312 }) |
| 230 | 313 |
| 231 Convey("ReadGeoPoint", func() { | 314 Convey("ReadGeoPoint", func() { |
| 232 » » » gp := GeoPoint{} | 315 » » » buf := mkBuf(nil) |
| 233 Convey("trunc 1", func() { | 316 Convey("trunc 1", func() { |
| 234 » » » » err := gp.Read(buf) | 317 » » » » _, err := ReadGeoPoint(buf) |
| 235 So(err, ShouldEqual, io.EOF) | 318 So(err, ShouldEqual, io.EOF) |
| 236 }) | 319 }) |
| 237 Convey("trunc 2", func() { | 320 Convey("trunc 2", func() { |
| 238 cmpbin.WriteFloat64(buf, 100) | 321 cmpbin.WriteFloat64(buf, 100) |
| 239 » » » » err := gp.Read(buf) | 322 » » » » _, err := ReadGeoPoint(buf) |
| 240 So(err, ShouldEqual, io.EOF) | 323 So(err, ShouldEqual, io.EOF) |
| 241 }) | 324 }) |
| 242 Convey("invalid", func() { | 325 Convey("invalid", func() { |
| 243 cmpbin.WriteFloat64(buf, 100) | 326 cmpbin.WriteFloat64(buf, 100) |
| 244 cmpbin.WriteFloat64(buf, 1000) | 327 cmpbin.WriteFloat64(buf, 1000) |
| 245 » » » » err := gp.Read(buf) | 328 » » » » _, err := ReadGeoPoint(buf) |
| 246 So(err, ShouldErrLike, "invalid GeoPoint") | 329 So(err, ShouldErrLike, "invalid GeoPoint") |
| 247 }) | 330 }) |
| 248 }) | 331 }) |
| 249 | 332 |
| 250 Convey("WriteTime", func() { | 333 Convey("WriteTime", func() { |
| 251 Convey("in non-UTC!", func() { | 334 Convey("in non-UTC!", func() { |
| 252 pst, err := time.LoadLocation("America/Los_Angel
es") | 335 pst, err := time.LoadLocation("America/Los_Angel
es") |
| 253 So(err, ShouldBeNil) | 336 So(err, ShouldBeNil) |
| 254 So(func() { | 337 So(func() { |
| 255 » » » » » WriteTime(buf, time.Now().In(pst)) | 338 » » » » » WriteTime(mkBuf(nil), time.Now().In(pst)
) |
| 256 }, ShouldPanic) | 339 }, ShouldPanic) |
| 257 }) | 340 }) |
| 258 }) | 341 }) |
| 259 | 342 |
| 260 Convey("ReadTime", func() { | 343 Convey("ReadTime", func() { |
| 261 Convey("trunc 1", func() { | 344 Convey("trunc 1", func() { |
| 262 » » » » _, err := ReadTime(buf) | 345 » » » » _, err := ReadTime(mkBuf(nil)) |
| 263 So(err, ShouldEqual, io.EOF) | 346 So(err, ShouldEqual, io.EOF) |
| 264 }) | 347 }) |
| 265 }) | 348 }) |
| 266 | 349 |
| 267 Convey("ReadProperty", func() { | 350 Convey("ReadProperty", func() { |
| 268 » » » p := Property{} | 351 » » » buf := mkBuf(nil) |
| 269 Convey("trunc 1", func() { | 352 Convey("trunc 1", func() { |
| 270 » » » » err := p.Read(buf, WithContext, "", "") | 353 » » » » p, err := ReadProperty(buf, WithContext, "", "") |
| 271 So(err, ShouldEqual, io.EOF) | 354 So(err, ShouldEqual, io.EOF) |
| 272 » » » » So(p.Type(), ShouldEqual, PTNull) | 355 » » » » So(p.Type(), ShouldEqual, ds.PTNull) |
| 273 So(p.Value(), ShouldBeNil) | 356 So(p.Value(), ShouldBeNil) |
| 274 }) | 357 }) |
| 275 Convey("trunc (PTBytes)", func() { | 358 Convey("trunc (PTBytes)", func() { |
| 276 » » » » buf.WriteByte(byte(PTBytes)) | 359 » » » » buf.WriteByte(byte(ds.PTBytes)) |
| 277 » » » » err := p.Read(buf, WithContext, "", "") | 360 » » » » _, err := ReadProperty(buf, WithContext, "", "") |
| 278 So(err, ShouldEqual, io.EOF) | 361 So(err, ShouldEqual, io.EOF) |
| 279 }) | 362 }) |
| 280 Convey("trunc (PTBlobKey)", func() { | 363 Convey("trunc (PTBlobKey)", func() { |
| 281 » » » » buf.WriteByte(byte(PTBlobKey)) | 364 » » » » buf.WriteByte(byte(ds.PTBlobKey)) |
| 282 » » » » err := p.Read(buf, WithContext, "", "") | 365 » » » » _, err := ReadProperty(buf, WithContext, "", "") |
| 283 So(err, ShouldEqual, io.EOF) | 366 So(err, ShouldEqual, io.EOF) |
| 284 }) | 367 }) |
| 285 Convey("invalid type", func() { | 368 Convey("invalid type", func() { |
| 286 » » » » buf.WriteByte(byte(PTUnknown + 1)) | 369 » » » » buf.WriteByte(byte(ds.PTUnknown + 1)) |
| 287 » » » » err := p.Read(buf, WithContext, "", "") | 370 » » » » _, err := ReadProperty(buf, WithContext, "", "") |
| 288 So(err, ShouldErrLike, "unknown type!") | 371 So(err, ShouldErrLike, "unknown type!") |
| 289 }) | 372 }) |
| 290 }) | 373 }) |
| 291 | 374 |
| 292 Convey("ReadPropertyMap", func() { | 375 Convey("ReadPropertyMap", func() { |
| 293 » » » pm := PropertyMap{} | 376 » » » buf := mkBuf(nil) |
| 294 Convey("trunc 1", func() { | 377 Convey("trunc 1", func() { |
| 295 » » » » err := pm.Read(buf, WithContext, "", "") | 378 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 296 So(err, ShouldEqual, io.EOF) | 379 So(err, ShouldEqual, io.EOF) |
| 297 }) | 380 }) |
| 298 Convey("too many rows", func() { | 381 Convey("too many rows", func() { |
| 299 cmpbin.WriteUint(buf, 1000000) | 382 cmpbin.WriteUint(buf, 1000000) |
| 300 » » » » err := pm.Read(buf, WithContext, "", "") | 383 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 301 So(err, ShouldErrLike, "huge number of rows") | 384 So(err, ShouldErrLike, "huge number of rows") |
| 302 }) | 385 }) |
| 303 Convey("trunc 2", func() { | 386 Convey("trunc 2", func() { |
| 304 cmpbin.WriteUint(buf, 10) | 387 cmpbin.WriteUint(buf, 10) |
| 305 » » » » err := pm.Read(buf, WithContext, "", "") | 388 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 306 So(err, ShouldEqual, io.EOF) | 389 So(err, ShouldEqual, io.EOF) |
| 307 }) | 390 }) |
| 308 Convey("trunc 3", func() { | 391 Convey("trunc 3", func() { |
| 309 cmpbin.WriteUint(buf, 10) | 392 cmpbin.WriteUint(buf, 10) |
| 310 cmpbin.WriteString(buf, "ohai") | 393 cmpbin.WriteString(buf, "ohai") |
| 311 » » » » err := pm.Read(buf, WithContext, "", "") | 394 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 312 So(err, ShouldEqual, io.EOF) | 395 So(err, ShouldEqual, io.EOF) |
| 313 }) | 396 }) |
| 314 Convey("too many values", func() { | 397 Convey("too many values", func() { |
| 315 cmpbin.WriteUint(buf, 10) | 398 cmpbin.WriteUint(buf, 10) |
| 316 cmpbin.WriteString(buf, "ohai") | 399 cmpbin.WriteString(buf, "ohai") |
| 317 cmpbin.WriteUint(buf, 100000) | 400 cmpbin.WriteUint(buf, 100000) |
| 318 » » » » err := pm.Read(buf, WithContext, "", "") | 401 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 319 So(err, ShouldErrLike, "huge number of propertie
s") | 402 So(err, ShouldErrLike, "huge number of propertie
s") |
| 320 }) | 403 }) |
| 321 Convey("trunc 4", func() { | 404 Convey("trunc 4", func() { |
| 322 cmpbin.WriteUint(buf, 10) | 405 cmpbin.WriteUint(buf, 10) |
| 323 cmpbin.WriteString(buf, "ohai") | 406 cmpbin.WriteString(buf, "ohai") |
| 324 cmpbin.WriteUint(buf, 10) | 407 cmpbin.WriteUint(buf, 10) |
| 325 » » » » err := pm.Read(buf, WithContext, "", "") | 408 » » » » _, err := ReadPropertyMap(buf, WithContext, "",
"") |
| 326 So(err, ShouldEqual, io.EOF) | 409 So(err, ShouldEqual, io.EOF) |
| 327 }) | 410 }) |
| 328 }) | 411 }) |
| 412 |
| 413 Convey("IndexDefinition", func() { |
| 414 id := ds.IndexDefinition{Kind: "kind"} |
| 415 data := ToBytes(id) |
| 416 So(string(data), ShouldStartWith, string(ds.IndexBuiltin
QueryPrefix())) |
| 417 newID, err := ReadIndexDefinition(mkBuf(data)) |
| 418 So(err, ShouldBeNil) |
| 419 So(newID, ShouldResemble, id) |
| 420 |
| 421 id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "
prop"}) |
| 422 data = ToBytes(id) |
| 423 So(string(data), ShouldStartWith, string(ds.IndexBuiltin
QueryPrefix())) |
| 424 newID, err = ReadIndexDefinition(mkBuf(data)) |
| 425 So(err, ShouldBeNil) |
| 426 So(newID, ShouldResemble, id) |
| 427 |
| 428 id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "
other", Direction: ds.DESCENDING}) |
| 429 id.Ancestor = true |
| 430 data = ToBytes(id) |
| 431 So(string(data), ShouldStartWith, string(ds.IndexComplex
QueryPrefix())) |
| 432 newID, err = ReadIndexDefinition(mkBuf(data)) |
| 433 So(err, ShouldBeNil) |
| 434 So(newID, ShouldResemble, id) |
| 435 |
| 436 // invalid |
| 437 id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "
", Direction: ds.DESCENDING}) |
| 438 data = ToBytes(id) |
| 439 So(string(data), ShouldStartWith, string(ds.IndexComplex
QueryPrefix())) |
| 440 newID, err = ReadIndexDefinition(mkBuf(data)) |
| 441 So(err, ShouldBeNil) |
| 442 So(newID, ShouldResemble, id) |
| 443 |
| 444 Convey("too many", func() { |
| 445 id := ds.IndexDefinition{Kind: "wat"} |
| 446 for i := 0; i < MaxIndexColumns+1; i++ { |
| 447 id.SortBy = append(id.SortBy, ds.IndexCo
lumn{Property: "Hi", Direction: ds.ASCENDING}) |
| 448 } |
| 449 data := ToBytes(id) |
| 450 newID, err = ReadIndexDefinition(mkBuf(data)) |
| 451 So(err, ShouldErrLike, "over 64 sort orders") |
| 452 }) |
| 453 }) |
| 329 }) | 454 }) |
| 330 } | 455 } |
| OLD | NEW |