/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ add_task(async function test_metadata() { await PlacesUtils.metadata.set("test/integer", 123); Assert.strictEqual( await PlacesUtils.metadata.get("test/integer"), 123, "Should store new integer value" ); await PlacesUtils.metadata.set("test/double", 123.45); Assert.strictEqual( await PlacesUtils.metadata.get("test/double"), 123.45, "Should store new double value" ); await PlacesUtils.metadata.set("test/double", 567.89); Assert.strictEqual( await PlacesUtils.metadata.get("test/double"), 567.89, "Should update existing double value" ); await PlacesUtils.metadata.set("test/boolean", false); Assert.strictEqual( await PlacesUtils.metadata.get("test/boolean"), false, "Should store new Boolean value" ); await PlacesUtils.metadata.set("test/boolean", true); Assert.strictEqual( await PlacesUtils.metadata.get("test/boolean"), true, "Should update existing Boolean value" ); await PlacesUtils.metadata.set("test/string", "hi"); Assert.equal( await PlacesUtils.metadata.get("test/string"), "hi", "Should store new string value" ); await PlacesUtils.metadata.cache.clear(); Assert.equal( await PlacesUtils.metadata.get("test/string"), "hi", "Should return string value after clearing cache" ); await Assert.rejects( PlacesUtils.metadata.get("test/nonexistent"), /No data stored for key test\/nonexistent/, "Should reject for a non-existent key and no default value." ); Assert.equal( await PlacesUtils.metadata.get("test/nonexistent", "defaultValue"), "defaultValue", "Should return the default value for a non-existent key." ); // Values are untyped; it's OK to store a value of a different type for the // same key. await PlacesUtils.metadata.set("test/string", 111); Assert.strictEqual( await PlacesUtils.metadata.get("test/string"), 111, "Should replace string with integer" ); await PlacesUtils.metadata.set("test/string", null); await Assert.rejects( PlacesUtils.metadata.get("test/string"), /No data stored for key test\/string/, "Should clear value when setting to NULL" ); await PlacesUtils.metadata.delete("test/string", "test/boolean"); await Assert.rejects( PlacesUtils.metadata.get("test/string"), /No data stored for key test\/string/, "Should delete string value" ); await Assert.rejects( PlacesUtils.metadata.get("test/boolean"), /No data stored for key test\/boolean/, "Should delete Boolean value" ); Assert.strictEqual( await PlacesUtils.metadata.get("test/integer"), 123, "Should keep undeleted integer value" ); await PlacesTestUtils.clearMetadata(); await Assert.rejects( PlacesUtils.metadata.get("test/integer"), /No data stored for key test\/integer/, "Should clear integer value" ); await Assert.rejects( PlacesUtils.metadata.get("test/double"), /No data stored for key test\/double/, "Should clear double value" ); }); add_task(async function test_metadata_canonical_keys() { await PlacesUtils.metadata.set("Test/Integer", 123); Assert.strictEqual( await PlacesUtils.metadata.get("tEsT/integer"), 123, "New keys should be case-insensitive" ); await PlacesUtils.metadata.set("test/integer", 456); Assert.strictEqual( await PlacesUtils.metadata.get("TEST/INTEGER"), 456, "Existing keys should be case-insensitive" ); await Assert.rejects( PlacesUtils.metadata.set("", 123), /Invalid metadata key/, "Should reject empty keys" ); await Assert.rejects( PlacesUtils.metadata.get(123), /Invalid metadata key/, "Should reject numeric keys" ); await Assert.rejects( PlacesUtils.metadata.delete(true), /Invalid metadata key/, "Should reject Boolean keys" ); await Assert.rejects( PlacesUtils.metadata.set({}), /Invalid metadata key/, "Should reject object keys" ); await Assert.rejects( PlacesUtils.metadata.get(null), /Invalid metadata key/, "Should reject null keys" ); await Assert.rejects( PlacesUtils.metadata.delete("!@#$"), /Invalid metadata key/, "Should reject keys with invalid characters" ); }); add_task(async function test_metadata_blobs() { let blob = new Uint8Array([1, 2, 3]); await PlacesUtils.metadata.set("test/blob", blob); let sameBlob = await PlacesUtils.metadata.get("test/blob"); Assert.equal( ChromeUtils.getClassName(sameBlob), "Uint8Array", "Should cache typed array for blob value" ); Assert.deepEqual(sameBlob, blob, "Should store new blob value"); info("Remove blob from cache"); await PlacesUtils.metadata.cache.clear(); let newBlob = await PlacesUtils.metadata.get("test/blob"); Assert.equal( ChromeUtils.getClassName(newBlob), "Uint8Array", "Should inflate blob into typed array" ); Assert.deepEqual( newBlob, blob, "Should return same blob after clearing cache" ); await PlacesTestUtils.clearMetadata(); }); add_task(async function test_metadata_arrays() { let array = [1, 2, 3, "\u2713 \u00E0 la mode"]; await PlacesUtils.metadata.set("test/array", array); let sameArray = await PlacesUtils.metadata.get("test/array"); Assert.ok(Array.isArray(sameArray), "Should cache array for array value"); Assert.deepEqual(sameArray, array, "Should store new array value"); info("Remove array from cache"); await PlacesUtils.metadata.cache.clear(); let newArray = await PlacesUtils.metadata.get("test/array"); Assert.ok(Array.isArray(newArray), "Should inflate into array"); Assert.deepEqual( newArray, array, "Should return same array after clearing cache" ); await PlacesTestUtils.clearMetadata(); }); add_task(async function test_metadata_objects() { let object = { foo: 123, bar: "test", meow: "\u2713 \u00E0 la mode" }; await PlacesUtils.metadata.set("test/object", object); let sameObject = await PlacesUtils.metadata.get("test/object"); Assert.equal( typeof sameObject, "object", "Should cache object for object value" ); Assert.deepEqual(sameObject, object, "Should store new object value"); info("Remove object from cache"); await PlacesUtils.metadata.cache.clear(); let newObject = await PlacesUtils.metadata.get("test/object"); Assert.equal(typeof newObject, "object", "Should inflate into object"); Assert.deepEqual( newObject, object, "Should return same object after clearing cache" ); await PlacesTestUtils.clearMetadata(); }); add_task(async function test_metadata_unparsable() { await PlacesUtils.withConnectionWrapper("test_medata", db => { let data = PlacesUtils.metadata._base64Encode("{hjjkhj}"); return db.execute(` INSERT INTO moz_meta (key, value) VALUES ("test/unparsable", "data:application/json;base64,${data}") `); }); await Assert.rejects( PlacesUtils.metadata.get("test/unparsable"), /SyntaxError: JSON.parse/, "Should reject for an unparsable value with no default" ); Assert.deepEqual( await PlacesUtils.metadata.get("test/unparsable", { foo: 1 }), { foo: 1 }, "Should return the default when encountering an unparsable value." ); await PlacesTestUtils.clearMetadata(); }); add_task(async function test_metadata_setMany() { await PlacesUtils.metadata.setMany( new Map([ ["test/string", "hi"], ["test/boolean", true], ]) ); await PlacesUtils.metadata.set("test/string", "hi"); Assert.deepEqual( await PlacesUtils.metadata.get("test/string"), "hi", "Should store new string value" ); Assert.deepEqual( await PlacesUtils.metadata.get("test/boolean"), true, "Should store new boolean value" ); await PlacesUtils.metadata.cache.clear(); Assert.equal( await PlacesUtils.metadata.get("test/string"), "hi", "Should return string value after clearing cache" ); Assert.deepEqual( await PlacesUtils.metadata.get("test/boolean"), true, "Should store new boolean value" ); await PlacesTestUtils.clearMetadata(); });