~smagoun/whoopsie/whoopsie-lp1017637

« back to all changes in this revision

Viewing changes to backend/stats/static/js/yui/tests/json/tests/src/json-stringify.js

  • Committer: Evan Dandrea
  • Date: 2012-05-09 05:53:45 UTC
  • Revision ID: evan.dandrea@canonical.com-20120509055345-z2j41tmcbf4as5uf
The backend now lives in lp:daisy and the website (errors.ubuntu.com) now lives in lp:errors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Automated tests should only cover js API.  Use a manual test for native API
2
 
Y.JSON.useNativeStringify = false;
3
 
 
4
 
var suite = new Y.Test.Suite("Y.JSON.stringify (JavaScript implementation)");
5
 
 
6
 
suite.add(new Y.Test.Case({
7
 
    name : "stringify",
8
 
        
9
 
    _should : {
10
 
        error : {
11
 
            test_failOnStringifyCyclicalRef1    : true,
12
 
            test_failOnStringifyCyclicalRef2    : true,
13
 
            test_failOnStringifyCyclicalRef3    : true
14
 
        }
15
 
    },
16
 
 
17
 
    setUp: function () {
18
 
        Y.one("body").append('<form id="testbed" action="">' +
19
 
            '<h3>Form used for field value extraction, stringification</h3>' +
20
 
            '<input type="text" id="empty_text">' +
21
 
            '<input type="text" id="text" value="text">' +
22
 
            '<input type="radio" name="radio" id="unchecked_radio" value="unchecked">' +
23
 
            '<input type="radio" name="radio" id="checked_radio" value="radio" checked="checked">' +
24
 
            '<input type="checkbox" name="box" id="unchecked_box" value="unchecked">' +
25
 
            '<input type="checkbox" name="box" id="checked_box" value="box" checked="checked">' +
26
 
            '<textarea id="empty_textarea"></textarea>' +
27
 
            '<textarea id="textarea">textarea</textarea>' +
28
 
            '<select id="select">' +
29
 
                '<option value="unselected">Unselected</option>' +
30
 
                '<option value="selected" selected="selected">Selected</option>' +
31
 
            '</select>' +
32
 
            '<select id="multiple_select" multiple="multiple" size="3">' +
33
 
                '<option value="unselected">Unselected</option>' +
34
 
                '<option value="selected" selected="selected">Selected</option>' +
35
 
                '<option value="selected also" selected="selected">Selected also</option>' +
36
 
            '</select>' +
37
 
            '<button id="button" type="button">content; no value</button>' +
38
 
            '<button id="button_with_value" type="button" value="button value">content and value</button>' +
39
 
            '<button id="button_submit" type="submit">content; no value</button>' +
40
 
            '<button id="button_submit_with_value" type="submit" value="submit button value">content and value</button>' +
41
 
            '<input type="button" id="input_button" value="input button">' +
42
 
            '<input type="submit" id="input_submit" value="input submit">' +
43
 
            '<!--input type="image" id="input_image" src="404.png" value="input image"-->' +
44
 
        '</form>');
45
 
    },
46
 
 
47
 
    tearDown: function () {
48
 
        Y.one("#testbed").remove(true);
49
 
    },
50
 
 
51
 
    test_stringifyNatives: function () {
52
 
        Y.Assert.areSame('[true,false,null,-0.12345,"string",{"object with one member":["array with one element"]}]',
53
 
            Y.JSON.stringify([true,false,null,-0.12345,"string",{"object with one member":["array with one element"]}]));
54
 
    },
55
 
 
56
 
    test_stringifyEscapes: function () {
57
 
        Y.Assert.areSame('["\\\\","\\\\\'","\\\\\\\"","\\\\\\\"","\\b","\\b","\\\\b","\\\\\\b","\\\\\\b","\\b","\\\\x08","\\\\\\b","\\\\\\\\x08","\\n","\\\\n","\\\\\\n"]',
58
 
            Y.JSON.stringify(['\\','\\\'', "\\\"", '\\"', "\b", '\b', "\\b","\\\b", '\\\b', "\x08", "\\x08", "\\\x08","\\\\x08", "\n", "\\n", "\\\n"]));
59
 
    },
60
 
 
61
 
    test_stringifyObject : function () {
62
 
        // stringify sorts the keys
63
 
        Y.Assert.areSame('{"one":1,"two":true,"three":false,"four":null,"five":"String with\\nnewline","six":{"nested":-0.12345}}',
64
 
            Y.JSON.stringify({one:1,two:true,three:false,four:null,five:"String with\nnewline",six :  {nested:-0.12345}}));
65
 
    },
66
 
 
67
 
    test_failOnStringifyCyclicalRef1 : function () {
68
 
        var o = { key: 'value' };
69
 
        o.recurse = o;
70
 
 
71
 
        // Should throw an error
72
 
        Y.JSON.stringify(o);
73
 
        Y.log("Stringified Object with cyclical reference, but should have failed.","warn","TestRunner");
74
 
    },
75
 
 
76
 
    test_failOnStringifyCyclicalRef2 : function () {
77
 
        var o = [1,2,3];
78
 
        o[3] = o;
79
 
 
80
 
        // Should throw an error
81
 
        Y.JSON.stringify(o);
82
 
        Y.log("Stringified Array with cyclical reference, but should have failed.","warn","TestRunner");
83
 
    },
84
 
 
85
 
    test_failOnStringifyCyclicalRef3 : function () {
86
 
        var o = [1,2,3,{key:"value",nest:[4,5,6,{foo:"bar"}]}];
87
 
        o[4] = o[3].x = o[3].nest[4] =
88
 
        o[3].nest[3].y = o[3].nest[3].z = o;
89
 
 
90
 
        // Should throw an error
91
 
        Y.JSON.stringify(o);
92
 
        Y.log("Stringified Object with cyclical reference, but should have failed.","warn","TestRunner");
93
 
    },
94
 
 
95
 
    test_stringifyFunction : function () {
96
 
        Y.Assert.areSame('{"arr":[null]}',
97
 
            Y.JSON.stringify({
98
 
                functions : function (are,ignored) {},
99
 
                arr       : [ function () {} ]
100
 
            }));
101
 
    },
102
 
 
103
 
    test_stringifyRegex : function () {
104
 
        Y.Assert.areSame('{"regex":{},"arr":[{}]}',
105
 
            Y.JSON.stringify({
106
 
                regex : /are treated as objects/,
107
 
                arr   : [ new RegExp("in array") ]
108
 
            }));
109
 
    },
110
 
 
111
 
    test_stringifyUndefined : function () {
112
 
        Y.Assert.areSame('{"arr":[null]}',
113
 
            Y.JSON.stringify({
114
 
                undef : undefined,
115
 
                arr   : [ undefined ]
116
 
            }));
117
 
    },
118
 
 
119
 
    test_stringifyDate : function () {
120
 
        // native toJSON method should be called if available
121
 
        var d = new Date(Date.UTC(1946,6,6)),
122
 
            ref = d.toJSON ? d.toJSON() : "1946-07-06T00:00:00Z";
123
 
 
124
 
        Y.Assert.areSame('{"dt":"'+ref+'"}', Y.JSON.stringify({dt : d}));
125
 
    },
126
 
 
127
 
    test_stringifyFormValue : function () {
128
 
        function $(id) { return document.getElementById(id); }
129
 
 
130
 
        var data = {
131
 
            empty_text              : $('empty_text').value,
132
 
            text                    : $('text').value,
133
 
            unchecked_radio         : $('unchecked_radio').value,
134
 
            checked_radio           : $('checked_radio').value,
135
 
            unchecked_box           : $('unchecked_box').value,
136
 
            checked_box             : $('checked_box').value,
137
 
            empty_textarea          : $('empty_textarea').value,
138
 
            textarea                : $('textarea').value,
139
 
            select                  : $('select').value,
140
 
            multiple_select         : $('multiple_select').value,
141
 
            // Buttons commented out for now because IE reports values
142
 
            // differently
143
 
            //button                  : $('button').value,
144
 
            //button_with_value       : $('button_with_value').value,
145
 
            //button_submit           : $('button_submit').value,
146
 
            //button_submit_with_value: $('button_submit_with_value').value,
147
 
            input_button            : $('input_button').value,
148
 
            input_submit            : $('input_submit').value//,
149
 
            //input_image             : $('input_image').value
150
 
        };
151
 
 
152
 
        Y.Assert.areSame('{'+
153
 
            '"empty_text":"",'+
154
 
            '"text":"text",'+
155
 
            '"unchecked_radio":"unchecked",'+
156
 
            '"checked_radio":"radio",'+
157
 
            '"unchecked_box":"unchecked",'+
158
 
            '"checked_box":"box",'+
159
 
            '"empty_textarea":"",'+
160
 
            '"textarea":"textarea",'+
161
 
            '"select":"selected",'+
162
 
            '"multiple_select":"selected",'+
163
 
            //'"button":"",'+
164
 
            //'"button_with_value":"button value",'+
165
 
            //'"button_submit":"",'+
166
 
            //'"button_submit_with_value":"submit button value",'+
167
 
            '"input_button":"input button",'+
168
 
            '"input_submit":"input submit"}',
169
 
            //'"input_image":"input image"}',
170
 
            Y.JSON.stringify(data));
171
 
    }
172
 
 
173
 
}));
174
 
 
175
 
