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.
9 var getRandomValuesStub = null;
11 QUnit.module('base', {
12 afterEach: function() {
13 if (getRandomValuesStub) {
14 getRandomValuesStub.restore();
15 getRandomValuesStub = null;
20 QUnit.test('mix(dest, src) should copy properties from |src| to |dest|',
22 var src = { a: 'a', b: 'b'};
26 assert.deepEqual(dest, {a: 'a', b: 'b', c: 'c'});
29 QUnit.test('mix(dest, src) should not override property.', function(assert) {
30 var src = { a: 'a', b: 'b'};
31 var dest = { a: 'a2'};
33 assert.equal(dest['a'], 'a2');
34 assert.equal(dest['b'], 'b');
37 QUnit.test('values(obj) should return an array containing the values of |obj|',
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');
45 QUnit.test('deepCopy(obj) should return null on NaN and undefined',
47 assert.equal(base.deepCopy(NaN), null);
48 assert.equal(base.deepCopy(undefined), null);
51 QUnit.test('deepCopy(obj) should copy primitive types recursively',
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'}}
63 assert.deepEqual(base.deepCopy([1, [2, [3]]]), [1, [2, [3]]]);
66 QUnit.test('copyWithoutNullFields returns a new object',
72 var copy = base.copyWithoutNullFields(obj);
73 assert.notEqual(obj, copy);
74 assert.deepEqual(obj, copy);
77 QUnit.test('copyWithoutNullFields removes null and undefined fields',
86 undefinedField: undefined
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));
97 QUnit.test('copyWithoutNullFields(null) returns a new empty object',
100 base.copyWithoutNullFields(null),
103 base.copyWithoutNullFields(null),
104 base.copyWithoutNullFields(null));
106 base.copyWithoutNullFields(undefined),
109 base.copyWithoutNullFields(undefined),
110 base.copyWithoutNullFields(undefined));
113 QUnit.test('isEmptyObject works',
115 assert.ok(base.isEmptyObject({}));
116 assert.ok(!base.isEmptyObject({1: 1}));
117 assert.ok(!base.isEmptyObject({1:null}));
121 assert.ok(base.isEmptyObject(obj));
125 QUnit.test('modify the original after deepCopy(obj) should not affect the copy',
127 var original = [1, 2, 3, 4];
128 var copy = base.deepCopy(original);
130 assert.deepEqual(copy, [1, 2, 3, 4]);
133 QUnit.test('dispose(obj) should invoke the dispose method on |obj|',
137 * @implements {base.Disposable}
139 base.MockDisposable = function() {};
140 base.MockDisposable.prototype.dispose = sinon.spy();
142 var obj = new base.MockDisposable();
144 sinon.assert.called(obj.dispose);
147 QUnit.test('dispose(obj) should not crash if |obj| is null',
154 'urljoin(url, opt_param) should return url if |opt_param| is missing',
157 base.urlJoin('http://www.chromium.org'), 'http://www.chromium.org');
160 QUnit.test('urljoin(url, opt_param) should urlencode |opt_param|',
162 var result = base.urlJoin('http://www.chromium.org', {
165 escapist: ':/?#[]@$&+,;='
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){
175 base.escapeHTML('<script>alert("hello")</script>'),
176 '<script>alert("hello")</script>');
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) {
188 return Promise.resolve().then(function() {
189 assert.ok(!resolved);
191 return timeoutPromise;
192 }).then(function(/** string */ value) {
193 assert.equal(value, 'defaultValue');
197 QUnit.test('Promise.sleep(delay) should fulfill the promise after |delay|',
199 var isCalled = false;
200 var clock = this.clock;
202 var promise = base.Promise.sleep(100).then(function(/** void */ value){
204 assert.ok(true, 'Promise.sleep() is fulfilled after delay.');
205 assert.strictEqual(value, undefined);
208 // Tick the clock for 2 seconds and check if the promise is fulfilled.
211 // Promise fulfillment always occur on a new stack. Therefore, we will run
212 // the verification in a requestAnimationFrame.
213 window.requestAnimationFrame(function(){
215 !isCalled, 'Promise.sleep() should not be fulfilled prematurely.');
222 QUnit.test('Promise.negate should fulfill iff the promise does not.',
224 return base.Promise.negate(Promise.reject())
227 }).catch(function() {
230 return base.Promise.negate(Promise.resolve());
233 }).catch(function() {
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) {
248 return Promise.resolve().then(function() {
249 assert.ok(!resolved);
251 return timeoutPromise;
252 }).then(function(/** string */ value) {
253 assert.equal(value, 'defaultValue');
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) {
267 return Promise.resolve().then(function() {
268 assert.ok(!resolved);
270 return timeoutPromise;
273 }).catch(function(value) {
274 assert.equal(value, 'defaultValue');
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');
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');
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++) {
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} */
309 var deferred = new base.Deferred();
310 deferred.resolve('bar');
311 return deferred.promise();
314 return async().then(function(/** string */ value){
315 assert.equal(value, 'bar');
317 assert.ok(false, 'The reject handler should not be invoked.');
321 QUnit.test('reject() should fail the underlying promise.', function(assert) {
322 /** @returns {Promise} */
324 var deferred = new base.Deferred();
325 deferred.reject('bar');
326 return deferred.promise();
329 return async().then(function(){
330 assert.ok(false, 'The then handler should not be invoked.');
332 assert.equal(value, 'bar');
337 /** @type {base.EventSourceImpl} */
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);
348 afterEach: function() {
354 QUnit.test('raiseEvent() should invoke the listener', function() {
355 source.raiseEvent('foo');
356 sinon.assert.called(listener);
360 'raiseEvent() should invoke the listener with the correct event data',
365 source.raiseEvent('foo', data);
366 sinon.assert.calledWith(listener, data);
370 'raiseEvent() should not invoke listeners that are added during raiseEvent',
372 source.addEventListener('foo', function() {
373 source.addEventListener('foo', function() {
378 source.raiseEvent('foo');
381 QUnit.test('raiseEvent() should not invoke listeners of a different event',
383 source.raiseEvent('bar');
384 sinon.assert.notCalled(listener);
387 QUnit.test('raiseEvent() should assert when undeclared events are raised',
389 sinon.stub(console, 'assert');
391 source.raiseEvent('undefined');
394 sinon.assert.called(console.assert);
395 $testStub(console.assert).restore();
400 'removeEventListener() should not invoke the listener in subsequent ' +
401 'calls to |raiseEvent|',
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|',
415 sink.listener = sinon.spy(function() {
416 source.removeEventListener('foo', sink.listener);
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) {
431 var array = new Uint8Array(arrayBuffer);
432 for (var i = 0; i < array.length; ++i) {
433 result.push(array[i]);
439 assert.deepEqual(toJsArray(base.encodeUtf8("ABC")), [0x41, 0x42, 0x43]);
441 // Some arbitrary characters from the basic Unicode plane.
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) {
453 assert.equal(base.decodeUtf8(new Uint8Array([0x41, 0x42, 0x43]).buffer),
456 // Some arbitrary characters from the basic Unicode plane.
459 new Uint8Array([/* 挂 */ 0xE6, 0x8C, 0x82,
461 /* ф */ 0xD1, 0x84]).buffer),
464 // Unicode surrogate pair for U+1F603.
465 assert.equal(base.decodeUtf8(new Uint8Array([0xF0, 0x9F, 0x98, 0x83]).buffer),