Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /** |
michael@0 | 2 | * Any copyright is dedicated to the Public Domain. |
michael@0 | 3 | * http://creativecommons.org/publicdomain/zero/1.0/ |
michael@0 | 4 | */ |
michael@0 | 5 | |
michael@0 | 6 | var testGenerator = testSteps(); |
michael@0 | 7 | |
michael@0 | 8 | function testSteps() |
michael@0 | 9 | { |
michael@0 | 10 | // Test object stores |
michael@0 | 11 | |
michael@0 | 12 | const name = "test_complex_keyPaths"; |
michael@0 | 13 | const keyPaths = [ |
michael@0 | 14 | { keyPath: "id", value: { id: 5 }, key: 5 }, |
michael@0 | 15 | { keyPath: "id", value: { id: "14", iid: 12 }, key: "14" }, |
michael@0 | 16 | { keyPath: "id", value: { iid: "14", id: 12 }, key: 12 }, |
michael@0 | 17 | { keyPath: "id", value: {} }, |
michael@0 | 18 | { keyPath: "id", value: { id: {} } }, |
michael@0 | 19 | { keyPath: "id", value: { id: /x/ } }, |
michael@0 | 20 | { keyPath: "id", value: 2 }, |
michael@0 | 21 | { keyPath: "id", value: undefined }, |
michael@0 | 22 | { keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 }, |
michael@0 | 23 | { keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" }, |
michael@0 | 24 | { keyPath: "foo.id", value: { foo: { id: undefined } } }, |
michael@0 | 25 | { keyPath: "foo.id", value: { foo: 47 } }, |
michael@0 | 26 | { keyPath: "foo.id", value: {} }, |
michael@0 | 27 | { keyPath: "", value: "foopy", key: "foopy" }, |
michael@0 | 28 | { keyPath: "", value: 2, key: 2 }, |
michael@0 | 29 | { keyPath: "", value: undefined }, |
michael@0 | 30 | { keyPath: "", value: { id: 12 } }, |
michael@0 | 31 | { keyPath: "", value: /x/ }, |
michael@0 | 32 | { keyPath: "foo.bar", value: { baz: 1, foo: { baz2: 2, bar: "xo" } }, key: "xo" }, |
michael@0 | 33 | { keyPath: "foo.bar.baz", value: { foo: { bar: { bazz: 16, baz: 17 } } }, key: 17 }, |
michael@0 | 34 | { keyPath: "foo..id", exception: true }, |
michael@0 | 35 | { keyPath: "foo.", exception: true }, |
michael@0 | 36 | { keyPath: "fo o", exception: true }, |
michael@0 | 37 | { keyPath: "foo ", exception: true }, |
michael@0 | 38 | { keyPath: "foo[bar]",exception: true }, |
michael@0 | 39 | { keyPath: "foo[1]", exception: true }, |
michael@0 | 40 | { keyPath: "$('id').stuff", exception: true }, |
michael@0 | 41 | { keyPath: "foo.2.bar", exception: true }, |
michael@0 | 42 | { keyPath: "foo. .bar", exception: true }, |
michael@0 | 43 | { keyPath: ".bar", exception: true }, |
michael@0 | 44 | { keyPath: [], exception: true }, |
michael@0 | 45 | |
michael@0 | 46 | { keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] }, |
michael@0 | 47 | { keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] }, |
michael@0 | 48 | { keyPath: ["foo", "bar", "bar"], value: { foo: 1, bar: "x" }, key: [1, "x", "x"] }, |
michael@0 | 49 | { keyPath: ["x", "y"], value: { x: [], y: "x" }, key: [[], "x"] }, |
michael@0 | 50 | { keyPath: ["x", "y"], value: { x: [[1]], y: "x" }, key: [[[1]], "x"] }, |
michael@0 | 51 | { keyPath: ["x", "y"], value: { x: [[1]], y: new Date(1) }, key: [[[1]], new Date(1)] }, |
michael@0 | 52 | { keyPath: ["x", "y"], value: { x: [[1]], y: [new Date(3)] }, key: [[[1]], [new Date(3)]] }, |
michael@0 | 53 | { keyPath: ["x", "y.bar"], value: { x: "hi", y: { bar: "x"} }, key: ["hi", "x"] }, |
michael@0 | 54 | { keyPath: ["x.y", "y.bar"], value: { x: { y: "hello" }, y: { bar: "nurse"} }, key: ["hello", "nurse"] }, |
michael@0 | 55 | { keyPath: ["", ""], value: 5, key: [5, 5] }, |
michael@0 | 56 | { keyPath: ["x", "y"], value: { x: 1 } }, |
michael@0 | 57 | { keyPath: ["x", "y"], value: { y: 1 } }, |
michael@0 | 58 | { keyPath: ["x", "y"], value: { x: 1, y: undefined } }, |
michael@0 | 59 | { keyPath: ["x", "y"], value: { x: null, y: 1 } }, |
michael@0 | 60 | { keyPath: ["x", "y.bar"], value: { x: null, y: { bar: "x"} } }, |
michael@0 | 61 | { keyPath: ["x", "y"], value: { x: 1, y: false } }, |
michael@0 | 62 | { keyPath: ["x", "y", "z"], value: { x: 1, y: false, z: "a" } }, |
michael@0 | 63 | { keyPath: [".x", "y", "z"], exception: true }, |
michael@0 | 64 | { keyPath: ["x", "y ", "z"], exception: true }, |
michael@0 | 65 | ]; |
michael@0 | 66 | |
michael@0 | 67 | let openRequest = indexedDB.open(name, 1); |
michael@0 | 68 | openRequest.onerror = errorHandler; |
michael@0 | 69 | openRequest.onupgradeneeded = grabEventAndContinueHandler; |
michael@0 | 70 | openRequest.onsuccess = unexpectedSuccessHandler; |
michael@0 | 71 | let event = yield undefined; |
michael@0 | 72 | let db = event.target.result; |
michael@0 | 73 | |
michael@0 | 74 | let stores = {}; |
michael@0 | 75 | |
michael@0 | 76 | // Test creating object stores and inserting data |
michael@0 | 77 | for (let i = 0; i < keyPaths.length; i++) { |
michael@0 | 78 | let info = keyPaths[i]; |
michael@0 | 79 | |
michael@0 | 80 | let test = " for objectStore test " + JSON.stringify(info); |
michael@0 | 81 | let indexName = JSON.stringify(info.keyPath); |
michael@0 | 82 | if (!stores[indexName]) { |
michael@0 | 83 | try { |
michael@0 | 84 | let objectStore = db.createObjectStore(indexName, { keyPath: info.keyPath }); |
michael@0 | 85 | ok(!("exception" in info), "shouldn't throw" + test); |
michael@0 | 86 | is(JSON.stringify(objectStore.keyPath), JSON.stringify(info.keyPath), |
michael@0 | 87 | "correct keyPath property" + test); |
michael@0 | 88 | ok(objectStore.keyPath === objectStore.keyPath, |
michael@0 | 89 | "object identity should be preserved"); |
michael@0 | 90 | stores[indexName] = objectStore; |
michael@0 | 91 | } catch (e) { |
michael@0 | 92 | ok("exception" in info, "should throw" + test); |
michael@0 | 93 | is(e.name, "SyntaxError", "expect a SyntaxError" + test); |
michael@0 | 94 | ok(e instanceof DOMException, "Got a DOM Exception" + test); |
michael@0 | 95 | is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); |
michael@0 | 96 | continue; |
michael@0 | 97 | } |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | let store = stores[indexName]; |
michael@0 | 101 | |
michael@0 | 102 | try { |
michael@0 | 103 | request = store.add(info.value); |
michael@0 | 104 | ok("key" in info, "successfully created request to insert value" + test); |
michael@0 | 105 | } catch (e) { |
michael@0 | 106 | ok(!("key" in info), "threw when attempted to insert" + test); |
michael@0 | 107 | ok(e instanceof DOMException, "Got a DOMException" + test); |
michael@0 | 108 | is(e.name, "DataError", "expect a DataError" + test); |
michael@0 | 109 | is(e.code, 0, "expect zero" + test); |
michael@0 | 110 | continue; |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | request.onerror = errorHandler; |
michael@0 | 114 | request.onsuccess = grabEventAndContinueHandler; |
michael@0 | 115 | |
michael@0 | 116 | let e = yield undefined; |
michael@0 | 117 | is(e.type, "success", "inserted successfully" + test); |
michael@0 | 118 | is(e.target, request, "expected target" + test); |
michael@0 | 119 | ok(compareKeys(request.result, info.key), "found correct key" + test); |
michael@0 | 120 | is(indexedDB.cmp(request.result, info.key), 0, "returned key compares correctly" + test); |
michael@0 | 121 | |
michael@0 | 122 | store.get(info.key).onsuccess = grabEventAndContinueHandler; |
michael@0 | 123 | e = yield undefined; |
michael@0 | 124 | isnot(e.target.result, undefined, "Did find entry"); |
michael@0 | 125 | |
michael@0 | 126 | // Check that cursor.update work as expected |
michael@0 | 127 | request = store.openCursor(); |
michael@0 | 128 | request.onerror = errorHandler; |
michael@0 | 129 | request.onsuccess = grabEventAndContinueHandler; |
michael@0 | 130 | e = yield undefined; |
michael@0 | 131 | let cursor = e.target.result; |
michael@0 | 132 | request = cursor.update(info.value); |
michael@0 | 133 | request.onerror = errorHandler; |
michael@0 | 134 | request.onsuccess = grabEventAndContinueHandler; |
michael@0 | 135 | yield undefined; |
michael@0 | 136 | ok(true, "Successfully updated cursor" + test); |
michael@0 | 137 | |
michael@0 | 138 | // Check that cursor.update throws as expected when key is changed |
michael@0 | 139 | let newValue = cursor.value; |
michael@0 | 140 | let destProp = Array.isArray(info.keyPath) ? info.keyPath[0] : info.keyPath; |
michael@0 | 141 | if (destProp) { |
michael@0 | 142 | eval("newValue." + destProp + " = 'newKeyValue'"); |
michael@0 | 143 | } |
michael@0 | 144 | else { |
michael@0 | 145 | newValue = 'newKeyValue'; |
michael@0 | 146 | } |
michael@0 | 147 | let didThrow; |
michael@0 | 148 | try { |
michael@0 | 149 | cursor.update(newValue); |
michael@0 | 150 | } |
michael@0 | 151 | catch (ex) { |
michael@0 | 152 | didThrow = ex; |
michael@0 | 153 | } |
michael@0 | 154 | ok(didThrow instanceof DOMException, "Got a DOMException" + test); |
michael@0 | 155 | is(didThrow.name, "DataError", "expect a DataError" + test); |
michael@0 | 156 | is(didThrow.code, 0, "expect zero" + test); |
michael@0 | 157 | |
michael@0 | 158 | // Clear object store to prepare for next test |
michael@0 | 159 | store.clear().onsuccess = grabEventAndContinueHandler; |
michael@0 | 160 | yield undefined; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | // Attempt to create indexes and insert data |
michael@0 | 164 | let store = db.createObjectStore("indexStore"); |
michael@0 | 165 | let indexes = {}; |
michael@0 | 166 | for (let i = 0; i < keyPaths.length; i++) { |
michael@0 | 167 | let test = " for index test " + JSON.stringify(info); |
michael@0 | 168 | let info = keyPaths[i]; |
michael@0 | 169 | let indexName = JSON.stringify(info.keyPath); |
michael@0 | 170 | if (!indexes[indexName]) { |
michael@0 | 171 | try { |
michael@0 | 172 | let index = store.createIndex(indexName, info.keyPath); |
michael@0 | 173 | ok(!("exception" in info), "shouldn't throw" + test); |
michael@0 | 174 | is(JSON.stringify(index.keyPath), JSON.stringify(info.keyPath), |
michael@0 | 175 | "index has correct keyPath property" + test); |
michael@0 | 176 | ok(index.keyPath === index.keyPath, |
michael@0 | 177 | "object identity should be preserved"); |
michael@0 | 178 | indexes[indexName] = index; |
michael@0 | 179 | } catch (e) { |
michael@0 | 180 | ok("exception" in info, "should throw" + test); |
michael@0 | 181 | is(e.name, "SyntaxError", "expect a SyntaxError" + test); |
michael@0 | 182 | ok(e instanceof DOMException, "Got a DOM Exception" + test); |
michael@0 | 183 | is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); |
michael@0 | 184 | continue; |
michael@0 | 185 | } |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | let index = indexes[indexName]; |
michael@0 | 189 | |
michael@0 | 190 | request = store.add(info.value, 1); |
michael@0 | 191 | if ("key" in info) { |
michael@0 | 192 | index.getKey(info.key).onsuccess = grabEventAndContinueHandler; |
michael@0 | 193 | e = yield undefined; |
michael@0 | 194 | is(e.target.result, 1, "found value when reading" + test); |
michael@0 | 195 | } |
michael@0 | 196 | else { |
michael@0 | 197 | index.count().onsuccess = grabEventAndContinueHandler; |
michael@0 | 198 | e = yield undefined; |
michael@0 | 199 | is(e.target.result, 0, "should be empty" + test); |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | store.clear().onsuccess = grabEventAndContinueHandler; |
michael@0 | 203 | yield undefined; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | // Autoincrement and complex key paths |
michael@0 | 207 | let aitests = [{ v: {}, k: 1, res: { foo: { id: 1 }} }, |
michael@0 | 208 | { v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 }} }, |
michael@0 | 209 | { v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 }} }, |
michael@0 | 210 | { v: { v: "x", foo: { x: "y" } }, k: 4, res: { v: "x", foo: { x: "y", id: 4 }} }, |
michael@0 | 211 | { v: { value: 2, foo: { id: 10 }}, k: 10 }, |
michael@0 | 212 | { v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 }} }, |
michael@0 | 213 | { v: true, }, |
michael@0 | 214 | { v: { value: 2, foo: 12 }, }, |
michael@0 | 215 | { v: { foo: { id: true }}, }, |
michael@0 | 216 | { v: { foo: { x: 5, id: {} }}, }, |
michael@0 | 217 | { v: undefined, }, |
michael@0 | 218 | { v: { foo: undefined }, }, |
michael@0 | 219 | { v: { foo: { id: undefined }}, }, |
michael@0 | 220 | { v: null, }, |
michael@0 | 221 | { v: { foo: null }, }, |
michael@0 | 222 | { v: { foo: { id: null }}, }, |
michael@0 | 223 | ]; |
michael@0 | 224 | |
michael@0 | 225 | store = db.createObjectStore("gen", { keyPath: "foo.id", autoIncrement: true }); |
michael@0 | 226 | for (let i = 0; i < aitests.length; ++i) { |
michael@0 | 227 | let info = aitests[i]; |
michael@0 | 228 | let test = " for autoIncrement test " + JSON.stringify(info); |
michael@0 | 229 | |
michael@0 | 230 | let preValue = JSON.stringify(info.v); |
michael@0 | 231 | if ("k" in info) { |
michael@0 | 232 | store.add(info.v).onsuccess = grabEventAndContinueHandler; |
michael@0 | 233 | is(JSON.stringify(info.v), preValue, "put didn't modify value" + test); |
michael@0 | 234 | } |
michael@0 | 235 | else { |
michael@0 | 236 | try { |
michael@0 | 237 | store.add(info.v); |
michael@0 | 238 | ok(false, "should throw" + test); |
michael@0 | 239 | } |
michael@0 | 240 | catch(e) { |
michael@0 | 241 | ok(true, "did throw" + test); |
michael@0 | 242 | ok(e instanceof DOMException, "Got a DOMException" + test); |
michael@0 | 243 | is(e.name, "DataError", "expect a DataError" + test); |
michael@0 | 244 | is(e.code, 0, "expect zero" + test); |
michael@0 | 245 | |
michael@0 | 246 | is(JSON.stringify(info.v), preValue, "failing put didn't modify value" + test); |
michael@0 | 247 | |
michael@0 | 248 | continue; |
michael@0 | 249 | } |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | let e = yield undefined; |
michael@0 | 253 | is(e.target.result, info.k, "got correct return key" + test); |
michael@0 | 254 | |
michael@0 | 255 | store.get(info.k).onsuccess = grabEventAndContinueHandler; |
michael@0 | 256 | e = yield undefined; |
michael@0 | 257 | is(JSON.stringify(e.target.result), JSON.stringify(info.res || info.v), |
michael@0 | 258 | "expected value stored" + test); |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | openRequest.onsuccess = grabEventAndContinueHandler; |
michael@0 | 262 | yield undefined; |
michael@0 | 263 | |
michael@0 | 264 | finishTest(); |
michael@0 | 265 | yield undefined; |
michael@0 | 266 | } |