suite.add(new Y.Test.Case({
176
 
    name : "whitelist",
177
 
 
178
 
    test_emptyWhitelistArray : function () {
179
 
        Y.Assert.areSame('{}',
180
 
            Y.JSON.stringify({foo:1,bar:[1,2,3],baz:true},[]));
181
 
 
182
 
        Y.Assert.areSame('[1,true,null,{},["string",null,{}]]',
183
 
            Y.JSON.stringify([
184
 
                1,true,null,{
185
 
                    foo : false,
186
 
                    bar : -0.12345
187
 
                },["string",undefined,/some regex/]
188
 
            ],[]));
189
 
    },
190
 
 
191
 
    test_whitelistArray : function () {
192
 
        Y.Assert.areSame('{"foo":[1,2,3,{"foo":"FOO"}]}',
193
 
            Y.JSON.stringify({
194
 
                foo : [
195
 
                    1,2,3,{
196
 
                        foo : "FOO",
197
 
                        baz : true
198
 
                    }
199
 
                ],
200
 
                bar : [1,2,3],
201
 
                baz : true
202
 
            },["foo"]));
203
 
 
204
 
        Y.Assert.areSame('{"foo":[1,2,3,{"foo":"FOO","baz":true}],"baz":true}',
205
 
            Y.JSON.stringify({
206
 
                foo : [
207
 
                    1,2,3,{
208
 
                        foo : "FOO",
209
 
                        baz : true
210
 
                    }
211
 
                ],
212
 
                bar : [
213
 
                    1,2,3,{
214
 
                        foo : "FOO",
215
 
                        baz : true
216
 
                    }
217
 
                ],
218
 
                baz : true},["foo","baz"]));
219
 
 
220
 
    }
221
 
 
222
 
    /*
223
 
    // REMOVED for spec compatibility
224
 
    test_whitelistObject : function () {
225
 
        // (undocumented) supports an obj literal as well
226
 
        Y.Assert.areSame('{"foo":[1,2,3,{"foo":"FOO","baz":true}],"baz":true}',
227
 
            Y.JSON.stringify({
228
 
                foo : [
229
 
                    1,2,3,{
230
 
                        foo : "FOO",
231
 
                        baz : true
232
 
                    }
233
 
                ],
234
 
                bar : [
235
 
                    1,2,3,{
236
 
                        foo : "FOO",
237
 
                        baz : true
238
 
                    }
239
 
                ],
240
 
                baz : true
241
 
            }, {foo : true, baz : false})); // values ignored
242
 
    }
243
 
    */
244
 
 
245
 
}));
246
 
 
247
 
