summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/tests/xpcshell/test_JSONFile.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/tests/xpcshell/test_JSONFile.js')
-rw-r--r--toolkit/modules/tests/xpcshell/test_JSONFile.js242
1 files changed, 242 insertions, 0 deletions
diff --git a/toolkit/modules/tests/xpcshell/test_JSONFile.js b/toolkit/modules/tests/xpcshell/test_JSONFile.js
new file mode 100644
index 000000000..77e8c55b9
--- /dev/null
+++ b/toolkit/modules/tests/xpcshell/test_JSONFile.js
@@ -0,0 +1,242 @@
+/**
+ * Tests the JSONFile object.
+ */
+
+"use strict";
+
+// Globals
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
+ "resource://gre/modules/DownloadPaths.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+ "resource://gre/modules/FileUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+ "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
+ "resource://gre/modules/JSONFile.jsm");
+
+let gFileCounter = Math.floor(Math.random() * 1000000);
+
+/**
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ * Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ * after calling nsIFile.createUnique, because on Windows the delete
+ * operation in the file system may still be pending, preventing a new
+ * file with the same name to be created.
+ */
+function getTempFile(aLeafName)
+{
+ // Prepend a serial number to the extension in the suggested leaf name.
+ let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+ let leafName = base + "-" + gFileCounter + ext;
+ gFileCounter++;
+
+ // Get a file reference under the temporary directory for this test file.
+ let file = FileUtils.getFile("TmpD", [leafName]);
+ do_check_false(file.exists());
+
+ do_register_cleanup(function () {
+ if (file.exists()) {
+ file.remove(false);
+ }
+ });
+
+ return file;
+}
+
+const TEST_STORE_FILE_NAME = "test-store.json";
+
+const TEST_DATA = {
+ number: 123,
+ string: "test",
+ object: {
+ prop1: 1,
+ prop2: 2,
+ },
+};
+
+// Tests
+
+add_task(function* test_save_reload()
+{
+ let storeForSave = new JSONFile({
+ path: getTempFile(TEST_STORE_FILE_NAME).path,
+ });
+
+ yield storeForSave.load();
+
+ do_check_true(storeForSave.dataReady);
+ do_check_matches(storeForSave.data, {});
+
+ Object.assign(storeForSave.data, TEST_DATA);
+
+ yield new Promise((resolve) => {
+ let save = storeForSave._save.bind(storeForSave);
+ storeForSave._save = () => {
+ save();
+ resolve();
+ };
+ storeForSave.saveSoon();
+ });
+
+ let storeForLoad = new JSONFile({
+ path: storeForSave.path,
+ });
+
+ yield storeForLoad.load();
+
+ Assert.deepEqual(storeForLoad.data, TEST_DATA);
+});
+
+add_task(function* test_load_sync()
+{
+ let storeForSave = new JSONFile({
+ path: getTempFile(TEST_STORE_FILE_NAME).path
+ });
+ yield storeForSave.load();
+ Object.assign(storeForSave.data, TEST_DATA);
+ yield storeForSave._save();
+
+ let storeForLoad = new JSONFile({
+ path: storeForSave.path,
+ });
+ storeForLoad.ensureDataReady();
+
+ Assert.deepEqual(storeForLoad.data, TEST_DATA);
+});
+
+add_task(function* test_load_with_dataPostProcessor()
+{
+ let storeForSave = new JSONFile({
+ path: getTempFile(TEST_STORE_FILE_NAME).path
+ });
+ yield storeForSave.load();
+ Object.assign(storeForSave.data, TEST_DATA);
+ yield 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;
+ },
+ });
+
+ yield storeForLoad.load();
+
+ do_check_eq(storeForLoad.data.test, random);
+});
+
+add_task(function* test_load_with_dataPostProcessor_fails()
+{
+ let store = new JSONFile({
+ path: getTempFile(TEST_STORE_FILE_NAME).path,
+ dataPostProcessor: () => {
+ throw new Error("dataPostProcessor fails.");
+ },
+ });
+
+ yield Assert.rejects(store.load(), /dataPostProcessor fails\./);
+
+ do_check_false(store.dataReady);
+});
+
+add_task(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\./);
+
+ do_check_false(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(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}}";
+
+ yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
+ { tmpPath: store.path + ".tmp" });
+
+ yield store.load();
+
+ Assert.deepEqual(store.data, TEST_DATA);
+});
+
+/**
+ * Loads data from a malformed JSON string.
+ */
+add_task(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,";
+
+ yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
+ { tmpPath: store.path + ".tmp" });
+
+ yield store.load();
+
+ // A backup file should have been created.
+ do_check_true(yield OS.File.exists(store.path + ".corrupt"));
+ yield OS.File.remove(store.path + ".corrupt");
+
+ // The store should be ready to accept new data.
+ do_check_true(store.dataReady);
+ do_check_matches(store.data, {});
+});
+
+/**
+ * Loads data from a malformed JSON string, using the synchronous initialization
+ * path.
+ */
+add_task(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,";
+
+ yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
+ { tmpPath: store.path + ".tmp" });
+
+ store.ensureDataReady();
+
+ // A backup file should have been created.
+ do_check_true(yield OS.File.exists(store.path + ".corrupt"));
+ yield OS.File.remove(store.path + ".corrupt");
+
+ // The store should be ready to accept new data.
+ do_check_true(store.dataReady);
+ do_check_matches(store.data, {});
+});