mirror of https://github.com/tc39/test262.git
Migrate staging tests for JSON-parse-with-source (#4265)
Co-authored-by: Philip Chimento <pchimento@igalia.com> Co-authored-by: Ms2ger <Ms2ger@igalia.com>
This commit is contained in:
parent
b2809feedf
commit
437f9a7631
|
@ -0,0 +1,25 @@
|
|||
// 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.israwjson
|
||||
description: Basic functionality of JSON.isRawJSON()
|
||||
info: |
|
||||
JSON.isRawJSON ( O )
|
||||
|
||||
1. If Type(O) is Object and O has an [[IsRawJSON]] internal slot, return true.
|
||||
2. Return false.
|
||||
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
const values = [1, 1.1, null, false, true, '123'];
|
||||
for (const value of values) {
|
||||
assert(!JSON.isRawJSON(value));
|
||||
assert(JSON.isRawJSON(JSON.rawJSON(value)));
|
||||
}
|
||||
assert(!JSON.isRawJSON(undefined));
|
||||
assert(!JSON.isRawJSON(Symbol('123')));
|
||||
assert(!JSON.isRawJSON([]));
|
||||
assert(!JSON.isRawJSON({}));
|
||||
assert(!JSON.isRawJSON({ rawJSON: '123' }));
|
|
@ -0,0 +1,47 @@
|
|||
// 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: >
|
||||
JSON.parse reviver is called with the correct arguments when the object is
|
||||
modified
|
||||
includes: [compareArray.js]
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
// Test Array append
|
||||
{
|
||||
let log = [];
|
||||
const o = JSON.parse('[1,[]]', function reviver(k, v, { source }) {
|
||||
log.push(`key: |${k}| value: ${JSON.stringify(v)} source: |${source}|`);
|
||||
if (v === 1) {
|
||||
this[1].push('barf');
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.compareArray(log, [
|
||||
'key: |0| value: 1 source: |1|',
|
||||
'key: |0| value: "barf" source: |undefined|',
|
||||
'key: |1| value: ["barf"] source: |undefined|',
|
||||
'key: || value: [1,["barf"]] source: |undefined|',
|
||||
]);
|
||||
}
|
||||
|
||||
// Test Object add property
|
||||
{
|
||||
let log = [];
|
||||
const o = JSON.parse('{"p":1,"q":{}}', function (k, v, { source }) {
|
||||
log.push(`key: |${k}| value: ${JSON.stringify(v)} source: |${source}|`);
|
||||
if (v === 1) {
|
||||
this.q.added = 'barf';
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.compareArray(log, [
|
||||
'key: |p| value: 1 source: |1|',
|
||||
'key: |added| value: "barf" source: |undefined|',
|
||||
'key: |q| value: {"added":"barf"} source: |undefined|',
|
||||
'key: || value: {"p":1,"q":{"added":"barf"}} source: |undefined|',
|
||||
]);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// 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: >
|
||||
Context argument and its source property behave as expected when parsing an
|
||||
ArrayLiteral JSON string
|
||||
includes: [compareArray.js, propertyHelper.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`);
|
||||
}
|
||||
|
||||
function reviverWithExpectedSources(expectedSources) {
|
||||
let i = 0;
|
||||
return function reviver(key, value, context) {
|
||||
assert.sameValue(typeof context, "object", "context should be an object");
|
||||
assert.sameValue(Object.getPrototypeOf(context), Object.prototype, "context should be a plain object");
|
||||
if (expectedSources[i] !== undefined) {
|
||||
assertOnlyOwnProperties(context, ["source"],
|
||||
"the JSON value is a primitve value, its context should only have a source property");
|
||||
verifyProperty(context, "source", {
|
||||
value: expectedSources[i++],
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
}, { restore: true });
|
||||
} else {
|
||||
assertOnlyOwnProperties(context, [],
|
||||
"the JSON value is an Array or Object, its context should have no property");
|
||||
i++;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
assert.compareArray(JSON.parse('[1.0]', reviverWithExpectedSources(['1.0'])), [1]);
|
||||
assert.compareArray(
|
||||
JSON.parse('[1.1]', reviverWithExpectedSources(['1.1'])),
|
||||
[1.1]
|
||||
);
|
||||
assert.compareArray(JSON.parse('[]', reviverWithExpectedSources([])), []);
|
||||
|
||||
const longArray = JSON.parse(
|
||||
'[1, "2", true, null, {"x": 1, "y": 1}]',
|
||||
reviverWithExpectedSources(['1', '"2"', 'true', 'null', '1', '1'])
|
||||
);
|
||||
assert.sameValue(longArray[0], 1, "array, element 0");
|
||||
assert.sameValue(longArray[1], "2", "array, element 1");
|
||||
assert.sameValue(longArray[2], true, "array, element 2");
|
||||
assert.sameValue(longArray[3], null, "array, element 3");
|
||||
assertOnlyOwnProperties(longArray[4], ["x", "y"], "array, element 5");
|
||||
assert.sameValue(longArray[4].x, 1, "array, element 5, prop x");
|
||||
assert.sameValue(longArray[4].y, 1, "array, element 5, prop y");
|
|
@ -0,0 +1,73 @@
|
|||
// 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: >
|
||||
Context argument and its source property behave as expected when parsing an
|
||||
ObjectLiteral JSON string
|
||||
includes: [compareArray.js, propertyHelper.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`);
|
||||
}
|
||||
|
||||
function reviverWithExpectedSources(expectedSources) {
|
||||
let i = 0;
|
||||
return function reviver(key, value, context) {
|
||||
assert.sameValue(typeof context, "object", "context should be an object");
|
||||
assert.sameValue(Object.getPrototypeOf(context), Object.prototype, "context should be a plain object");
|
||||
if (expectedSources[i] !== undefined) {
|
||||
assertOnlyOwnProperties(context, ["source"],
|
||||
"the JSON value is a primitve value, its context should only have a source property");
|
||||
verifyProperty(context, "source", {
|
||||
value: expectedSources[i++],
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
}, { restore: true });
|
||||
} else {
|
||||
assertOnlyOwnProperties(context, [],
|
||||
"the JSON value is an Array or Object, its context should have no property");
|
||||
i++;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
assertOnlyOwnProperties(
|
||||
JSON.parse('{}', reviverWithExpectedSources([])),
|
||||
[],
|
||||
"empty object"
|
||||
);
|
||||
|
||||
const singleProp = JSON.parse('{"42":37}', reviverWithExpectedSources(['37']));
|
||||
assertOnlyOwnProperties(singleProp, ["42"], "single numeric property key");
|
||||
assert.sameValue(singleProp[42], 37, "value of single numeric property key");
|
||||
|
||||
const multipleProps = JSON.parse('{"x": 1, "y": 2}', reviverWithExpectedSources(['1', '2']));
|
||||
assertOnlyOwnProperties(multipleProps, ["x", "y"], "multiple properties");
|
||||
assert.sameValue(multipleProps.x, 1, "multiple properties, value of x");
|
||||
assert.sameValue(multipleProps.y, 2, "multiple properties, value of y");
|
||||
|
||||
// undefined means the json value is JSObject or JSArray and the passed
|
||||
// context to the reviver function has no source property.
|
||||
const arrayProps = JSON.parse(
|
||||
'{"x": [1,2], "y": [2,3]}',
|
||||
reviverWithExpectedSources(['1', '2', undefined, '2', '3', undefined])
|
||||
);
|
||||
assertOnlyOwnProperties(arrayProps, ["x", "y"], "array-valued properties");
|
||||
assert.compareArray(arrayProps.x, [1, 2], "array-valued properties, value of x");
|
||||
assert.compareArray(arrayProps.y, [2, 3], "array-valued properties, value of y");
|
||||
|
||||
const objectProps = JSON.parse(
|
||||
'{"x": {"x": 1, "y": 2}}',
|
||||
reviverWithExpectedSources(['1', '2', undefined, undefined])
|
||||
);
|
||||
assertOnlyOwnProperties(objectProps, ["x"], "object-valued properties");
|
||||
assertOnlyOwnProperties(objectProps.x, ["x", "y"], "object-valued properties, value of x");
|
||||
assert.sameValue(objectProps.x.x, 1, "object-valued properties, value of x.x");
|
||||
assert.sameValue(objectProps.x.y, 2, "object-valued properties, value of x.y");
|
|
@ -0,0 +1,89 @@
|
|||
// 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: >
|
||||
Context argument and its source property behave as expected when parsing a
|
||||
NumericLiteral, NullLiteral, BoolLiteral, or StringLiteral JSON string
|
||||
includes: [compareArray.js, propertyHelper.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`);
|
||||
}
|
||||
|
||||
function reviverWithExpectedSources(expectedSources) {
|
||||
let i = 0;
|
||||
return function reviver(key, value, context) {
|
||||
assert.sameValue(typeof context, "object", "context should be an object");
|
||||
assert.sameValue(Object.getPrototypeOf(context), Object.prototype, "context should be a plain object");
|
||||
if (expectedSources[i] !== undefined) {
|
||||
assertOnlyOwnProperties(context, ["source"],
|
||||
"the JSON value is a primitve value, its context should only have a source property");
|
||||
verifyProperty(context, "source", {
|
||||
value: expectedSources[i++],
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
}, { restore: true });
|
||||
} else {
|
||||
assertOnlyOwnProperties(context, [],
|
||||
"the JSON value is an Array or Object, its context should have no property");
|
||||
i++;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
assert.sameValue(1, JSON.parse('1', reviverWithExpectedSources(['1'])));
|
||||
assert.sameValue(1.1, JSON.parse('1.1', reviverWithExpectedSources(['1.1'])));
|
||||
assert.sameValue(-1, JSON.parse('-1', reviverWithExpectedSources(['-1'])));
|
||||
assert.sameValue(
|
||||
-1.1,
|
||||
JSON.parse('-1.1', reviverWithExpectedSources(['-1.1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1e1', reviverWithExpectedSources(['1.1e1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1e+1', reviverWithExpectedSources(['1.1e+1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
0.11,
|
||||
JSON.parse('1.1e-1', reviverWithExpectedSources(['1.1e-1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1E1', reviverWithExpectedSources(['1.1E1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1E+1', reviverWithExpectedSources(['1.1E+1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
0.11,
|
||||
JSON.parse('1.1E-1', reviverWithExpectedSources(['1.1E-1']))
|
||||
);
|
||||
|
||||
// Test NullLiteral, BoolLiteral, StringLiteral
|
||||
assert.sameValue(
|
||||
JSON.parse('null', reviverWithExpectedSources(['null'])),
|
||||
null
|
||||
);
|
||||
assert.sameValue(
|
||||
JSON.parse('true', reviverWithExpectedSources(['true'])),
|
||||
true
|
||||
);
|
||||
assert.sameValue(
|
||||
JSON.parse('false', reviverWithExpectedSources(['false'])),
|
||||
false
|
||||
);
|
||||
assert.sameValue(
|
||||
JSON.parse('"foo"', reviverWithExpectedSources(['"foo"'])),
|
||||
"foo"
|
||||
);
|
|
@ -0,0 +1,129 @@
|
|||
// 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");
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 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.rawjson
|
||||
description: Basic functionality of JSON.rawJSON().
|
||||
info: |
|
||||
JSON.rawJSON ( text )
|
||||
|
||||
1. Let jsonString be ? ToString(text).
|
||||
...
|
||||
4. Let internalSlotsList be « [[IsRawJSON]] ».
|
||||
5. Let obj be OrdinaryObjectCreate(null, internalSlotsList).
|
||||
6. Perform ! CreateDataPropertyOrThrow(obj, "rawJSON", jsonString).
|
||||
7. Perform ! SetIntegrityLevel(obj, frozen).
|
||||
8. Return obj.
|
||||
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(1)), '1');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(1.1)), '1.1');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(-1)), '-1');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(-1.1)), '-1.1');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(1.1e1)), '11');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(1.1e-1)), '0.11');
|
||||
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(null)), 'null');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(true)), 'true');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON(false)), 'false');
|
||||
assert.sameValue(JSON.stringify(JSON.rawJSON('"foo"')), '"foo"');
|
||||
|
||||
assert.sameValue(JSON.stringify({ 42: JSON.rawJSON(37) }), '{"42":37}');
|
||||
assert.sameValue(
|
||||
JSON.stringify({ x: JSON.rawJSON(1), y: JSON.rawJSON(2) }),
|
||||
'{"x":1,"y":2}'
|
||||
);
|
||||
assert.sameValue(
|
||||
JSON.stringify({ x: { x: JSON.rawJSON(1), y: JSON.rawJSON(2) } }),
|
||||
'{"x":{"x":1,"y":2}}'
|
||||
);
|
||||
|
||||
assert.sameValue(JSON.stringify([JSON.rawJSON(1), JSON.rawJSON(1.1)]), '[1,1.1]');
|
||||
assert.sameValue(
|
||||
JSON.stringify([
|
||||
JSON.rawJSON('"1"'),
|
||||
JSON.rawJSON(true),
|
||||
JSON.rawJSON(null),
|
||||
JSON.rawJSON(false),
|
||||
]),
|
||||
'["1",true,null,false]'
|
||||
);
|
||||
assert.sameValue(
|
||||
JSON.stringify([{ x: JSON.rawJSON(1), y: JSON.rawJSON(1) }]),
|
||||
'[{"x":1,"y":1}]'
|
||||
);
|
|
@ -0,0 +1,30 @@
|
|||
// 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.rawjson
|
||||
description: BigInt rawJSON can be stringified.
|
||||
info: |
|
||||
JSON.rawJSON ( text )
|
||||
|
||||
1. Let jsonString be ? ToString(text).
|
||||
...
|
||||
4. Let internalSlotsList be « [[IsRawJSON]] ».
|
||||
5. Let obj be OrdinaryObjectCreate(null, internalSlotsList).
|
||||
6. Perform ! CreateDataPropertyOrThrow(obj, "rawJSON", jsonString).
|
||||
7. Perform ! SetIntegrityLevel(obj, frozen).
|
||||
8. Return obj.
|
||||
|
||||
features: [BigInt, json-parse-with-source]
|
||||
---*/
|
||||
|
||||
const tooBigForNumber = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
|
||||
const intToBigInt = (key, val, { source }) =>
|
||||
typeof val === 'number' && val % 1 === 0 ? BigInt(source) : val;
|
||||
const roundTripped = JSON.parse(String(tooBigForNumber), intToBigInt);
|
||||
assert.sameValue(roundTripped, tooBigForNumber);
|
||||
|
||||
const bigIntToRawJSON = (key, val) =>
|
||||
typeof val === 'bigint' ? JSON.rawJSON(val) : val;
|
||||
const embedded = JSON.stringify({ tooBigForNumber }, bigIntToRawJSON);
|
||||
assert.sameValue(embedded, '{"tooBigForNumber":9007199254740993}');
|
|
@ -0,0 +1,31 @@
|
|||
// 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.rawjson
|
||||
description: Throw SyntaxError on empty string, or illegal start/end chars
|
||||
info: |
|
||||
JSON.rawJSON ( text )
|
||||
|
||||
1. Let jsonString be ? ToString(text).
|
||||
2. Throw a SyntaxError exception if jsonString is the empty String, or if
|
||||
either the first or last code unit of jsonString is any of 0x0009
|
||||
(CHARACTER TABULATION), 0x000A (LINE FEED), 0x000D (CARRIAGE RETURN), or
|
||||
0x0020 (SPACE).
|
||||
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
const ILLEGAL_END_CHARS = ['\n', '\t', '\r', ' '];
|
||||
for (const char of ILLEGAL_END_CHARS) {
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(`${char}123`);
|
||||
});
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(`123${char}`);
|
||||
});
|
||||
}
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON('');
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
// 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.rawjson
|
||||
description: >
|
||||
Inputs not convertible to string, or convertible to invalid JSON string
|
||||
info: |
|
||||
JSON.rawJSON ( text )
|
||||
|
||||
1. Let jsonString be ? ToString(text).
|
||||
...
|
||||
3. Parse StringToCodePoints(jsonString) as a JSON text as specified in
|
||||
ECMA-404. Throw a SyntaxError exception if it is not a valid JSON text as
|
||||
defined in that specification, or if its outermost value is an object or
|
||||
array as defined in that specification.
|
||||
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
assert.throws(TypeError, () => {
|
||||
JSON.rawJSON(Symbol('123'));
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(undefined);
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON({});
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON([]);
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
// 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.rawjson
|
||||
description: Object returned from JSON.rawJSON() is the expected shape.
|
||||
info: |
|
||||
JSON.rawJSON ( text )
|
||||
|
||||
5. Let _obj_ be OrdinaryObjectCreate(*null*, _internalSlotsList_).
|
||||
6. Perform ! CreateDataPropertyOrThrow(_obj_, *"rawJSON"*, _jsonString_).
|
||||
...
|
||||
8. Return _obj_.
|
||||
|
||||
includes: [compareArray.js]
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
function assertIsRawJSON(rawJSON, expectedRawJSONValue) {
|
||||
assert.sameValue(Object.getPrototypeOf(rawJSON), null, "RawJSON object should have null prototype");
|
||||
assert(Object.hasOwn(rawJSON, "rawJSON"), "RawJSON object should have rawJSON own property");
|
||||
assert.compareArray(Object.getOwnPropertyNames(rawJSON), ["rawJSON"], "RawJSON object should have only rawJSON own property");
|
||||
assert.compareArray(Object.getOwnPropertySymbols(rawJSON), [], "RawJSON object should have no own property symbols");
|
||||
assert.sameValue(rawJSON.rawJSON, expectedRawJSONValue, "rawJSON value");
|
||||
}
|
||||
|
||||
assertIsRawJSON(JSON.rawJSON(1), "1");
|
||||
assertIsRawJSON(JSON.rawJSON(null), "null");
|
||||
assertIsRawJSON(JSON.rawJSON(true), "true");
|
||||
assertIsRawJSON(JSON.rawJSON(false), "false");
|
||||
assertIsRawJSON(JSON.rawJSON('"foo"'), '"foo"');
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (C) 2023 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
description: V8 mjsunit test for JSON.parse with source snapshotting
|
||||
includes: [deepEqual.js]
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
const replacements = [42,
|
||||
['foo'],
|
||||
{foo:'bar'},
|
||||
'foo'];
|
||||
|
||||
function TestArrayForwardModify(replacement) {
|
||||
let alreadyReplaced = false;
|
||||
let expectedKeys = ['0','1',''];
|
||||
// lol who designed reviver semantics
|
||||
if (typeof replacement === 'object') {
|
||||
expectedKeys.splice(1, 0, ...Object.keys(replacement));
|
||||
}
|
||||
const o = JSON.parse('[1, 2]', function (k, v, { source }) {
|
||||
assert.sameValue(expectedKeys.shift(), k);
|
||||
if (k === '0') {
|
||||
if (!alreadyReplaced) {
|
||||
this[1] = replacement;
|
||||
alreadyReplaced = true;
|
||||
}
|
||||
} else if (k !== '') {
|
||||
assert.sameValue(undefined, source);
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.sameValue(0, expectedKeys.length);
|
||||
assert.deepEqual([1, replacement], o);
|
||||
}
|
||||
|
||||
function TestObjectForwardModify(replacement) {
|
||||
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(expectedKeys.shift(), k);
|
||||
if (k === 'p') {
|
||||
if (!alreadyReplaced) {
|
||||
this.q = replacement;
|
||||
alreadyReplaced = true;
|
||||
}
|
||||
} else if (k !== '') {
|
||||
assert.sameValue(undefined, source);
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.sameValue(0, expectedKeys.length);
|
||||
assert.deepEqual({p:1, q:replacement}, o);
|
||||
}
|
||||
|
||||
for (const r of replacements) {
|
||||
TestArrayForwardModify(r);
|
||||
TestObjectForwardModify(r);
|
||||
}
|
||||
|
||||
(function TestArrayAppend() {
|
||||
let log = [];
|
||||
const o = JSON.parse('[1,[]]', function (k, v, { source }) {
|
||||
log.push([k, v, source]);
|
||||
if (v === 1) {
|
||||
this[1].push('barf');
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.deepEqual([['0', 1, '1'],
|
||||
['0', 'barf', undefined],
|
||||
['1', ['barf'], undefined],
|
||||
['', [1, ['barf']], undefined]],
|
||||
log);
|
||||
})();
|
||||
|
||||
(function TestObjectAddProperty() {
|
||||
let log = [];
|
||||
const o = JSON.parse('{"p":1,"q":{}}', function (k, v, { source }) {
|
||||
log.push([k, v, source]);
|
||||
if (v === 1) {
|
||||
this.q.added = 'barf';
|
||||
}
|
||||
return this[k];
|
||||
});
|
||||
assert.deepEqual([['p', 1, '1'],
|
||||
['added', 'barf', undefined],
|
||||
['q', {added:'barf'}, undefined],
|
||||
['', {p:1, q:{added:'barf'}}, undefined]],
|
||||
log);
|
||||
})();
|
|
@ -1,289 +0,0 @@
|
|||
// Copyright (C) 2023 the V8 project authors. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
description: V8 mjsunit test for JSON.parse with source
|
||||
includes: [deepEqual.js]
|
||||
features: [json-parse-with-source]
|
||||
---*/
|
||||
|
||||
(function TestBigInt() {
|
||||
const tooBigForNumber = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
|
||||
const intToBigInt = (key, val, { source }) =>
|
||||
typeof val === 'number' && val % 1 === 0 ? BigInt(source) : val;
|
||||
const roundTripped = JSON.parse(String(tooBigForNumber), intToBigInt);
|
||||
assert.sameValue(tooBigForNumber, roundTripped);
|
||||
|
||||
const bigIntToRawJSON = (key, val) =>
|
||||
typeof val === 'bigint' ? JSON.rawJSON(val) : val;
|
||||
const embedded = JSON.stringify({ tooBigForNumber }, bigIntToRawJSON);
|
||||
assert.sameValue('{"tooBigForNumber":9007199254740993}', embedded);
|
||||
})();
|
||||
|
||||
function GenerateParseReviverFunction(texts) {
|
||||
let i = 0;
|
||||
return function (key, value, context) {
|
||||
assert(typeof context === 'object');
|
||||
assert.sameValue(Object.prototype, Object.getPrototypeOf(context));
|
||||
// The json value is a primitive value, it's context only has a source property.
|
||||
if (texts[i] !== undefined) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(context, 'source');
|
||||
assert(descriptor.configurable);
|
||||
assert(descriptor.enumerable);
|
||||
assert(descriptor.writable);
|
||||
assert.sameValue(undefined, descriptor.get);
|
||||
assert.sameValue(undefined, descriptor.set);
|
||||
assert.sameValue(texts[i++], descriptor.value);
|
||||
|
||||
assert.deepEqual(['source'], Object.getOwnPropertyNames(context));
|
||||
assert.deepEqual([], Object.getOwnPropertySymbols(context));
|
||||
} else {
|
||||
// The json value is JSArray or JSObject, it's context has no property.
|
||||
assert(!Object.hasOwn(context, 'source'));
|
||||
assert.deepEqual([], Object.getOwnPropertyNames(context));
|
||||
assert.deepEqual([], Object.getOwnPropertySymbols(context));
|
||||
i++;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
(function TestNumber() {
|
||||
assert.sameValue(1, JSON.parse('1', GenerateParseReviverFunction(['1'])));
|
||||
assert.sameValue(1.1, JSON.parse('1.1', GenerateParseReviverFunction(['1.1'])));
|
||||
assert.sameValue(-1, JSON.parse('-1', GenerateParseReviverFunction(['-1'])));
|
||||
assert.sameValue(
|
||||
-1.1,
|
||||
JSON.parse('-1.1', GenerateParseReviverFunction(['-1.1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1e1', GenerateParseReviverFunction(['1.1e1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1e+1', GenerateParseReviverFunction(['1.1e+1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
0.11,
|
||||
JSON.parse('1.1e-1', GenerateParseReviverFunction(['1.1e-1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1E1', GenerateParseReviverFunction(['1.1E1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
11,
|
||||
JSON.parse('1.1E+1', GenerateParseReviverFunction(['1.1E+1']))
|
||||
);
|
||||
assert.sameValue(
|
||||
0.11,
|
||||
JSON.parse('1.1E-1', GenerateParseReviverFunction(['1.1E-1']))
|
||||
);
|
||||
|
||||
assert.sameValue('1', JSON.stringify(JSON.rawJSON(1)));
|
||||
assert.sameValue('1.1', JSON.stringify(JSON.rawJSON(1.1)));
|
||||
assert.sameValue('-1', JSON.stringify(JSON.rawJSON(-1)));
|
||||
assert.sameValue('-1.1', JSON.stringify(JSON.rawJSON(-1.1)));
|
||||
assert.sameValue('11', JSON.stringify(JSON.rawJSON(1.1e1)));
|
||||
assert.sameValue('0.11', JSON.stringify(JSON.rawJSON(1.1e-1)));
|
||||
})();
|
||||
|
||||
(function TestBasic() {
|
||||
assert.sameValue(
|
||||
null,
|
||||
JSON.parse('null', GenerateParseReviverFunction(['null']))
|
||||
);
|
||||
assert.sameValue(
|
||||
true,
|
||||
JSON.parse('true', GenerateParseReviverFunction(['true']))
|
||||
);
|
||||
assert.sameValue(
|
||||
false,
|
||||
JSON.parse('false', GenerateParseReviverFunction(['false']))
|
||||
);
|
||||
assert.sameValue(
|
||||
'foo',
|
||||
JSON.parse('"foo"', GenerateParseReviverFunction(['"foo"']))
|
||||
);
|
||||
|
||||
assert.sameValue('null', JSON.stringify(JSON.rawJSON(null)));
|
||||
assert.sameValue('true', JSON.stringify(JSON.rawJSON(true)));
|
||||
assert.sameValue('false', JSON.stringify(JSON.rawJSON(false)));
|
||||
assert.sameValue('"foo"', JSON.stringify(JSON.rawJSON('"foo"')));
|
||||
})();
|
||||
|
||||
(function TestObject() {
|
||||
assert.deepEqual(
|
||||
{},
|
||||
JSON.parse('{}', GenerateParseReviverFunction([]))
|
||||
);
|
||||
assert.deepEqual(
|
||||
{ 42: 37 },
|
||||
JSON.parse('{"42":37}', GenerateParseReviverFunction(['37']))
|
||||
);
|
||||
assert.deepEqual(
|
||||
{ x: 1, y: 2 },
|
||||
JSON.parse('{"x": 1, "y": 2}', GenerateParseReviverFunction(['1', '2']))
|
||||
);
|
||||
// undefined means the json value is JSObject or JSArray and the passed
|
||||
// context to the reviver function has no source property.
|
||||
assert.deepEqual(
|
||||
{ x: [1, 2], y: [2, 3] },
|
||||
JSON.parse(
|
||||
'{"x": [1,2], "y": [2,3]}',
|
||||
GenerateParseReviverFunction(['1', '2', undefined, '2', '3', undefined])
|
||||
)
|
||||
);
|
||||
assert.deepEqual(
|
||||
{ x: { x: 1, y: 2 } },
|
||||
JSON.parse(
|
||||
'{"x": {"x": 1, "y": 2}}',
|
||||
GenerateParseReviverFunction(['1', '2', undefined, undefined])
|
||||
)
|
||||
);
|
||||
|
||||
assert.sameValue('{"42":37}', JSON.stringify({ 42: JSON.rawJSON(37) }));
|
||||
assert.sameValue(
|
||||
'{"x":1,"y":2}',
|
||||
JSON.stringify({ x: JSON.rawJSON(1), y: JSON.rawJSON(2) })
|
||||
);
|
||||
assert.sameValue(
|
||||
'{"x":{"x":1,"y":2}}',
|
||||
JSON.stringify({ x: { x: JSON.rawJSON(1), y: JSON.rawJSON(2) } })
|
||||
);
|
||||
})();
|
||||
|
||||
(function TestArray() {
|
||||
assert.deepEqual([1], JSON.parse('[1.0]', GenerateParseReviverFunction(['1.0'])));
|
||||
assert.deepEqual(
|
||||
[1.1],
|
||||
JSON.parse('[1.1]', GenerateParseReviverFunction(['1.1']))
|
||||
);
|
||||
assert.deepEqual([], JSON.parse('[]', GenerateParseReviverFunction([])));
|
||||
assert.deepEqual(
|
||||
[1, '2', true, null, { x: 1, y: 1 }],
|
||||
JSON.parse(
|
||||
'[1, "2", true, null, {"x": 1, "y": 1}]',
|
||||
GenerateParseReviverFunction(['1', '"2"', 'true', 'null', '1', '1'])
|
||||
)
|
||||
);
|
||||
|
||||
assert.sameValue('[1,1.1]', JSON.stringify([JSON.rawJSON(1), JSON.rawJSON(1.1)]));
|
||||
assert.sameValue(
|
||||
'["1",true,null,false]',
|
||||
JSON.stringify([
|
||||
JSON.rawJSON('"1"'),
|
||||
JSON.rawJSON(true),
|
||||
JSON.rawJSON(null),
|
||||
JSON.rawJSON(false),
|
||||
])
|
||||
);
|
||||
assert.sameValue(
|
||||
'[{"x":1,"y":1}]',
|
||||
JSON.stringify([{ x: JSON.rawJSON(1), y: JSON.rawJSON(1) }])
|
||||
);
|
||||
})();
|
||||
|
||||
function assertIsRawJson(rawJson, expectedRawJsonValue) {
|
||||
assert.sameValue(null, Object.getPrototypeOf(rawJson));
|
||||
assert(Object.hasOwn(rawJson, 'rawJSON'));
|
||||
assert.deepEqual(['rawJSON'], Object.getOwnPropertyNames(rawJson));
|
||||
assert.deepEqual([], Object.getOwnPropertySymbols(rawJson));
|
||||
assert.sameValue(expectedRawJsonValue, rawJson.rawJSON);
|
||||
}
|
||||
|
||||
(function TestRawJson() {
|
||||
assertIsRawJson(JSON.rawJSON(1), '1');
|
||||
assertIsRawJson(JSON.rawJSON(null), 'null');
|
||||
assertIsRawJson(JSON.rawJSON(true), 'true');
|
||||
assertIsRawJson(JSON.rawJSON(false), 'false');
|
||||
assertIsRawJson(JSON.rawJSON('"foo"'), '"foo"');
|
||||
|
||||
assert.throws(TypeError, () => {
|
||||
JSON.rawJSON(Symbol('123'));
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(undefined);
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON({});
|
||||
});
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON([]);
|
||||
});
|
||||
|
||||
const ILLEGAL_END_CHARS = ['\n', '\t', '\r', ' '];
|
||||
for (const char of ILLEGAL_END_CHARS) {
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(`${char}123`);
|
||||
});
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON(`123${char}`);
|
||||
});
|
||||
}
|
||||
|
||||
assert.throws(SyntaxError, () => {
|
||||
JSON.rawJSON('');
|
||||
});
|
||||
|
||||
const values = [1, 1.1, null, false, true, '123'];
|
||||
for (const value of values) {
|
||||
assert(!JSON.isRawJSON(value));
|
||||
assert(JSON.isRawJSON(JSON.rawJSON(value)));
|
||||
}
|
||||
assert(!JSON.isRawJSON(undefined));
|
||||
assert(!JSON.isRawJSON(Symbol('123')));
|
||||
assert(!JSON.isRawJSON([]));
|
||||
assert(!JSON.isRawJSON({ rawJSON: '123' }));
|
||||
})();
|
||||
|
||||
(function TestReviverModifyJsonValue() {
|
||||
{
|
||||
let reviverCallIndex = 0;
|
||||
const expectedKeys = ['a', 'b', 'c', ''];
|
||||
const reviver = function(key, value, {source}) {
|
||||
assert.sameValue(expectedKeys[reviverCallIndex++], key);
|
||||
if (key == 'a') {
|
||||
this.b = 2;
|
||||
assert.sameValue('0', source);
|
||||
} else if (key == 'b') {
|
||||
this.c = 3;
|
||||
assert.sameValue(2, value);
|
||||
assert.sameValue(undefined, source);
|
||||
} else if (key == 'c') {
|
||||
assert.sameValue(3, value);
|
||||
assert.sameValue(undefined, source);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
assert.deepEqual({a: 0, b: 2, c: 3}, JSON.parse('{"a": 0, "b": 1, "c": [1, 2]}', reviver));
|
||||
}
|
||||
{
|
||||
let reviverCallIndex = 0;
|
||||
const expectedKeys = ['0', '1', '2', '3', ''];
|
||||
const reviver = function(key, value, {source}) {
|
||||
assert.sameValue(expectedKeys[reviverCallIndex++], key);
|
||||
if (key == '0') {
|
||||
this[1] = 3;
|
||||
assert.sameValue(1, value);
|
||||
assert.sameValue('1', source);
|
||||
} else if (key == '1') {
|
||||
this[2] = 4;
|
||||
assert.sameValue(3, value);
|
||||
assert.sameValue(undefined, source);
|
||||
} else if(key == '2') {
|
||||
this[3] = 5;
|
||||
assert.sameValue(4, value);
|
||||
assert.sameValue(undefined, source);
|
||||
} else if(key == '5'){
|
||||
assert.sameValue(5, value);
|
||||
assert.sameValue(undefined, source);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
assert.deepEqual([1, 3, 4, 5], JSON.parse('[1, 2, 3, {"a": 1}]', reviver));
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue