mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
12 years ago
11 changed files with 406 additions and 49 deletions
@ -0,0 +1,40 @@ |
|||
/*=== |
|||
codepoint test (no output) |
|||
===*/ |
|||
|
|||
/* Test that all codepoint escapes can be parsed. */ |
|||
|
|||
function codepointTest() { |
|||
var i; |
|||
var str; |
|||
var t; |
|||
var nybbles = "0123456789abcdef"; |
|||
|
|||
for (i = 0; i < 65536; i++) { |
|||
str = '"\\u' + |
|||
nybbles.charAt((i >> 12) & 0x0f) + |
|||
nybbles.charAt((i >> 8) & 0x0f) + |
|||
nybbles.charAt((i >> 4) & 0x0f) + |
|||
nybbles.charAt((i >> 0) & 0x0f) + |
|||
'"'; |
|||
t = JSON.parse(str); |
|||
if (typeof t !== 'string') { |
|||
throw new Error('result not string, codepoint: ' + i); |
|||
} |
|||
if (t.length !== 1) { |
|||
throw new Error('result string length not 1, codepoint: ' + i); |
|||
} |
|||
if (t.charCodeAt(0) !== i) { |
|||
throw new Error('result codepoint incorrect, codepoint: ' + i); |
|||
} |
|||
} |
|||
} |
|||
|
|||
print('codepoint test (no output)'); |
|||
|
|||
try { |
|||
codepointTest(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,27 @@ |
|||
/*=== |
|||
[object JSON] |
|||
true |
|||
TypeError |
|||
TypeError |
|||
===*/ |
|||
|
|||
/* [[Class]] is "JSON" */ |
|||
print(Object.prototype.toString.call(JSON)); |
|||
|
|||
/* extensible */ |
|||
print(Object.isExtensible(JSON)); |
|||
|
|||
try { |
|||
// not constructable -> TypeError
|
|||
new JSON(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
try { |
|||
// not callable -> TypeError
|
|||
new JSON(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,77 @@ |
|||
print=console.log; |
|||
|
|||
/*=== |
|||
{"foo":1,"bar":2,"baz":4} |
|||
{"baz":4,"foo":1,"bar":2,"baz":4,"baz":4} |
|||
{"foo":1,"bar":2,"baz":4} |
|||
{"baz":4,"foo":1,"bar":2,"baz":4,"baz":4} |
|||
===*/ |
|||
|
|||
/* If the 2nd argument to stringify() is an array, it becomes the |
|||
* PropertyList of the serialization algorithm and affects the JO() |
|||
* algorithm concretely. |
|||
* |
|||
* The specification requires that serialization of properties will: |
|||
* |
|||
* (1) allow serialization of non-enumerable properties |
|||
* (2) will follow PropertyList order, not the object's enumeration order |
|||
* (order of properties in Object.keys()) |
|||
* (3) allows the same property to be serialized multiple times |
|||
*/ |
|||
|
|||
function stringifyPropertyListTest1() { |
|||
var obj = { |
|||
"foo": 1, |
|||
"bar": 2, |
|||
"quux": 3 |
|||
}; |
|||
|
|||
Object.defineProperties(obj, { |
|||
baz: { value: 4, enumerable: false, configurable: true, writable: true } |
|||
}); |
|||
|
|||
// baz is non-enumerable
|
|||
var txt = JSON.stringify(obj, [ 'foo', 'bar', 'baz' ]); |
|||
print(txt); |
|||
|
|||
// different order, 'baz' appears multiple times
|
|||
var txt = JSON.stringify(obj, [ 'baz', 'foo', 'bar', 'baz', 'baz' ]); |
|||
print(txt); |
|||
} |
|||
|
|||
function stringifyPropertyListTest2() { |
|||
// test that inherited properties are also correctly enumerated
|
|||
// when using a PropertyList
|
|||
|
|||
var proto = {}; |
|||
|
|||
function F() { |
|||
// quux and baz are inherited
|
|||
this.foo = 1; |
|||
this.bar = 2; |
|||
} |
|||
F.prototype = proto; |
|||
|
|||
var obj; |
|||
|
|||
Object.defineProperties(proto, { |
|||
quux: { value: 3, enumerable: true, writable: true, configurable: true }, |
|||
baz: { value: 4, enumerable: false, writable: true, configurable: true }, |
|||
}); |
|||
|
|||
obj = new F(); |
|||
|
|||
var txt = JSON.stringify(obj, [ 'foo', 'bar', 'baz' ]); |
|||
print(txt); |
|||
|
|||
var txt = JSON.stringify(obj, [ 'baz', 'foo', 'bar', 'baz', 'baz' ]); |
|||
print(txt); |
|||
} |
|||
|
|||
try { |
|||
stringifyPropertyListTest1(); |
|||
stringifyPropertyListTest2(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,85 @@ |
|||
print=console.log |
|||
|
|||
/*=== |
|||
identity replacer |
|||
replacer: [object Object] string object [object Object] |
|||
replacer: [object Object] string foo number 1 |
|||
replacer: [object Object] string bar string bar |
|||
{"foo":1,"bar":"bar"} |
|||
replace top level with foo |
|||
"foo" |
|||
replace non-empty primitive values |
|||
{"foo":"foo","bar":"foo","quux":{"key1":"foo","key2":"foo"},"quuux":["foo","foo","foo"]} |
|||
===*/ |
|||
|
|||
function replacerTest1() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: 'bar' |
|||
}; |
|||
|
|||
function repl(k, v) { |
|||
print('replacer:', this, typeof k, k, typeof v, v); |
|||
return v; |
|||
} |
|||
|
|||
// Replacer will be called first for the specification mandated
|
|||
// holder object and an empty string key.
|
|||
print(JSON.stringify(obj, repl)); |
|||
} |
|||
|
|||
function replacerTest2() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: 'bar' |
|||
}; |
|||
|
|||
function repl(k, v) { |
|||
return 'foo'; |
|||
} |
|||
|
|||
// When the replacer is called for the top-level holder, return
|
|||
// 'foo', thus serializing only that string.
|
|||
print(JSON.stringify(obj, repl)); |
|||
} |
|||
|
|||
function replacerTest3() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: 'bar', |
|||
quux: { |
|||
key1: 'val1', key2: 'val2' |
|||
}, |
|||
quuux: [ |
|||
'arr1', 'arr2', 'arr3' |
|||
] |
|||
}; |
|||
|
|||
function repl(k, v) { |
|||
if (k.length > 0 && typeof v !== 'object') { |
|||
return 'foo'; |
|||
} else { |
|||
return v; |
|||
} |
|||
} |
|||
|
|||
// Replace every non-object value with a non-empty key with 'foo'.
|
|||
//
|
|||
// Note that this also affects the array serialization.
|
|||
// Rhino seems to skip replacer for the array.
|
|||
|
|||
print(JSON.stringify(obj, repl)); |
|||
} |
|||
|
|||
try { |
|||
print('identity replacer'); |
|||
replacerTest1(); |
|||
|
|||
print('replace top level with foo'); |
|||
replacerTest2(); |
|||
|
|||
print('replace non-empty primitive values') |
|||
replacerTest3(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
@ -0,0 +1,72 @@ |
|||
/*=== |
|||
{"foo":1,"bar":"bar/toJSON"} |
|||
{"foo":1,"bar":"bar/toJSON","quux":{"toJSON":123}} |
|||
Error quuux/toJSON error |
|||
{"foo":1,"bar":"bar/toJSON","quux":{"toJSON":123},"quuux":"2012-01-02T03:04:05.006Z"} |
|||
===*/ |
|||
|
|||
/* Any Object values with a callable toJSON() property will get called, |
|||
* and the return value of toJSON() replaces the value to be serialized. |
|||
* |
|||
* If toJSON property exists but is not callable, it is ignored. |
|||
* If toJSON() throws an error, serialization stops with the error. |
|||
*/ |
|||
|
|||
function toJsonPropertyTest1() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: { toJSON: function() { return 'bar/toJSON'; } } |
|||
}; |
|||
|
|||
print(JSON.stringify(obj)); |
|||
} |
|||
|
|||
function toJsonPropertyTest2() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: { toJSON: function() { return 'bar/toJSON'; } }, |
|||
quux: { toJSON: 123 } |
|||
}; |
|||
|
|||
print(JSON.stringify(obj)); |
|||
} |
|||
|
|||
function toJsonPropertyTest3() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: { toJSON: function() { return 'bar/toJSON'; } }, |
|||
quux: { toJSON: 123 }, |
|||
quuux: { toJSON: function() { throw new Error('quuux/toJSON error'); } } |
|||
}; |
|||
|
|||
try { |
|||
print(JSON.stringify(obj)); |
|||
} catch (e) { |
|||
// FIXME: here we assume that message is intact
|
|||
print(e.name, e.message); |
|||
} |
|||
} |
|||
|
|||
function toJsonPropertyTest4() { |
|||
var obj = { |
|||
foo: 1, |
|||
bar: { toJSON: function() { return 'bar/toJSON'; } }, |
|||
quux: { toJSON: 123 }, |
|||
quuux: new Date(Date.parse('2012-01-02T03:04:05.006Z')) |
|||
}; |
|||
|
|||
// Date.prototype.toJSON() ultimately calls Date.prototype.toISOString()
|
|||
// which has an exact output format
|
|||
print(JSON.stringify(obj)); |
|||
} |
|||
|
|||
|
|||
try { |
|||
toJsonPropertyTest1(); |
|||
toJsonPropertyTest2(); |
|||
toJsonPropertyTest3(); |
|||
toJsonPropertyTest4(); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,66 @@ |
|||
/*=== |
|||
undefined undefined |
|||
string null |
|||
string true |
|||
string false |
|||
string 123 |
|||
string null |
|||
string null |
|||
string null |
|||
string "text" |
|||
string {"foo":"bar"} |
|||
string ["foo","bar"] |
|||
===*/ |
|||
|
|||
/* JSON top level value can be any type, not just an object or an array. */ |
|||
|
|||
function testStringify(x) { |
|||
var t = JSON.stringify(x); |
|||
print(typeof t, t); |
|||
} |
|||
|
|||
try { |
|||
testStringify(undefined); // this returns 'undefined', not a string
|
|||
testStringify(null); |
|||
testStringify(true); |
|||
testStringify(false); |
|||
testStringify(123.0); |
|||
testStringify(Number.NaN); |
|||
testStringify(Number.POSITIVE_INFINITY); |
|||
testStringify(Number.NEGATIVE_INFINITY); |
|||
testStringify('text'); |
|||
testStringify({foo:'bar'}); |
|||
testStringify(['foo','bar']); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
|||
/*=== |
|||
object |
|||
boolean |
|||
boolean |
|||
number |
|||
string |
|||
object |
|||
object |
|||
===*/ |
|||
|
|||
/* Test parsing of arbitrary top-level value. */ |
|||
|
|||
function testParse(x) { |
|||
var t = JSON.parse(x); |
|||
print(typeof t); |
|||
} |
|||
|
|||
try { |
|||
testParse('null'); // note: typeof null -> 'object'
|
|||
testParse('true'); |
|||
testParse('false'); |
|||
testParse('123.0'); |
|||
testParse('"text"'); |
|||
testParse('{"foo":"bar"}'); |
|||
testParse('["foo","bar"]'); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -0,0 +1,39 @@ |
|||
/* When encoding any value (val) using JSON.stringigy(), encoding begins |
|||
* with a dummy wrapper object: |
|||
* |
|||
* { "": val } |
|||
* |
|||
* This seems to be a purely internal matter but is not: the wrapper |
|||
* object is accessible to a replacement function. |
|||
*/ |
|||
|
|||
var val; |
|||
var t; |
|||
|
|||
/*=== |
|||
replacer |
|||
object |
|||
foo |
|||
|
|||
foo |
|||
===*/ |
|||
|
|||
// Here the wrapper object is: { "": "foo" }
|
|||
|
|||
try { |
|||
val = "foo"; |
|||
t = JSON.stringify(val, function(k, v) { |
|||
// this binding: holder object, i.e. the wrapper
|
|||
// k: key
|
|||
// v: value
|
|||
|
|||
print("replacer"); |
|||
print(typeof this); |
|||
print(this['']); // access the empty string key of the wrapper!
|
|||
print(k); // empty string
|
|||
print(v); // 'foo'
|
|||
}); |
|||
} catch (e) { |
|||
print(e.name); |
|||
} |
|||
|
@ -1,15 +0,0 @@ |
|||
/* |
|||
* JSON object (E5 Section 15.12). |
|||
* |
|||
* There are detailed JSON tests elsewhere. Here we test the basic |
|||
* functionality. |
|||
*/ |
|||
|
|||
/*--- |
|||
{ |
|||
"skip": true |
|||
} |
|||
---*/ |
|||
|
|||
/* FIXME */ |
|||
|
@ -1,34 +0,0 @@ |
|||
/* When encoding any value (val) using JSON.stringigy(), encoding begins |
|||
* with a dummy wrapper object: |
|||
* |
|||
* { "": val } |
|||
* |
|||
* This seems to be a purely internal matter but is not: the wrapper |
|||
* object is accessible to a replacement function. |
|||
*/ |
|||
|
|||
var val; |
|||
var t; |
|||
|
|||
/*=== |
|||
replacer |
|||
object |
|||
foo |
|||
|
|||
foo |
|||
===*/ |
|||
|
|||
// Here the wrapper object is: { "": "foo" }
|
|||
|
|||
val = "foo"; |
|||
t = JSON.stringify(val, function(k, v) { |
|||
// this binding: holder object, i.e. the wrapper
|
|||
// k: key
|
|||
// v: value
|
|||
|
|||
print("replacer"); |
|||
print(typeof this); |
|||
print(this['']); // access the empty string key of the wrapper!
|
|||
print(k); // empty string
|
|||
print(v); // 'foo'
|
|||
}); |
Loading…
Reference in new issue