suite.add(new Y.Test.Case({
248
 
    name : "formatting",
249
 
 
250
 
    test_falseyIndents : function () {
251
 
        Y.Assert.areSame('{"foo0":[2,{"bar":[4,{"baz":[6,{"deep enough":7}]}]}]}',
252
 
            Y.JSON.stringify({
253
 
                foo0 : [ 2, {
254
 
                    bar : [ 4, {
255
 
                        baz : [ 6, {
256
 
                            "deep enough" : 7
257
 
                        }]
258
 
                    }]
259
 
                }]
260
 
            },null,0));
261
 
 
262
 
        /* Commented out because FF3.5 has infinite loop bug for neg indents
263
 
         * Fixed in FF for next version.
264
 
        Y.Assert.areSame('{"foo-4":[2,{"bar":[4,{"baz":[6,{"deep enough":7}]}]}]}',
265
 
            Y.JSON.stringify({
266
 
                "foo-4" : [ 2, {
267
 
                    bar : [ 4, {
268
 
                        baz : [ 6, {
269
 
                            "deep enough" : 7
270
 
                        }]
271
 
                    }]
272
 
                }]
273
 
            },null,-4));
274
 
        */
275
 
 
276
 
        Y.Assert.areSame('{"foo_false":[2,{"bar":[4,{"baz":[6,{"deep enough":7}]}]}]}',
277
 
            Y.JSON.stringify({
278
 
                foo_false : [ 2, {
279
 
                    bar : [ 4, {
280
 
                        baz : [ 6, {
281
 
                            "deep enough" : 7
282
 
                        }]
283
 
                    }]
284
 
                }]
285
 
            },null,false));
286
 
 
287
 
        Y.Assert.areSame('{"foo_empty":[2,{"bar":[4,{"baz":[6,{"deep enough":7}]}]}]}',
288
 
            Y.JSON.stringify({
289
 
                foo_empty : [ 2, {
290
 
                    bar : [ 4, {
291
 
                        baz : [ 6, {
292
 
                            "deep enough" : 7
293
 
                        }]
294
 
                    }]
295
 
                }]
296
 
            },null,""));
297
 
 
298
 
    },
299
 
 
300
 
    test_indentNumber : function () {
301
 
        Y.Assert.areSame("{\n" +
302
 
"  \"foo\": [\n" +
303
 
"    2,\n" +
304
 
"    {\n" +
305
 
"      \"bar\": [\n" +
306
 
"        4,\n" +
307
 
"        {\n" +
308
 
"          \"baz\": [\n" +
309
 
"            6,\n" +
310
 
"            {\n" +
311
 
"              \"deep enough\": 7\n" +
312
 
"            }\n" +
313
 
"          ]\n" +
314
 
"        }\n" +
315
 
"      ]\n" +
316
 
"    }\n" +
317
 
"  ]\n" +
318
 
"}",
319
 
            Y.JSON.stringify({
320
 
                foo : [ 2, {
321
 
                    bar : [ 4, {
322
 
                        baz : [ 6, {
323
 
                            "deep enough" : 7
324
 
                        }]
325
 
                    }]
326
 
                }]
327
 
            },null,2));
328
 
    },
329
 
    test_indentString : function () {
330
 
        Y.Assert.areSame("{\n" +
331
 
"Xo\"foo\": [\n" +
332
 
"XoXo2,\n" +
333
 
"XoXo{\n" +
334
 
"XoXoXo\"bar\": [\n" +
335
 
"XoXoXoXo4,\n" +
336
 
"XoXoXoXo{\n" +
337
 
"XoXoXoXoXo\"baz\": [\n" +
338
 
"XoXoXoXoXoXo6,\n" +
339
 
"XoXoXoXoXoXo{\n" +
340
 
"XoXoXoXoXoXoXo\"deep enough\": 7\n" +
341
 
"XoXoXoXoXoXo}\n" +
342
 
"XoXoXoXoXo]\n" +
343
 
"XoXoXoXo}\n" +
344
 
"XoXoXo]\n" +
345
 
"XoXo}\n" +
346
 
"Xo]\n" +
347
 
"}",
348
 
            Y.JSON.stringify({
349
 
                foo : [ 2, {
350
 
                    bar : [ 4, {
351
 
                        baz : [ 6, {
352
 
                            "deep enough" : 7
353
 
                        }]
354
 
                    }]
355
 
                }]
356
 
            },null,"Xo"));
357
 
    }
358
 
}));
359
 
 
360
 
