diff options
Diffstat (limited to 'dom/base/test/unit/test_structuredcloneholder.js')
-rw-r--r-- | dom/base/test/unit/test_structuredcloneholder.js | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/dom/base/test/unit/test_structuredcloneholder.js b/dom/base/test/unit/test_structuredcloneholder.js new file mode 100644 index 0000000000..4711a1b26b --- /dev/null +++ b/dom/base/test/unit/test_structuredcloneholder.js @@ -0,0 +1,159 @@ +"use strict"; + +const global = this; + +add_task(async function test_structuredCloneHolder() { + let principal = Services.scriptSecurityManager.createContentPrincipal( + Services.io.newURI("http://example.com/"), + {} + ); + + let sandbox = Cu.Sandbox(principal); + + const obj = { foo: [{ bar: "baz" }] }; + + let holder = new StructuredCloneHolder(obj); + + // Test same-compartment deserialization + + let res = holder.deserialize(global, true); + + notEqual( + res, + obj, + "Deserialized result is a different object from the original" + ); + + deepEqual( + res, + obj, + "Deserialized result is deeply equivalent to the original" + ); + + equal( + Cu.getObjectPrincipal(res), + Cu.getObjectPrincipal(global), + "Deserialized result has the correct principal" + ); + + // Test non-object-value round-trip. + + equal( + new StructuredCloneHolder("foo").deserialize(global), + "foo", + "Round-tripping non-object values works as expected" + ); + + // Test cross-compartment deserialization + + res = holder.deserialize(sandbox, true); + + notEqual( + res, + obj, + "Cross-compartment-deserialized result is a different object from the original" + ); + + deepEqual( + res, + obj, + "Cross-compartment-deserialized result is deeply equivalent to the original" + ); + + equal( + Cu.getObjectPrincipal(res), + principal, + "Cross-compartment-deserialized result has the correct principal" + ); + + // Test message manager transportability + + const MSG = "StructuredCloneHolder"; + + let resultPromise = new Promise(resolve => { + Services.ppmm.addMessageListener(MSG, resolve); + }); + + Services.cpmm.sendAsyncMessage(MSG, holder); + + res = await resultPromise; + + ok( + res.data instanceof StructuredCloneHolder, + "Sending structured clone holders through message managers works as expected" + ); + + deepEqual( + res.data.deserialize(global, true), + obj, + "Sending structured clone holders through message managers works as expected" + ); + + // Test that attempting to deserialize a neutered holder throws. + + deepEqual( + holder.deserialize(global), + obj, + "Deserialized result is correct when discarding data" + ); + + Assert.throws( + () => holder.deserialize(global), + err => err.result == Cr.NS_ERROR_NOT_INITIALIZED, + "Attempting to deserialize neutered holder throws" + ); + + Assert.throws( + () => holder.deserialize(global, true), + err => err.result == Cr.NS_ERROR_NOT_INITIALIZED, + "Attempting to deserialize neutered holder throws" + ); +}); + +// Test that X-rays passed to an exported function are serialized +// through their exported wrappers. +add_task(async function test_structuredCloneHolder_xray() { + let principal = Services.scriptSecurityManager.createContentPrincipal( + Services.io.newURI("http://example.com/"), + {} + ); + + let sandbox1 = Cu.Sandbox(principal, { wantXrays: true }); + + let sandbox2 = Cu.Sandbox(principal, { wantXrays: true }); + Cu.evalInSandbox(`this.x = {y: "z", get z() { return "q" }}`, sandbox2); + + sandbox1.x = sandbox2.x; + + let holder; + Cu.exportFunction( + function serialize(val) { + holder = new StructuredCloneHolder(val, sandbox1); + }, + sandbox1, + { defineAs: "serialize" } + ); + + Cu.evalInSandbox(`serialize(x)`, sandbox1); + + const obj = { y: "z" }; + + let res = holder.deserialize(global); + + deepEqual( + res, + obj, + "Deserialized result is deeply equivalent to the expected object" + ); + deepEqual( + res, + sandbox2.x, + "Deserialized result is deeply equivalent to the X-ray-wrapped object" + ); + + equal( + Cu.getObjectPrincipal(res), + Cu.getObjectPrincipal(global), + "Deserialized result has the correct principal" + ); +}); |