Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: dom/localstorage/test/unit/xpcshell.toml
/**
* Any copyright is dedicated to the Public Domain.
*/
const interpretChar = (chars, index) => {
return chars.charCodeAt(index).toString(16).padStart(4, "0");
};
const hexEncode = str => {
let result = "";
const len = str.length;
for (let i = 0; i < len; ++i) {
result += interpretChar(str, i);
}
return result;
};
const collectCorrupted = (expected, actual) => {
const len = Math.min(expected.length, actual.length);
let notEquals = [];
for (let i = 0; i < len; ++i) {
if (expected[i] !== actual[i]) {
notEquals.push([hexEncode(expected[i]), hexEncode(actual[i])]);
}
}
return notEquals;
};
const sanitizeOutputWithSurrogates = (testValue, prefix = "") => {
let utf8What = prefix;
for (let i = 0; i < testValue.length; ++i) {
const valueChar = testValue.charCodeAt(i);
const isPlanar = 0xd800 <= valueChar && valueChar <= 0xdfff;
utf8What += isPlanar ? "\\u" + interpretChar(testValue, i) : testValue[i];
}
return utf8What;
};
const getEncodingSample = () => {
const expectedSample =
"3681207208613504e0a5028800b945551988c60050008027ebc2808c00d38e806e03d8210ac906722b85499be9d00000";
let result = "";
const len = expectedSample.length;
for (let i = 0; i < len; i += 4) {
result += String.fromCharCode(parseInt(expectedSample.slice(i, i + 4), 16));
}
return result;
};
const getSeparatedBasePlane = () => {
let result = "";
for (let i = 0xffff; i >= 0; --i) {
result += String.fromCharCode(i) + "\n";
}
return result;
};
const getJoinedBasePlane = () => {
let result = "";
for (let i = 0; i <= 0xffff; ++i) {
result += String.fromCharCode(i);
}
return result;
};
const getSurrogateCombinations = () => {
const upperLead = String.fromCharCode(0xdbff);
const lowerTrail = String.fromCharCode(0xdc00);
const regularSlot = ["w", "abcdefghijklmnopqrst", "aaaaaaaaaaaaaaaaaaaa", ""];
const surrogateSlot = [lowerTrail, upperLead];
let samples = [];
for (const leadSnippet of regularSlot) {
for (const firstSlot of surrogateSlot) {
for (const trailSnippet of regularSlot) {
for (const secondSlot of surrogateSlot) {
samples.push(leadSnippet + firstSlot + secondSlot + trailSnippet);
}
samples.push(leadSnippet + firstSlot + trailSnippet);
}
}
}
return samples;
};
const fetchFrom = async (itemKey, sample, meanwhile) => {
let request = clearOrigin(principal);
await requestFinished(request);
const storage = getLocalStorage(principal);
await storage.setItem(itemKey, sample);
await meanwhile(principal);
return storage.getItem(itemKey);
};
/**
* Value fetched from existing snapshot based on
* existing in-memory datastore in the parent process
* without any communication between content/parent
*/
const fetchFromExistingSnapshotExistingDatastore = async (itemKey, sample) => {
return fetchFrom(itemKey, sample, async () => {});
};
/**
* Value fetched from newly created snapshot based on
* existing in-memory datastore in the parent process
*/
const fetchFromNewSnapshotExistingDatastore = async (itemKey, sample) => {
return fetchFrom(itemKey, sample, async () => {
await returnToEventLoop();
});
};
/**
* Value fetched from newly created snapshot based on newly created
* in-memory datastore based on database in the parent process
*/
const fetchFromNewSnapshotNewDatastore = async (itemKey, sample) => {
return fetchFrom(itemKey, sample, async principal => {
let request = resetClient(principal);
await requestFinished(request);
});
};
add_task(async function testSteps() {
Services.prefs.setBoolPref(
"dom.storage.enable_unsupported_legacy_implementation",
false
);
Services.prefs.setBoolPref("dom.storage.snapshot_reusing", false);
const reportWhat = (testKey, testValue) => {
if (testKey.length + testValue.length > 82) {
return testKey;
}
return sanitizeOutputWithSurrogates(testValue, /* prefix */ testKey + ":");
};
const testFetchMode = async (testType, storeAndLookup) => {
const testPairs = [
{ testEmptyValue: [""] },
{ testSampleKey: [getEncodingSample()] },
{ testSeparatedKey: [getSeparatedBasePlane()] },
{ testJoinedKey: [getJoinedBasePlane()] },
{ testCombinations: getSurrogateCombinations() },
];
for (const testPair of testPairs) {
for (const [testKey, expectedValues] of Object.entries(testPair)) {
for (const expected of expectedValues) {
const actual = await storeAndLookup(testKey, expected);
const testInfo = reportWhat(testKey, expected);
is(
null != actual,
true,
testType + ": Value not null for " + testInfo
);
is(
expected.length,
actual.length,
testType + ": Returned size for " + testInfo
);
const notEquals = collectCorrupted(expected, actual);
for (let i = 0; i < notEquals.length; ++i) {
is(
notEquals[i][0],
notEquals[i][1],
testType + ": Unequal character at " + i + " for " + testInfo
);
}
}
}
}
};
await testFetchMode(
"ExistingSnapshotExistingDatastore",
fetchFromExistingSnapshotExistingDatastore
);
await testFetchMode(
"NewSnapshotExistingDatastore",
fetchFromNewSnapshotExistingDatastore
);
await testFetchMode(
"NewSnapshotNewDatastore",
fetchFromNewSnapshotNewDatastore
);
});