Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / remoting / webapp / unittests / base_unittest.js
blob6ffc8c90b4b3b811b3620807a776c1f1cee9f8ed
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 module('base');
11 test('mix(dest, src) should copy properties from |src| to |dest|',
12   function() {
13     var src = { a: 'a', b: 'b'};
14     var dest = { c: 'c'};
16     base.mix(dest, src);
17     deepEqual(dest, {a: 'a', b: 'b', c: 'c'});
18 });
20 test('mix(dest, src) should assert if properties are overwritten',
21   function() {
22     var src = { a: 'a', b: 'b'};
23     var dest = { a: 'a'};
25     sinon.spy(base.debug, 'assert');
27     try {
28       base.mix(dest, src);
29     } catch (e) {
30     } finally {
31       sinon.assert.called(base.debug.assert);
32       base.debug.assert.restore();
33     }
34 });
36 test('values(obj) should return an array containing the values of |obj|',
37   function() {
38     var output = base.values({ a: 'a', b: 'b'});
40     notEqual(output.indexOf('a'), -1, '"a" should be in the output');
41     notEqual(output.indexOf('b'), -1, '"b" should be in the output');
42 });
44 test('deepCopy(obj) should return null on NaN and undefined',
45   function() {
46     QUnit.equal(base.deepCopy(NaN), null);
47     QUnit.equal(base.deepCopy(undefined), null);
48 });
50 test('deepCopy(obj) should copy primitive types recursively',
51   function() {
52     QUnit.equal(base.deepCopy(1), 1);
53     QUnit.equal(base.deepCopy('hello'), 'hello');
54     QUnit.equal(base.deepCopy(false), false);
55     QUnit.equal(base.deepCopy(null), null);
56     QUnit.deepEqual(base.deepCopy([1, 2]), [1, 2]);
57     QUnit.deepEqual(base.deepCopy({'key': 'value'}), {'key': 'value'});
58     QUnit.deepEqual(base.deepCopy(
59       {'key': {'key_nested': 'value_nested'}}),
60       {'key': {'key_nested': 'value_nested'}}
61     );
62     QUnit.deepEqual(base.deepCopy([1, [2, [3]]]), [1, [2, [3]]]);
63 });
65 test('modify the original after deepCopy(obj) should not affect the copy',
66   function() {
67     var original = [1, 2, 3, 4];
68     var copy = base.deepCopy(original);
69     original[2] = 1000;
70     QUnit.deepEqual(copy, [1, 2, 3, 4]);
71 });
73 test('dispose(obj) should invoke the dispose method on |obj|',
74   function() {
75     var obj = {
76       dispose: sinon.spy()
77     };
78     base.dispose(obj);
79     sinon.assert.called(obj.dispose);
80 });
82 test('dispose(obj) should not crash if |obj| is null',
83   function() {
84     expect(0);
85     base.dispose(null);
86 });
88 test('urljoin(url, opt_param) should return url if |opt_param| is missing',
89   function() {
90     QUnit.equal(
91         base.urlJoin('http://www.chromium.org'), 'http://www.chromium.org');
92 });
94 test('urljoin(url, opt_param) should urlencode |opt_param|',
95   function() {
96     var result = base.urlJoin('http://www.chromium.org', {
97       a: 'a',
98       foo: 'foo',
99       escapist: ':/?#[]@$&+,;='
100     });
101     QUnit.equal(
102         result,
103         'http://www.chromium.org?a=a&foo=foo' +
104         '&escapist=%3A%2F%3F%23%5B%5D%40%24%26%2B%2C%3B%3D');
107 test('escapeHTML(str) should escape special characters', function() {
108   QUnit.equal(
109     base.escapeHTML('<script>alert("hello")</script>'),
110     '&lt;script&gt;alert("hello")&lt;/script&gt;');
113 QUnit.asyncTest('Promise.sleep(delay) should fulfill the promise after |delay|',
114   function() {
115     var isCalled = false;
116     var clock = this.clock;
118     base.Promise.sleep(100).then(function(){
119       isCalled = true;
120       ok(true, 'Promise.sleep() is fulfilled after delay.');
121       QUnit.start();
122     });
124     // Tick the clock for 2 seconds and check if the promise is fulfilled.
125     clock.tick(2);
127     // Promise fulfillment always occur on a new stack.  Therefore, we will run
128     // the verification in a requestAnimationFrame.
129     window.requestAnimationFrame(function(){
130       ok(!isCalled, 'Promise.sleep() should not be fulfilled prematurely.');
131       clock.tick(101);
132     }.bind(this));
135 QUnit.asyncTest('Promise.negate should fulfill iff the promise does not.',
136   function() {
138     base.Promise.negate(Promise.reject()).then(
139         ok.bind(null, true),
140         ok.bind(null, false));
141     base.Promise.negate(Promise.resolve()).then(
142         ok.bind(null, false),
143         ok.bind(null, true));
144     window.requestAnimationFrame(function(){
145       QUnit.start();
146     });
149 module('base.Deferred');
151 QUnit.asyncTest('resolve() should fulfill the underlying promise.', function() {
152   function async() {
153     var deferred = new base.Deferred();
154     deferred.resolve('bar');
155     return deferred.promise();
156   }
158   async().then(function(value){
159     QUnit.equal(value, 'bar');
160     QUnit.start();
161   }, function() {
162     QUnit.ok(false, 'The reject handler should not be invoked.');
163   });
166 QUnit.asyncTest('reject() should fail the underlying promise.', function() {
167   function async() {
168     var deferred = new base.Deferred();
169     deferred.reject('bar');
170     return deferred.promise();
171   }
173   async().then(function(){
174     QUnit.ok(false, 'The then handler should not be invoked.');
175   }, function(value) {
176     QUnit.equal(value, 'bar');
177     QUnit.start();
178   });
182 var source = null;
183 var listener = null;
185 module('base.EventSource', {
186   setup: function() {
187     source = new base.EventSourceImpl();
188     source.defineEvents(['foo', 'bar']);
189     listener = sinon.spy();
190     source.addEventListener('foo', listener);
191   },
192   teardown: function() {
193     source = null;
194     listener = null;
195   }
198 test('raiseEvent() should invoke the listener', function() {
199   source.raiseEvent('foo');
200   sinon.assert.called(listener);
203 test('raiseEvent() should invoke the listener with the correct event data',
204   function() {
205     var data = {
206       field: 'foo'
207     };
208     source.raiseEvent('foo', data);
209     sinon.assert.calledWith(listener, data);
212 test(
213   'raiseEvent() should not invoke listeners that are added during raiseEvent',
214   function() {
215     source.addEventListener('foo', function() {
216       source.addEventListener('foo', function() {
217         ok(false);
218       });
219       ok(true);
220     });
221     source.raiseEvent('foo');
224 test('raiseEvent() should not invoke listeners of a different event',
225   function() {
226     source.raiseEvent('bar');
227     sinon.assert.notCalled(listener);
230 test('raiseEvent() should assert when undeclared events are raised',
231   function() {
232     sinon.spy(base.debug, 'assert');
233     try {
234       source.raiseEvent('undefined');
235     } catch (e) {
236     } finally {
237       sinon.assert.called(base.debug.assert);
238       base.debug.assert.restore();
239     }
242 test(
243   'removeEventListener() should not invoke the listener in subsequent ' +
244   'calls to |raiseEvent|',
245   function() {
246     source.raiseEvent('foo');
247     sinon.assert.calledOnce(listener);
249     source.removeEventListener('foo', listener);
250     source.raiseEvent('foo');
251     sinon.assert.calledOnce(listener);
254 test('removeEventListener() should work even if the listener ' +
255   'is removed during |raiseEvent|',
256   function() {
257     var sink = {};
258     sink.listener = sinon.spy(function() {
259       source.removeEventListener('foo', sink.listener);
260     });
262     source.addEventListener('foo', sink.listener);
263     source.raiseEvent('foo');
264     sinon.assert.calledOnce(sink.listener);
266     source.raiseEvent('foo');
267     sinon.assert.calledOnce(sink.listener);
270 test('encodeUtf8() can encode UTF8 strings', function() {
271   function toJsArray(arrayBuffer) {
272     var result = [];
273     var array = new Uint8Array(arrayBuffer);
274     for (var i = 0; i < array.length; ++i) {
275       result.push(array[i]);
276     }
277     return result;
278   }
280   // ASCII.
281   QUnit.deepEqual(toJsArray(base.encodeUtf8("ABC")), [0x41, 0x42, 0x43]);
283   // Some arbitrary characters from the basic Unicode plane.
284   QUnit.deepEqual(
285       toJsArray(base.encodeUtf8("挂Ѓф")),
286       [/* 挂 */ 0xE6, 0x8C, 0x82, /* Ѓ */ 0xD0, 0x83, /* ф */ 0xD1, 0x84]);
288   // Unicode surrogate pair for U+1F603.
289   QUnit.deepEqual(toJsArray(base.encodeUtf8("😃")),
290                   [0xF0, 0x9F, 0x98, 0x83]);
293 test('decodeUtf8() can decode UTF8 strings', function() {
294   // ASCII.
295   QUnit.equal(base.decodeUtf8(new Uint8Array([0x41, 0x42, 0x43]).buffer),
296               "ABC");
298   // Some arbitrary characters from the basic Unicode plane.
299   QUnit.equal(
300       base.decodeUtf8(
301           new Uint8Array([/* 挂 */ 0xE6, 0x8C, 0x82,
302                           /* Ѓ */ 0xD0, 0x83,
303                           /* ф */ 0xD1, 0x84]).buffer),
304       "挂Ѓф");
306   // Unicode surrogate pair for U+1F603.
307   QUnit.equal(base.decodeUtf8(new Uint8Array([0xF0, 0x9F, 0x98, 0x83]).buffer),
308               "😃");
311 })();