1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-simple-storage.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,506 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +const file = require("sdk/io/file"); 1.9 +const prefs = require("sdk/preferences/service"); 1.10 + 1.11 +const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota"; 1.12 +const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod"; 1.13 + 1.14 +let {Cc,Ci} = require("chrome"); 1.15 + 1.16 +const { Loader } = require("sdk/test/loader"); 1.17 +const { id } = require("sdk/self"); 1.18 + 1.19 +let storeFile = Cc["@mozilla.org/file/directory_service;1"]. 1.20 + getService(Ci.nsIProperties). 1.21 + get("ProfD", Ci.nsIFile); 1.22 +storeFile.append("jetpack"); 1.23 +storeFile.append(id); 1.24 +storeFile.append("simple-storage"); 1.25 +file.mkpath(storeFile.path); 1.26 +storeFile.append("store.json"); 1.27 +let storeFilename = storeFile.path; 1.28 + 1.29 +function manager(loader) loader.sandbox("sdk/simple-storage").manager; 1.30 + 1.31 +exports.testSetGet = function (assert, done) { 1.32 + // Load the module once, set a value. 1.33 + let loader = Loader(module); 1.34 + let ss = loader.require("sdk/simple-storage"); 1.35 + manager(loader).jsonStore.onWrite = function (storage) { 1.36 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.37 + 1.38 + // Load the module again and make sure the value stuck. 1.39 + loader = Loader(module); 1.40 + ss = loader.require("sdk/simple-storage"); 1.41 + assert.equal(ss.storage.foo, val, "Value should persist"); 1.42 + manager(loader).jsonStore.onWrite = function (storage) { 1.43 + assert.fail("Nothing should be written since `storage` was not changed."); 1.44 + }; 1.45 + loader.unload(); 1.46 + file.remove(storeFilename); 1.47 + done(); 1.48 + }; 1.49 + let val = "foo"; 1.50 + ss.storage.foo = val; 1.51 + assert.equal(ss.storage.foo, val, "Value read should be value set"); 1.52 + loader.unload(); 1.53 +}; 1.54 + 1.55 +exports.testSetGetRootArray = function (assert, done) { 1.56 + setGetRoot(assert, done, [1, 2, 3], function (arr1, arr2) { 1.57 + if (arr1.length !== arr2.length) 1.58 + return false; 1.59 + for (let i = 0; i < arr1.length; i++) { 1.60 + if (arr1[i] !== arr2[i]) 1.61 + return false; 1.62 + } 1.63 + return true; 1.64 + }); 1.65 +}; 1.66 + 1.67 +exports.testSetGetRootBool = function (assert, done) { 1.68 + setGetRoot(assert, done, true); 1.69 +}; 1.70 + 1.71 +exports.testSetGetRootFunction = function (assert, done) { 1.72 + setGetRootError(assert, done, function () {}, 1.73 + "Setting storage to a function should fail"); 1.74 +}; 1.75 + 1.76 +exports.testSetGetRootNull = function (assert, done) { 1.77 + setGetRoot(assert, done, null); 1.78 +}; 1.79 + 1.80 +exports.testSetGetRootNumber = function (assert, done) { 1.81 + setGetRoot(assert, done, 3.14); 1.82 +}; 1.83 + 1.84 +exports.testSetGetRootObject = function (assert, done) { 1.85 + setGetRoot(assert, done, { foo: 1, bar: 2 }, function (obj1, obj2) { 1.86 + for (let prop in obj1) { 1.87 + if (!(prop in obj2) || obj2[prop] !== obj1[prop]) 1.88 + return false; 1.89 + } 1.90 + for (let prop in obj2) { 1.91 + if (!(prop in obj1) || obj1[prop] !== obj2[prop]) 1.92 + return false; 1.93 + } 1.94 + return true; 1.95 + }); 1.96 +}; 1.97 + 1.98 +exports.testSetGetRootString = function (assert, done) { 1.99 + setGetRoot(assert, done, "sho' 'nuff"); 1.100 +}; 1.101 + 1.102 +exports.testSetGetRootUndefined = function (assert, done) { 1.103 + setGetRootError(assert, done, undefined, "Setting storage to undefined should fail"); 1.104 +}; 1.105 + 1.106 +exports.testEmpty = function (assert) { 1.107 + let loader = Loader(module); 1.108 + let ss = loader.require("sdk/simple-storage"); 1.109 + loader.unload(); 1.110 + assert.ok(!file.exists(storeFilename), "Store file should not exist"); 1.111 +}; 1.112 + 1.113 +exports.testStorageDataRecovery = function(assert) { 1.114 + const data = { 1.115 + a: true, 1.116 + b: [3, 13], 1.117 + c: "guilty!", 1.118 + d: { e: 1, f: 2 } 1.119 + }; 1.120 + let stream = file.open(storeFilename, "w"); 1.121 + stream.write(JSON.stringify(data)); 1.122 + stream.close(); 1.123 + let loader = Loader(module); 1.124 + let ss = loader.require("sdk/simple-storage"); 1.125 + assert.deepEqual(ss.storage, data, "Recovered data should be the same as written"); 1.126 + file.remove(storeFilename); 1.127 + loader.unload(); 1.128 +} 1.129 + 1.130 +exports.testMalformed = function (assert) { 1.131 + let stream = file.open(storeFilename, "w"); 1.132 + stream.write("i'm not json"); 1.133 + stream.close(); 1.134 + let loader = Loader(module); 1.135 + let ss = loader.require("sdk/simple-storage"); 1.136 + let empty = true; 1.137 + for (let key in ss.storage) { 1.138 + empty = false; 1.139 + break; 1.140 + } 1.141 + assert.ok(empty, "Malformed storage should cause root to be empty"); 1.142 + file.remove(storeFilename); 1.143 + loader.unload(); 1.144 +}; 1.145 + 1.146 +// Go over quota and handle it by listener. 1.147 +exports.testQuotaExceededHandle = function (assert, done) { 1.148 + prefs.set(QUOTA_PREF, 18); 1.149 + 1.150 + let loader = Loader(module); 1.151 + let ss = loader.require("sdk/simple-storage"); 1.152 + ss.on("OverQuota", function () { 1.153 + assert.pass("OverQuota was emitted as expected"); 1.154 + assert.equal(this, ss, "`this` should be simple storage"); 1.155 + ss.storage = { x: 4, y: 5 }; 1.156 + 1.157 + manager(loader).jsonStore.onWrite = function () { 1.158 + loader = Loader(module); 1.159 + ss = loader.require("sdk/simple-storage"); 1.160 + let numProps = 0; 1.161 + for (let prop in ss.storage) 1.162 + numProps++; 1.163 + assert.ok(numProps, 2, 1.164 + "Store should contain 2 values: " + ss.storage.toSource()); 1.165 + assert.equal(ss.storage.x, 4, "x value should be correct"); 1.166 + assert.equal(ss.storage.y, 5, "y value should be correct"); 1.167 + manager(loader).jsonStore.onWrite = function (storage) { 1.168 + assert.fail("Nothing should be written since `storage` was not changed."); 1.169 + }; 1.170 + loader.unload(); 1.171 + prefs.reset(QUOTA_PREF); 1.172 + done(); 1.173 + }; 1.174 + loader.unload(); 1.175 + }); 1.176 + // This will be JSON.stringify()ed to: {"a":1,"b":2,"c":3} (19 bytes) 1.177 + ss.storage = { a: 1, b: 2, c: 3 }; 1.178 + manager(loader).jsonStore.write(); 1.179 +}; 1.180 + 1.181 +// Go over quota but don't handle it. The last good state should still persist. 1.182 +exports.testQuotaExceededNoHandle = function (assert, done) { 1.183 + prefs.set(QUOTA_PREF, 5); 1.184 + 1.185 + let loader = Loader(module); 1.186 + let ss = loader.require("sdk/simple-storage"); 1.187 + 1.188 + manager(loader).jsonStore.onWrite = function (storage) { 1.189 + loader = Loader(module); 1.190 + ss = loader.require("sdk/simple-storage"); 1.191 + assert.equal(ss.storage, val, 1.192 + "Value should have persisted: " + ss.storage); 1.193 + ss.storage = "some very long string that is very long"; 1.194 + ss.on("OverQuota", function () { 1.195 + assert.pass("OverQuota emitted as expected"); 1.196 + manager(loader).jsonStore.onWrite = function () { 1.197 + assert.fail("Over-quota value should not have been written"); 1.198 + }; 1.199 + loader.unload(); 1.200 + 1.201 + loader = Loader(module); 1.202 + ss = loader.require("sdk/simple-storage"); 1.203 + assert.equal(ss.storage, val, 1.204 + "Over-quota value should not have been written, " + 1.205 + "old value should have persisted: " + ss.storage); 1.206 + manager(loader).jsonStore.onWrite = function (storage) { 1.207 + assert.fail("Nothing should be written since `storage` was not changed."); 1.208 + }; 1.209 + loader.unload(); 1.210 + prefs.reset(QUOTA_PREF); 1.211 + done(); 1.212 + }); 1.213 + manager(loader).jsonStore.write(); 1.214 + }; 1.215 + 1.216 + let val = "foo"; 1.217 + ss.storage = val; 1.218 + loader.unload(); 1.219 +}; 1.220 + 1.221 +exports.testQuotaUsage = function (assert, done) { 1.222 + let quota = 21; 1.223 + prefs.set(QUOTA_PREF, quota); 1.224 + 1.225 + let loader = Loader(module); 1.226 + let ss = loader.require("sdk/simple-storage"); 1.227 + 1.228 + // {"a":1} (7 bytes) 1.229 + ss.storage = { a: 1 }; 1.230 + assert.equal(ss.quotaUsage, 7 / quota, "quotaUsage should be correct"); 1.231 + 1.232 + // {"a":1,"bb":2} (14 bytes) 1.233 + ss.storage = { a: 1, bb: 2 }; 1.234 + assert.equal(ss.quotaUsage, 14 / quota, "quotaUsage should be correct"); 1.235 + 1.236 + // {"a":1,"bb":2,"cc":3} (21 bytes) 1.237 + ss.storage = { a: 1, bb: 2, cc: 3 }; 1.238 + assert.equal(ss.quotaUsage, 21 / quota, "quotaUsage should be correct"); 1.239 + 1.240 + manager(loader).jsonStore.onWrite = function () { 1.241 + prefs.reset(QUOTA_PREF); 1.242 + done(); 1.243 + }; 1.244 + loader.unload(); 1.245 +}; 1.246 + 1.247 +exports.testUninstall = function (assert, done) { 1.248 + let loader = Loader(module); 1.249 + let ss = loader.require("sdk/simple-storage"); 1.250 + manager(loader).jsonStore.onWrite = function () { 1.251 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.252 + 1.253 + loader = Loader(module); 1.254 + ss = loader.require("sdk/simple-storage"); 1.255 + loader.unload("uninstall"); 1.256 + assert.ok(!file.exists(storeFilename), "Store file should be removed"); 1.257 + done(); 1.258 + }; 1.259 + ss.storage.foo = "foo"; 1.260 + loader.unload(); 1.261 +}; 1.262 + 1.263 +exports.testChangeInnerArray = function(assert, done) { 1.264 + prefs.set(WRITE_PERIOD_PREF, 10); 1.265 + 1.266 + let expected = { 1.267 + x: [5, 7], 1.268 + y: [7, 28], 1.269 + z: [6, 2] 1.270 + }; 1.271 + 1.272 + // Load the module, set a value. 1.273 + let loader = Loader(module); 1.274 + let ss = loader.require("sdk/simple-storage"); 1.275 + manager(loader).jsonStore.onWrite = function (storage) { 1.276 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.277 + 1.278 + // Load the module again and check the result 1.279 + loader = Loader(module); 1.280 + ss = loader.require("sdk/simple-storage"); 1.281 + assert.equal(JSON.stringify(ss.storage), 1.282 + JSON.stringify(expected), "Should see the expected object"); 1.283 + 1.284 + // Add a property 1.285 + ss.storage.x.push(["bar"]); 1.286 + expected.x.push(["bar"]); 1.287 + manager(loader).jsonStore.onWrite = function (storage) { 1.288 + assert.equal(JSON.stringify(ss.storage), 1.289 + JSON.stringify(expected), "Should see the expected object"); 1.290 + 1.291 + // Modify a property 1.292 + ss.storage.y[0] = 42; 1.293 + expected.y[0] = 42; 1.294 + manager(loader).jsonStore.onWrite = function (storage) { 1.295 + assert.equal(JSON.stringify(ss.storage), 1.296 + JSON.stringify(expected), "Should see the expected object"); 1.297 + 1.298 + // Delete a property 1.299 + delete ss.storage.z[1]; 1.300 + delete expected.z[1]; 1.301 + manager(loader).jsonStore.onWrite = function (storage) { 1.302 + assert.equal(JSON.stringify(ss.storage), 1.303 + JSON.stringify(expected), "Should see the expected object"); 1.304 + 1.305 + // Modify the new inner-object 1.306 + ss.storage.x[2][0] = "baz"; 1.307 + expected.x[2][0] = "baz"; 1.308 + manager(loader).jsonStore.onWrite = function (storage) { 1.309 + assert.equal(JSON.stringify(ss.storage), 1.310 + JSON.stringify(expected), "Should see the expected object"); 1.311 + 1.312 + manager(loader).jsonStore.onWrite = function (storage) { 1.313 + assert.fail("Nothing should be written since `storage` was not changed."); 1.314 + }; 1.315 + loader.unload(); 1.316 + 1.317 + // Load the module again and check the result 1.318 + loader = Loader(module); 1.319 + ss = loader.require("sdk/simple-storage"); 1.320 + assert.equal(JSON.stringify(ss.storage), 1.321 + JSON.stringify(expected), "Should see the expected object"); 1.322 + loader.unload(); 1.323 + file.remove(storeFilename); 1.324 + prefs.reset(WRITE_PERIOD_PREF); 1.325 + done(); 1.326 + }; 1.327 + }; 1.328 + }; 1.329 + }; 1.330 + }; 1.331 + 1.332 + ss.storage = { 1.333 + x: [5, 7], 1.334 + y: [7, 28], 1.335 + z: [6, 2] 1.336 + }; 1.337 + assert.equal(JSON.stringify(ss.storage), 1.338 + JSON.stringify(expected), "Should see the expected object"); 1.339 + 1.340 + loader.unload(); 1.341 +}; 1.342 + 1.343 +exports.testChangeInnerObject = function(assert, done) { 1.344 + prefs.set(WRITE_PERIOD_PREF, 10); 1.345 + 1.346 + let expected = { 1.347 + x: { 1.348 + a: 5, 1.349 + b: 7 1.350 + }, 1.351 + y: { 1.352 + c: 7, 1.353 + d: 28 1.354 + }, 1.355 + z: { 1.356 + e: 6, 1.357 + f: 2 1.358 + } 1.359 + }; 1.360 + 1.361 + // Load the module, set a value. 1.362 + let loader = Loader(module); 1.363 + let ss = loader.require("sdk/simple-storage"); 1.364 + manager(loader).jsonStore.onWrite = function (storage) { 1.365 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.366 + 1.367 + // Load the module again and check the result 1.368 + loader = Loader(module); 1.369 + ss = loader.require("sdk/simple-storage"); 1.370 + assert.equal(JSON.stringify(ss.storage), 1.371 + JSON.stringify(expected), "Should see the expected object"); 1.372 + 1.373 + // Add a property 1.374 + ss.storage.x.g = {foo: "bar"}; 1.375 + expected.x.g = {foo: "bar"}; 1.376 + manager(loader).jsonStore.onWrite = function (storage) { 1.377 + assert.equal(JSON.stringify(ss.storage), 1.378 + JSON.stringify(expected), "Should see the expected object"); 1.379 + 1.380 + // Modify a property 1.381 + ss.storage.y.c = 42; 1.382 + expected.y.c = 42; 1.383 + manager(loader).jsonStore.onWrite = function (storage) { 1.384 + assert.equal(JSON.stringify(ss.storage), 1.385 + JSON.stringify(expected), "Should see the expected object"); 1.386 + 1.387 + // Delete a property 1.388 + delete ss.storage.z.f; 1.389 + delete expected.z.f; 1.390 + manager(loader).jsonStore.onWrite = function (storage) { 1.391 + assert.equal(JSON.stringify(ss.storage), 1.392 + JSON.stringify(expected), "Should see the expected object"); 1.393 + 1.394 + // Modify the new inner-object 1.395 + ss.storage.x.g.foo = "baz"; 1.396 + expected.x.g.foo = "baz"; 1.397 + manager(loader).jsonStore.onWrite = function (storage) { 1.398 + assert.equal(JSON.stringify(ss.storage), 1.399 + JSON.stringify(expected), "Should see the expected object"); 1.400 + 1.401 + manager(loader).jsonStore.onWrite = function (storage) { 1.402 + assert.fail("Nothing should be written since `storage` was not changed."); 1.403 + }; 1.404 + loader.unload(); 1.405 + 1.406 + // Load the module again and check the result 1.407 + loader = Loader(module); 1.408 + ss = loader.require("sdk/simple-storage"); 1.409 + assert.equal(JSON.stringify(ss.storage), 1.410 + JSON.stringify(expected), "Should see the expected object"); 1.411 + loader.unload(); 1.412 + file.remove(storeFilename); 1.413 + prefs.reset(WRITE_PERIOD_PREF); 1.414 + done(); 1.415 + }; 1.416 + }; 1.417 + }; 1.418 + }; 1.419 + }; 1.420 + 1.421 + ss.storage = { 1.422 + x: { 1.423 + a: 5, 1.424 + b: 7 1.425 + }, 1.426 + y: { 1.427 + c: 7, 1.428 + d: 28 1.429 + }, 1.430 + z: { 1.431 + e: 6, 1.432 + f: 2 1.433 + } 1.434 + }; 1.435 + assert.equal(JSON.stringify(ss.storage), 1.436 + JSON.stringify(expected), "Should see the expected object"); 1.437 + 1.438 + loader.unload(); 1.439 +}; 1.440 + 1.441 +exports.testSetNoSetRead = function (assert, done) { 1.442 + // Load the module, set a value. 1.443 + let loader = Loader(module); 1.444 + let ss = loader.require("sdk/simple-storage"); 1.445 + manager(loader).jsonStore.onWrite = function (storage) { 1.446 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.447 + 1.448 + // Load the module again but don't access ss.storage. 1.449 + loader = Loader(module); 1.450 + ss = loader.require("sdk/simple-storage"); 1.451 + manager(loader).jsonStore.onWrite = function (storage) { 1.452 + assert.fail("Nothing should be written since `storage` was not accessed."); 1.453 + }; 1.454 + loader.unload(); 1.455 + 1.456 + // Load the module a third time and make sure the value stuck. 1.457 + loader = Loader(module); 1.458 + ss = loader.require("sdk/simple-storage"); 1.459 + assert.equal(ss.storage.foo, val, "Value should persist"); 1.460 + manager(loader).jsonStore.onWrite = function (storage) { 1.461 + assert.fail("Nothing should be written since `storage` was not changed."); 1.462 + }; 1.463 + loader.unload(); 1.464 + file.remove(storeFilename); 1.465 + done(); 1.466 + }; 1.467 + let val = "foo"; 1.468 + ss.storage.foo = val; 1.469 + assert.equal(ss.storage.foo, val, "Value read should be value set"); 1.470 + loader.unload(); 1.471 +}; 1.472 + 1.473 + 1.474 +function setGetRoot(assert, done, val, compare) { 1.475 + compare = compare || function (a, b) a === b; 1.476 + 1.477 + // Load the module once, set a value. 1.478 + let loader = Loader(module); 1.479 + let ss = loader.require("sdk/simple-storage"); 1.480 + manager(loader).jsonStore.onWrite = function () { 1.481 + assert.ok(file.exists(storeFilename), "Store file should exist"); 1.482 + 1.483 + // Load the module again and make sure the value stuck. 1.484 + loader = Loader(module); 1.485 + ss = loader.require("sdk/simple-storage"); 1.486 + assert.ok(compare(ss.storage, val), "Value should persist"); 1.487 + manager(loader).jsonStore.onWrite = function (storage) { 1.488 + assert.fail("Nothing should be written since `storage` was not changed."); 1.489 + }; 1.490 + loader.unload(); 1.491 + file.remove(storeFilename); 1.492 + done(); 1.493 + }; 1.494 + ss.storage = val; 1.495 + assert.ok(compare(ss.storage, val), "Value read should be value set"); 1.496 + loader.unload(); 1.497 +} 1.498 + 1.499 +function setGetRootError(assert, done, val, msg) { 1.500 + let pred = new RegExp("storage must be one of the following types: " + 1.501 + "array, boolean, null, number, object, string"); 1.502 + let loader = Loader(module); 1.503 + let ss = loader.require("sdk/simple-storage"); 1.504 + assert.throws(function () ss.storage = val, pred, msg); 1.505 + done(); 1.506 + loader.unload(); 1.507 +} 1.508 + 1.509 +require('sdk/test').run(exports);