1
// Automated tests should only cover js API. Use a manual test for native API
2
Y.JSON.useNativeParse = false;
4
var suite = new Y.Test.Suite("Y.JSON.parse (JavaScript implementation)"),
7
'"JSON Test Pattern pass1",' +
8
'{"object with 1 member":["array with 1 element"]},' +
16
'"integer": 1234567890,' +
17
'"real": -9876.543210,' +
18
'"e": 0.123456789e-12,' +
19
'"E": 1.234567890E+34,' +
20
'"": 23456789012E66,' +
25
'"backslash": "\\\\",' +
26
'"controls": "\\b\\f\\n\\r\\t",' +
27
'"slash": "/ & \\/",' +
28
'"alpha": "abcdefghijklmnopqrstuvwxyz",' +
29
'"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",' +
30
'"digit": "0123456789",' +
31
'"0123456789": "digit",' +
32
'"special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",' +
33
'"hex": "\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A",' +
39
'"address": "50 St. James Street",' +
40
'"url": "http://www.JSON.org/",' +
41
'"comment": "// /* <!-- --",' +
42
'"# -- --> */": " ",' +
43
'" s p a c e d " :[1,2 , 3,4 , 5 , 6 ,7 ],' +
44
'"compact":[1,2,3,4,5,6,7],' +
45
'"jsontext": "{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}",' +
46
'"quotes": "" \\u0022 %22 0x22 034 "",' +
47
'"\\/\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?" : "A key can be any string"' +
60
/*****************************/
61
/* Tests begin here */
62
/*****************************/
63
suite.add(new Y.Test.Case({
68
test_failOnEmptyString : true,
69
test_failOnFunction : true,
70
test_failOnRegex : true,
71
test_failOnNew : true,
72
test_failOnUnquotedVal : true,
73
test_failOnUnquotedKey : true,
74
test_failOnUnclosedObject : true,
75
test_failOnUnclosedArray : true,
76
test_failOnExtraCommaInObject : true,
77
test_failOnDoubleExtraCommaInObject : true,
78
test_failOnExtraCommaInArray : true,
79
test_failOnDoubleExtraCommaInArray : true,
80
test_failOnMissingValue : true,
81
test_failOnCommaAfterClose : true,
82
test_failOnValueAfterClose : true,
83
test_failOnExtraClose : true,
84
test_failOnExpression : true,
85
test_failOnZeroPrefixedNumber : true,
86
test_failOnHex : true,
87
test_failOnIllegalBackslashEscape : true,
88
test_failOnMissingColon : true,
89
test_failOnDoubleColon : true,
90
test_failOnCommaInsteadOfColon : true,
91
test_failOnColonInsteadOfComma : true,
92
test_failOnSingleQuote : true,
93
test_failOnTabCharacter : true,
94
test_failOnLineBreakChar : true,
95
test_failOnMismatchedClose : true,
96
test_failOnObjectInput : true,
97
test_failOnArrayInput : true,
98
test_failOnDateInput : true,
99
test_failOnRegExpInput : true,
100
test_failOnErrorInput : true,
101
test_failOnFunctionInput : true,
102
test_failOnNaNInput : true,
103
test_failOnInfinityInput : true,
104
test_failOnUndefinedInput : true
108
test_emptyObject : function () {
109
Y.Assert.isObject(Y.JSON.parse("{}"));
111
test_emptyArray : function () {
112
Y.Assert.isObject(Y.JSON.parse("[]"));
114
test_JSONNatives : function () {
115
// Note: backslashes are double escaped to emulate string returned from
117
var data = Y.JSON.parse('{"obj":{},"arr":[],"f":false,"t":true,"n":null,"int":12345,"fl":1.2345,"str":"String\\nwith\\tescapes"}');
118
Y.Assert.isObject(data);
119
Y.Assert.isObject(data.obj);
120
Y.Assert.isArray(data.arr);
121
Y.Assert.isNull(data.n);
122
Y.Assert.areSame(false,data.f);
123
Y.Assert.areSame(true,data.t);
124
Y.Assert.areSame(12345,data["int"]);
125
Y.Assert.areSame(1.2345,data.fl);
126
Y.Assert.areSame("String\nwith\tescapes",data.str);
128
test_basics : function () {
129
var data = Y.JSON.parse(JSON_STRING);
131
Y.Assert.isArray(data);
132
Y.Assert.areSame(20,data.length);
133
Y.Assert.isString(data[0]);
134
Y.Assert.isObject(data[1]);
135
Y.Assert.isArray(data[1]["object with 1 member"]);
136
Y.Assert.areSame(1,data[1]["object with 1 member"].length);
137
Y.Assert.isNumber(data[4]);
138
Y.Assert.isBoolean(data[5]);
139
Y.Assert.isBoolean(data[6]);
140
Y.Assert.isNull(data[7]);
141
Y.Assert.areSame(1234567890,data[8].integer);
142
Y.Assert.areSame(-9876.543210,data[8].real);
143
Y.Assert.areSame(0.123456789e-12,data[8].e);
144
Y.Assert.areSame(1.234567890e+34,data[8].E);
145
Y.Assert.areSame(23456789012E66,data[8][""]);
146
Y.Assert.areSame(0,data[8].zero);
147
Y.Assert.areSame(1,data[8].one);
148
Y.Assert.areSame(" ",data[8].space);
149
Y.Assert.areSame('"',data[8].quote);
150
Y.Assert.areSame("\\",data[8].backslash);
151
Y.Assert.areSame("\b\f\n\r\t",data[8].controls);
152
Y.Assert.areSame("/ & \/",data[8].slash);
153
Y.Assert.areSame("abcdefghijklmnopqrstuvwxyz",data[8].alpha);
154
Y.Assert.areSame("ABCDEFGHIJKLMNOPQRSTUVWXYZ",data[8].ALPHA);
155
Y.Assert.areSame("0123456789",data[8].digit);
156
Y.Assert.areSame("digit",data[8]["0123456789"]);
158
Y.Assert.areSame(1234567890,data[8].integer);
159
Y.Assert.areSame("`1~!@#$%^&*()_+-={':[,]}|;.</>?",data[8].special);
160
Y.Assert.areSame("\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",data[8].hex);
161
Y.Assert.areSame(true,data[8]["true"]);
162
Y.Assert.areSame(false,data[8]["false"]);
163
Y.Assert.isNull(data[8]["null"]);
164
Y.Assert.isArray(data[8]["array"]);
165
Y.Assert.isObject(data[8]["object"]);
166
Y.Assert.areSame("http://www.JSON.org/",data[8].url);
167
Y.Assert.areSame("// /* <!-- --",data[8].comment);
168
Y.Assert.areSame(" ",data[8]["# -- --> */"]);
169
Y.ArrayAssert.itemsAreSame([1,2,3,4,5,6,7],data[8][" s p a c e d "]);
170
Y.ArrayAssert.itemsAreSame([1,2,3,4,5,6,7],data[8].compact);
171
Y.Assert.areSame("{\"object with 1 member\":[\"array with 1 element\"]}",data[8].jsontext);
172
Y.Assert.areSame("" \u0022 %22 0x22 034 "",data[8].quotes);
173
Y.Assert.areSame("A key can be any string",data[8]["\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"]);
175
Y.Assert.areSame(0.5,data[9]);
176
Y.Assert.areSame(98.6,data[10]);
177
Y.Assert.areSame(99.44,data[11]);
178
Y.Assert.areSame(1066,data[12]);
179
Y.Assert.areSame(1e1,data[13]);
180
Y.Assert.areSame(0.1e1,data[14]);
181
Y.Assert.areSame(1e-1,data[15]);
182
Y.Assert.areSame(1e00,data[16]);
183
Y.Assert.areSame(2e+00,data[17]);
184
Y.Assert.areSame(2e-00,data[18]);
185
Y.Assert.areSame("rosebud",data[19]);
187
test_nonObjectWrapper : function () {
188
//Y.Assert.areSame('this is a string',Y.JSON.parse('"this is a string"'));
189
//Y.Assert.areSame(true,Y.JSON.parse('true'));
190
//Y.Assert.areSame(12345,Y.JSON.parse("12345"));
191
//Y.Assert.areSame(1.2345,Y.JSON.parse("1.2345"));
192
Y.Assert.areSame(null,Y.JSON.parse("null"));
194
test_failOnEmptyString : function () {
195
// parse should throw an error
196
Y.Assert.isString(Y.JSON.parse(""));
197
Y.log("Parsed empty string, but should have failed.","warn","TestRunner");
199
test_failOnFunction : function () {
200
// parse should throw an error
201
Y.JSON.parse('{"fn":function(){}}');
202
Y.log("Parsed a function, but should have failed.","warn","TestRunner");
204
test_failOnRegex : function () {
205
// parse should throw an error
206
Y.JSON.parse('{"re":/abc/}');
207
Y.log("Parsed regular expression literal, but should have failed.","warn","TestRunner");
209
test_failOnNew : function () {
210
// parse should throw an error
211
Y.JSON.parse('{"dt":new Date()}');
212
Y.log("Parsed <code>new Date()</code>, but should have failed.","warn","TestRunner");
214
test_failOnUnquotedVal : function () {
215
// parse should throw an error
216
Y.JSON.parse('{"foo":bar}');
217
Y.log("Parsed unquoted non-native value, but should have failed.","warn","TestRunner");
219
test_failOnUnquotedKey : function () {
220
// parse should throw an error
221
Y.JSON.parse('{foo:1}');
222
Y.log("Parsed unquoted object key, but should have failed.","warn","TestRunner");
224
test_failOnUnclosedObject : function () {
225
// parse should throw an error
226
Y.JSON.parse('{"unclosed":"object"');
227
Y.log("Parsed unclosed object, but should have failed.","warn","TestRunner");
229
test_failOnUnclosedArray : function () {
230
// parse should throw an error
231
Y.JSON.parse('["unclosed array"');
232
Y.log("Parsed unclosed array, but should have failed.","warn","TestRunner");
234
test_failOnExtraCommaInObject : function () {
235
// JS validator will allow, FF 3.1b2 native will allow. IE8 errors.
236
// eval will fail in IE6-7, but pass in others
237
// Trailing commas are invalid, but not a security risk, so acceptable
238
Y.JSON.parse('{"extra":"comma",}');
239
Y.log("Parsed object with extra comma, but should have failed.","warn","TestRunner");
240
throw new Error("Parsed object with extra comma, but should have failed.");
242
test_failOnDoubleExtraCommaInObject : function () {
243
// parse should throw an error
244
Y.JSON.parse('{"extra":"commas",,}');
245
Y.log("Parsed object with two extra commas, but should have failed.","warn","TestRunner");
247
test_failOnExtraCommaInArray : function () {
248
// Correct failure in IE6-8. FF accepts trailing commas without error
249
// Trailing commas are invalid, but not a security risk, so acceptable
250
Y.JSON.parse('["extra","comma",]');
251
Y.log("Parsed array with extra comma, but should have failed.","warn","TestRunner");
252
throw new Error("Parsed array with extra comma, but should have failed.");
254
test_failOnDoubleExtraCommaInArray : function () {
255
// Correct failure in IE6-8. FF accepts trailing commas without error
256
// Trailing commas are invalid, but not a security risk, so acceptable
257
Y.JSON.parse('["extra","commas",,]');
258
Y.log("Parsed array with two extra commas, but should have failed.","warn","TestRunner");
259
throw new Error("Parsed array with two extra commas, but should have failed.");
261
test_failOnMissingValue : function () {
262
// Correct failure in IE6-8. FF accepts trailing commas without error
263
// Trailing commas are invalid, but not a security risk, so acceptable
264
var data = Y.JSON.parse('[,"<-- missing value"]');
265
Y.log("Parsed array with missing value ("+data[0]+"), but should have failed.","warn","TestRunner");
266
throw new Error("Parsed array with missing value ("+data[0]+"), but should have failed.");
268
test_failOnCommaAfterClose : function () {
269
// parse should throw an error
270
Y.JSON.parse('["comma","after","close"],');
271
Y.log("Parsed comma after array close, but should have failed.","warn","TestRunner");
273
test_failOnValueAfterClose : function () {
274
// parse should throw an error
275
Y.JSON.parse('{"misplaced":"value"}" after close"');
276
Y.log("Parsed string value after object close, but should have failed.","warn","TestRunner");
278
test_failOnExtraClose : function () {
279
// parse should throw an error
280
var data = Y.JSON.parse('{"foo":1}}');
281
Y.log("Parsed extra closing curly brace on object, but should have failed.","warn","TestRunner");
282
throw new Error("Parsed extra closing curly brace on object, but should have failed.");
284
test_failOnExpression : function () {
285
// parse should throw an error
286
Y.JSON.parse('{"foo":1+2}');
287
Y.log("Parsed expression, but should have failed.","warn","TestRunner");
289
test_failOnZeroPrefixedNumber : function () {
290
// Correct failure in IE8. FF accepts leading zeros without error
291
// Leading zeros are invalid, but not a security risk, so acceptable
292
Y.JSON.parse('{"foo":01}');
293
Y.log("Parsed zero prefixed number, but should have failed.","warn","TestRunner");
294
throw new Error("Parsed zero prefixed number, but should have failed.");
296
test_failOnHex : function () {
297
// parse should throw an error
298
Y.JSON.parse('{"foo":0x14}');
299
Y.log("Parsed hex value, but should have failed.","warn","TestRunner");
301
test_failOnIllegalBackslashEscape : function () {
302
// Correctly fails in all but IE8's native parse.
303
// The spec does not specify a limitation to the escape characters a
304
// decoder supports, so either is acceptable.
305
var data = Y.JSON.parse('["illegal backslash escape: \\x15"]');
306
Y.log("Parsed illegal backslash escape \\x15, but should have failed.","warn","TestRunner");
307
throw new Error("Parsed illegal backslash escape \\x15, but should have failed.");
309
test_failOnMissingColon : function () {
310
// parse should throw an error
311
Y.JSON.parse('{"foo" null}');
312
Y.log("Parsed object with missing colon, but should have failed.","warn","TestRunner");
314
test_failOnDoubleColon : function () {
315
// parse should throw an error
316
Y.JSON.parse('{"foo"::1}');
317
Y.log("Parsed double colon in object, but should have failed.","warn","TestRunner");
319
test_failOnCommaInsteadOfColon : function () {
320
// parse should throw an error
321
Y.JSON.parse('{"foo",1}');
322
Y.log("Parsed comma in place of colon, but should have failed.","warn","TestRunner");
324
test_failOnColonInsteadOfComma : function () {
325
// parse should throw an error
326
Y.JSON.parse('["colon instead of":"comma"]');
327
Y.log("Parsed colon in place of comma, but should have failed.","warn","TestRunner");
329
test_failOnSingleQuote : function () {
330
// parse should throw an error
331
Y.JSON.parse("{'foo':1}");
332
Y.log("Parsed single quote, but should have failed.","warn","TestRunner");
334
test_failOnLineBreakChar : function () {
335
// FF3.1b2 currently allows linebreak chars in native implementation
336
// Harmless, so permissable
337
Y.JSON.parse("[\"line\nbreak\"]");
338
Y.log("Parsed unescaped line break character, but should have failed.","warn","TestRunner");
339
throw new Error("Parsed unescaped line break character, but should have failed.");
341
test_failOnMismatchedClose : function () {
342
// parse should throw an error
343
Y.JSON.parse('["mismatched"}');
344
Y.log("Parsed curly brace close for array, but should have failed.","warn","TestRunner");
346
test_failOnObjectInput: function () {
347
// parse should throw an error
348
Y.JSON.parse({"should": "be treated as [object Object]"});
349
Y.log("Parsed object input, but should have failed.","warn","TestRunner");
351
test_arrayContainingValidJSON: function () {
352
// Should be ToString'ed to '{"foo":"bar"}' which is valid
353
var o = Y.JSON.parse(['{"foo":"bar"}']);
355
Y.Assert.isObject(o);
356
Y.Assert.areSame("bar", o.foo);
358
test_failOnArrayInput: function () {
359
// parse should throw an error
360
Y.JSON.parse(['x', 'y']); // should be treated as "x,y");
361
Y.log("Parsed array input, but should have failed.","warn","TestRunner");
363
test_failOnDateInput: function () {
364
// parse should throw an error
365
Y.JSON.parse(new Date()); // should be treated as date string
366
Y.log("Parsed Date input, but should have failed.","warn","TestRunner");
368
test_failOnRegExpInput: function () {
369
// parse should throw an error
370
Y.JSON.parse(/should fail/); // should ToString to '/should fail/'
371
Y.JSON.parse(/true/); // should ToString to '/true/'
372
Y.log("Parsed RegExp input, but should have failed.","warn","TestRunner");
374
test_failOnErrorInput: function () {
375
// parse should throw an error
376
Y.JSON.parse(new Error("Boom")); // ToString to 'Error: Boom'
377
Y.JSON.parse(new Error("true")); // ToString to 'Error: true'
378
Y.JSON.parse(new SyntaxError("true")); // ToString to 'Error: true'
379
Y.log("Parsed Error input, but should have failed.","warn","TestRunner");
381
test_failOnFunctionInput: function () {
382
// parse should throw an error
383
Y.JSON.parse(function () { return "decompiled!"; }); // ToString 'function ...'
384
Y.log("Parsed function input, but should have failed.","warn","TestRunner");
386
test_failOnNaNInput: function () {
387
// parse should throw an error
388
Y.JSON.parse(NaN); // ToString to 'NaN', but not a valid JSON number
389
Y.log("Parsed NaN input, but should have failed.","warn","TestRunner");
391
test_failOnInfinityInput: function () {
392
// parse should throw an error
393
Y.JSON.parse(Infinity); // ToString to 'Infinity', but not valid JSON
394
Y.log("Parsed Infinity input, but should have failed.","warn","TestRunner");
396
test_failOnUndefinedInput: function () {
397
// Should be ToString'ed to 'undefined'
398
Y.JSON.parse(undefined);
400
Y.log("Parsed undefined input, but should have failed.","warn","TestRunner");
402
test_booleanInput: function () {
403
// Should be ToString'ed to 'true'
404
var bool = Y.JSON.parse(true);
406
Y.Assert.isBoolean(bool);
407
Y.Assert.isTrue(bool);
409
bool = Y.JSON.parse(false);
411
Y.Assert.isBoolean(bool);
412
Y.Assert.isFalse(bool);
414
// Should be ToString'ed to 'true'
415
bool = Y.JSON.parse(new Boolean(true));
417
Y.Assert.isBoolean(bool);
418
Y.Assert.isTrue(bool);
420
bool = Y.JSON.parse(new Boolean(false));
422
Y.Assert.isBoolean(bool);
423
Y.Assert.isFalse(bool);
425
test_stringObjectInput: function () {
426
// Should be ToString'ed to '{"foo":"bar"}' which is valid
427
var o = Y.JSON.parse(new String('{"foo":"bar"}'));
429
Y.Assert.isObject(o);
430
Y.Assert.areSame("bar", o.foo);
432
test_numberInput: function () {
433
Y.Assert.areSame(0, Y.JSON.parse(0));
434
Y.Assert.areSame(100, Y.JSON.parse(100));
435
Y.Assert.areSame(-100, Y.JSON.parse(-100));
436
Y.Assert.areSame(-1.05e2, Y.JSON.parse(-1.05e2));
438
test_nullInput: function () {
439
// Should be ToString'ed to 'null'
440
Y.Assert.isNull(Y.JSON.parse(null));
442
test_objectWithToStringInput: function () {
443
// Should be ToString'ed to '{"foo":"bar"}' which is valid
444
var o = Y.JSON.parse({
445
toString: function () {
446
return '{"foo":"bar"}';
450
Y.Assert.isObject(o);
451
Y.Assert.areSame("bar", o.foo);
455
suite.add(new Y.Test.Case({
458
test_reviver : function () {
459
var data = Y.JSON.parse(JSON_STRING, function (k,v) {
461
case "alpha" : return "LOWER CASE";
462
case "ALPHA" : return "upper case";
465
case "null" : return undefined;
468
if (typeof v === 'number') {
469
return -(Math.abs(v|0));
472
if (Y.Lang.isArray(v)) {
479
Y.Assert.areSame("LOWER CASE", data[8].alpha);
480
Y.Assert.areSame("upper case", data[8].ALPHA);
481
Y.Assert.isUndefined(data[8]["true"]);
482
Y.Assert.isUndefined(data[8]["false"]);
483
Y.Assert.isUndefined(data[8]["null"]);
484
Y.Assert.areSame(-42, data[4]);
485
Y.Assert.areSame(-1234567890, data[8].integer);
486
Y.Assert.areSame(-9876, data[8].real);
487
Y.Assert.areSame(-1, data[8].one);
488
Y.Assert.areSame(-3, data[8][" s p a c e d "][2]);
490
Y.Assert.areSame("NEW ITEM", data[99]);
491
Y.Assert.areSame("NEW ITEM", data[8][" s p a c e d "][99]);
492
Y.Assert.areSame("NEW ITEM", data[8].compact[99]);
496
Y.Test.Runner.add(suite);