test_keys.js (8439B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 /* exported testGenerator */ 7 var testGenerator = testSteps(); 8 9 // helper function that ensures that ArrayBuffer instances are meaningfully 10 // displayed (not just as 'object ArrayBuffer') 11 // TODO better move to helpers.js? 12 function showKey(key) { 13 if (key instanceof Array) { 14 return key.map(x => showKey(x)).toString(); 15 } 16 if (key instanceof ArrayBuffer) { 17 return "ArrayBuffer([" + new Uint8Array(key).toString() + "])"; 18 } 19 return key.toString(); 20 } 21 22 function* testSteps() { 23 const dbname = this.window ? window.location.pathname : "Splendid Test"; 24 25 let openRequest = indexedDB.open(dbname, 1); 26 openRequest.onerror = errorHandler; 27 openRequest.onupgradeneeded = grabEventAndContinueHandler; 28 openRequest.onsuccess = unexpectedSuccessHandler; 29 let event = yield undefined; 30 let db = event.target.result; 31 32 // Create test stores 33 let store = db.createObjectStore("store"); 34 let enc = new TextEncoder(); 35 36 // Test simple inserts 37 // Note: the keys must be in order 38 var keys = [ 39 -1 / 0, 40 -1.7e308, 41 -10000, 42 -2, 43 -1.5, 44 -1, 45 -1.00001e-200, 46 -1e-200, 47 0, 48 1e-200, 49 1.00001e-200, 50 1, 51 2, 52 10000, 53 1.7e308, 54 1 / 0, 55 new Date("1750-01-02"), 56 new Date("1800-12-31T12:34:56.001"), 57 new Date(-1000), 58 new Date(-10), 59 new Date(-1), 60 new Date(0), 61 new Date(1), 62 new Date(2), 63 new Date(1000), 64 new Date("1971-01-01"), 65 new Date("1971-01-01T01:01:01Z"), 66 new Date("1971-01-01T01:01:01.001Z"), 67 new Date("1971-01-01T01:01:01.01Z"), 68 new Date("1971-01-01T01:01:01.1Z"), 69 new Date("1980-02-02"), 70 new Date("3333-03-19T03:33:33.333"), 71 "", 72 "\x00", 73 "\x00\x00", 74 "\x00\x01", 75 "\x01", 76 "\x02", 77 "\x03", 78 "\x04", 79 "\x07", 80 "\x08", 81 "\x0F", 82 "\x10", 83 "\x1F", 84 "\x20", 85 "01234", 86 "\x3F", 87 "\x40", 88 "A", 89 "A\x00", 90 "A1", 91 "ZZZZ", 92 "a", 93 "a\x00", 94 "aa", 95 "azz", 96 "}", 97 "\x7E", 98 "\x7F", 99 "\x80", 100 "\xFF", 101 "\u0100", 102 "\u01FF", 103 "\u0200", 104 "\u03FF", 105 "\u0400", 106 "\u07FF", 107 "\u0800", 108 "\u0FFF", 109 "\u1000", 110 "\u1FFF", 111 "\u2000", 112 "\u3FFF", 113 "\u4000", 114 "\u7FFF", 115 "\u8000", 116 "\uD800", 117 "\uD800a", 118 "\uD800\uDC01", 119 "\uDBFF", 120 "\uDC00", 121 "\uDFFF\uD800", 122 "\uFFFE", 123 "\uFFFF", 124 "\uFFFF\x00", 125 "\uFFFFZZZ", 126 // Note: enc.encode returns an Uint8Array, which is a valid key, but when 127 // converting it back and forth, the result will be a plain ArrayBuffer, 128 // which is expected in comparisons below 129 // TODO is it ok that the information that the original key was an 130 // Uint8Array is lost? 131 new ArrayBuffer(0), 132 Uint8Array.from([0]).buffer, 133 Uint8Array.from([0, 0]).buffer, 134 Uint8Array.from([0, 1]).buffer, 135 Uint8Array.from([0, 1, 0]).buffer, 136 enc.encode("abc").buffer, 137 enc.encode("abcd").buffer, 138 enc.encode("xyz").buffer, 139 Uint8Array.from([0x80]).buffer, 140 [], 141 [-1 / 0], 142 [-1], 143 [0], 144 [1], 145 [1, "a"], 146 [1, []], 147 [1, [""]], 148 [2, 3], 149 [2, 3.0000000000001], 150 [12, [[]]], 151 [12, [[[]]]], 152 [12, [[[""]]]], 153 [12, [[["foo"]]]], 154 [12, [[[[[3]]]]]], 155 [12, [[[[[[3]]]]]]], 156 [new Date(-1)], 157 [new Date(1)], 158 [""], 159 ["", [[]]], 160 ["", [[[]]]], 161 ["abc"], 162 ["abc", "def"], 163 ["abc\x00"], 164 ["abc\x00", "\x00\x01"], 165 ["abc\x00", "\x00def"], 166 ["abc\x00\x00def"], 167 ["x", [[]]], 168 ["x", [[[]]]], 169 // see comment on scalar ArrayBuffers above 170 [new ArrayBuffer(0)], 171 [new ArrayBuffer(0), "abc"], 172 [new ArrayBuffer(0), new ArrayBuffer(0)], 173 [new ArrayBuffer(0), enc.encode("abc").buffer], 174 [enc.encode("abc").buffer], 175 [enc.encode("abc").buffer, new ArrayBuffer(0)], 176 [enc.encode("abc").buffer, enc.encode("xyz").buffer], 177 [enc.encode("xyz").buffer], 178 [[]], 179 [[], "foo"], 180 [[], []], 181 [[[]]], 182 [[[]], []], 183 [[[]], [[]]], 184 [[[]], [[1]]], 185 [[[]], [[[]]]], 186 [[[1]]], 187 [[[[]], []]], 188 ]; 189 190 for (var i = 0; i < keys.length; ++i) { 191 let keyI = keys[i]; 192 is(indexedDB.cmp(keyI, keyI), 0, i + " compared to self"); 193 194 function doCompare(keyI) { 195 for (var j = i - 1; j >= i - 10 && j >= 0; --j) { 196 is(indexedDB.cmp(keyI, keys[j]), 1, i + " compared to " + j); 197 is(indexedDB.cmp(keys[j], keyI), -1, j + " compared to " + i); 198 } 199 } 200 201 doCompare(keyI); 202 store.add(i, keyI).onsuccess = function (e) { 203 is( 204 indexedDB.cmp(e.target.result, keyI), 205 0, 206 "Returned key should cmp as equal; index = " + 207 i + 208 ", input = " + 209 showKey(keyI) + 210 ", returned = " + 211 showKey(e.target.result) 212 ); 213 ok( 214 compareKeys(e.target.result, keyI), 215 "Returned key should actually be equal; index = " + 216 i + 217 ", input = " + 218 showKey(keyI) + 219 ", returned = " + 220 showKey(e.target.result) 221 ); 222 }; 223 224 // Test that -0 compares the same as 0 225 if (keyI === 0) { 226 doCompare(-0); 227 let req = store.add(i, -0); 228 req.addEventListener("error", new ExpectError("ConstraintError", true)); 229 req.onsuccess = unexpectedSuccessHandler; 230 yield undefined; 231 } else if (Array.isArray(keyI) && keyI.length === 1 && keyI[0] === 0) { 232 doCompare([-0]); 233 let req = store.add(i, [-0]); 234 req.addEventListener("error", new ExpectError("ConstraintError", true)); 235 req.onsuccess = unexpectedSuccessHandler; 236 yield undefined; 237 } 238 } 239 240 store.openCursor().onsuccess = grabEventAndContinueHandler; 241 for (i = 0; i < keys.length; ++i) { 242 event = yield undefined; 243 let cursor = event.target.result; 244 is( 245 indexedDB.cmp(cursor.key, keys[i]), 246 0, 247 "Read back key should cmp as equal; index = " + 248 i + 249 ", input = " + 250 showKey(keys[i]) + 251 ", readBack = " + 252 showKey(cursor.key) 253 ); 254 ok( 255 compareKeys(cursor.key, keys[i]), 256 "Read back key should actually be equal; index = " + 257 i + 258 ", input = " + 259 showKey(keys[i]) + 260 ", readBack = " + 261 showKey(cursor.key) 262 ); 263 is(cursor.value, i, "Stored with right value"); 264 265 cursor.continue(); 266 } 267 event = yield undefined; 268 is(event.target.result, null, "no more results expected"); 269 270 let nan = 0 / 0; 271 let invalidKeys = [ 272 nan, 273 undefined, 274 null, 275 /x/, 276 {}, 277 new Date(NaN), 278 new Date("foopy"), 279 [nan], 280 [undefined], 281 [null], 282 [/x/], 283 [{}], 284 [new Date(NaN)], 285 [1, nan], 286 [1, undefined], 287 [1, null], 288 [1, /x/], 289 [1, {}], 290 [1, [nan]], 291 [1, [undefined]], 292 [1, [null]], 293 [1, [/x/]], 294 [1, [{}]], 295 ]; 296 297 try { 298 // ATTENTION, the following key allocates 2GB of memory and might cause 299 // subtle failures in some environments, see bug 1796753. We might 300 // want to have some common way between IndexeDB mochitests and 301 // xpcshell tests how to access AppConstants in order to dynamically 302 // exclude this key from some environments, rather than disabling the 303 // entire xpcshell variant of this test for ASAN/TSAN. 304 invalidKeys.push(new Uint8Array(2147483647)); 305 } catch { 306 info("Key instantiation failed, skipping"); 307 } 308 309 function checkInvalidKeyException(ex, i, callText) { 310 let suffix = ` during ${callText} with invalid key ${i}: ${invalidKeys[i]}`; 311 // isInstance() is not available in mochitest, and we use this JS also as mochitest. 312 // eslint-disable-next-line mozilla/use-isInstance 313 ok(ex instanceof DOMException, "Threw DOMException" + suffix); 314 is(ex.name, "DataError", "Threw right DOMException" + suffix); 315 is(ex.code, 0, "Threw with right code" + suffix); 316 } 317 318 for (let key of invalidKeys) { 319 try { 320 indexedDB.cmp(key, 1); 321 ok(false, "didn't throw"); 322 } catch (ex) { 323 checkInvalidKeyException(ex, i, "cmp(key, 1)"); 324 } 325 try { 326 indexedDB.cmp(1, key); 327 ok(false, "didn't throw2"); 328 } catch (ex) { 329 checkInvalidKeyException(ex, i, "cmp(1, key)"); 330 } 331 try { 332 store.put(1, key); 333 ok(false, "didn't throw3"); 334 } catch (ex) { 335 checkInvalidKeyException(ex, i, "store.put(1, key)"); 336 } 337 } 338 339 openRequest.onsuccess = grabEventAndContinueHandler; 340 yield undefined; 341 342 finishTest(); 343 }