OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function() { | 5 (function() { |
6 | 6 |
7 'use strict'; | 7 'use strict'; |
8 | 8 |
9 module('base'); | 9 QUnit.module('base'); |
10 | 10 |
11 test('mix(dest, src) should copy properties from |src| to |dest|', | 11 QUnit.test('mix(dest, src) should copy properties from |src| to |dest|', |
12 function() { | 12 function() { |
13 var src = { a: 'a', b: 'b'}; | 13 var src = { a: 'a', b: 'b'}; |
14 var dest = { c: 'c'}; | 14 var dest = { c: 'c'}; |
15 | 15 |
16 base.mix(dest, src); | 16 base.mix(dest, src); |
17 deepEqual(dest, {a: 'a', b: 'b', c: 'c'}); | 17 QUnit.deepEqual(dest, {a: 'a', b: 'b', c: 'c'}); |
18 }); | 18 }); |
19 | 19 |
20 test('mix(dest, src) should assert if properties are overwritten', | 20 QUnit.test('mix(dest, src) should assert if properties are overwritten', |
21 function() { | 21 function() { |
22 var src = { a: 'a', b: 'b'}; | 22 var src = { a: 'a', b: 'b'}; |
23 var dest = { a: 'a'}; | 23 var dest = { a: 'a'}; |
24 | 24 |
25 sinon.stub(base.debug, 'assert'); | 25 sinon.stub(base.debug, 'assert'); |
26 | 26 |
27 try { | 27 try { |
28 base.mix(dest, src); | 28 base.mix(dest, src); |
29 } catch (e) { | 29 } catch (e) { |
30 } finally { | 30 } finally { |
31 sinon.assert.called(base.debug.assert); | 31 sinon.assert.called(base.debug.assert); |
32 $testStub(base.debug.assert).restore(); | 32 $testStub(base.debug.assert).restore(); |
33 } | 33 } |
34 }); | 34 }); |
35 | 35 |
36 test('values(obj) should return an array containing the values of |obj|', | 36 QUnit.test('values(obj) should return an array containing the values of |obj|', |
37 function() { | 37 function() { |
38 var output = base.values({ a: 'a', b: 'b'}); | 38 var output = base.values({ a: 'a', b: 'b'}); |
39 | 39 |
40 notEqual(output.indexOf('a'), -1, '"a" should be in the output'); | 40 QUnit.notEqual(output.indexOf('a'), -1, '"a" should be in the output'); |
41 notEqual(output.indexOf('b'), -1, '"b" should be in the output'); | 41 QUnit.notEqual(output.indexOf('b'), -1, '"b" should be in the output'); |
42 }); | 42 }); |
43 | 43 |
44 test('deepCopy(obj) should return null on NaN and undefined', | 44 QUnit.test('deepCopy(obj) should return null on NaN and undefined', |
45 function() { | 45 function() { |
46 QUnit.equal(base.deepCopy(NaN), null); | 46 QUnit.equal(base.deepCopy(NaN), null); |
47 QUnit.equal(base.deepCopy(undefined), null); | 47 QUnit.equal(base.deepCopy(undefined), null); |
48 }); | 48 }); |
49 | 49 |
50 test('deepCopy(obj) should copy primitive types recursively', | 50 QUnit.test('deepCopy(obj) should copy primitive types recursively', |
51 function() { | 51 function() { |
52 QUnit.equal(base.deepCopy(1), 1); | 52 QUnit.equal(base.deepCopy(1), 1); |
53 QUnit.equal(base.deepCopy('hello'), 'hello'); | 53 QUnit.equal(base.deepCopy('hello'), 'hello'); |
54 QUnit.equal(base.deepCopy(false), false); | 54 QUnit.equal(base.deepCopy(false), false); |
55 QUnit.equal(base.deepCopy(null), null); | 55 QUnit.equal(base.deepCopy(null), null); |
56 QUnit.deepEqual(base.deepCopy([1, 2]), [1, 2]); | 56 QUnit.deepEqual(base.deepCopy([1, 2]), [1, 2]); |
57 QUnit.deepEqual(base.deepCopy({'key': 'value'}), {'key': 'value'}); | 57 QUnit.deepEqual(base.deepCopy({'key': 'value'}), {'key': 'value'}); |
58 QUnit.deepEqual(base.deepCopy( | 58 QUnit.deepEqual(base.deepCopy( |
59 {'key': {'key_nested': 'value_nested'}}), | 59 {'key': {'key_nested': 'value_nested'}}), |
60 {'key': {'key_nested': 'value_nested'}} | 60 {'key': {'key_nested': 'value_nested'}} |
61 ); | 61 ); |
62 QUnit.deepEqual(base.deepCopy([1, [2, [3]]]), [1, [2, [3]]]); | 62 QUnit.deepEqual(base.deepCopy([1, [2, [3]]]), [1, [2, [3]]]); |
63 }); | 63 }); |
64 | 64 |
65 test('modify the original after deepCopy(obj) should not affect the copy', | 65 QUnit.test('modify the original after deepCopy(obj) should not affect the copy', |
66 function() { | 66 function() { |
67 var original = [1, 2, 3, 4]; | 67 var original = [1, 2, 3, 4]; |
68 var copy = base.deepCopy(original); | 68 var copy = base.deepCopy(original); |
69 original[2] = 1000; | 69 original[2] = 1000; |
70 QUnit.deepEqual(copy, [1, 2, 3, 4]); | 70 QUnit.deepEqual(copy, [1, 2, 3, 4]); |
71 }); | 71 }); |
72 | 72 |
73 test('dispose(obj) should invoke the dispose method on |obj|', | 73 QUnit.test('dispose(obj) should invoke the dispose method on |obj|', |
74 function() { | 74 function() { |
75 /** | 75 /** |
76 * @constructor | 76 * @constructor |
77 * @implements {base.Disposable} | 77 * @implements {base.Disposable} |
78 */ | 78 */ |
79 base.MockDisposable = function() {}; | 79 base.MockDisposable = function() {}; |
80 base.MockDisposable.prototype.dispose = sinon.spy(); | 80 base.MockDisposable.prototype.dispose = sinon.spy(); |
81 | 81 |
82 var obj = new base.MockDisposable(); | 82 var obj = new base.MockDisposable(); |
83 base.dispose(obj); | 83 base.dispose(obj); |
84 sinon.assert.called(obj.dispose); | 84 sinon.assert.called(obj.dispose); |
85 }); | 85 }); |
86 | 86 |
87 test('dispose(obj) should not crash if |obj| is null', | 87 QUnit.test('dispose(obj) should not crash if |obj| is null', |
88 function() { | 88 function() { |
89 expect(0); | 89 QUnit.expect(0); |
90 base.dispose(null); | 90 base.dispose(null); |
91 }); | 91 }); |
92 | 92 |
93 test('urljoin(url, opt_param) should return url if |opt_param| is missing', | 93 QUnit.test( |
| 94 'urljoin(url, opt_param) should return url if |opt_param| is missing', |
94 function() { | 95 function() { |
95 QUnit.equal( | 96 QUnit.equal( |
96 base.urlJoin('http://www.chromium.org'), 'http://www.chromium.org'); | 97 base.urlJoin('http://www.chromium.org'), 'http://www.chromium.org'); |
97 }); | 98 }); |
98 | 99 |
99 test('urljoin(url, opt_param) should urlencode |opt_param|', | 100 QUnit.test('urljoin(url, opt_param) should urlencode |opt_param|', |
100 function() { | 101 function() { |
101 var result = base.urlJoin('http://www.chromium.org', { | 102 var result = base.urlJoin('http://www.chromium.org', { |
102 a: 'a', | 103 a: 'a', |
103 foo: 'foo', | 104 foo: 'foo', |
104 escapist: ':/?#[]@$&+,;=' | 105 escapist: ':/?#[]@$&+,;=' |
105 }); | 106 }); |
106 QUnit.equal( | 107 QUnit.equal( |
107 result, | 108 result, |
108 'http://www.chromium.org?a=a&foo=foo' + | 109 'http://www.chromium.org?a=a&foo=foo' + |
109 '&escapist=%3A%2F%3F%23%5B%5D%40%24%26%2B%2C%3B%3D'); | 110 '&escapist=%3A%2F%3F%23%5B%5D%40%24%26%2B%2C%3B%3D'); |
110 }); | 111 }); |
111 | 112 |
112 test('escapeHTML(str) should escape special characters', function() { | 113 QUnit.test('escapeHTML(str) should escape special characters', function() { |
113 QUnit.equal( | 114 QUnit.equal( |
114 base.escapeHTML('<script>alert("hello")</script>'), | 115 base.escapeHTML('<script>alert("hello")</script>'), |
115 '<script>alert("hello")</script>'); | 116 '<script>alert("hello")</script>'); |
116 }); | 117 }); |
117 | 118 |
118 QUnit.asyncTest('Promise.sleep(delay) should fulfill the promise after |delay|', | 119 QUnit.test('Promise.sleep(delay) should fulfill the promise after |delay|', |
119 /** | 120 /** |
120 * 'this' is not defined for jscompile, so it can't figure out the type of | 121 * 'this' is not defined for jscompile, so it can't figure out the type of |
121 * this.clock. | 122 * this.clock. |
122 * @suppress {reportUnknownTypes|checkVars|checkTypes} | 123 * @suppress {reportUnknownTypes|checkVars|checkTypes} |
123 */ | 124 */ |
124 function() { | 125 function() { |
125 var isCalled = false; | 126 var isCalled = false; |
126 var clock = /** @type {QUnit.Clock} */ (this.clock); | 127 var clock = /** @type {QUnit.Clock} */ (this.clock); |
127 | 128 |
128 base.Promise.sleep(100).then(function(){ | 129 var promise = base.Promise.sleep(100).then(function(){ |
129 isCalled = true; | 130 isCalled = true; |
130 ok(true, 'Promise.sleep() is fulfilled after delay.'); | 131 QUnit.ok(true, 'Promise.sleep() is fulfilled after delay.'); |
131 QUnit.start(); | |
132 }); | 132 }); |
133 | 133 |
134 // Tick the clock for 2 seconds and check if the promise is fulfilled. | 134 // Tick the clock for 2 seconds and check if the promise is fulfilled. |
135 clock.tick(2); | 135 clock.tick(2); |
136 | 136 |
137 // Promise fulfillment always occur on a new stack. Therefore, we will run | 137 // Promise fulfillment always occur on a new stack. Therefore, we will run |
138 // the verification in a requestAnimationFrame. | 138 // the verification in a requestAnimationFrame. |
139 window.requestAnimationFrame(function(){ | 139 window.requestAnimationFrame(function(){ |
140 ok(!isCalled, 'Promise.sleep() should not be fulfilled prematurely.'); | 140 QUnit.ok( |
| 141 !isCalled, 'Promise.sleep() should not be fulfilled prematurely.'); |
141 clock.tick(101); | 142 clock.tick(101); |
142 }); | 143 }); |
| 144 |
| 145 return promise; |
| 146 }); |
| 147 |
| 148 QUnit.test('Promise.negate should fulfill iff the promise does not.', |
| 149 function() { |
| 150 return base.Promise.negate(Promise.reject()) |
| 151 .then(function() { |
| 152 QUnit.ok(true); |
| 153 }).catch(function() { |
| 154 QUnit.ok(false); |
| 155 }).then(function() { |
| 156 return base.Promise.negate(Promise.resolve()); |
| 157 }).then(function() { |
| 158 QUnit.ok(false); |
| 159 }).catch(function() { |
| 160 QUnit.ok(true); |
| 161 }); |
143 }); | 162 }); |
144 | 163 |
145 QUnit.asyncTest('Promise.negate should fulfill iff the promise does not.', | 164 QUnit.module('base.Deferred'); |
146 function() { | |
147 | 165 |
148 base.Promise.negate(Promise.reject()).then( | 166 QUnit.test('resolve() should fulfill the underlying promise.', function() { |
149 QUnit.ok.bind(null, true), | |
150 /** @type {Function} */ (QUnit.ok.bind(null, false))); | |
151 base.Promise.negate(Promise.resolve()).then( | |
152 QUnit.ok.bind(null, false), | |
153 /** @type {Function} */ (QUnit.ok.bind(null, true))); | |
154 window.requestAnimationFrame(function(){ | |
155 QUnit.start(); | |
156 }); | |
157 }); | |
158 | |
159 module('base.Deferred'); | |
160 | |
161 QUnit.asyncTest('resolve() should fulfill the underlying promise.', function() { | |
162 /** @returns {Promise} */ | 167 /** @returns {Promise} */ |
163 function async() { | 168 function async() { |
164 var deferred = new base.Deferred(); | 169 var deferred = new base.Deferred(); |
165 deferred.resolve('bar'); | 170 deferred.resolve('bar'); |
166 return deferred.promise(); | 171 return deferred.promise(); |
167 } | 172 } |
168 | 173 |
169 async().then( | 174 return async().then(function(/** string */ value){ |
170 /** @param {string} value */ | 175 QUnit.equal(value, 'bar'); |
171 function(value){ | 176 }, function() { |
172 QUnit.equal(value, 'bar'); | 177 QUnit.ok(false, 'The reject handler should not be invoked.'); |
173 QUnit.start(); | 178 }); |
174 }, function() { | |
175 QUnit.ok(false, 'The reject handler should not be invoked.'); | |
176 }); | |
177 }); | 179 }); |
178 | 180 |
179 QUnit.asyncTest('reject() should fail the underlying promise.', function() { | 181 QUnit.test('reject() should fail the underlying promise.', function() { |
180 /** @returns {Promise} */ | 182 /** @returns {Promise} */ |
181 function async() { | 183 function async() { |
182 var deferred = new base.Deferred(); | 184 var deferred = new base.Deferred(); |
183 deferred.reject('bar'); | 185 deferred.reject('bar'); |
184 return deferred.promise(); | 186 return deferred.promise(); |
185 } | 187 } |
186 | 188 |
187 async().then(function(){ | 189 return async().then(function(){ |
188 QUnit.ok(false, 'The then handler should not be invoked.'); | 190 QUnit.ok(false, 'The then handler should not be invoked.'); |
189 }, function(value) { | 191 }, function(value) { |
190 QUnit.equal(value, 'bar'); | 192 QUnit.equal(value, 'bar'); |
191 QUnit.start(); | |
192 }); | 193 }); |
193 }); | 194 }); |
194 | 195 |
195 | 196 |
196 /** @type {base.EventSourceImpl} */ | 197 /** @type {base.EventSourceImpl} */ |
197 var source = null; | 198 var source = null; |
198 var listener = null; | 199 var listener = null; |
199 | 200 |
200 module('base.EventSource', { | 201 QUnit.module('base.EventSource', { |
201 setup: function() { | 202 beforeEach: function() { |
202 source = new base.EventSourceImpl(); | 203 source = new base.EventSourceImpl(); |
203 source.defineEvents(['foo', 'bar']); | 204 source.defineEvents(['foo', 'bar']); |
204 listener = sinon.spy(); | 205 listener = sinon.spy(); |
205 source.addEventListener('foo', listener); | 206 source.addEventListener('foo', listener); |
206 }, | 207 }, |
207 teardown: function() { | 208 afterEach: function() { |
208 source = null; | 209 source = null; |
209 listener = null; | 210 listener = null; |
210 } | 211 } |
211 }); | 212 }); |
212 | 213 |
213 test('raiseEvent() should invoke the listener', function() { | 214 QUnit.test('raiseEvent() should invoke the listener', function() { |
214 source.raiseEvent('foo'); | 215 source.raiseEvent('foo'); |
215 sinon.assert.called(listener); | 216 sinon.assert.called(listener); |
216 }); | 217 }); |
217 | 218 |
218 test('raiseEvent() should invoke the listener with the correct event data', | 219 QUnit.test( |
| 220 'raiseEvent() should invoke the listener with the correct event data', |
219 function() { | 221 function() { |
220 var data = { | 222 var data = { |
221 field: 'foo' | 223 field: 'foo' |
222 }; | 224 }; |
223 source.raiseEvent('foo', data); | 225 source.raiseEvent('foo', data); |
224 sinon.assert.calledWith(listener, data); | 226 sinon.assert.calledWith(listener, data); |
225 }); | 227 }); |
226 | 228 |
227 test( | 229 QUnit.test( |
228 'raiseEvent() should not invoke listeners that are added during raiseEvent', | 230 'raiseEvent() should not invoke listeners that are added during raiseEvent', |
229 function() { | 231 function() { |
230 source.addEventListener('foo', function() { | 232 source.addEventListener('foo', function() { |
231 source.addEventListener('foo', function() { | 233 source.addEventListener('foo', function() { |
232 ok(false); | 234 QUnit.ok(false); |
233 }); | 235 }); |
234 ok(true); | 236 QUnit.ok(true); |
235 }); | 237 }); |
236 source.raiseEvent('foo'); | 238 source.raiseEvent('foo'); |
237 }); | 239 }); |
238 | 240 |
239 test('raiseEvent() should not invoke listeners of a different event', | 241 QUnit.test('raiseEvent() should not invoke listeners of a different event', |
240 function() { | 242 function() { |
241 source.raiseEvent('bar'); | 243 source.raiseEvent('bar'); |
242 sinon.assert.notCalled(listener); | 244 sinon.assert.notCalled(listener); |
243 }); | 245 }); |
244 | 246 |
245 test('raiseEvent() should assert when undeclared events are raised', | 247 QUnit.test('raiseEvent() should assert when undeclared events are raised', |
246 function() { | 248 function() { |
247 sinon.stub(base.debug, 'assert'); | 249 sinon.stub(base.debug, 'assert'); |
248 try { | 250 try { |
249 source.raiseEvent('undefined'); | 251 source.raiseEvent('undefined'); |
250 } catch (e) { | 252 } catch (e) { |
251 } finally { | 253 } finally { |
252 sinon.assert.called(base.debug.assert); | 254 sinon.assert.called(base.debug.assert); |
253 $testStub(base.debug.assert).restore(); | 255 $testStub(base.debug.assert).restore(); |
254 } | 256 } |
255 }); | 257 }); |
256 | 258 |
257 test( | 259 QUnit.test( |
258 'removeEventListener() should not invoke the listener in subsequent ' + | 260 'removeEventListener() should not invoke the listener in subsequent ' + |
259 'calls to |raiseEvent|', | 261 'calls to |raiseEvent|', |
260 function() { | 262 function() { |
261 source.raiseEvent('foo'); | 263 source.raiseEvent('foo'); |
262 sinon.assert.calledOnce(listener); | 264 sinon.assert.calledOnce(listener); |
263 | 265 |
264 source.removeEventListener('foo', listener); | 266 source.removeEventListener('foo', listener); |
265 source.raiseEvent('foo'); | 267 source.raiseEvent('foo'); |
266 sinon.assert.calledOnce(listener); | 268 sinon.assert.calledOnce(listener); |
267 }); | 269 }); |
268 | 270 |
269 test('removeEventListener() should work even if the listener ' + | 271 QUnit.test('removeEventListener() should work even if the listener ' + |
270 'is removed during |raiseEvent|', | 272 'is removed during |raiseEvent|', |
271 function() { | 273 function() { |
272 var sink = {}; | 274 var sink = {}; |
273 sink.listener = sinon.spy(function() { | 275 sink.listener = sinon.spy(function() { |
274 source.removeEventListener('foo', sink.listener); | 276 source.removeEventListener('foo', sink.listener); |
275 }); | 277 }); |
276 | 278 |
277 source.addEventListener('foo', sink.listener); | 279 source.addEventListener('foo', sink.listener); |
278 source.raiseEvent('foo'); | 280 source.raiseEvent('foo'); |
279 sinon.assert.calledOnce(sink.listener); | 281 sinon.assert.calledOnce(sink.listener); |
280 | 282 |
281 source.raiseEvent('foo'); | 283 source.raiseEvent('foo'); |
282 sinon.assert.calledOnce(sink.listener); | 284 sinon.assert.calledOnce(sink.listener); |
283 }); | 285 }); |
284 | 286 |
285 test('encodeUtf8() can encode UTF8 strings', function() { | 287 QUnit.test('encodeUtf8() can encode UTF8 strings', function() { |
286 /** @type {function(ArrayBuffer):Array} */ | 288 /** @type {function(ArrayBuffer):Array} */ |
287 function toJsArray(arrayBuffer) { | 289 function toJsArray(arrayBuffer) { |
288 var result = []; | 290 var result = []; |
289 var array = new Uint8Array(arrayBuffer); | 291 var array = new Uint8Array(arrayBuffer); |
290 for (var i = 0; i < array.length; ++i) { | 292 for (var i = 0; i < array.length; ++i) { |
291 result.push(array[i]); | 293 result.push(array[i]); |
292 } | 294 } |
293 return result; | 295 return result; |
294 } | 296 } |
295 | 297 |
296 // ASCII. | 298 // ASCII. |
297 QUnit.deepEqual(toJsArray(base.encodeUtf8("ABC")), [0x41, 0x42, 0x43]); | 299 QUnit.deepEqual(toJsArray(base.encodeUtf8("ABC")), [0x41, 0x42, 0x43]); |
298 | 300 |
299 // Some arbitrary characters from the basic Unicode plane. | 301 // Some arbitrary characters from the basic Unicode plane. |
300 QUnit.deepEqual( | 302 QUnit.deepEqual( |
301 toJsArray(base.encodeUtf8("挂Ѓф")), | 303 toJsArray(base.encodeUtf8("挂Ѓф")), |
302 [/* 挂 */ 0xE6, 0x8C, 0x82, /* Ѓ */ 0xD0, 0x83, /* ф */ 0xD1, 0x84]); | 304 [/* 挂 */ 0xE6, 0x8C, 0x82, /* Ѓ */ 0xD0, 0x83, /* ф */ 0xD1, 0x84]); |
303 | 305 |
304 // Unicode surrogate pair for U+1F603. | 306 // Unicode surrogate pair for U+1F603. |
305 QUnit.deepEqual(toJsArray(base.encodeUtf8("😃")), | 307 QUnit.deepEqual(toJsArray(base.encodeUtf8("😃")), |
306 [0xF0, 0x9F, 0x98, 0x83]); | 308 [0xF0, 0x9F, 0x98, 0x83]); |
307 }); | 309 }); |
308 | 310 |
309 test('decodeUtf8() can decode UTF8 strings', function() { | 311 QUnit.test('decodeUtf8() can decode UTF8 strings', function() { |
310 // ASCII. | 312 // ASCII. |
311 QUnit.equal(base.decodeUtf8(new Uint8Array([0x41, 0x42, 0x43]).buffer), | 313 QUnit.equal(base.decodeUtf8(new Uint8Array([0x41, 0x42, 0x43]).buffer), |
312 "ABC"); | 314 "ABC"); |
313 | 315 |
314 // Some arbitrary characters from the basic Unicode plane. | 316 // Some arbitrary characters from the basic Unicode plane. |
315 QUnit.equal( | 317 QUnit.equal( |
316 base.decodeUtf8( | 318 base.decodeUtf8( |
317 new Uint8Array([/* 挂 */ 0xE6, 0x8C, 0x82, | 319 new Uint8Array([/* 挂 */ 0xE6, 0x8C, 0x82, |
318 /* Ѓ */ 0xD0, 0x83, | 320 /* Ѓ */ 0xD0, 0x83, |
319 /* ф */ 0xD1, 0x84]).buffer), | 321 /* ф */ 0xD1, 0x84]).buffer), |
320 "挂Ѓф"); | 322 "挂Ѓф"); |
321 | 323 |
322 // Unicode surrogate pair for U+1F603. | 324 // Unicode surrogate pair for U+1F603. |
323 QUnit.equal(base.decodeUtf8(new Uint8Array([0xF0, 0x9F, 0x98, 0x83]).buffer), | 325 QUnit.equal(base.decodeUtf8(new Uint8Array([0xF0, 0x9F, 0x98, 0x83]).buffer), |
324 "😃"); | 326 "😃"); |
325 }); | 327 }); |
326 | 328 |
327 })(); | 329 })(); |
OLD | NEW |