v8/test/mjsunit/harmony/json-parse-with-source.js
jameslahm e2f9097647 [json-parse-with-source] Implement the JSON.parse source text
... access proposal.

Bug: v8:12955
Change-Id: I339c4ee1849c67f85d7b975105a53a17d2b2360c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3911270
Commit-Queue: 王澳 <wangao.james@bytedance.com>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83586}
2022-10-10 07:33:07 +00:00

288 lines
8.6 KiB
JavaScript

// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-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);
assertEquals(tooBigForNumber, roundTripped);
const bigIntToRawJSON = (key, val) =>
typeof val === 'bigint' ? JSON.rawJSON(val) : val;
const embedded = JSON.stringify({ tooBigForNumber }, bigIntToRawJSON);
assertEquals('{"tooBigForNumber":9007199254740993}', embedded);
})();
function GenerateParseReviverFunction(texts) {
let i = 0;
return function (key, value, context) {
assertTrue(typeof context === 'object');
assertEquals(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');
assertTrue(descriptor.configurable);
assertTrue(descriptor.enumerable);
assertTrue(descriptor.writable);
assertEquals(undefined, descriptor.get);
assertEquals(undefined, descriptor.set);
assertEquals(texts[i++], descriptor.value);
assertEquals(['source'], Object.getOwnPropertyNames(context));
assertEquals([], Object.getOwnPropertySymbols(context));
} else {
// The json value is JSArray or JSObject, it's context has no property.
assertFalse(Object.hasOwn(context, 'source'));
assertEquals([], Object.getOwnPropertyNames(context));
assertEquals([], Object.getOwnPropertySymbols(context));
i++;
}
return value;
};
}
(function TestNumber() {
assertEquals(1, JSON.parse('1', GenerateParseReviverFunction(['1'])));
assertEquals(1.1, JSON.parse('1.1', GenerateParseReviverFunction(['1.1'])));
assertEquals(-1, JSON.parse('-1', GenerateParseReviverFunction(['-1'])));
assertEquals(
-1.1,
JSON.parse('-1.1', GenerateParseReviverFunction(['-1.1']))
);
assertEquals(
11,
JSON.parse('1.1e1', GenerateParseReviverFunction(['1.1e1']))
);
assertEquals(
11,
JSON.parse('1.1e+1', GenerateParseReviverFunction(['1.1e+1']))
);
assertEquals(
0.11,
JSON.parse('1.1e-1', GenerateParseReviverFunction(['1.1e-1']))
);
assertEquals(
11,
JSON.parse('1.1E1', GenerateParseReviverFunction(['1.1E1']))
);
assertEquals(
11,
JSON.parse('1.1E+1', GenerateParseReviverFunction(['1.1E+1']))
);
assertEquals(
0.11,
JSON.parse('1.1E-1', GenerateParseReviverFunction(['1.1E-1']))
);
assertEquals('1', JSON.stringify(JSON.rawJSON(1)));
assertEquals('1.1', JSON.stringify(JSON.rawJSON(1.1)));
assertEquals('-1', JSON.stringify(JSON.rawJSON(-1)));
assertEquals('-1.1', JSON.stringify(JSON.rawJSON(-1.1)));
assertEquals('11', JSON.stringify(JSON.rawJSON(1.1e1)));
assertEquals('0.11', JSON.stringify(JSON.rawJSON(1.1e-1)));
})();
(function TestBasic() {
assertEquals(
null,
JSON.parse('null', GenerateParseReviverFunction(['null']))
);
assertEquals(
true,
JSON.parse('true', GenerateParseReviverFunction(['true']))
);
assertEquals(
false,
JSON.parse('false', GenerateParseReviverFunction(['false']))
);
assertEquals(
'foo',
JSON.parse('"foo"', GenerateParseReviverFunction(['"foo"']))
);
assertEquals('null', JSON.stringify(JSON.rawJSON(null)));
assertEquals('true', JSON.stringify(JSON.rawJSON(true)));
assertEquals('false', JSON.stringify(JSON.rawJSON(false)));
assertEquals('"foo"', JSON.stringify(JSON.rawJSON('"foo"')));
})();
(function TestObject() {
assertEquals(
{},
JSON.parse('{}', GenerateParseReviverFunction([]))
);
assertEquals(
{ 42: 37 },
JSON.parse('{"42":37}', GenerateParseReviverFunction(['37']))
);
assertEquals(
{ 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.
assertEquals(
{ x: [1, 2], y: [2, 3] },
JSON.parse(
'{"x": [1,2], "y": [2,3]}',
GenerateParseReviverFunction(['1', '2', undefined, '2', '3', undefined])
)
);
assertEquals(
{ x: { x: 1, y: 2 } },
JSON.parse(
'{"x": {"x": 1, "y": 2}}',
GenerateParseReviverFunction(['1', '2', undefined, undefined])
)
);
assertEquals('{"42":37}', JSON.stringify({ 42: JSON.rawJSON(37) }));
assertEquals(
'{"x":1,"y":2}',
JSON.stringify({ x: JSON.rawJSON(1), y: JSON.rawJSON(2) })
);
assertEquals(
'{"x":{"x":1,"y":2}}',
JSON.stringify({ x: { x: JSON.rawJSON(1), y: JSON.rawJSON(2) } })
);
})();
(function TestArray() {
assertEquals([1], JSON.parse('[1.0]', GenerateParseReviverFunction(['1.0'])));
assertEquals(
[1.1],
JSON.parse('[1.1]', GenerateParseReviverFunction(['1.1']))
);
assertEquals([], JSON.parse('[]', GenerateParseReviverFunction([])));
assertEquals(
[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'])
)
);
assertEquals('[1,1.1]', JSON.stringify([JSON.rawJSON(1), JSON.rawJSON(1.1)]));
assertEquals(
'["1",true,null,false]',
JSON.stringify([
JSON.rawJSON('"1"'),
JSON.rawJSON(true),
JSON.rawJSON(null),
JSON.rawJSON(false),
])
);
assertEquals(
'[{"x":1,"y":1}]',
JSON.stringify([{ x: JSON.rawJSON(1), y: JSON.rawJSON(1) }])
);
})();
function assertIsRawJson(rawJson, expectedRawJsonValue) {
assertEquals(null, Object.getPrototypeOf(rawJson));
assertTrue(Object.hasOwn(rawJson, 'rawJSON'));
assertEquals(['rawJSON'], Object.getOwnPropertyNames(rawJson));
assertEquals([], Object.getOwnPropertySymbols(rawJson));
assertEquals(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"');
assertThrows(() => {
JSON.rawJSON(Symbol('123'));
}, TypeError);
assertThrows(() => {
JSON.rawJSON(undefined);
}, SyntaxError);
assertThrows(() => {
JSON.rawJSON({});
}, SyntaxError);
assertThrows(() => {
JSON.rawJSON([]);
}, SyntaxError);
const ILLEGAL_END_CHARS = ['\n', '\t', '\r', ' '];
for (const char of ILLEGAL_END_CHARS) {
assertThrows(() => {
JSON.rawJSON(`${char}123`);
}, SyntaxError);
assertThrows(() => {
JSON.rawJSON(`123${char}`);
}, SyntaxError);
}
assertThrows(() => {
JSON.rawJSON('');
}, SyntaxError);
const values = [1, 1.1, null, false, true, '123'];
for (const value of values) {
assertFalse(JSON.isRawJSON(value));
assertTrue(JSON.isRawJSON(JSON.rawJSON(value)));
}
assertFalse(JSON.isRawJSON(undefined));
assertFalse(JSON.isRawJSON(Symbol('123')));
assertFalse(JSON.isRawJSON([]));
assertFalse(JSON.isRawJSON({ rawJSON: '123' }));
})();
(function TestReviverModifyJsonValue() {
{
let reviverCallIndex = 0;
const expectedKeys = ['a', 'b', 'c', ''];
const reviver = function(key, value, {source}) {
assertEquals(expectedKeys[reviverCallIndex++], key);
if (key == 'a') {
this.b = 2;
assertEquals('0', source);
} else if (key == 'b') {
this.c = 3;
assertEquals(2, value);
assertEquals('1', source);
} else if (key == 'c') {
assertEquals(3, value);
assertEquals(undefined, source);
}
return value;
}
assertEquals({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}) {
assertEquals(expectedKeys[reviverCallIndex++], key);
if (key == '0') {
this[1] = 3;
assertEquals(1, value);
assertEquals('1', source);
} else if (key == '1') {
this[2] = 4;
assertEquals(3, value);
assertEquals('2', source);
} else if(key == '2') {
this[3] = 5;
assertEquals(4, value);
assertEquals('3', source);
} else if(key == '5'){
assertEquals(5, value);
assertEquals(undefined, source);
}
return value;
}
assertEquals([1, 3, 4, 5], JSON.parse('[1, 2, 3, {"a": 1}]', reviver));
}
})();