Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <!DOCTYPE html> | 1 <!doctype html> |
| 2 <meta charset=utf-8> | |
| 2 <title>IndexedDB: Exceptions thrown during key conversion</title> | 3 <title>IndexedDB: Exceptions thrown during key conversion</title> |
| 3 <script src="../../resources/testharness.js"></script> | 4 <script src="/resources/testharness.js"></script> |
| 4 <script src="../../resources/testharnessreport.js"></script> | 5 <script src="/resources/testharnessreport.js"></script> |
| 6 <script src="support.js"></script> | |
| 5 <script> | 7 <script> |
| 6 | 8 |
| 7 function simple_idb_test(upgrade_callback, description) { | 9 // Convenience function for tests that only need to run code in onupgradeneeded. |
| 8 async_test(function(t) { | 10 function indexeddb_upgrade_test(upgrade_callback, description) { |
|
jsbell
2017/02/03 19:29:42
How about indexeddb_upgrade_only_test ?
Just "ind
pwnall
2017/02/07 23:30:04
Done.
| |
| 9 var dbname = document.location + '-' + t.name; | 11 indexeddb_test(upgrade_callback, t => { t.done(); }, description); |
| 10 var del = indexedDB.deleteDatabase(dbname); | |
| 11 del.onerror = t.unreached_func('deleteDatabase should succeed'); | |
| 12 var open = indexedDB.open(dbname); | |
| 13 open.onerror = t.unreached_func('open should succeed'); | |
| 14 open.onupgradeneeded = t.step_func(function(e) { | |
| 15 upgrade_callback(t, open.result); | |
| 16 }); | |
| 17 open.onsuccess = t.step_func(function() { | |
| 18 open.result.close(); | |
| 19 t.done(); | |
| 20 }); | |
| 21 }, description); | |
| 22 } | 12 } |
| 23 | 13 |
| 24 // Key that throws during conversion. | 14 // Key that throws during conversion. |
| 25 function throwing_key(name) { | 15 function throwing_key(name) { |
| 26 var throws = []; | 16 var throws = []; |
| 27 throws.length = 1; | 17 throws.length = 1; |
| 28 Object.defineProperty(throws, '0', {get: function() { | 18 Object.defineProperty(throws, '0', {get: function() { |
| 29 var err = new Error('throwing from getter'); | 19 var err = new Error('throwing from getter'); |
| 30 err.name = name; | 20 err.name = name; |
| 31 throw err; | 21 throw err; |
| 32 }, enumerable: true}); | 22 }, enumerable: true}); |
| 33 return throws; | 23 return throws; |
| 34 } | 24 } |
| 35 | 25 |
| 36 var valid_key = []; | 26 var valid_key = []; |
| 37 var invalid_key = {}; | 27 var invalid_key = {}; |
| 38 | 28 |
| 39 // Calls method on receiver with the specified number of args (default 1) | 29 // Calls method on receiver with the specified number of args (default 1) |
| 40 // and asserts that the method fails appropriately (rethrowing if | 30 // and asserts that the method fails appropriately (rethrowing if |
| 41 // conversion throws, or DataError if not a valid key), and that | 31 // conversion throws, or DataError if not a valid key), and that |
| 42 // the first argument is fully processed before the second argument | 32 // the first argument is fully processed before the second argument |
| 43 // (if appropriate). | 33 // (if appropriate). |
| 44 function check_method(receiver, method, args) { | 34 function check_method(receiver, method, args) { |
| 45 args = args || 1; | 35 args = args || 1; |
| 46 if (args < 2) { | 36 if (args < 2) { |
| 47 assert_throws({name:'getter'}, function() { | 37 assert_throws({name:'getter'}, () => { |
| 48 receiver[method](throwing_key('getter')); | 38 receiver[method](throwing_key('getter')); |
| 49 }, 'key conversion with throwing getter should rethrow'); | 39 }, 'key conversion with throwing getter should rethrow'); |
| 50 | 40 |
| 51 assert_throws('DataError', function() { | 41 assert_throws('DataError', () => { |
| 52 receiver[method](invalid_key); | 42 receiver[method](invalid_key); |
| 53 }, 'key conversion with invalid key should throw DataError'); | 43 }, 'key conversion with invalid key should throw DataError'); |
| 54 } else { | 44 } else { |
| 55 assert_throws({name:'getter 1'}, function() { | 45 assert_throws({name:'getter 1'}, () => { |
| 56 receiver[method](throwing_key('getter 1'), throwing_key('getter 2')) ; | 46 receiver[method](throwing_key('getter 1'), throwing_key('getter 2')) ; |
| 57 }, 'first key conversion with throwing getter should rethrow'); | 47 }, 'first key conversion with throwing getter should rethrow'); |
| 58 | 48 |
| 59 assert_throws('DataError', function() { | 49 assert_throws('DataError', () => { |
| 60 receiver[method](invalid_key, throwing_key('getter 2')); | 50 receiver[method](invalid_key, throwing_key('getter 2')); |
| 61 }, 'first key conversion with invalid key should throw DataError'); | 51 }, 'first key conversion with invalid key should throw DataError'); |
| 62 | 52 |
| 63 assert_throws({name:'getter 2'}, function() { | 53 assert_throws({name:'getter 2'}, () => { |
| 64 receiver[method](valid_key, throwing_key('getter 2')); | 54 receiver[method](valid_key, throwing_key('getter 2')); |
| 65 }, 'second key conversion with throwing getter should rethrow'); | 55 }, 'second key conversion with throwing getter should rethrow'); |
| 66 | 56 |
| 67 assert_throws('DataError', function() { | 57 assert_throws('DataError', () => { |
| 68 receiver[method](valid_key, invalid_key); | 58 receiver[method](valid_key, invalid_key); |
| 69 }, 'second key conversion with invalid key should throw DataError'); | 59 }, 'second key conversion with invalid key should throw DataError'); |
| 70 } | 60 } |
| 71 } | 61 } |
| 72 | 62 |
| 73 // Static key comparison utility on IDBFactory. | 63 // Static key comparison utility on IDBFactory. |
| 74 test(function(t) { | 64 test((t) => { |
|
jsbell
2017/02/03 19:29:42
nit: no () required around single argument (here a
pwnall
2017/02/07 23:30:04
Done.
Gah, I keep falling for this :( Thanks for y
| |
| 75 check_method(indexedDB, 'cmp', 2); | 65 check_method(indexedDB, 'cmp', 2); |
| 76 }, 'IDBFactory cmp() static with throwing/invalid keys'); | 66 }, 'IDBFactory cmp() static with throwing/invalid keys'); |
| 77 | 67 |
| 78 // Continue methods on IDBCursor. | 68 // Continue methods on IDBCursor. |
| 79 simple_idb_test(function(t, db) { | 69 indexeddb_upgrade_test((t, db) => { |
| 80 var store = db.createObjectStore('store'); | 70 var store = db.createObjectStore('store'); |
| 81 store.put('a', 1).onerror = t.unreached_func('put should succeed'); | 71 store.put('a', 1).onerror = t.unreached_func('put should succeed'); |
| 82 | 72 |
| 83 var request = store.openCursor(); | 73 var request = store.openCursor(); |
| 84 request.onerror = t.unreached_func('openCursor should succeed'); | 74 request.onerror = t.unreached_func('openCursor should succeed'); |
| 85 request.onsuccess = t.step_func(function() { | 75 request.onsuccess = t.step_func(() => { |
| 86 var cursor = request.result; | 76 var cursor = request.result; |
| 87 assert_not_equals(cursor, null, 'cursor should find a value'); | 77 assert_not_equals(cursor, null, 'cursor should find a value'); |
| 88 check_method(cursor, 'continue'); | 78 check_method(cursor, 'continue'); |
| 89 }); | 79 }); |
| 90 }, 'IDBCursor continue() method with throwing/invalid keys'); | 80 }, 'IDBCursor continue() method with throwing/invalid keys'); |
| 91 | 81 |
| 92 simple_idb_test(function(t, db) { | 82 indexeddb_upgrade_test((t, db) => { |
| 93 var store = db.createObjectStore('store'); | 83 var store = db.createObjectStore('store'); |
| 94 var index = store.createIndex('index', 'prop'); | 84 var index = store.createIndex('index', 'prop'); |
| 95 store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed'); | 85 store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed'); |
| 96 | 86 |
| 97 var request = index.openCursor(); | 87 var request = index.openCursor(); |
| 98 request.onerror = t.unreached_func('openCursor should succeed'); | 88 request.onerror = t.unreached_func('openCursor should succeed'); |
| 99 request.onsuccess = t.step_func(function() { | 89 request.onsuccess = t.step_func(() => { |
| 100 var cursor = request.result; | 90 var cursor = request.result; |
| 101 assert_not_equals(cursor, null, 'cursor should find a value'); | 91 assert_not_equals(cursor, null, 'cursor should find a value'); |
| 102 | 92 |
| 103 check_method(cursor, 'continuePrimaryKey', 2); | 93 check_method(cursor, 'continuePrimaryKey', 2); |
| 104 }); | 94 }); |
| 105 }, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys'); | 95 }, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys'); |
| 106 | 96 |
| 107 // Mutation methods on IDBCursor. | 97 // Mutation methods on IDBCursor. |
| 108 simple_idb_test(function(t, db) { | 98 indexeddb_upgrade_test((t, db) => { |
| 109 var store = db.createObjectStore('store', {keyPath: 'prop'}); | 99 var store = db.createObjectStore('store', {keyPath: 'prop'}); |
| 110 store.put({prop: 1}).onerror = t.unreached_func('put should succeed'); | 100 store.put({prop: 1}).onerror = t.unreached_func('put should succeed'); |
| 111 | 101 |
| 112 var request = store.openCursor(); | 102 var request = store.openCursor(); |
| 113 request.onerror = t.unreached_func('openCursor should succeed'); | 103 request.onerror = t.unreached_func('openCursor should succeed'); |
| 114 request.onsuccess = t.step_func(function() { | 104 request.onsuccess = t.step_func(() => { |
| 115 var cursor = request.result; | 105 var cursor = request.result; |
| 116 assert_not_equals(cursor, null, 'cursor should find a value'); | 106 assert_not_equals(cursor, null, 'cursor should find a value'); |
| 117 | 107 |
| 118 var value = {}; | 108 var value = {}; |
| 119 value.prop = throwing_key('getter'); | 109 value.prop = throwing_key('getter'); |
| 120 assert_throws({name: 'getter'}, function() { | 110 assert_throws({name: 'getter'}, () => { |
| 121 cursor.update(value); | 111 cursor.update(value); |
| 122 }, 'throwing getter should rethrow during clone'); | 112 }, 'throwing getter should rethrow during clone'); |
| 123 | 113 |
| 124 // Throwing from the getter during key conversion is | 114 // Throwing from the getter during key conversion is |
| 125 // not possible since (1) a clone is used, (2) only own | 115 // not possible since (1) a clone is used, (2) only own |
| 126 // properties are cloned, and (3) only own properties | 116 // properties are cloned, and (3) only own properties |
| 127 // are used for key path evaluation. | 117 // are used for key path evaluation. |
| 128 | 118 |
| 129 value.prop = invalid_key; | 119 value.prop = invalid_key; |
| 130 assert_throws('DataError', function() { | 120 assert_throws('DataError', () => { |
| 131 cursor.update(value); | 121 cursor.update(value); |
| 132 }, 'key conversion with invalid key should throw DataError'); | 122 }, 'key conversion with invalid key should throw DataError'); |
| 133 }); | 123 }); |
| 134 }, 'IDBCursor update() method with throwing/invalid keys'); | 124 }, 'IDBCursor update() method with throwing/invalid keys'); |
| 135 | 125 |
| 136 // Static constructors on IDBKeyRange | 126 // Static constructors on IDBKeyRange |
| 137 ['only', 'lowerBound', 'upperBound'].forEach(function(method) { | 127 ['only', 'lowerBound', 'upperBound'].forEach((method) => { |
| 138 test(function(t) { | 128 test((t) => { |
| 139 check_method(IDBKeyRange, method); | 129 check_method(IDBKeyRange, method); |
| 140 }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys'); | 130 }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys'); |
| 141 }); | 131 }); |
| 142 | 132 |
| 143 test(function(t) { | 133 test((t) => { |
| 144 check_method(IDBKeyRange, 'bound', 2); | 134 check_method(IDBKeyRange, 'bound', 2); |
| 145 }, 'IDBKeyRange bound() static with throwing/invalid keys'); | 135 }, 'IDBKeyRange bound() static with throwing/invalid keys'); |
| 146 | 136 |
| 147 // Insertion methods on IDBObjectStore. | 137 // Insertion methods on IDBObjectStore. |
| 148 ['add', 'put'].forEach(function(method) { | 138 ['add', 'put'].forEach((method) => { |
| 149 simple_idb_test(function(t, db) { | 139 indexeddb_upgrade_test((t, db) => { |
| 150 var out_of_line = db.createObjectStore('out-of-line keys'); | 140 var out_of_line = db.createObjectStore('out-of-line keys'); |
| 151 var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'}); | 141 var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'}); |
| 152 | 142 |
| 153 assert_throws({name:'getter'}, function() { | 143 assert_throws({name:'getter'}, () => { |
| 154 out_of_line[method]('value', throwing_key('getter')); | 144 out_of_line[method]('value', throwing_key('getter')); |
| 155 }, 'key conversion with throwing getter should rethrow'); | 145 }, 'key conversion with throwing getter should rethrow'); |
| 156 | 146 |
| 157 assert_throws('DataError', function() { | 147 assert_throws('DataError', () => { |
| 158 out_of_line[method]('value', invalid_key); | 148 out_of_line[method]('value', invalid_key); |
| 159 }, 'key conversion with invalid key should throw DataError'); | 149 }, 'key conversion with invalid key should throw DataError'); |
| 160 | 150 |
| 161 var value = {}; | 151 var value = {}; |
| 162 value.prop = throwing_key('getter'); | 152 value.prop = throwing_key('getter'); |
| 163 assert_throws({name:'getter'}, function() { | 153 assert_throws({name:'getter'}, () => { |
| 164 in_line[method](value); | 154 in_line[method](value); |
| 165 }, 'throwing getter should rethrow during clone'); | 155 }, 'throwing getter should rethrow during clone'); |
| 166 | 156 |
| 167 // Throwing from the getter during key conversion is | 157 // Throwing from the getter during key conversion is |
| 168 // not possible since (1) a clone is used, (2) only own | 158 // not possible since (1) a clone is used, (2) only own |
| 169 // properties are cloned, and (3) only own properties | 159 // properties are cloned, and (3) only own properties |
| 170 // are used for key path evaluation. | 160 // are used for key path evaluation. |
| 171 | 161 |
| 172 value.prop = invalid_key; | 162 value.prop = invalid_key; |
| 173 assert_throws('DataError', function() { | 163 assert_throws('DataError', () => { |
| 174 in_line[method](value); | 164 in_line[method](value); |
| 175 }, 'key conversion with invalid key should throw DataError'); | 165 }, 'key conversion with invalid key should throw DataError'); |
| 176 }, 'IDBObjectStore ' + method + '() method with throwing/invalid keys'); | 166 }, `IDBObjectStore ${method}() method with throwing/invalid keys`); |
| 177 }); | 167 }); |
| 178 | 168 |
| 179 // Generic (key-or-key-path) methods on IDBObjectStore. | 169 // Generic (key-or-key-path) methods on IDBObjectStore. |
| 180 [ | 170 [ |
| 181 // TODO(jsbell): Add 'getAllKeys' | 171 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor', |
| 182 'delete', 'get', 'getAll', 'count', 'openCursor', 'openKeyCursor' | 172 'openKeyCursor' |
| 183 ].forEach(function(method) { | 173 ].forEach((method) => { |
| 184 simple_idb_test(function(t, db) { | 174 indexeddb_upgrade_test((t, db) => { |
| 185 var store = db.createObjectStore('store'); | 175 var store = db.createObjectStore('store'); |
| 186 | 176 |
| 187 check_method(store, method); | 177 check_method(store, method); |
| 188 }, 'IDBObjectStore ' + method + '() method with throwing/invalid keys'); | 178 }, `IDBObjectStore ${method}() method with throwing/invalid keys`); |
| 189 }); | 179 }); |
| 190 | 180 |
| 191 // Generic (key-or-key-path) methods on IDBIndex. | 181 // Generic (key-or-key-path) methods on IDBIndex. |
| 192 [ | 182 [ |
| 193 // TODO(jsbell): Add 'getAllKeys' | 183 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor', |
| 194 'get', 'getKey', 'getAll', 'count', 'openCursor', 'openKeyCursor' | 184 'openKeyCursor' |
| 195 ].forEach(function(method) { | 185 ].forEach((method) => { |
| 196 simple_idb_test(function(t, db) { | 186 indexeddb_upgrade_test((t, db) => { |
| 197 var store = db.createObjectStore('store'); | 187 var store = db.createObjectStore('store'); |
| 198 var index = store.createIndex('index', 'keyPath'); | 188 var index = store.createIndex('index', 'keyPath'); |
| 199 | 189 |
| 200 check_method(index, method); | 190 check_method(index, method); |
| 201 }, 'IDBIndex ' + method + '() method with throwing/invalid keys'); | 191 }, `IDBIndex ${method}() method with throwing/invalid keys`); |
| 202 }); | 192 }); |
| 203 | 193 |
| 204 </script> | 194 </script> |
| OLD | NEW |