Bug 1816170 - Disable perftest-on-autoland cron. r=aglavic
[gecko.git] / dom / indexedDB / test / unit / test_complex_keyPaths.js
blob87fd191d8f10980d4b6d2fd9d1b9035b10ea9178
1 /**
2  * Any copyright is dedicated to the Public Domain.
3  * http://creativecommons.org/publicdomain/zero/1.0/
4  */
6 /* exported testGenerator */
7 var testGenerator = testSteps();
9 function* testSteps() {
10   // Test object stores
12   const name = "test_complex_keyPaths";
13   const keyPaths = [
14     { keyPath: "id", value: { id: 5 }, key: 5 },
15     { keyPath: "id", value: { id: "14", iid: 12 }, key: "14" },
16     { keyPath: "id", value: { iid: "14", id: 12 }, key: 12 },
17     { keyPath: "id", value: {} },
18     { keyPath: "id", value: { id: {} } },
19     { keyPath: "id", value: { id: /x/ } },
20     { keyPath: "id", value: 2 },
21     { keyPath: "id", value: undefined },
22     { keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 },
23     { keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" },
24     { keyPath: "foo.id", value: { foo: { id: undefined } } },
25     { keyPath: "foo.id", value: { foo: 47 } },
26     { keyPath: "foo.id", value: {} },
27     { keyPath: "", value: "foopy", key: "foopy" },
28     { keyPath: "", value: 2, key: 2 },
29     { keyPath: "", value: undefined },
30     { keyPath: "", value: { id: 12 } },
31     { keyPath: "", value: /x/ },
32     {
33       keyPath: "foo.bar",
34       value: { baz: 1, foo: { baz2: 2, bar: "xo" } },
35       key: "xo",
36     },
37     {
38       keyPath: "foo.bar.baz",
39       value: { foo: { bar: { bazz: 16, baz: 17 } } },
40       key: 17,
41     },
42     { keyPath: "foo..id", exception: true },
43     { keyPath: "foo.", exception: true },
44     { keyPath: "fo o", exception: true },
45     { keyPath: "foo ", exception: true },
46     { keyPath: "foo[bar]", exception: true },
47     { keyPath: "foo[1]", exception: true },
48     { keyPath: "$('id').stuff", exception: true },
49     { keyPath: "foo.2.bar", exception: true },
50     { keyPath: "foo. .bar", exception: true },
51     { keyPath: ".bar", exception: true },
52     { keyPath: [], exception: true },
54     { keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] },
55     { keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] },
56     {
57       keyPath: ["foo", "bar", "bar"],
58       value: { foo: 1, bar: "x" },
59       key: [1, "x", "x"],
60     },
61     { keyPath: ["x", "y"], value: { x: [], y: "x" }, key: [[], "x"] },
62     { keyPath: ["x", "y"], value: { x: [[1]], y: "x" }, key: [[[1]], "x"] },
63     {
64       keyPath: ["x", "y"],
65       value: { x: [[1]], y: new Date(1) },
66       key: [[[1]], new Date(1)],
67     },
68     {
69       keyPath: ["x", "y"],
70       value: { x: [[1]], y: [new Date(3)] },
71       key: [[[1]], [new Date(3)]],
72     },
73     {
74       keyPath: ["x", "y.bar"],
75       value: { x: "hi", y: { bar: "x" } },
76       key: ["hi", "x"],
77     },
78     {
79       keyPath: ["x.y", "y.bar"],
80       value: { x: { y: "hello" }, y: { bar: "nurse" } },
81       key: ["hello", "nurse"],
82     },
83     { keyPath: ["", ""], value: 5, key: [5, 5] },
84     { keyPath: ["x", "y"], value: { x: 1 } },
85     { keyPath: ["x", "y"], value: { y: 1 } },
86     { keyPath: ["x", "y"], value: { x: 1, y: undefined } },
87     { keyPath: ["x", "y"], value: { x: null, y: 1 } },
88     { keyPath: ["x", "y.bar"], value: { x: null, y: { bar: "x" } } },
89     { keyPath: ["x", "y"], value: { x: 1, y: false } },
90     { keyPath: ["x", "y", "z"], value: { x: 1, y: false, z: "a" } },
91     { keyPath: [".x", "y", "z"], exception: true },
92     { keyPath: ["x", "y ", "z"], exception: true },
93   ];
95   let openRequest = indexedDB.open(name, 1);
96   openRequest.onerror = errorHandler;
97   openRequest.onupgradeneeded = grabEventAndContinueHandler;
98   openRequest.onsuccess = unexpectedSuccessHandler;
99   let event = yield undefined;
100   let db = event.target.result;
102   let stores = {};
104   // Test creating object stores and inserting data
105   for (let i = 0; i < keyPaths.length; i++) {
106     let info = keyPaths[i];
108     let test = " for objectStore test " + JSON.stringify(info);
109     let indexName = JSON.stringify(info.keyPath);
110     if (!stores[indexName]) {
111       try {
112         let objectStore = db.createObjectStore(indexName, {
113           keyPath: info.keyPath,
114         });
115         ok(!("exception" in info), "shouldn't throw" + test);
116         is(
117           JSON.stringify(objectStore.keyPath),
118           JSON.stringify(info.keyPath),
119           "correct keyPath property" + test
120         );
121         ok(
122           // eslint-disable-next-line no-self-compare
123           objectStore.keyPath === objectStore.keyPath,
124           "object identity should be preserved"
125         );
126         stores[indexName] = objectStore;
127       } catch (e) {
128         ok("exception" in info, "should throw" + test);
129         is(e.name, "SyntaxError", "expect a SyntaxError" + test);
130         ok(e instanceof DOMException, "Got a DOM Exception" + test);
131         is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
132         continue;
133       }
134     }
136     let store = stores[indexName];
138     try {
139       var request = store.add(info.value);
140       ok("key" in info, "successfully created request to insert value" + test);
141     } catch (e) {
142       ok(!("key" in info), "threw when attempted to insert" + test);
143       ok(e instanceof DOMException, "Got a DOMException" + test);
144       is(e.name, "DataError", "expect a DataError" + test);
145       is(e.code, 0, "expect zero" + test);
146       continue;
147     }
149     request.onerror = errorHandler;
150     request.onsuccess = grabEventAndContinueHandler;
152     let e = yield undefined;
153     is(e.type, "success", "inserted successfully" + test);
154     is(e.target, request, "expected target" + test);
155     ok(compareKeys(request.result, info.key), "found correct key" + test);
156     is(
157       indexedDB.cmp(request.result, info.key),
158       0,
159       "returned key compares correctly" + test
160     );
162     store.get(info.key).onsuccess = grabEventAndContinueHandler;
163     e = yield undefined;
164     isnot(e.target.result, undefined, "Did find entry");
166     // Check that cursor.update work as expected
167     request = store.openCursor();
168     request.onerror = errorHandler;
169     request.onsuccess = grabEventAndContinueHandler;
170     e = yield undefined;
171     let cursor = e.target.result;
172     request = cursor.update(info.value);
173     request.onerror = errorHandler;
174     request.onsuccess = grabEventAndContinueHandler;
175     yield undefined;
176     ok(true, "Successfully updated cursor" + test);
178     // Check that cursor.update throws as expected when key is changed
179     let newValue = cursor.value;
180     let destProp = Array.isArray(info.keyPath) ? info.keyPath[0] : info.keyPath;
181     if (destProp) {
182       let splitDestProp = destProp.split(".");
183       if (splitDestProp.length == 1) {
184         newValue[splitDestProp[0]] = "newKeyValue";
185       } else if (splitDestProp.length == 2) {
186         newValue[splitDestProp[0]][splitDestProp[1]] = "newKeyValue";
187       } else {
188         newValue[splitDestProp[0]][splitDestProp[1]][splitDestProp[2]] =
189           "newKeyValue";
190       }
191     } else {
192       newValue = "newKeyValue";
193     }
194     let didThrow;
195     try {
196       cursor.update(newValue);
197     } catch (ex) {
198       didThrow = ex;
199     }
200     ok(didThrow instanceof DOMException, "Got a DOMException" + test);
201     is(didThrow.name, "DataError", "expect a DataError" + test);
202     is(didThrow.code, 0, "expect zero" + test);
204     // Clear object store to prepare for next test
205     store.clear().onsuccess = grabEventAndContinueHandler;
206     yield undefined;
207   }
209   // Attempt to create indexes and insert data
210   let store = db.createObjectStore("indexStore");
211   let indexes = {};
212   for (let i = 0; i < keyPaths.length; i++) {
213     let info = keyPaths[i];
214     let test = " for index test " + JSON.stringify(info);
215     let indexName = JSON.stringify(info.keyPath);
216     if (!indexes[indexName]) {
217       try {
218         let index = store.createIndex(indexName, info.keyPath);
219         ok(!("exception" in info), "shouldn't throw" + test);
220         is(
221           JSON.stringify(index.keyPath),
222           JSON.stringify(info.keyPath),
223           "index has correct keyPath property" + test
224         );
225         ok(
226           // eslint-disable-next-line no-self-compare
227           index.keyPath === index.keyPath,
228           "object identity should be preserved"
229         );
230         indexes[indexName] = index;
231       } catch (e) {
232         ok("exception" in info, "should throw" + test);
233         is(e.name, "SyntaxError", "expect a SyntaxError" + test);
234         ok(e instanceof DOMException, "Got a DOM Exception" + test);
235         is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
236         continue;
237       }
238     }
240     let index = indexes[indexName];
242     request = store.add(info.value, 1);
243     if ("key" in info) {
244       index.getKey(info.key).onsuccess = grabEventAndContinueHandler;
245       let e = yield undefined;
246       is(e.target.result, 1, "found value when reading" + test);
247     } else {
248       index.count().onsuccess = grabEventAndContinueHandler;
249       let e = yield undefined;
250       is(e.target.result, 0, "should be empty" + test);
251     }
253     store.clear().onsuccess = grabEventAndContinueHandler;
254     yield undefined;
255   }
257   // Autoincrement and complex key paths
258   let aitests = [
259     { v: {}, k: 1, res: { foo: { id: 1 } } },
260     { v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 } } },
261     { v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 } } },
262     {
263       v: { v: "x", foo: { x: "y" } },
264       k: 4,
265       res: { v: "x", foo: { x: "y", id: 4 } },
266     },
267     { v: { value: 2, foo: { id: 10 } }, k: 10 },
268     { v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 } } },
269     { v: true },
270     { v: { value: 2, foo: 12 } },
271     { v: { foo: { id: true } } },
272     { v: { foo: { x: 5, id: {} } } },
273     { v: undefined },
274     { v: { foo: undefined } },
275     { v: { foo: { id: undefined } } },
276     { v: null },
277     { v: { foo: null } },
278     { v: { foo: { id: null } } },
279   ];
281   store = db.createObjectStore("gen", {
282     keyPath: "foo.id",
283     autoIncrement: true,
284   });
285   for (let i = 0; i < aitests.length; ++i) {
286     let info = aitests[i];
287     let test = " for autoIncrement test " + JSON.stringify(info);
289     let preValue = JSON.stringify(info.v);
290     if ("k" in info) {
291       store.add(info.v).onsuccess = grabEventAndContinueHandler;
292       is(JSON.stringify(info.v), preValue, "put didn't modify value" + test);
293     } else {
294       try {
295         store.add(info.v);
296         ok(false, "should throw" + test);
297       } catch (e) {
298         ok(true, "did throw" + test);
299         ok(e instanceof DOMException, "Got a DOMException" + test);
300         is(e.name, "DataError", "expect a DataError" + test);
301         is(e.code, 0, "expect zero" + test);
303         is(
304           JSON.stringify(info.v),
305           preValue,
306           "failing put didn't modify value" + test
307         );
309         continue;
310       }
311     }
313     let e = yield undefined;
314     is(e.target.result, info.k, "got correct return key" + test);
316     store.get(info.k).onsuccess = grabEventAndContinueHandler;
317     e = yield undefined;
318     is(
319       JSON.stringify(e.target.result),
320       JSON.stringify(info.res || info.v),
321       "expected value stored" + test
322     );
323   }
325   openRequest.onsuccess = grabEventAndContinueHandler;
326   yield undefined;
328   finishTest();