suite.add(new Y.Test.Case({
361
 
    name : "toJSON",
362
 
 
363
 
    test_toJSON_on_object: function () {
364
 
        Y.Assert.areSame('"toJSON"',
365
 
            Y.JSON.stringify({ toJSON: function () { return "toJSON"; } }));
366
 
 
367
 
        // TODO: complex object with toJSON
368
 
    },
369
 
 
370
 
    test_toJSON_on_proto: function () {
371
 
        function A() {}
372
 
        A.prototype.toJSON = function () { return "A"; };
373
 
        
374
 
        function B() {}
375
 
        B.prototype = new A();
376
 
 
377
 
        function C() {
378
 
            this.x = "X";
379
 
            this.y = "Y";
380
 
            this.z = "Z";
381
 
        }
382
 
        C.prototype = new B();
383
 
 
384
 
        Y.Assert.areSame('"A"', Y.JSON.stringify(new C()));
385
 
    }
386
 
}));
387
 
 
388
 
suite.add(new Y.Test.Case({
389
 
    name : "replacer",
390
 
 
391
 
    test_replacer : function () {
392
 
        // replacer applies to even simple value stringifications
393
 
        Y.Assert.areSame("20",
394
 
            Y.JSON.stringify(10,function (k,v) {
395
 
                return typeof(v) === 'number' ? v * 2 : v;
396
 
            }));
397
 
 
398
 
        // replacer is applied to every nested property as well.
399
 
        // can modify the host object en route
400
 
        // executes from the context of the key:value container
401
 
        Y.Assert.areSame('{"num":2,"alpha":"ABC","obj":{"nested_num":100,"alpha":"abc"},"arr":[2,null,4]}',
402
 
            Y.JSON.stringify({
403
 
                    num: 1,
404
 
                    alpha: "abc",
405
 
                    ignore: "me",
406
 
                    change: "to a function",
407
 
                    toUpper: true,
408
 
                    obj: {
409
 
                        nested_num: 50,
410
 
                        undef: undefined,
411
 
                        alpha: "abc"
412
 
                    },
413
 
                    arr: [1, 7, 2]
414
 
                },
415
 
                function (k,v) {
416
 
                    var t = typeof v;
417
 
 
418
 
                    if (k === 'change') {
419
 
                        // this property should then be ignored
420
 
                        return function () {};
421
 
                    } else if (k === 'ignore') {
422
 
                        // this property should then be ignored
423
 
                        return undefined;
424
 
                    } else if (t === 'number') {
425
 
                        // undefined returned to arrays should become null
426
 
                        return v % 7 ? v * 2 : undefined;
427
 
 
428
 
                    // this refers to the object containing the key:value
429
 
                    } else if (t === 'string' && (this.toUpper)) {
430
 
                        // modify the object during stringification
431
 
                        delete this.toUpper;
432
 
                        return v.toUpperCase();
433
 
                    } else {
434
 
                        return v;
435
 
                    }
436
 
                }));
437
 
 
438
 
        // replacer works in conjunction with indent
439
 
        Y.Assert.areSame("{\n_\"num\": 2,\n_\"alpha\": \"ABC\",\n_\"obj\": {\n__\"nested_num\": 100,\n__\"alpha\": \"abc\"\n_},\n_\"arr\": [\n__2,\n__null,\n__4\n_]\n}",
440
 
            Y.JSON.stringify({
441
 
                    num: 1,
442
 
                    alpha: "abc",
443
 
                    ignore: "me",
444
 
                    change: "to a function",
445
 
                    toUpper: true,
446
 
                    obj: {
447
 
                        nested_num: 50,
448
 
                        undef: undefined,
449
 
                        alpha: "abc"
450
 
                    },
451
 
                    arr: [1, 7, 2]
452
 
                },
453
 
                function (k,v) {
454
 
                    var t = typeof v;
455
 
 
456
 
                    if (k === 'change') {
457
 
                        // this property should then be ignored
458
 
                        return function () {};
459
 
                    } else if (k === 'ignore') {
460
 
                        // this property should then be ignored
461
 
                        return undefined;
462
 
                    } else if (t === 'number') {
463
 
                        // undefined returned to arrays should become null
464
 
                        return v % 7 ? v * 2 : undefined;
465
 
 
466
 
                    // this refers to the object containing the key:value
467
 
                    } else if (t === 'string' && (this.toUpper)) {
468
 
                        // modify the object during stringification
469
 
                        delete this.toUpper;
470
 
                        return v.toUpperCase();
471
 
                    } else {
472
 
                        return v;
473
 
                    }
474
 
                },'_'));
475
 
    },
476
 
 
477
 
    test_replacer_after_toJSON : function () {
478
 
        Y.Assert.areSame('{"a":"ABC"}',
479
 
            Y.JSON.stringify({a:{ toJSON: function () { return "abc"; } } },
480
 
                function (k,v) {
481
 
                    return typeof v === 'string' ? v.toUpperCase() : v;
482
 
                }));
483
 
 
484
 
        // Date instances in ES5 have toJSON that outputs toISOString, which
485
 
        // means the replacer should never receive a Date instance
486
 
        var str = Y.JSON.stringify([new Date()], function (k,v) {
487
 
            return (v instanceof Date) ? "X" : v;
488
 
        });
489
 
        Y.Assert.areSame(-1, str.indexOf("X"), "Date incorrectly received by replacer");
490
 
    },
491
 
 
492
 
    test_replacer_returning_Date : function () {
493
 
        var d = new Date(),
494
 
            ref = Y.JSON.stringify(d);
495
 
 
496
 
        Y.Assert.areSame('{"dt":'+ref+',"date_from_replacer":{}}',
497
 
            Y.JSON.stringify({ dt: d, date_from_replacer: 1 },
498
 
                function (k,v) {
499
 
                    return typeof v === 'number' ? d : v;
500
 
                }));
501
 
    }
502
 
}));
503
 
 
504
 
Y.Test.Runner.add(suite);