datastore_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package datastore
  15. import (
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "reflect"
  20. "strings"
  21. "testing"
  22. "time"
  23. )
  24. type (
  25. myBlob []byte
  26. myByte byte
  27. myString string
  28. )
  29. func makeMyByteSlice(n int) []myByte {
  30. b := make([]myByte, n)
  31. for i := range b {
  32. b[i] = myByte(i)
  33. }
  34. return b
  35. }
  36. func makeInt8Slice(n int) []int8 {
  37. b := make([]int8, n)
  38. for i := range b {
  39. b[i] = int8(i)
  40. }
  41. return b
  42. }
  43. func makeUint8Slice(n int) []uint8 {
  44. b := make([]uint8, n)
  45. for i := range b {
  46. b[i] = uint8(i)
  47. }
  48. return b
  49. }
  50. func newKey(stringID string, parent *Key) *Key {
  51. return &Key{
  52. kind: "kind",
  53. name: stringID,
  54. id: 0,
  55. parent: parent,
  56. }
  57. }
  58. var (
  59. testKey0 = newKey("name0", nil)
  60. testKey1a = newKey("name1", nil)
  61. testKey1b = newKey("name1", nil)
  62. testKey2a = newKey("name2", testKey0)
  63. testKey2b = newKey("name2", testKey0)
  64. )
  65. type B0 struct {
  66. B []byte `datastore:",noindex"`
  67. }
  68. type B1 struct {
  69. B []int8
  70. }
  71. type B2 struct {
  72. B myBlob `datastore:",noindex"`
  73. }
  74. type B3 struct {
  75. B []myByte `datastore:",noindex"`
  76. }
  77. type B4 struct {
  78. B [][]byte
  79. }
  80. type C0 struct {
  81. I int
  82. C chan int
  83. }
  84. type C1 struct {
  85. I int
  86. C *chan int
  87. }
  88. type C2 struct {
  89. I int
  90. C []chan int
  91. }
  92. type C3 struct {
  93. C string
  94. }
  95. type E struct{}
  96. type K0 struct {
  97. K *Key
  98. }
  99. type K1 struct {
  100. K []*Key
  101. }
  102. type N0 struct {
  103. X0
  104. Nonymous X0
  105. Ignore string `datastore:"-"`
  106. Other string
  107. }
  108. type N1 struct {
  109. X0
  110. Nonymous []X0
  111. Ignore string `datastore:"-"`
  112. Other string
  113. }
  114. type N2 struct {
  115. N1 `datastore:"red"`
  116. Green N1 `datastore:"green"`
  117. Blue N1
  118. White N1 `datastore:"-"`
  119. }
  120. type O0 struct {
  121. I int64
  122. }
  123. type O1 struct {
  124. I int32
  125. }
  126. type U0 struct {
  127. U uint
  128. }
  129. type U1 struct {
  130. U string
  131. }
  132. type T struct {
  133. T time.Time
  134. }
  135. type X0 struct {
  136. S string
  137. I int
  138. i int
  139. }
  140. type X1 struct {
  141. S myString
  142. I int32
  143. J int64
  144. }
  145. type X2 struct {
  146. Z string
  147. i int
  148. }
  149. type X3 struct {
  150. S bool
  151. I int
  152. }
  153. type Y0 struct {
  154. B bool
  155. F []float64
  156. G []float64
  157. }
  158. type Y1 struct {
  159. B bool
  160. F float64
  161. }
  162. type Y2 struct {
  163. B bool
  164. F []int64
  165. }
  166. type Tagged struct {
  167. A int `datastore:"a,noindex"`
  168. B []int `datastore:"b"`
  169. C int `datastore:",noindex"`
  170. D int `datastore:""`
  171. E int
  172. I int `datastore:"-"`
  173. J int `datastore:",noindex" json:"j"`
  174. Y0 `datastore:"-"`
  175. Z chan int `datastore:"-,"`
  176. }
  177. type InvalidTagged1 struct {
  178. I int `datastore:"\t"`
  179. }
  180. type InvalidTagged2 struct {
  181. I int
  182. J int `datastore:"I"`
  183. }
  184. type Inner1 struct {
  185. W int32
  186. X string
  187. }
  188. type Inner2 struct {
  189. Y float64
  190. }
  191. type Inner3 struct {
  192. Z bool
  193. }
  194. type Outer struct {
  195. A int16
  196. I []Inner1
  197. J Inner2
  198. Inner3
  199. }
  200. type OuterEquivalent struct {
  201. A int16
  202. IDotW []int32 `datastore:"I.W"`
  203. IDotX []string `datastore:"I.X"`
  204. JDotY float64 `datastore:"J.Y"`
  205. Z bool
  206. }
  207. type Dotted struct {
  208. A DottedA `datastore:"A0.A1.A2"`
  209. }
  210. type DottedA struct {
  211. B DottedB `datastore:"B3"`
  212. }
  213. type DottedB struct {
  214. C int `datastore:"C4.C5"`
  215. }
  216. type SliceOfSlices struct {
  217. I int
  218. S []struct {
  219. J int
  220. F []float64
  221. }
  222. }
  223. type Recursive struct {
  224. I int
  225. R []Recursive
  226. }
  227. type MutuallyRecursive0 struct {
  228. I int
  229. R []MutuallyRecursive1
  230. }
  231. type MutuallyRecursive1 struct {
  232. I int
  233. R []MutuallyRecursive0
  234. }
  235. type Doubler struct {
  236. S string
  237. I int64
  238. B bool
  239. }
  240. func (d *Doubler) Load(props []Property) error {
  241. return LoadStruct(d, props)
  242. }
  243. func (d *Doubler) Save() ([]Property, error) {
  244. // Save the default Property slice to an in-memory buffer (a PropertyList).
  245. props, err := SaveStruct(d)
  246. if err != nil {
  247. return nil, err
  248. }
  249. var list PropertyList
  250. if err := list.Load(props); err != nil {
  251. return nil, err
  252. }
  253. // Edit that PropertyList, and send it on.
  254. for i := range list {
  255. switch v := list[i].Value.(type) {
  256. case string:
  257. // + means string concatenation.
  258. list[i].Value = v + v
  259. case int64:
  260. // + means integer addition.
  261. list[i].Value = v + v
  262. }
  263. }
  264. return list.Save()
  265. }
  266. var _ PropertyLoadSaver = (*Doubler)(nil)
  267. type Deriver struct {
  268. S, Derived, Ignored string
  269. }
  270. func (e *Deriver) Load(props []Property) error {
  271. for _, p := range props {
  272. if p.Name != "S" {
  273. continue
  274. }
  275. e.S = p.Value.(string)
  276. e.Derived = "derived+" + e.S
  277. }
  278. return nil
  279. }
  280. func (e *Deriver) Save() ([]Property, error) {
  281. return []Property{
  282. {
  283. Name: "S",
  284. Value: e.S,
  285. },
  286. }, nil
  287. }
  288. var _ PropertyLoadSaver = (*Deriver)(nil)
  289. type BadMultiPropEntity struct{}
  290. func (e *BadMultiPropEntity) Load(props []Property) error {
  291. return errors.New("unimplemented")
  292. }
  293. func (e *BadMultiPropEntity) Save() ([]Property, error) {
  294. // Write multiple properties with the same name "I", but Multiple is false.
  295. var props []Property
  296. for i := 0; i < 3; i++ {
  297. props = append(props, Property{
  298. Name: "I",
  299. Value: int64(i),
  300. })
  301. }
  302. return props, nil
  303. }
  304. var _ PropertyLoadSaver = (*BadMultiPropEntity)(nil)
  305. type testCase struct {
  306. desc string
  307. src interface{}
  308. want interface{}
  309. putErr string
  310. getErr string
  311. }
  312. var testCases = []testCase{
  313. {
  314. "chan save fails",
  315. &C0{I: -1},
  316. &E{},
  317. "unsupported struct field",
  318. "",
  319. },
  320. {
  321. "*chan save fails",
  322. &C1{I: -1},
  323. &E{},
  324. "unsupported struct field",
  325. "",
  326. },
  327. {
  328. "[]chan save fails",
  329. &C2{I: -1, C: make([]chan int, 8)},
  330. &E{},
  331. "unsupported struct field",
  332. "",
  333. },
  334. {
  335. "chan load fails",
  336. &C3{C: "not a chan"},
  337. &C0{},
  338. "",
  339. "type mismatch",
  340. },
  341. {
  342. "*chan load fails",
  343. &C3{C: "not a *chan"},
  344. &C1{},
  345. "",
  346. "type mismatch",
  347. },
  348. {
  349. "[]chan load fails",
  350. &C3{C: "not a []chan"},
  351. &C2{},
  352. "",
  353. "type mismatch",
  354. },
  355. {
  356. "empty struct",
  357. &E{},
  358. &E{},
  359. "",
  360. "",
  361. },
  362. {
  363. "key",
  364. &K0{K: testKey1a},
  365. &K0{K: testKey1b},
  366. "",
  367. "",
  368. },
  369. {
  370. "key with parent",
  371. &K0{K: testKey2a},
  372. &K0{K: testKey2b},
  373. "",
  374. "",
  375. },
  376. {
  377. "nil key",
  378. &K0{},
  379. &K0{},
  380. "",
  381. "",
  382. },
  383. {
  384. "all nil keys in slice",
  385. &K1{[]*Key{nil, nil}},
  386. &K1{[]*Key{nil, nil}},
  387. "",
  388. "",
  389. },
  390. {
  391. "some nil keys in slice",
  392. &K1{[]*Key{testKey1a, nil, testKey2a}},
  393. &K1{[]*Key{testKey1b, nil, testKey2b}},
  394. "",
  395. "",
  396. },
  397. {
  398. "overflow",
  399. &O0{I: 1 << 48},
  400. &O1{},
  401. "",
  402. "overflow",
  403. },
  404. {
  405. "time",
  406. &T{T: time.Unix(1e9, 0)},
  407. &T{T: time.Unix(1e9, 0)},
  408. "",
  409. "",
  410. },
  411. {
  412. "time as props",
  413. &T{T: time.Unix(1e9, 0)},
  414. &PropertyList{
  415. Property{Name: "T", Value: time.Unix(1e9, 0), NoIndex: false},
  416. },
  417. "",
  418. "",
  419. },
  420. {
  421. "uint save",
  422. &U0{U: 1},
  423. &U0{},
  424. "unsupported struct field",
  425. "",
  426. },
  427. {
  428. "uint load",
  429. &U1{U: "not a uint"},
  430. &U0{},
  431. "",
  432. "type mismatch",
  433. },
  434. {
  435. "zero",
  436. &X0{},
  437. &X0{},
  438. "",
  439. "",
  440. },
  441. {
  442. "basic",
  443. &X0{S: "one", I: 2, i: 3},
  444. &X0{S: "one", I: 2},
  445. "",
  446. "",
  447. },
  448. {
  449. "save string/int load myString/int32",
  450. &X0{S: "one", I: 2, i: 3},
  451. &X1{S: "one", I: 2},
  452. "",
  453. "",
  454. },
  455. {
  456. "missing fields",
  457. &X0{S: "one", I: 2, i: 3},
  458. &X2{},
  459. "",
  460. "no such struct field",
  461. },
  462. {
  463. "save string load bool",
  464. &X0{S: "one", I: 2, i: 3},
  465. &X3{I: 2},
  466. "",
  467. "type mismatch",
  468. },
  469. {
  470. "basic slice",
  471. &Y0{B: true, F: []float64{7, 8, 9}},
  472. &Y0{B: true, F: []float64{7, 8, 9}},
  473. "",
  474. "",
  475. },
  476. {
  477. "save []float64 load float64",
  478. &Y0{B: true, F: []float64{7, 8, 9}},
  479. &Y1{B: true},
  480. "",
  481. "requires a slice",
  482. },
  483. {
  484. "save []float64 load []int64",
  485. &Y0{B: true, F: []float64{7, 8, 9}},
  486. &Y2{B: true},
  487. "",
  488. "type mismatch",
  489. },
  490. {
  491. "single slice is too long",
  492. &Y0{F: make([]float64, maxIndexedProperties+1)},
  493. &Y0{},
  494. "too many indexed properties",
  495. "",
  496. },
  497. {
  498. "two slices are too long",
  499. &Y0{F: make([]float64, maxIndexedProperties), G: make([]float64, maxIndexedProperties)},
  500. &Y0{},
  501. "too many indexed properties",
  502. "",
  503. },
  504. {
  505. "one slice and one scalar are too long",
  506. &Y0{F: make([]float64, maxIndexedProperties), B: true},
  507. &Y0{},
  508. "too many indexed properties",
  509. "",
  510. },
  511. {
  512. "long blob",
  513. &B0{B: makeUint8Slice(maxIndexedProperties + 1)},
  514. &B0{B: makeUint8Slice(maxIndexedProperties + 1)},
  515. "",
  516. "",
  517. },
  518. {
  519. "long []int8 is too long",
  520. &B1{B: makeInt8Slice(maxIndexedProperties + 1)},
  521. &B1{},
  522. "too many indexed properties",
  523. "",
  524. },
  525. {
  526. "short []int8",
  527. &B1{B: makeInt8Slice(3)},
  528. &B1{B: makeInt8Slice(3)},
  529. "",
  530. "",
  531. },
  532. {
  533. "long myBlob",
  534. &B2{B: makeUint8Slice(maxIndexedProperties + 1)},
  535. &B2{B: makeUint8Slice(maxIndexedProperties + 1)},
  536. "",
  537. "",
  538. },
  539. {
  540. "short myBlob",
  541. &B2{B: makeUint8Slice(3)},
  542. &B2{B: makeUint8Slice(3)},
  543. "",
  544. "",
  545. },
  546. {
  547. "long []myByte",
  548. &B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
  549. &B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
  550. "",
  551. "",
  552. },
  553. {
  554. "short []myByte",
  555. &B3{B: makeMyByteSlice(3)},
  556. &B3{B: makeMyByteSlice(3)},
  557. "",
  558. "",
  559. },
  560. {
  561. "slice of blobs",
  562. &B4{B: [][]byte{
  563. makeUint8Slice(3),
  564. makeUint8Slice(4),
  565. makeUint8Slice(5),
  566. }},
  567. &B4{B: [][]byte{
  568. makeUint8Slice(3),
  569. makeUint8Slice(4),
  570. makeUint8Slice(5),
  571. }},
  572. "",
  573. "",
  574. },
  575. {
  576. "[]byte must be noindex",
  577. &PropertyList{
  578. Property{Name: "B", Value: makeUint8Slice(1501), NoIndex: false},
  579. },
  580. nil,
  581. "is too long to index",
  582. "",
  583. },
  584. {
  585. "string must be noindex",
  586. &PropertyList{
  587. Property{Name: "B", Value: strings.Repeat("x", 1501), NoIndex: false},
  588. },
  589. nil,
  590. "is too long to index",
  591. "",
  592. },
  593. {
  594. "save tagged load props",
  595. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7},
  596. &PropertyList{
  597. // A and B are renamed to a and b; A and C are noindex, I is ignored.
  598. // Order is alphabetical
  599. Property{Name: "a", Value: int64(1), NoIndex: true},
  600. Property{Name: "b", Value: int64(21), NoIndex: false, Multiple: true},
  601. Property{Name: "b", Value: int64(22), NoIndex: false, Multiple: true},
  602. Property{Name: "b", Value: int64(23), NoIndex: false, Multiple: true},
  603. Property{Name: "C", Value: int64(3), NoIndex: true},
  604. Property{Name: "D", Value: int64(4), NoIndex: false},
  605. Property{Name: "E", Value: int64(5), NoIndex: false},
  606. Property{Name: "J", Value: int64(7), NoIndex: true},
  607. },
  608. "",
  609. "",
  610. },
  611. {
  612. "save tagged load tagged",
  613. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7},
  614. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7},
  615. "",
  616. "",
  617. },
  618. {
  619. "save props load tagged",
  620. &PropertyList{
  621. Property{Name: "A", Value: int64(11), NoIndex: true},
  622. Property{Name: "a", Value: int64(12), NoIndex: true},
  623. },
  624. &Tagged{A: 12},
  625. "",
  626. `cannot load field "A"`,
  627. },
  628. {
  629. "invalid tagged1",
  630. &InvalidTagged1{I: 1},
  631. &InvalidTagged1{},
  632. "struct tag has invalid property name",
  633. "",
  634. },
  635. {
  636. "invalid tagged2",
  637. &InvalidTagged2{I: 1, J: 2},
  638. &InvalidTagged2{},
  639. "struct tag has repeated property name",
  640. "",
  641. },
  642. {
  643. "doubler",
  644. &Doubler{S: "s", I: 1, B: true},
  645. &Doubler{S: "ss", I: 2, B: true},
  646. "",
  647. "",
  648. },
  649. {
  650. "save struct load props",
  651. &X0{S: "s", I: 1},
  652. &PropertyList{
  653. Property{Name: "S", Value: "s", NoIndex: false},
  654. Property{Name: "I", Value: int64(1), NoIndex: false},
  655. },
  656. "",
  657. "",
  658. },
  659. {
  660. "save props load struct",
  661. &PropertyList{
  662. Property{Name: "S", Value: "s", NoIndex: false},
  663. Property{Name: "I", Value: int64(1), NoIndex: false},
  664. },
  665. &X0{S: "s", I: 1},
  666. "",
  667. "",
  668. },
  669. {
  670. "nil-value props",
  671. &PropertyList{
  672. Property{Name: "I", Value: nil, NoIndex: false},
  673. Property{Name: "B", Value: nil, NoIndex: false},
  674. Property{Name: "S", Value: nil, NoIndex: false},
  675. Property{Name: "F", Value: nil, NoIndex: false},
  676. Property{Name: "K", Value: nil, NoIndex: false},
  677. Property{Name: "T", Value: nil, NoIndex: false},
  678. Property{Name: "J", Value: nil, NoIndex: false},
  679. Property{Name: "J", Value: int64(7), NoIndex: false},
  680. Property{Name: "J", Value: nil, NoIndex: false},
  681. },
  682. &struct {
  683. I int64
  684. B bool
  685. S string
  686. F float64
  687. K *Key
  688. T time.Time
  689. J []int64
  690. }{
  691. J: []int64{0, 7, 0},
  692. },
  693. "",
  694. "",
  695. },
  696. {
  697. "save outer load props",
  698. &Outer{
  699. A: 1,
  700. I: []Inner1{
  701. {10, "ten"},
  702. {20, "twenty"},
  703. {30, "thirty"},
  704. },
  705. J: Inner2{
  706. Y: 3.14,
  707. },
  708. Inner3: Inner3{
  709. Z: true,
  710. },
  711. },
  712. &PropertyList{
  713. Property{Name: "A", Value: int64(1), NoIndex: false},
  714. Property{Name: "I.W", Value: int64(10), NoIndex: false, Multiple: true},
  715. Property{Name: "I.W", Value: int64(20), NoIndex: false, Multiple: true},
  716. Property{Name: "I.W", Value: int64(30), NoIndex: false, Multiple: true},
  717. Property{Name: "I.X", Value: "ten", NoIndex: false, Multiple: true},
  718. Property{Name: "I.X", Value: "twenty", NoIndex: false, Multiple: true},
  719. Property{Name: "I.X", Value: "thirty", NoIndex: false, Multiple: true},
  720. Property{Name: "J.Y", Value: float64(3.14), NoIndex: false},
  721. Property{Name: "Z", Value: true, NoIndex: false},
  722. },
  723. "",
  724. "",
  725. },
  726. {
  727. "save props load outer-equivalent",
  728. &PropertyList{
  729. Property{Name: "A", Value: int64(1), NoIndex: false},
  730. Property{Name: "I.W", Value: int64(10), NoIndex: false},
  731. Property{Name: "I.X", Value: "ten", NoIndex: false},
  732. Property{Name: "I.W", Value: int64(20), NoIndex: false},
  733. Property{Name: "I.X", Value: "twenty", NoIndex: false},
  734. Property{Name: "I.W", Value: int64(30), NoIndex: false},
  735. Property{Name: "I.X", Value: "thirty", NoIndex: false},
  736. Property{Name: "J.Y", Value: float64(3.14), NoIndex: false},
  737. Property{Name: "Z", Value: true, NoIndex: false},
  738. },
  739. &OuterEquivalent{
  740. A: 1,
  741. IDotW: []int32{10, 20, 30},
  742. IDotX: []string{"ten", "twenty", "thirty"},
  743. JDotY: 3.14,
  744. Z: true,
  745. },
  746. "",
  747. "",
  748. },
  749. {
  750. "save outer-equivalent load outer",
  751. &OuterEquivalent{
  752. A: 1,
  753. IDotW: []int32{10, 20, 30},
  754. IDotX: []string{"ten", "twenty", "thirty"},
  755. JDotY: 3.14,
  756. Z: true,
  757. },
  758. &Outer{
  759. A: 1,
  760. I: []Inner1{
  761. {10, "ten"},
  762. {20, "twenty"},
  763. {30, "thirty"},
  764. },
  765. J: Inner2{
  766. Y: 3.14,
  767. },
  768. Inner3: Inner3{
  769. Z: true,
  770. },
  771. },
  772. "",
  773. "",
  774. },
  775. {
  776. "dotted names save",
  777. &Dotted{A: DottedA{B: DottedB{C: 88}}},
  778. &PropertyList{
  779. Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(88), NoIndex: false},
  780. },
  781. "",
  782. "",
  783. },
  784. {
  785. "dotted names load",
  786. &PropertyList{
  787. Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(99), NoIndex: false},
  788. },
  789. &Dotted{A: DottedA{B: DottedB{C: 99}}},
  790. "",
  791. "",
  792. },
  793. {
  794. "save struct load deriver",
  795. &X0{S: "s", I: 1},
  796. &Deriver{S: "s", Derived: "derived+s"},
  797. "",
  798. "",
  799. },
  800. {
  801. "save deriver load struct",
  802. &Deriver{S: "s", Derived: "derived+s", Ignored: "ignored"},
  803. &X0{S: "s"},
  804. "",
  805. "",
  806. },
  807. {
  808. "zero time.Time",
  809. &T{T: time.Time{}},
  810. &T{T: time.Time{}},
  811. "",
  812. "",
  813. },
  814. {
  815. "time.Time near Unix zero time",
  816. &T{T: time.Unix(0, 4e3)},
  817. &T{T: time.Unix(0, 4e3)},
  818. "",
  819. "",
  820. },
  821. {
  822. "time.Time, far in the future",
  823. &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
  824. &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
  825. "",
  826. "",
  827. },
  828. {
  829. "time.Time, very far in the past",
  830. &T{T: time.Date(-300000, 1, 1, 0, 0, 0, 0, time.UTC)},
  831. &T{},
  832. "time value out of range",
  833. "",
  834. },
  835. {
  836. "time.Time, very far in the future",
  837. &T{T: time.Date(294248, 1, 1, 0, 0, 0, 0, time.UTC)},
  838. &T{},
  839. "time value out of range",
  840. "",
  841. },
  842. {
  843. "structs",
  844. &N0{
  845. X0: X0{S: "one", I: 2, i: 3},
  846. Nonymous: X0{S: "four", I: 5, i: 6},
  847. Ignore: "ignore",
  848. Other: "other",
  849. },
  850. &N0{
  851. X0: X0{S: "one", I: 2},
  852. Nonymous: X0{S: "four", I: 5},
  853. Other: "other",
  854. },
  855. "",
  856. "",
  857. },
  858. {
  859. "slice of structs",
  860. &N1{
  861. X0: X0{S: "one", I: 2, i: 3},
  862. Nonymous: []X0{
  863. {S: "four", I: 5, i: 6},
  864. {S: "seven", I: 8, i: 9},
  865. {S: "ten", I: 11, i: 12},
  866. {S: "thirteen", I: 14, i: 15},
  867. },
  868. Ignore: "ignore",
  869. Other: "other",
  870. },
  871. &N1{
  872. X0: X0{S: "one", I: 2},
  873. Nonymous: []X0{
  874. {S: "four", I: 5},
  875. {S: "seven", I: 8},
  876. {S: "ten", I: 11},
  877. {S: "thirteen", I: 14},
  878. },
  879. Other: "other",
  880. },
  881. "",
  882. "",
  883. },
  884. {
  885. "structs with slices of structs",
  886. &N2{
  887. N1: N1{
  888. X0: X0{S: "rouge"},
  889. Nonymous: []X0{
  890. {S: "rosso0"},
  891. {S: "rosso1"},
  892. },
  893. },
  894. Green: N1{
  895. X0: X0{S: "vert"},
  896. Nonymous: []X0{
  897. {S: "verde0"},
  898. {S: "verde1"},
  899. {S: "verde2"},
  900. },
  901. },
  902. Blue: N1{
  903. X0: X0{S: "bleu"},
  904. Nonymous: []X0{
  905. {S: "blu0"},
  906. {S: "blu1"},
  907. {S: "blu2"},
  908. {S: "blu3"},
  909. },
  910. },
  911. },
  912. &N2{
  913. N1: N1{
  914. X0: X0{S: "rouge"},
  915. Nonymous: []X0{
  916. {S: "rosso0"},
  917. {S: "rosso1"},
  918. },
  919. },
  920. Green: N1{
  921. X0: X0{S: "vert"},
  922. Nonymous: []X0{
  923. {S: "verde0"},
  924. {S: "verde1"},
  925. {S: "verde2"},
  926. },
  927. },
  928. Blue: N1{
  929. X0: X0{S: "bleu"},
  930. Nonymous: []X0{
  931. {S: "blu0"},
  932. {S: "blu1"},
  933. {S: "blu2"},
  934. {S: "blu3"},
  935. },
  936. },
  937. },
  938. "",
  939. "",
  940. },
  941. {
  942. "save structs load props",
  943. &N2{
  944. N1: N1{
  945. X0: X0{S: "rouge"},
  946. Nonymous: []X0{
  947. {S: "rosso0"},
  948. {S: "rosso1"},
  949. },
  950. },
  951. Green: N1{
  952. X0: X0{S: "vert"},
  953. Nonymous: []X0{
  954. {S: "verde0"},
  955. {S: "verde1"},
  956. {S: "verde2"},
  957. },
  958. },
  959. Blue: N1{
  960. X0: X0{S: "bleu"},
  961. Nonymous: []X0{
  962. {S: "blu0"},
  963. {S: "blu1"},
  964. {S: "blu2"},
  965. {S: "blu3"},
  966. },
  967. },
  968. },
  969. &PropertyList{
  970. Property{Name: "red.S", Value: "rouge", NoIndex: false},
  971. Property{Name: "red.I", Value: int64(0), NoIndex: false},
  972. Property{Name: "red.Nonymous.S", Value: "rosso0", NoIndex: false, Multiple: true},
  973. Property{Name: "red.Nonymous.S", Value: "rosso1", NoIndex: false, Multiple: true},
  974. Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  975. Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  976. Property{Name: "red.Other", Value: "", NoIndex: false},
  977. Property{Name: "green.S", Value: "vert", NoIndex: false},
  978. Property{Name: "green.I", Value: int64(0), NoIndex: false},
  979. Property{Name: "green.Nonymous.S", Value: "verde0", NoIndex: false, Multiple: true},
  980. Property{Name: "green.Nonymous.S", Value: "verde1", NoIndex: false, Multiple: true},
  981. Property{Name: "green.Nonymous.S", Value: "verde2", NoIndex: false, Multiple: true},
  982. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  983. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  984. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  985. Property{Name: "green.Other", Value: "", NoIndex: false},
  986. Property{Name: "Blue.S", Value: "bleu", NoIndex: false},
  987. Property{Name: "Blue.I", Value: int64(0), NoIndex: false},
  988. Property{Name: "Blue.Nonymous.S", Value: "blu0", NoIndex: false, Multiple: true},
  989. Property{Name: "Blue.Nonymous.S", Value: "blu1", NoIndex: false, Multiple: true},
  990. Property{Name: "Blue.Nonymous.S", Value: "blu2", NoIndex: false, Multiple: true},
  991. Property{Name: "Blue.Nonymous.S", Value: "blu3", NoIndex: false, Multiple: true},
  992. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  993. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  994. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  995. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  996. Property{Name: "Blue.Other", Value: "", NoIndex: false},
  997. },
  998. "",
  999. "",
  1000. },
  1001. {
  1002. "save props load structs with ragged fields",
  1003. &PropertyList{
  1004. Property{Name: "red.S", Value: "rot", NoIndex: false},
  1005. Property{Name: "green.Nonymous.I", Value: int64(10), NoIndex: false},
  1006. Property{Name: "green.Nonymous.I", Value: int64(11), NoIndex: false},
  1007. Property{Name: "green.Nonymous.I", Value: int64(12), NoIndex: false},
  1008. Property{Name: "green.Nonymous.I", Value: int64(13), NoIndex: false},
  1009. Property{Name: "Blue.Nonymous.S", Value: "blau0", NoIndex: false},
  1010. Property{Name: "Blue.Nonymous.I", Value: int64(20), NoIndex: false},
  1011. Property{Name: "Blue.Nonymous.S", Value: "blau1", NoIndex: false},
  1012. Property{Name: "Blue.Nonymous.I", Value: int64(21), NoIndex: false},
  1013. Property{Name: "Blue.Nonymous.S", Value: "blau2", NoIndex: false},
  1014. },
  1015. &N2{
  1016. N1: N1{
  1017. X0: X0{S: "rot"},
  1018. },
  1019. Green: N1{
  1020. Nonymous: []X0{
  1021. {I: 10},
  1022. {I: 11},
  1023. {I: 12},
  1024. {I: 13},
  1025. },
  1026. },
  1027. Blue: N1{
  1028. Nonymous: []X0{
  1029. {S: "blau0", I: 20},
  1030. {S: "blau1", I: 21},
  1031. {S: "blau2"},
  1032. },
  1033. },
  1034. },
  1035. "",
  1036. "",
  1037. },
  1038. {
  1039. "save structs with noindex tags",
  1040. &struct {
  1041. A struct {
  1042. X string `datastore:",noindex"`
  1043. Y string
  1044. } `datastore:",noindex"`
  1045. B struct {
  1046. X string `datastore:",noindex"`
  1047. Y string
  1048. }
  1049. }{},
  1050. &PropertyList{
  1051. Property{Name: "A.X", Value: "", NoIndex: true},
  1052. Property{Name: "A.Y", Value: "", NoIndex: true},
  1053. Property{Name: "B.X", Value: "", NoIndex: true},
  1054. Property{Name: "B.Y", Value: "", NoIndex: false},
  1055. },
  1056. "",
  1057. "",
  1058. },
  1059. {
  1060. "embedded struct with name override",
  1061. &struct {
  1062. Inner1 `datastore:"foo"`
  1063. }{},
  1064. &PropertyList{
  1065. Property{Name: "foo.W", Value: int64(0), NoIndex: false},
  1066. Property{Name: "foo.X", Value: "", NoIndex: false},
  1067. },
  1068. "",
  1069. "",
  1070. },
  1071. {
  1072. "slice of slices",
  1073. &SliceOfSlices{},
  1074. nil,
  1075. "flattening nested structs leads to a slice of slices",
  1076. "",
  1077. },
  1078. {
  1079. "recursive struct",
  1080. &Recursive{},
  1081. nil,
  1082. "recursive struct",
  1083. "",
  1084. },
  1085. {
  1086. "mutually recursive struct",
  1087. &MutuallyRecursive0{},
  1088. nil,
  1089. "recursive struct",
  1090. "",
  1091. },
  1092. {
  1093. "non-exported struct fields",
  1094. &struct {
  1095. i, J int64
  1096. }{i: 1, J: 2},
  1097. &PropertyList{
  1098. Property{Name: "J", Value: int64(2), NoIndex: false},
  1099. },
  1100. "",
  1101. "",
  1102. },
  1103. {
  1104. "json.RawMessage",
  1105. &struct {
  1106. J json.RawMessage
  1107. }{
  1108. J: json.RawMessage("rawr"),
  1109. },
  1110. &PropertyList{
  1111. Property{Name: "J", Value: []byte("rawr"), NoIndex: false},
  1112. },
  1113. "",
  1114. "",
  1115. },
  1116. {
  1117. "json.RawMessage to myBlob",
  1118. &struct {
  1119. B json.RawMessage
  1120. }{
  1121. B: json.RawMessage("rawr"),
  1122. },
  1123. &B2{B: myBlob("rawr")},
  1124. "",
  1125. "",
  1126. },
  1127. }
  1128. // checkErr returns the empty string if either both want and err are zero,
  1129. // or if want is a non-empty substring of err's string representation.
  1130. func checkErr(want string, err error) string {
  1131. if err != nil {
  1132. got := err.Error()
  1133. if want == "" || strings.Index(got, want) == -1 {
  1134. return got
  1135. }
  1136. } else if want != "" {
  1137. return fmt.Sprintf("want error %q", want)
  1138. }
  1139. return ""
  1140. }
  1141. func TestRoundTrip(t *testing.T) {
  1142. for _, tc := range testCases {
  1143. p, err := saveEntity(testKey0, tc.src)
  1144. if s := checkErr(tc.putErr, err); s != "" {
  1145. t.Errorf("%s: save: %s", tc.desc, s)
  1146. continue
  1147. }
  1148. if p == nil {
  1149. continue
  1150. }
  1151. var got interface{}
  1152. if _, ok := tc.want.(*PropertyList); ok {
  1153. got = new(PropertyList)
  1154. } else {
  1155. got = reflect.New(reflect.TypeOf(tc.want).Elem()).Interface()
  1156. }
  1157. err = loadEntity(got, p)
  1158. if s := checkErr(tc.getErr, err); s != "" {
  1159. t.Errorf("%s: load: %s", tc.desc, s)
  1160. continue
  1161. }
  1162. equal := false
  1163. if gotT, ok := got.(*T); ok {
  1164. // Round tripping a time.Time can result in a different time.Location: Local instead of UTC.
  1165. // We therefore test equality explicitly, instead of relying on reflect.DeepEqual.
  1166. equal = gotT.T.Equal(tc.want.(*T).T)
  1167. } else {
  1168. equal = reflect.DeepEqual(got, tc.want)
  1169. }
  1170. if !equal {
  1171. t.Errorf("%s: compare: got %v want %v", tc.desc, got, tc.want)
  1172. continue
  1173. }
  1174. }
  1175. }
  1176. func TestQueryConstruction(t *testing.T) {
  1177. tests := []struct {
  1178. q, exp *Query
  1179. err string
  1180. }{
  1181. {
  1182. q: NewQuery("Foo"),
  1183. exp: &Query{
  1184. kind: "Foo",
  1185. limit: -1,
  1186. },
  1187. },
  1188. {
  1189. // Regular filtered query with standard spacing.
  1190. q: NewQuery("Foo").Filter("foo >", 7),
  1191. exp: &Query{
  1192. kind: "Foo",
  1193. filter: []filter{
  1194. {
  1195. FieldName: "foo",
  1196. Op: greaterThan,
  1197. Value: 7,
  1198. },
  1199. },
  1200. limit: -1,
  1201. },
  1202. },
  1203. {
  1204. // Filtered query with no spacing.
  1205. q: NewQuery("Foo").Filter("foo=", 6),
  1206. exp: &Query{
  1207. kind: "Foo",
  1208. filter: []filter{
  1209. {
  1210. FieldName: "foo",
  1211. Op: equal,
  1212. Value: 6,
  1213. },
  1214. },
  1215. limit: -1,
  1216. },
  1217. },
  1218. {
  1219. // Filtered query with funky spacing.
  1220. q: NewQuery("Foo").Filter(" foo< ", 8),
  1221. exp: &Query{
  1222. kind: "Foo",
  1223. filter: []filter{
  1224. {
  1225. FieldName: "foo",
  1226. Op: lessThan,
  1227. Value: 8,
  1228. },
  1229. },
  1230. limit: -1,
  1231. },
  1232. },
  1233. {
  1234. // Filtered query with multicharacter op.
  1235. q: NewQuery("Foo").Filter("foo >=", 9),
  1236. exp: &Query{
  1237. kind: "Foo",
  1238. filter: []filter{
  1239. {
  1240. FieldName: "foo",
  1241. Op: greaterEq,
  1242. Value: 9,
  1243. },
  1244. },
  1245. limit: -1,
  1246. },
  1247. },
  1248. {
  1249. // Query with ordering.
  1250. q: NewQuery("Foo").Order("bar"),
  1251. exp: &Query{
  1252. kind: "Foo",
  1253. order: []order{
  1254. {
  1255. FieldName: "bar",
  1256. Direction: ascending,
  1257. },
  1258. },
  1259. limit: -1,
  1260. },
  1261. },
  1262. {
  1263. // Query with reverse ordering, and funky spacing.
  1264. q: NewQuery("Foo").Order(" - bar"),
  1265. exp: &Query{
  1266. kind: "Foo",
  1267. order: []order{
  1268. {
  1269. FieldName: "bar",
  1270. Direction: descending,
  1271. },
  1272. },
  1273. limit: -1,
  1274. },
  1275. },
  1276. {
  1277. // Query with an empty ordering.
  1278. q: NewQuery("Foo").Order(""),
  1279. err: "empty order",
  1280. },
  1281. {
  1282. // Query with a + ordering.
  1283. q: NewQuery("Foo").Order("+bar"),
  1284. err: "invalid order",
  1285. },
  1286. }
  1287. for i, test := range tests {
  1288. if test.q.err != nil {
  1289. got := test.q.err.Error()
  1290. if !strings.Contains(got, test.err) {
  1291. t.Errorf("%d: error mismatch: got %q want something containing %q", i, got, test.err)
  1292. }
  1293. continue
  1294. }
  1295. if !reflect.DeepEqual(test.q, test.exp) {
  1296. t.Errorf("%d: mismatch: got %v want %v", i, test.q, test.exp)
  1297. }
  1298. }
  1299. }