Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / webapp / base / js / base_unittest.js
blob7fd746f7c30c7f1949488b4653246159dd77c933
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 (function() {
7 'use strict';
9 var getRandomValuesStub = null;
11 QUnit.module('base', {
12   afterEach: function() {
13     if (getRandomValuesStub) {
14       getRandomValuesStub.restore();
15       getRandomValuesStub = null;
16     }
17   }
18 });
20 QUnit.test('mix(dest, src) should copy properties from |src| to |dest|',
21   function(assert) {
22     var src = { a: 'a', b: 'b'};
23     var dest = { c: 'c'};
25     base.mix(dest, src);
26     assert.deepEqual(dest, {a: 'a', b: 'b', c: 'c'});
27 });
29 QUnit.test('mix(dest, src) should not override property.', function(assert) {
30     var src = { a: 'a', b: 'b'};
31     var dest = { a: 'a2'};
32     base.mix(dest, src);
33     assert.equal(dest['a'], 'a2');
34     assert.equal(dest['b'], 'b');
35 });
37 QUnit.test('values(obj) should return an array containing the values of |obj|',
38   function(assert) {
39     var output = base.values({ a: 'a', b: 'b'});
41     assert.notEqual(output.indexOf('a'), -1, '"a" should be in the output');
42     assert.notEqual(output.indexOf('b'), -1, '"b" should be in the output');
43 });
45 QUnit.test('deepCopy(obj) should return null on NaN and undefined',
46   function(assert) {
47     assert.equal(base.deepCopy(NaN), null);
48     assert.equal(base.deepCopy(undefined), null);
49 });
51 QUnit.test('deepCopy(obj) should copy primitive types recursively',
52   function(assert) {
53     assert.equal(base.deepCopy(1), 1);
54     assert.equal(base.deepCopy('hello'), 'hello');
55     assert.equal(base.deepCopy(false), false);
56     assert.equal(base.deepCopy(null), null);
57     assert.deepEqual(base.deepCopy([1, 2]), [1, 2]);
58     assert.deepEqual(base.deepCopy({'key': 'value'}), {'key': 'value'});
59     assert.deepEqual(base.deepCopy(
60       {'key': {'key_nested': 'value_nested'}}),
61       {'key': {'key_nested': 'value_nested'}}
62     );
63     assert.deepEqual(base.deepCopy([1, [2, [3]]]), [1, [2, [3]]]);
64 });
66 QUnit.test('copyWithoutNullFields returns a new object',
67   function(assert) {
68     var obj = {
69       a: 'foo',
70       b: 42
71     };
72     var copy = base.copyWithoutNullFields(obj);
73     assert.notEqual(obj, copy);
74     assert.deepEqual(obj, copy);
75 });
77 QUnit.test('copyWithoutNullFields removes null and undefined fields',
78   function(assert) {
79     /** @const */
80     var obj = {
81       a: 'foo',
82       b: 42,
83       zero: 0,
84       emptyString: '',
85       nullField: null,
86       undefinedField: undefined
87     };
88     var copy = base.copyWithoutNullFields(obj);
89     assert.equal(copy['a'], obj['a']);
90     assert.equal(copy['b'], obj['b']);
91     assert.equal(copy['zero'], 0);
92     assert.equal(copy['emptyString'], '');
93     assert.ok(!('nullField' in copy));
94     assert.ok(!('undefinedField' in copy));
95 });
97 QUnit.test('copyWithoutNullFields(null) returns a new empty object',
98   function(assert) {
99     assert.deepEqual(
100         base.copyWithoutNullFields(null),
101         {});
102     assert.notEqual(
103         base.copyWithoutNullFields(null),
104         base.copyWithoutNullFields(null));
105     assert.deepEqual(
106         base.copyWithoutNullFields(undefined),
107         {});
108     assert.notEqual(
109         base.copyWithoutNullFields(undefined),
110         base.copyWithoutNullFields(undefined));
113 QUnit.test('isEmptyObject works',
114   function(assert) {
115     assert.ok(base.isEmptyObject({}));
116     assert.ok(!base.isEmptyObject({1: 1}));
117     assert.ok(!base.isEmptyObject({1:null}));
119     var obj = {1: 1};
120     delete obj[1];
121     assert.ok(base.isEmptyObject(obj));
125 QUnit.test('modify the original after deepCopy(obj) should not affect the copy',
126   function(assert) {
127     var original = [1, 2, 3, 4];
128     var copy = base.deepCopy(original);
129     original[2] = 1000;
130     assert.deepEqual(copy, [1, 2, 3, 4]);
133 QUnit.test('dispose(obj) should invoke the dispose method on |obj|',
134   function(assert) {
135     /**
136      * @constructor
137      * @implements {base.Disposable}
138      */
139     base.MockDisposable = function() {};
140     base.MockDisposable.prototype.dispose = sinon.spy();
142     var obj = new base.MockDisposable();
143     base.dispose(obj);
144     sinon.assert.called(obj.dispose);
147 QUnit.test('dispose(obj) should not crash if |obj| is null',
148   function(assert) {
149     assert.expect(0);
150     base.dispose(null);
153 QUnit.test(
154   'urljoin(url, opt_param) should return url if |opt_param| is missing',
155   function(assert) {
156     assert.equal(
157         base.urlJoin('http://www.chromium.org'), 'http://www.chromium.org');
160 QUnit.test('urljoin(url, opt_param) should urlencode |opt_param|',
161   function(assert) {
162     var result = base.urlJoin('http://www.chromium.org', {
163       a: 'a',
164       foo: 'foo',
165       escapist: ':/?#[]@$&+,;='
166     });
167     assert.equal(
168         result,
169         'http://www.chromium.org?a=a&foo=foo' +
170         '&escapist=%3A%2F%3F%23%5B%5D%40%24%26%2B%2C%3B%3D');
173 QUnit.test('escapeHTML(str) should escape special characters', function(assert){
174   assert.equal(
175     base.escapeHTML('<script>alert("hello")</script>'),
176     '&lt;script&gt;alert("hello")&lt;/script&gt;');
179 QUnit.test('Promise.sleep(delay,value) fulfills after delay', function(assert) {
180   var clock = this.clock;
181   var badPromise = new Promise(function() {});
182   var timeoutPromise = base.Promise.sleep(100, 'defaultValue');
183   var resolved = false;
184   timeoutPromise.then(function(value) {
185     resolved = true;
186   });
187   clock.tick(50);
188   return Promise.resolve().then(function() {
189     assert.ok(!resolved);
190     clock.tick(50);
191     return timeoutPromise;
192   }).then(function(/** string */ value) {
193     assert.equal(value, 'defaultValue');
194   });
197 QUnit.test('Promise.sleep(delay) should fulfill the promise after |delay|',
198   function(assert) {
199     var isCalled = false;
200     var clock = this.clock;
202     var promise = base.Promise.sleep(100).then(function(/** void */ value){
203       isCalled = true;
204       assert.ok(true, 'Promise.sleep() is fulfilled after delay.');
205       assert.strictEqual(value, undefined);
206     });
208     // Tick the clock for 2 seconds and check if the promise is fulfilled.
209     clock.tick(2);
211     // Promise fulfillment always occur on a new stack.  Therefore, we will run
212     // the verification in a requestAnimationFrame.
213     window.requestAnimationFrame(function(){
214       assert.ok(
215           !isCalled, 'Promise.sleep() should not be fulfilled prematurely.');
216       clock.tick(101);
217     });
219     return promise;
222 QUnit.test('Promise.negate should fulfill iff the promise does not.',
223   function(assert) {
224     return base.Promise.negate(Promise.reject())
225     .then(function() {
226       assert.ok(true);
227     }).catch(function() {
228       assert.ok(false);
229     }).then(function() {
230       return base.Promise.negate(Promise.resolve());
231     }).then(function() {
232       assert.ok(false);
233     }).catch(function() {
234       assert.ok(true);
235     });
238 QUnit.test('Promise.withTimeout resolves to default value', function(assert) {
239   var clock = this.clock;
240   var badPromise = new Promise(function() {});
241   var timeoutPromise = base.Promise.withTimeout(
242       badPromise, 100, 'defaultValue');
243   var resolved = false;
244   timeoutPromise.then(function(value) {
245     resolved = true;
246   });
247   clock.tick(50);
248   return Promise.resolve().then(function() {
249     assert.ok(!resolved);
250     clock.tick(50);
251     return timeoutPromise;
252   }).then(function(/** string */ value) {
253     assert.equal(value, 'defaultValue');
254   });
257 QUnit.test('Promise.withTimeout can be rejected', function(assert) {
258   var clock = this.clock;
259   var badPromise = new Promise(function() {});
260   var timeoutPromise = base.Promise.withTimeout(
261       badPromise, 100, Promise.reject('defaultValue'));
262   var resolved = false;
263   timeoutPromise.catch(function(value) {
264     resolved = true;
265   });
266   clock.tick(50);
267   return Promise.resolve().then(function() {
268     assert.ok(!resolved);
269     clock.tick(50);
270     return timeoutPromise;
271   }).then(function() {
272     assert.ok(false);
273   }).catch(function(value) {
274     assert.equal(value, 'defaultValue');
275   });
278 QUnit.test('Promise.withTimeout can resolve early', function(assert) {
279   var timeoutPromise = base.Promise.withTimeout(
280       Promise.resolve('originalValue'), 100, 'defaultValue');
281   return timeoutPromise.then(function(value) {
282     assert.equal(value, 'originalValue');
283   });
286 QUnit.test('Promise.withTimeout can reject early', function(assert) {
287   var timeoutPromise = base.Promise.withTimeout(
288       Promise.reject('error'), 100, 'defaultValue');
289   return timeoutPromise.catch(function(error) {
290     assert.equal(error, 'error');
291   });
294 QUnit.test('generateUuid generates a UUID', function(assert) {
295   getRandomValuesStub = sinon.stub(
296       window.crypto, 'getRandomValues', function(/** Uint16Array*/ out) {
297         for (var i = 0; i < out.length; i++) {
298           out[i] = i;
299         }
300       });
301   assert.equal(base.generateUuid(), '00000001-0002-0003-0004-000500060007');
304 QUnit.module('base.Deferred');
306 QUnit.test('resolve() should fulfill the underlying promise.', function(assert){
307   /** @returns {Promise} */
308   function async() {
309     var deferred = new base.Deferred();
310     deferred.resolve('bar');
311     return deferred.promise();
312   }
314   return async().then(function(/** string */ value){
315     assert.equal(value, 'bar');
316   }, function() {
317     assert.ok(false, 'The reject handler should not be invoked.');
318   });
321 QUnit.test('reject() should fail the underlying promise.', function(assert) {
322   /** @returns {Promise} */
323   function async() {
324     var deferred = new base.Deferred();
325     deferred.reject('bar');
326     return deferred.promise();
327   }
329   return async().then(function(){
330     assert.ok(false, 'The then handler should not be invoked.');
331   }, function(value) {
332     assert.equal(value, 'bar');
333   });
337 /** @type {base.EventSourceImpl} */
338 var source = null;
339 var listener = null;
341 QUnit.module('base.EventSource', {
342   beforeEach: function() {
343     source = new base.EventSourceImpl();
344     source.defineEvents(['foo', 'bar']);
345     listener = sinon.spy();
346     source.addEventListener('foo', listener);
347   },
348   afterEach: function() {
349     source = null;
350     listener = null;
351   }
354 QUnit.test('raiseEvent() should invoke the listener', function() {
355   source.raiseEvent('foo');
356   sinon.assert.called(listener);
359 QUnit.test(
360   'raiseEvent() should invoke the listener with the correct event data',
361   function(assert) {
362     var data = {
363       field: 'foo'
364     };
365     source.raiseEvent('foo', data);
366     sinon.assert.calledWith(listener, data);
369 QUnit.test(
370   'raiseEvent() should not invoke listeners that are added during raiseEvent',
371   function(assert) {
372     source.addEventListener('foo', function() {
373       source.addEventListener('foo', function() {
374         assert.ok(false);
375       });
376      assert.ok(true);
377     });
378     source.raiseEvent('foo');
381 QUnit.test('raiseEvent() should not invoke listeners of a different event',
382   function(assert) {
383     source.raiseEvent('bar');
384     sinon.assert.notCalled(listener);
387 QUnit.test('raiseEvent() should assert when undeclared events are raised',
388   function(assert) {
389     sinon.stub(console, 'assert');
390     try {
391       source.raiseEvent('undefined');
392     } catch (e) {
393     } finally {
394       sinon.assert.called(console.assert);
395       $testStub(console.assert).restore();
396     }
399 QUnit.test(
400   'removeEventListener() should not invoke the listener in subsequent ' +
401   'calls to |raiseEvent|',
402   function(assert) {
403     source.raiseEvent('foo');
404     sinon.assert.calledOnce(listener);
406     source.removeEventListener('foo', listener);
407     source.raiseEvent('foo');
408     sinon.assert.calledOnce(listener);
411 QUnit.test('removeEventListener() should work even if the listener ' +
412   'is removed during |raiseEvent|',
413   function(assert) {
414     var sink = {};
415     sink.listener = sinon.spy(function() {
416       source.removeEventListener('foo', sink.listener);
417     });
419     source.addEventListener('foo', sink.listener);
420     source.raiseEvent('foo');
421     sinon.assert.calledOnce(sink.listener);
423     source.raiseEvent('foo');
424     sinon.assert.calledOnce(sink.listener);
427 QUnit.test('encodeUtf8() can encode UTF8 strings', function(assert) {
428   /** @type {function(ArrayBuffer):Array} */
429   function toJsArray(arrayBuffer) {
430     var result = [];
431     var array = new Uint8Array(arrayBuffer);
432     for (var i = 0; i < array.length; ++i) {
433       result.push(array[i]);
434     }
435     return result;
436   }
438   // ASCII.
439   assert.deepEqual(toJsArray(base.encodeUtf8("ABC")), [0x41, 0x42, 0x43]);
441   // Some arbitrary characters from the basic Unicode plane.
442   assert.deepEqual(
443       toJsArray(base.encodeUtf8("挂Ѓф")),
444       [/* 挂 */ 0xE6, 0x8C, 0x82, /* Ѓ */ 0xD0, 0x83, /* ф */ 0xD1, 0x84]);
446   // Unicode surrogate pair for U+1F603.
447   assert.deepEqual(toJsArray(base.encodeUtf8("😃")),
448                   [0xF0, 0x9F, 0x98, 0x83]);
451 QUnit.test('decodeUtf8() can decode UTF8 strings', function(assert) {
452   // ASCII.
453   assert.equal(base.decodeUtf8(new Uint8Array([0x41, 0x42, 0x43]).buffer),
454               "ABC");
456   // Some arbitrary characters from the basic Unicode plane.
457   assert.equal(
458       base.decodeUtf8(
459           new Uint8Array([/* 挂 */ 0xE6, 0x8C, 0x82,
460                           /* Ѓ */ 0xD0, 0x83,
461                           /* ф */ 0xD1, 0x84]).buffer),
462       "挂Ѓф");
464   // Unicode surrogate pair for U+1F603.
465   assert.equal(base.decodeUtf8(new Uint8Array([0xF0, 0x9F, 0x98, 0x83]).buffer),
466               "😃");
469 })();