OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 package datastore | |
6 | |
7 import ( | |
8 "encoding/json" | |
9 "fmt" | |
10 "testing" | |
11 | |
12 . "github.com/smartystreets/goconvey/convey" | |
13 ) | |
14 | |
15 func mkKey(aid, ns string, elems ...interface{}) Key { | |
16 if len(elems)%2 != 0 { | |
17 panic("odd number of tokens") | |
18 } | |
19 toks := make([]KeyTok, len(elems)/2) | |
20 for i := 0; i < len(elems); i += 2 { | |
21 toks[i/2].Kind = elems[i].(string) | |
22 switch x := elems[i+1].(type) { | |
23 case string: | |
24 toks[i/2].StringID = x | |
25 case int: | |
26 toks[i/2].IntID = int64(x) | |
27 default: | |
28 panic("bad token id") | |
29 } | |
30 } | |
31 return NewKeyToks(aid, ns, toks) | |
32 } | |
33 | |
34 func ShouldEqualKey(actual interface{}, expected ...interface{}) string { | |
35 if len(expected) != 1 { | |
36 return fmt.Sprintf("Assertion requires 1 expected value, got %d"
, len(expected)) | |
37 } | |
38 if KeysEqual(actual.(Key), expected[0].(Key)) { | |
39 return "" | |
40 } | |
41 return fmt.Sprintf("Expected: %q\nActual: %q", actual, expected[0]) | |
42 } | |
43 | |
44 func TestKeyEncode(t *testing.T) { | |
45 t.Parallel() | |
46 | |
47 keys := []Key{ | |
48 mkKey("appid", "ns", "kind", 1), | |
49 mkKey("appid", "ns", "nerd", "moo"), | |
50 mkKey("appid", "ns", "parent", 10, "renerd", "moo"), | |
51 } | |
52 | |
53 Convey("Key Round trip", t, func() { | |
54 for _, k := range keys { | |
55 k := k | |
56 Convey(k.String(), func() { | |
57 enc := KeyEncode(k) | |
58 aid, ns, toks, err := KeyToksDecode(enc) | |
59 So(err, ShouldBeNil) | |
60 dec := NewKeyToks(aid, ns, toks) | |
61 So(dec, ShouldNotBeNil) | |
62 So(dec, ShouldEqualKey, k) | |
63 | |
64 dec2, err := NewKeyFromEncoded(enc) | |
65 So(err, ShouldBeNil) | |
66 So(dec2, ShouldEqualKey, dec) | |
67 So(dec2, ShouldEqualKey, k) | |
68 }) | |
69 | |
70 Convey(k.String()+" (json)", func() { | |
71 data, err := KeyMarshalJSON(k) | |
72 So(err, ShouldBeNil) | |
73 | |
74 aid, ns, toks, err := KeyUnmarshalJSON(data) | |
75 So(err, ShouldBeNil) | |
76 So(NewKeyToks(aid, ns, toks), ShouldEqualKey, k) | |
77 }) | |
78 } | |
79 }) | |
80 | |
81 Convey("NewKey", t, func() { | |
82 Convey("single", func() { | |
83 k := NewKey("appid", "ns", "kind", "", 1, nil) | |
84 So(k, ShouldEqualKey, keys[0]) | |
85 }) | |
86 | |
87 Convey("nest", func() { | |
88 k := NewKey("appid", "ns", "renerd", "moo", 0, | |
89 NewKey("appid", "ns", "parent", "", 10, nil)) | |
90 So(k, ShouldEqualKey, keys[2]) | |
91 }) | |
92 }) | |
93 | |
94 Convey("Key bad encoding", t, func() { | |
95 Convey("extra junk before", func() { | |
96 enc := KeyEncode(keys[2]) | |
97 _, _, _, err := KeyToksDecode("/" + enc) | |
98 So(err, ShouldErrLike, "illegal base64") | |
99 }) | |
100 | |
101 Convey("extra junk after", func() { | |
102 enc := KeyEncode(keys[2]) | |
103 _, _, _, err := KeyToksDecode(enc[:len(enc)-1]) | |
104 So(err, ShouldErrLike, "EOF") | |
105 }) | |
106 | |
107 Convey("json encoding includes quotes", func() { | |
108 data, err := KeyMarshalJSON(keys[0]) | |
109 So(err, ShouldBeNil) | |
110 | |
111 _, _, _, err = KeyUnmarshalJSON(append(data, '!')) | |
112 So(err, ShouldErrLike, "bad JSON key") | |
113 }) | |
114 }) | |
115 } | |
116 | |
117 type dumbKey1 struct{ Key } | |
118 | |
119 func (dk dumbKey1) Namespace() string { return "ns" } | |
120 func (dk dumbKey1) Parent() Key { return dk.Key } | |
121 func (dk dumbKey1) String() string { return "dumbKey1" } | |
122 | |
123 type dumbKey2 struct{ Key } | |
124 | |
125 /// This is the dumb part... can't have both IDs set. | |
126 func (dk dumbKey2) IntID() int64 { return 1 } | |
127 func (dk dumbKey2) StringID() string { return "wat" } | |
128 | |
129 func (dk dumbKey2) Kind() string { return "kind" } | |
130 func (dk dumbKey2) Parent() Key { return nil } | |
131 func (dk dumbKey2) Namespace() string { return "ns" } | |
132 func (dk dumbKey2) AppID() string { return "aid" } | |
133 func (dk dumbKey2) String() string { return "dumbKey2" } | |
134 | |
135 func TestBadKeyEncode(t *testing.T) { | |
136 t.Parallel() | |
137 | |
138 Convey("bad keys", t, func() { | |
139 Convey("incomplete", func() { | |
140 So(KeyIncomplete(mkKey("aid", "ns", "kind", 1)), ShouldB
eFalse) | |
141 So(KeyIncomplete(mkKey("aid", "ns", "kind", 0)), ShouldB
eTrue) | |
142 }) | |
143 | |
144 Convey("invalid", func() { | |
145 So(KeyValid(mkKey("aid", "ns", "hat", "face", "__kind__"
, 1), true, "aid", "ns"), ShouldBeTrue) | |
146 | |
147 bads := []Key{ | |
148 nil, | |
149 mkKey("", "ns", "hat", "face"), | |
150 mkKey("aid", "ns", "base", 1, "", "id"), | |
151 mkKey("aid", "ns", "hat", "face", "__kind__", 1)
, | |
152 mkKey("aid", "ns", "hat", 0, "kind", 1), | |
153 dumbKey1{mkKey("aid", "badNS", "hat", 1)}, | |
154 dumbKey2{}, | |
155 } | |
156 for _, k := range bads { | |
157 s := "<nil>" | |
158 if k != nil { | |
159 s = k.String() | |
160 } | |
161 Convey(s, func() { | |
162 So(KeyValid(k, false, "aid", "ns"), Shou
ldBeFalse) | |
163 }) | |
164 } | |
165 }) | |
166 }) | |
167 } | |
168 | |
169 type keyWrap struct{ Key } | |
170 | |
171 func (k keyWrap) Parent() Key { | |
172 if k.Key.Parent() != nil { | |
173 return keyWrap{k.Key.Parent()} | |
174 } | |
175 return nil | |
176 } | |
177 | |
178 func TestMiscKey(t *testing.T) { | |
179 t.Parallel() | |
180 | |
181 Convey("KeyRoot", t, func() { | |
182 k := mkKey("appid", "ns", "parent", 10, "renerd", "moo") | |
183 r := mkKey("appid", "ns", "parent", 10) | |
184 So(KeyRoot(k), ShouldEqualKey, r) | |
185 So(KeyRoot(nil), ShouldBeNil) | |
186 }) | |
187 | |
188 Convey("KeySplit", t, func() { | |
189 // keyWrap forces KeySplit to not take the GenericKey shortcut. | |
190 k := keyWrap{mkKey("appid", "ns", "parent", 10, "renerd", "moo")
} | |
191 aid, ns, toks := KeySplit(k) | |
192 So(aid, ShouldEqual, "appid") | |
193 So(ns, ShouldEqual, "ns") | |
194 So(toks, ShouldResemble, []KeyTok{ | |
195 {Kind: "parent", IntID: 10}, | |
196 {Kind: "renerd", StringID: "moo"}, | |
197 }) | |
198 }) | |
199 | |
200 Convey("KeySplit (nil)", t, func() { | |
201 aid, ns, toks := KeySplit(nil) | |
202 So(aid, ShouldEqual, "") | |
203 So(ns, ShouldEqual, "") | |
204 So(toks, ShouldResemble, []KeyTok(nil)) | |
205 }) | |
206 | |
207 Convey("KeySplit ((*GenericKey)(nil))", t, func() { | |
208 aid, ns, toks := KeySplit((*GenericKey)(nil)) | |
209 So(aid, ShouldEqual, "") | |
210 So(ns, ShouldEqual, "") | |
211 So(toks, ShouldResemble, []KeyTok(nil)) | |
212 }) | |
213 | |
214 Convey("KeysEqual", t, func() { | |
215 k1 := mkKey("a", "n", "knd", 1) | |
216 k2 := mkKey("a", "n", "knd", 1) | |
217 So(KeysEqual(k1, k2), ShouldBeTrue) | |
218 k3 := mkKey("a", "n", "knd", 2) | |
219 So(KeysEqual(k1, k3), ShouldBeFalse) | |
220 }) | |
221 | |
222 Convey("KeyString", t, func() { | |
223 k1 := mkKey("a", "n", "knd", 1, "other", "wat") | |
224 So(KeyString(k1), ShouldEqual, "/knd,1/other,wat") | |
225 So(KeyString(nil), ShouldEqual, "") | |
226 }) | |
227 | |
228 Convey("*GenericKey supports json encoding", t, func() { | |
229 type TestStruct struct { | |
230 Key *GenericKey | |
231 } | |
232 t := &TestStruct{ | |
233 NewKey("aid", "ns", "kind", "id", 0, | |
234 NewKey("aid", "ns", "parent", "", 1, nil), | |
235 )} | |
236 d, err := json.Marshal(t) | |
237 So(err, ShouldBeNil) | |
238 t2 := &TestStruct{} | |
239 err = json.Unmarshal(d, t2) | |
240 So(err, ShouldBeNil) | |
241 So(t, ShouldResemble, t2) | |
242 }) | |
243 } | |
OLD | NEW |