Skip to content

Commit

Permalink
Migrate staging tests for JSON-parse-with-source
Browse files Browse the repository at this point in the history
  • Loading branch information
ioannad committed Oct 15, 2024
1 parent df91072 commit 3e3e685
Show file tree
Hide file tree
Showing 8 changed files with 440 additions and 309 deletions.
42 changes: 42 additions & 0 deletions test/built-ins/JSON/isRawJSON/invoked-as-a-fn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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: >
JSON.isRawJSON can be invoked as a function
info: |
JSON.isRawJSON ( O )
1. If Type(O) is Object and O has an [[IsRawJSON]] internal slot, return true.
2. Return false.
includes: [deepEqual.js]
features: [json-parse-with-source]
---*/

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);
}

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"');


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' }));
220 changes: 220 additions & 0 deletions test/built-ins/JSON/parse/test-CreateJSONParseRecord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// 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-createjsonparserecord
description: Codepaths involving CreateJSONParseRecord behave as expected
includes: [deepEqual.js]
features: [json-parse-with-source]
---*/

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;
};
}

// Test NumericLiteral
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)));

// Test NullLiteral, BoolLiteral, StringLiteral
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"')));

// Test ObjectLiteral
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) } })
);

// Test ArrayLiteral
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) }])
);

// Test combinations of possible JSON input

{
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));
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// 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
esid: sec-internalizejsonproperty
description: Codepaths involving InternaliseJSONProperty behave as expected
includes: [deepEqual.js]
features: [json-parse-with-source]
---*/
Expand All @@ -11,7 +14,8 @@ const replacements = [42,
{foo:'bar'},
'foo'];

function TestArrayForwardModify(replacement) {
// Test Array forward modify
for (const replacement of replacements) {
let alreadyReplaced = false;
let expectedKeys = ['0','1',''];
// lol who designed reviver semantics
Expand All @@ -34,7 +38,8 @@ function TestArrayForwardModify(replacement) {
assert.deepEqual([1, replacement], o);
}

function TestObjectForwardModify(replacement) {
// Test Object forward modify
for (const replacement of replacements) {
let alreadyReplaced = false;
let expectedKeys = ['p','q',''];
if (typeof replacement === 'object') {
Expand All @@ -56,12 +61,9 @@ function TestObjectForwardModify(replacement) {
assert.deepEqual({p:1, q:replacement}, o);
}

for (const r of replacements) {
TestArrayForwardModify(r);
TestObjectForwardModify(r);
}

(function TestArrayAppend() {
// Test Array append
{
let log = [];
const o = JSON.parse('[1,[]]', function (k, v, { source }) {
log.push([k, v, source]);
Expand All @@ -71,24 +73,25 @@ for (const r of replacements) {
return this[k];
});
assert.deepEqual([['0', 1, '1'],
['0', 'barf', undefined],
['1', ['barf'], undefined],
['', [1, ['barf']], undefined]],
log);
})();
['0', 'barf', undefined],
['1', ['barf'], undefined],
['', [1, ['barf']], undefined]],
log);
}

(function TestObjectAddProperty() {
// Test Object add property
{
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];
return this[k];
});
assert.deepEqual([['p', 1, '1'],
['added', 'barf', undefined],
['q', {added:'barf'}, undefined],
['', {p:1, q:{added:'barf'}}, undefined]],
log);
})();
['added', 'barf', undefined],
['q', {added:'barf'}, undefined],
['', {p:1, q:{added:'barf'}}, undefined]],
log);
}
32 changes: 32 additions & 0 deletions test/built-ins/JSON/rawJSON/illegal-empty-and-start-end-chars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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: >
JSON.rawJSON can be invoked as a function
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('');
});
Loading

0 comments on commit 3e3e685

Please sign in to comment.