fune/toolkit/modules/tests/xpcshell/test_JSONFile.js
Kris Maglione 918ed6c474 Bug 1431533: Part 5a - Auto-rewrite code to use ChromeUtils import methods. r=florian
This was done using the following script:
37e3803c7a/processors/chromeutils-import.jsm

MozReview-Commit-ID: 1Nc3XDu0wGl

--HG--
extra : source : 12fc4dee861c812fd2bd032c63ef17af61800c70
extra : intermediate-source : 34c999fa006bffe8705cf50c54708aa21a962e62
extra : histedit_source : b2be2c5e5d226e6c347312456a6ae339c1e634b0
2018-01-29 15:20:18 -08:00

330 lines
9 KiB
JavaScript

/**
* Tests the JSONFile object.
*/
"use strict";
// Globals
ChromeUtils.defineModuleGetter(this, "AsyncShutdown",
"resource://gre/modules/AsyncShutdown.jsm");
ChromeUtils.defineModuleGetter(this, "DownloadPaths",
"resource://gre/modules/DownloadPaths.jsm");
ChromeUtils.defineModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
ChromeUtils.defineModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(this, "JSONFile",
"resource://gre/modules/JSONFile.jsm");
ChromeUtils.defineModuleGetter(this, "FileTestUtils",
"resource://testing-common/FileTestUtils.jsm");
/**
* Returns a reference to a temporary file that is guaranteed not to exist and
* is cleaned up later. See FileTestUtils.getTempFile for details.
*/
function getTempFile(leafName) {
return FileTestUtils.getTempFile(leafName);
}
const TEST_STORE_FILE_NAME = "test-store.json";
const TEST_DATA = {
number: 123,
string: "test",
object: {
prop1: 1,
prop2: 2,
},
};
// Tests
add_task(async function test_save_reload() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
await storeForSave.load();
Assert.ok(storeForSave.dataReady);
Assert.deepEqual(storeForSave.data, {});
Object.assign(storeForSave.data, TEST_DATA);
await new Promise((resolve) => {
let save = storeForSave._save.bind(storeForSave);
storeForSave._save = () => {
save();
resolve();
};
storeForSave.saveSoon();
});
let storeForLoad = new JSONFile({
path: storeForSave.path,
});
await storeForLoad.load();
Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_load_sync() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path
});
await storeForSave.load();
Object.assign(storeForSave.data, TEST_DATA);
await storeForSave._save();
let storeForLoad = new JSONFile({
path: storeForSave.path,
});
storeForLoad.ensureDataReady();
Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_load_with_dataPostProcessor() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path
});
await storeForSave.load();
Object.assign(storeForSave.data, TEST_DATA);
await storeForSave._save();
let random = Math.random();
let storeForLoad = new JSONFile({
path: storeForSave.path,
dataPostProcessor: (data) => {
Assert.deepEqual(data, TEST_DATA);
data.test = random;
return data;
},
});
await storeForLoad.load();
Assert.equal(storeForLoad.data.test, random);
});
add_task(async function test_load_with_dataPostProcessor_fails() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
dataPostProcessor: () => {
throw new Error("dataPostProcessor fails.");
},
});
await Assert.rejects(store.load(), /dataPostProcessor fails\./);
Assert.ok(!store.dataReady);
});
add_task(async function test_load_sync_with_dataPostProcessor_fails() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
dataPostProcessor: () => {
throw new Error("dataPostProcessor fails.");
},
});
Assert.throws(() => store.ensureDataReady(), /dataPostProcessor fails\./);
Assert.ok(!store.dataReady);
});
/**
* Loads data from a string in a predefined format. The purpose of this test is
* to verify that the JSON format used in previous versions can be loaded.
*/
add_task(async function test_load_string_predefined() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string =
"{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,\"prop2\":2}}";
await OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
{ tmpPath: store.path + ".tmp" });
await store.load();
Assert.deepEqual(store.data, TEST_DATA);
});
/**
* Loads data from a malformed JSON string.
*/
add_task(async function test_load_string_malformed() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = "{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,";
await OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
{ tmpPath: store.path + ".tmp" });
await store.load();
// A backup file should have been created.
Assert.ok(await OS.File.exists(store.path + ".corrupt"));
await OS.File.remove(store.path + ".corrupt");
// The store should be ready to accept new data.
Assert.ok(store.dataReady);
Assert.deepEqual(store.data, {});
});
/**
* Loads data from a malformed JSON string, using the synchronous initialization
* path.
*/
add_task(async function test_load_string_malformed_sync() {
let store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = "{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,";
await OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
{ tmpPath: store.path + ".tmp" });
store.ensureDataReady();
// A backup file should have been created.
Assert.ok(await OS.File.exists(store.path + ".corrupt"));
await OS.File.remove(store.path + ".corrupt");
// The store should be ready to accept new data.
Assert.ok(store.dataReady);
Assert.deepEqual(store.data, {});
});
add_task(async function test_overwrite_data() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
});
let string = `{"number":456,"string":"tset","object":{"prop1":3,"prop2":4}}`;
await OS.File.writeAtomic(storeForSave.path, new TextEncoder().encode(string),
{ tmpPath: storeForSave.path + ".tmp" });
Assert.ok(!storeForSave.dataReady);
storeForSave.data = TEST_DATA;
Assert.ok(storeForSave.dataReady);
Assert.equal(storeForSave.data, TEST_DATA);
await new Promise((resolve) => {
let save = storeForSave._save.bind(storeForSave);
storeForSave._save = () => {
save();
resolve();
};
storeForSave.saveSoon();
});
let storeForLoad = new JSONFile({
path: storeForSave.path,
});
await storeForLoad.load();
Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_beforeSave() {
let store;
let promiseBeforeSave = new Promise((resolve) => {
store = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
beforeSave: resolve,
saveDelayMs: 250,
});
});
store.saveSoon();
await promiseBeforeSave;
});
add_task(async function test_beforeSave_rejects() {
let storeForSave = new JSONFile({
path: getTempFile(TEST_STORE_FILE_NAME).path,
beforeSave() {
return Promise.reject(new Error("oops"));
},
saveDelayMs: 250,
});
let promiseSave = new Promise((resolve, reject) => {
let save = storeForSave._save.bind(storeForSave);
storeForSave._save = () => {
save().then(resolve, reject);
};
storeForSave.saveSoon();
});
await Assert.rejects(promiseSave, function(ex) {
return ex.message == "oops";
});
});
add_task(async function test_finalize() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let barrier = new AsyncShutdown.Barrier("test-auto-finalize");
let storeForSave = new JSONFile({
path,
saveDelayMs: 2000,
finalizeAt: barrier.client,
});
await storeForSave.load();
storeForSave.data = TEST_DATA;
storeForSave.saveSoon();
let promiseFinalize = storeForSave.finalize();
await Assert.rejects(storeForSave.finalize(), /has already been finalized$/);
await promiseFinalize;
Assert.ok(!storeForSave.dataReady);
// Finalization removes the blocker, so waiting should not log an unhandled
// error even though the object has been explicitly finalized.
await barrier.wait();
let storeForLoad = new JSONFile({ path });
await storeForLoad.load();
Assert.deepEqual(storeForLoad.data, TEST_DATA);
});
add_task(async function test_finalize_on_shutdown() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let barrier = new AsyncShutdown.Barrier("test-finalize-shutdown");
let storeForSave = new JSONFile({
path,
saveDelayMs: 2000,
finalizeAt: barrier.client,
});
await storeForSave.load();
storeForSave.data = TEST_DATA;
// Arm the saver, then simulate shutdown and ensure the file is
// automatically finalized.
storeForSave.saveSoon();
await barrier.wait();
// It's possible for `finalize` to reject when called concurrently with
// shutdown. We don't distinguish between explicit `finalize` calls and
// finalization on shutdown because we expect most consumers to rely on the
// latter. However, this behavior can be safely changed if needed.
await Assert.rejects(storeForSave.finalize(), /has already been finalized$/);
Assert.ok(!storeForSave.dataReady);
let storeForLoad = new JSONFile({ path });
await storeForLoad.load();
Assert.deepEqual(storeForLoad.data, TEST_DATA);
});