Source code

Revision control

Copy as Markdown

Other Tools

// |reftest| shell-option(--enable-json-parse-with-source) skip-if(!JSON.hasOwnProperty('isRawJSON')||!xulRuntime.shell) -- json-parse-with-source is not enabled unconditionally, requires shell-options
// Copyright (C) 2023 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-json.parse
description: Codepaths involving InternaliseJSONProperty behave as expected
includes: [compareArray.js]
features: [json-parse-with-source]
---*/
function assertOnlyOwnProperties(object, props, message) {
assert.compareArray(Object.getOwnPropertyNames(object), props, `${message}: object should have no other properties than expected`);
assert.compareArray(Object.getOwnPropertySymbols(object), [], `${message}: object should have no own symbol properties`);
}
const replacements = [
42,
["foo"],
{ foo: "bar" },
"foo"
];
// Test Array forward modify
for (const replacement of replacements) {
let alreadyReplaced = false;
let expectedKeys = ["0", "1", ""];
// if the replacement is an object, add its keys to the expected keys
if (typeof replacement === "object") {
expectedKeys.splice(1, 0, ...Object.keys(replacement));
}
const o = JSON.parse("[1, 2]", function (k, v, { source }) {
assert.sameValue(k, expectedKeys.shift());
if (k === "0") {
if (!alreadyReplaced) {
this[1] = replacement;
alreadyReplaced = true;
}
} else if (k !== "") {
assert.sameValue(source, undefined);
}
return this[k];
});
assert.sameValue(expectedKeys.length, 0);
assert.compareArray(o, [1, replacement], `array forward-modified with ${replacement}`);
}
function assertOnlyOwnProperties(object, props, message) {
assert.compareArray(Object.getOwnPropertyNames(object), props, `${message}: object should have no other properties than expected`);
assert.compareArray(Object.getOwnPropertySymbols(object), [], `${message}: object should have no own symbol properties`);
}
// Test Object forward modify
for (const replacement of replacements) {
let alreadyReplaced = false;
let expectedKeys = ["p", "q", ""];
if (typeof replacement === "object") {
expectedKeys.splice(1, 0, ...Object.keys(replacement));
}
const o = JSON.parse('{"p":1, "q":2}', function (k, v, { source }) {
assert.sameValue(k, expectedKeys.shift());
if (k === 'p') {
if (!alreadyReplaced) {
this.q = replacement;
alreadyReplaced = true;
}
} else if (k !== "") {
assert.sameValue(source, undefined);
}
return this[k];
});
assert.sameValue(expectedKeys.length, 0);
assertOnlyOwnProperties(o, ["p", "q"], `object forward-modified with ${replacement}`);
assert.sameValue(o.p, 1, "property p should not be replaced");
assert.sameValue(o.q, replacement, `property q should be replaced with ${replacement}`);
}
// Test combinations of possible JSON input with multiple forward modifications
{
let reviverCallIndex = 0;
const expectedKeys = ["a", "b", "c", ""];
const reviver = function(key, value, {source}) {
assert.sameValue(key, expectedKeys[reviverCallIndex++]);
if (key === "a") {
this.b = 2;
assert.sameValue(source, "0");
} else if (key === "b") {
this.c = 3;
assert.sameValue(value, 2);
assert.sameValue(source, undefined);
} else if (key === "c") {
assert.sameValue(value, 3);
assert.sameValue(source, undefined);
}
return value;
}
const parsed = JSON.parse('{"a": 0, "b": 1, "c": [1, 2]}', reviver);
assertOnlyOwnProperties(parsed, ["a", "b", "c"], "object with forward-modified properties");
assert.sameValue(parsed.a, 0, "'a' property should be unmodified");
assert.sameValue(parsed.b, 2, "'b' property should be modified to 2");
assert.sameValue(parsed.c, 3, "'c' property should be modified to 3");
}
{
let reviverCallIndex = 0;
const expectedKeys = ["0", "1", "2", "3", ""];
const reviver = function(key, value, {source}) {
assert.sameValue(key, expectedKeys[reviverCallIndex++]);
if (key === "0") {
this[1] = 3;
assert.sameValue(value, 1);
assert.sameValue(source, "1");
} else if (key === "1") {
this[2] = 4;
assert.sameValue(value, 3);
assert.sameValue(source, undefined);
} else if(key === "2") {
this[3] = 5;
assert.sameValue(value, 4);
assert.sameValue(source, undefined);
} else if(key === "5") {
assert.sameValue(value, 5);
assert.sameValue(source, undefined);
}
return value;
}
assert.compareArray(JSON.parse('[1, 2, 3, {"a": 1}]', reviver), [1, 3, 4, 5], "array with forward-modified elements");
}
reportCompare(0, 0);