Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / core / test / unit / spec / lang / Object.js
1 describe("Ext.Object", function(){
2
3     describe("getKeys", function(){
4         var getKeys = Ext.Object.getKeys;
5         it("should return an empty array for a null value", function(){
6             expect(getKeys(null)).toEqual([]);
7         });
8
9         it("should return an empty array for an empty object", function(){
10             expect(getKeys({})).toEqual([]);
11         });
12
13         it("should return all the keys in the object", function(){
14             expect(getKeys({
15                 foo: 1,
16                 bar: 2,
17                 baz: 3
18             })).toEqual(['foo', 'bar', 'baz']);
19         });
20     });
21
22     describe("getValues", function(){
23         var getValues = Ext.Object.getValues;
24         it("should return an empty array for a null value", function(){
25             expect(getValues(null)).toEqual([]);
26         });
27
28         it("should return an empty array for an empty object", function(){
29             expect(getValues({})).toEqual([]);
30         });
31
32         it("should return all the values in the object", function(){
33             expect(getValues({
34                 foo: 1,
35                 bar: 2,
36                 baz: 3
37             })).toEqual([1, 2, 3]);
38         });
39     });
40
41     describe("getKey", function(){
42         var getKey = Ext.Object.getKey;
43
44         it("should return null for a null object", function(){
45             expect(getKey(null, 'foo')).toBeNull();
46         });
47
48         it("should return null for an empty object", function(){
49             expect(getKey({}, 'foo')).toBeNull();
50         });
51
52         it("should return null if the value doesn't exist", function(){
53             expect(getKey({
54                 foo: 1,
55                 bar: 2
56             }, 3)).toBeNull();
57         });
58
59         it("should only do strict matching", function(){
60             expect(getKey({
61                 foo: 1
62             }, '1')).toBeNull();
63         });
64
65         it("should return the correct key if it matches", function(){
66             expect(getKey({
67                 foo: 1
68             }, 1)).toEqual('foo');
69         });
70
71         it("should only return the first matched value", function(){
72             expect(getKey({
73                 bar: 1,
74                 foo: 1
75             }, 1)).toEqual('bar');
76         });
77     });
78
79     describe("each", function(){
80         var each = Ext.Object.each;
81
82         describe("scope/params", function(){
83             it("should execute using the passed scope", function(){
84                 var scope = {},
85                     actual;
86
87                 each({
88                     foo: 1,
89                     bar: 'value',
90                     baz: false
91                 }, function(){
92                     actual = this;
93                 }, scope);
94                 expect(actual).toBe(scope);
95             });
96
97             it("should default the scope to the object", function(){
98                 var o = {
99                     foo: 1,
100                     bar: 'value',
101                     baz: false
102                 }, actual;
103
104                 each(o, function(){
105                     actual = this;
106                 });
107                 expect(actual).toBe(o);
108             });
109
110             it("should execute passing the key value and object", function(){
111                 var keys = [],
112                     values = [],
113                     data = {
114                         foo: 1,
115                         bar: 'value',
116                         baz: false
117                     },
118                     obj;
119
120                 each(data, function(key, value, o){
121                     keys.push(key);
122                     values.push(value);
123                     obj = o;
124                 });
125
126                 expect(keys).toEqual(['foo', 'bar', 'baz']);
127                 expect(values).toEqual([1, 'value', false]);
128                 expect(obj).toBe(data);
129             });
130         });
131
132         describe("stopping", function(){
133             it("should not stop by default", function(){
134                 var count = 0;
135                 each({
136                     a: 1,
137                     b: 2,
138                     c: 3,
139                     d: 4
140                 }, function(){
141                     ++count;
142                 });
143                 expect(count).toEqual(4);
144             });
145
146             it("should only stop if the function returns false", function(){
147                 var count = 0;
148                 each({
149                     a: 1,
150                     b: 2,
151                     c: 3,
152                     d: 4
153                 }, function(){
154                     ++count;
155                     return null;
156                 });
157                 expect(count).toEqual(4);
158             });
159
160             it("should stop immediately when false is returned", function(){
161                 var count = 0;
162                 each({
163                     a: 1,
164                     b: 2,
165                     c: 3,
166                     d: 4
167                 }, function(key){
168                     ++count;
169                     return key != 'b';
170                 });
171                 expect(count).toEqual(2);
172             });
173         });
174     });
175
176     describe("toQueryString", function(){
177         var toQueryString = Ext.Object.toQueryString;
178
179         describe("defaults", function(){
180             it("should return an empty string for a null object", function(){
181                 expect(toQueryString(null)).toEqual('');
182             });
183
184             it("should return an empty string for an empty object", function(){
185                 expect(toQueryString({})).toEqual('');
186             });
187         });
188
189         describe("simple values", function(){
190             it("should separate a property/value by an =", function(){
191                 expect(toQueryString({
192                     foo: 1
193                 })).toEqual('foo=1');
194             });
195
196             it("should separate pairs by an &", function(){
197                 expect(toQueryString({
198                     foo: 1,
199                     bar: 2
200                 })).toEqual('foo=1&bar=2');
201             });
202
203             it("should handle properties with empty values", function(){
204                 expect(toQueryString({
205                     foo: null
206                 })).toEqual('foo=');
207             });
208
209             it("should encode dates", function(){
210                 var d = new Date(2011, 0, 1);
211                 expect(toQueryString({
212                     foo: d
213                 })).toEqual('foo=2011-01-01T00%3A00%3A00');
214             });
215
216             it("should url encode the key", function(){
217                 expect(toQueryString({
218                     'a prop': 1
219                 })).toEqual('a%20prop=1');
220             });
221
222             it("should url encode the value", function(){
223                 expect(toQueryString({
224                     prop: '$300 & 5 cents'
225                 })).toEqual('prop=%24300%20%26%205%20cents');
226             });
227
228             it("should encode both key and value at the same time", function(){
229                expect(toQueryString({
230                    'a prop': '$300'
231                })).toEqual('a%20prop=%24300');
232             });
233         });
234
235         describe("arrays", function(){
236             it("should support an array value", function(){
237                 expect(toQueryString({
238                     foo: [1, 2, 3]
239                 })).toEqual('foo=1&foo=2&foo=3');
240             });
241
242             it("should be able to support multiple arrays", function(){
243                 expect(toQueryString({
244                     foo: [1, 2],
245                     bar: [3, 4]
246                 })).toEqual('foo=1&foo=2&bar=3&bar=4');
247             });
248
249             it("should be able to mix arrays and normal values", function(){
250                 expect(toQueryString({
251                     foo: 'val1',
252                     bar: ['val2', 'val3'],
253                     baz: 'val4'
254                 })).toEqual('foo=val1&bar=val2&bar=val3&baz=val4');
255             });
256         });
257
258         describe("recursive", function() {
259             it("should support both nested arrays and objects", function() {
260                 expect(decodeURIComponent(Ext.Object.toQueryString({
261                     username: 'Jacky',
262                     dateOfBirth: {
263                         day: 1,
264                         month: 2,
265                         year: 1911
266                     },
267                     hobbies: ['coding', 'eating', 'sleeping', [1,2]]
268                 }, true))).toEqual('username=Jacky&dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=1&hobbies[3][1]=2')
269             })
270         });
271
272     });
273
274     describe("merge", function(){
275         var merge = Ext.Object.merge;
276
277         describe("simple values", function(){
278             it("should copy over numeric values", function(){
279                 expect(merge({}, 'prop1', 1)).toEqual({
280                     prop1: 1
281                 });
282             });
283
284             it("should copy over string values", function(){
285                 expect(merge({}, 'prop1', 'val')).toEqual({
286                     prop1: 'val'
287                 });
288             });
289
290             it("should copy over boolean values", function(){
291                 expect(merge({}, 'prop1', true)).toEqual({
292                     prop1: true
293                 });
294             });
295
296             it("should copy over null values", function(){
297                 expect(merge({}, 'prop1', null)).toEqual({
298                     prop1: null
299                 });
300             });
301         });
302
303         describe("complex values", function(){
304             it("should copy a simple object but not have the same reference", function(){
305                 var o = {
306                     foo: 'prop',
307                     tada: {
308                         blah: 'bleh'
309                     }
310                 }, result = merge({}, 'prop', o);
311
312                 expect(result.prop).toEqual({
313                     foo: 'prop',
314                     tada: {
315                         blah: 'bleh'
316                     }
317                 });
318                 expect(result.prop).not.toBe(o);
319             });
320
321             it("should NOT merge an instance (the constructor of which is not Object)", function(){
322                 var o = new Ext.Base(),
323                     result = merge({}, 'prop1', o);
324
325                 expect(result.prop1).toBe(o);
326             });
327         });
328
329         describe("overwriting properties", function(){
330             it("should merge objects if an object exists on the source and the passed value is an object literal", function(){
331                 expect(merge({
332                     prop: {
333                         foo: 1
334                     }
335                 }, 'prop', {
336                     bar: 2
337                 })).toEqual({
338                     prop: {
339                         foo: 1,
340                         bar: 2
341                     }
342                 });
343             });
344
345             it("should copy an object reference if an object exists on the source and the passed value is some kind of class", function(){
346                 var o = new Ext.Base(),
347                     result = merge({
348                         prop: {}
349                     }, 'prop', o);
350
351                 expect(result).toEqual({
352                     prop: o
353                 });
354                 expect(result.prop).toBe(o);
355             });
356
357             it("should replace the value of the target object if it is not an object", function(){
358                 var o = new Ext.Base(),
359                     result = merge({
360                         prop: 1
361                     }, 'prop', o);
362
363                 expect(result.prop).toEqual(o);
364                 expect(result.prop).toBe(o);
365             });
366
367             it("should overwrite simple values", function(){
368                 expect(merge({
369                     prop: 1
370                 }, 'prop', 2)).toEqual({
371                     prop: 2
372                 });
373             });
374         });
375
376         describe("merging objects", function(){
377             it("should merge objects", function(){
378                 expect(merge({}, {
379                     foo: 1
380                 })).toEqual({
381                     foo: 1
382                 });
383             });
384
385             it("should merge left to right", function(){
386                 expect(merge({}, {
387                     foo: 1
388                 }, {
389                     foo: 2
390                 }, {
391                     foo: 3
392                 })).toEqual({
393                     foo: 3
394                 })
395             });
396         });
397
398         it("should modify and return the source", function(){
399             var o = {},
400                 result = merge(o, 'foo', 'bar');
401
402             expect(result.foo).toEqual('bar');
403             expect(result).toBe(o);
404
405         });
406     });
407
408     describe("toQueryObjects", function() {
409         var object = {
410             username: 'Jacky',
411             dateOfBirth: {
412                 day: 1,
413                 month: 2,
414                 year: 1911
415             },
416             hobbies: ['coding', 'eating', 'sleeping', [1,2,3]]
417         };
418
419         it("simple key value", function() {
420             expect(Ext.Object.toQueryObjects('username', 'Jacky')).toEqual([
421                 {
422                     name: 'username',
423                     value: 'Jacky'
424                 }
425             ]);
426         });
427
428         it("non-recursive array", function() {
429             expect(Ext.Object.toQueryObjects('hobbies', ['eating', 'sleeping', 'coding'])).toEqual([
430                 {
431                     name: 'hobbies',
432                     value: 'eating'
433                 },
434                 {
435                     name: 'hobbies',
436                     value: 'sleeping'
437                 },
438                 {
439                     name: 'hobbies',
440                     value: 'coding'
441                 }
442             ]);
443         });
444
445         it("recursive object", function() {
446             expect(Ext.Object.toQueryObjects('dateOfBirth', {
447                 day: 1,
448                 month: 2,
449                 year: 1911,
450                 somethingElse: {
451                     nested: {
452                         very: 'very',
453                         deep: {
454                             inHere: true
455                         }
456                     }
457                 }
458             }, true)).toEqual([
459                 {
460                     name: 'dateOfBirth[day]',
461                     value: 1
462                 },
463                 {
464                     name: 'dateOfBirth[month]',
465                     value: 2
466                 },
467                 {
468                     name: 'dateOfBirth[year]',
469                     value: 1911
470                 },
471                 {
472                     name: 'dateOfBirth[somethingElse][nested][very]',
473                     value: 'very'
474                 },
475                 {
476                     name: 'dateOfBirth[somethingElse][nested][deep][inHere]',
477                     value: true
478                 }
479             ]);
480         });
481
482         it("recursive array", function() {
483             expect(Ext.Object.toQueryObjects('hobbies', [
484                 'eating', 'sleeping', 'coding', ['even', ['more']]
485             ], true)).toEqual([
486                 {
487                     name: 'hobbies[0]',
488                     value: 'eating'
489                 },
490                 {
491                     name: 'hobbies[1]',
492                     value: 'sleeping'
493                 },
494                 {
495                     name: 'hobbies[2]',
496                     value: 'coding'
497                 },
498                 {
499                     name: 'hobbies[3][0]',
500                     value: 'even'
501                 },
502                 {
503                     name: 'hobbies[3][1][0]',
504                     value: 'more'
505                 }
506             ]);
507         });
508     });
509
510     describe("fromQueryString", function() {
511         var fromQueryString = Ext.Object.fromQueryString;
512
513         describe("standard mode", function() {
514             it("empty string", function(){
515                 expect(fromQueryString('')).toEqual({});
516             });
517
518             it("simple single key value pair", function(){
519                 expect(fromQueryString('name=Jacky')).toEqual({name: 'Jacky'});
520             });
521
522             it("simple single key value pair with empty value", function(){
523                 expect(fromQueryString('name=')).toEqual({name: ''});
524             });
525
526             it("multiple key value pairs", function(){
527                 expect(fromQueryString('name=Jacky&loves=food')).toEqual({name: 'Jacky', loves: 'food'});
528             });
529
530             it("multiple key value pairs with URI encoded component", function(){
531                 expect(fromQueryString('a%20property=%24300%20%26%205%20cents')).toEqual({'a property': '$300 & 5 cents'});
532             });
533
534             it("simple array", function(){
535                 expect(fromQueryString('foo=1&foo=2&foo=3')).toEqual({foo: ['1', '2', '3']});
536             });
537         });
538
539         describe("recursive mode", function() {
540             it("empty string", function(){
541                 expect(fromQueryString('', true)).toEqual({});
542             });
543
544             it("simple single key value pair", function(){
545                 expect(fromQueryString('name=Jacky', true)).toEqual({name: 'Jacky'});
546             });
547
548             it("simple single key value pair with empty value", function(){
549                 expect(fromQueryString('name=', true)).toEqual({name: ''});
550             });
551
552             it("multiple key value pairs", function(){
553                 expect(fromQueryString('name=Jacky&loves=food', true)).toEqual({name: 'Jacky', loves: 'food'});
554             });
555
556             it("multiple key value pairs with URI encoded component", function(){
557                 expect(fromQueryString('a%20property=%24300%20%26%205%20cents', true)).toEqual({'a property': '$300 & 5 cents'});
558             });
559
560             it("simple array (last value with the same name will overwrite previous value)", function(){
561                 expect(fromQueryString('foo=1&foo=2&foo=3', true)).toEqual({foo: '3'});
562             });
563
564             it("simple array with empty brackets", function(){
565                 expect(fromQueryString('foo[]=1&foo[]=2&foo[]=3', true)).toEqual({foo: ['1', '2', '3']});
566             });
567
568             it("simple array with non-empty brackets", function(){
569                 expect(fromQueryString('foo[0]=1&foo[1]=2&foo[2]=3', true)).toEqual({foo: ['1', '2', '3']});
570             });
571
572             it("simple array with non-empty brackets and non sequential keys", function(){
573                 expect(fromQueryString('foo[3]=1&foo[1]=2&foo[2]=3&foo[0]=0', true)).toEqual({foo: ['0', '2', '3', '1']});
574             });
575
576             it("simple array with non-empty brackets and non sequential keys and holes", function(){
577                 expect(fromQueryString('foo[3]=1&foo[1]=2&foo[2]=3', true)).toEqual({foo: [undefined, '2', '3', '1']});
578             });
579
580             it("nested array", function(){
581                 expect(fromQueryString('some[0][0]=stuff&some[0][1]=morestuff&some[0][]=otherstuff&some[1]=thingelse', true)).toEqual({
582                     some: [
583                         ['stuff', 'morestuff', 'otherstuff'],
584                         'thingelse'
585                     ]
586                 });
587             });
588
589             it("nested object", function(){
590                 expect(fromQueryString('dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&dateOfBirth[extra][hour]=4&dateOfBirth[extra][minute]=30', true)).toEqual({
591                     dateOfBirth: {
592                         day: '1',
593                         month: '2',
594                         year: '1911',
595                         extra: {
596                             hour: '4',
597                             minute: '30'
598                         }
599                     }
600                 });
601             });
602
603             it("nested mixed types", function(){
604                 expect(fromQueryString('username=Jacky&dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff', true)).toEqual({
605                     username: 'Jacky',
606                     dateOfBirth: {
607                         day: '1',
608                         month: '2',
609                         year: '1911'
610                     },
611                     hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
612                 });
613             });
614         });
615     });
616
617 });