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