1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 (function () { 27 28 module("base"); 29 30 test("joinPath", 1, function() { 31 var value = base.joinPath("path/to", "test.html"); 32 equals(value, "path/to/test.html"); 33 }); 34 35 test("endsWith", 9, function() { 36 ok(base.endsWith("xyz", "")); 37 ok(base.endsWith("xyz", "z")); 38 ok(base.endsWith("xyz", "yz")); 39 ok(base.endsWith("xyz", "xyz")); 40 ok(!base.endsWith("xyz", "wxyz")); 41 ok(!base.endsWith("xyz", "gwxyz")); 42 ok(base.endsWith("", "")); 43 ok(!base.endsWith("", "z")); 44 ok(!base.endsWith("xyxy", "yx")); 45 }); 46 47 test("trimExtension", 6, function() { 48 equals(base.trimExtension("xyz"), "xyz"); 49 equals(base.trimExtension("xy.z"), "xy"); 50 equals(base.trimExtension("x.yz"), "x"); 51 equals(base.trimExtension("x.y.z"), "x.y"); 52 equals(base.trimExtension(".xyz"), ""); 53 equals(base.trimExtension(""), ""); 54 }); 55 56 test("joinPath with empty parent", 1, function() { 57 var value = base.joinPath("", "test.html"); 58 equals(value, "test.html"); 59 }); 60 61 test("dirName", 3, function() { 62 equals(base.dirName("foo.html"), "foo.html"); 63 equals(base.dirName("foo/bar.html"), "foo"); 64 equals(base.dirName("foo/bar/baz.html"), "foo/bar"); 65 }); 66 67 test("uniquifyArray", 5, function() { 68 deepEqual(base.uniquifyArray([]), []); 69 deepEqual(base.uniquifyArray(["a"]), ["a"]); 70 deepEqual(base.uniquifyArray(["a", "b"]), ["a", "b"]); 71 deepEqual(base.uniquifyArray(["a", "b", "b"]), ["a", "b"]); 72 deepEqual(base.uniquifyArray(["a", "b", "b", "a"]), ["a", "b"]); 73 }); 74 75 test("flattenArray", 5, function() { 76 deepEqual(base.flattenArray([]), []); 77 deepEqual(base.flattenArray([["a"]]), ["a"]); 78 deepEqual(base.flattenArray([["a"], ["b"]]), ["a", "b"]); 79 deepEqual(base.flattenArray([["a"], ["b", "c"]]), ["a", "b", "c"]); 80 deepEqual(base.flattenArray([["a"], [], ["b"]]), ["a", "b"]); 81 }); 82 83 test("callInParallel", 4, function() { 84 var expectedCall = [true, true, true]; 85 var expectCompletionCallback = true; 86 87 base.callInParallel([ 88 function(callback) { 89 ok(expectedCall[0]); 90 expectedCall[0] = false; 91 callback(); 92 }, 93 function(callback) { 94 ok(expectedCall[1]); 95 expectedCall[1] = false; 96 callback(); 97 }, 98 function(callback) { 99 ok(expectedCall[2]); 100 expectedCall[2] = false; 101 callback(); 102 }, 103 ], function() { 104 ok(expectCompletionCallback); 105 expectCompletionCallback = false; 106 }) 107 }); 108 109 test("RequestTracker", 5, function() { 110 var ready = false; 111 var tracker = new base.RequestTracker(1, function() { 112 ok(ready); 113 }); 114 ready = true; 115 tracker.requestComplete(); 116 ready = false; 117 118 tracker = new base.RequestTracker(2, function(parameter) { 119 ok(ready); 120 equals(parameter, 'argument'); 121 }, ['argument']); 122 tracker.requestComplete(); 123 ready = true; 124 tracker.requestComplete(); 125 ready = false; 126 127 tracker = new base.RequestTracker(0, function() { 128 ok(true); 129 }); 130 tracker.requestComplete(); 131 132 tracker = new base.RequestTracker(0); 133 tracker.requestComplete(); 134 // Should not barf. 135 ok(true); 136 }); 137 138 test("filterDictionary", 3, function() { 139 var dictionary = { 140 'foo': 43, 141 'bar': 11 142 }; 143 deepEqual(base.filterDictionary(dictionary, function() { return true; }), { 144 "foo": 43, 145 "bar": 11 146 }); 147 deepEqual(base.filterDictionary(dictionary, function() { return false; }), { }); 148 deepEqual(base.filterDictionary(dictionary, function(key) { return key == 'foo'; }), { 149 "foo": 43 150 }); 151 }); 152 153 test("mapDictionary", 3, function() { 154 deepEqual(base.mapDictionary({}, function(value) { return value - 10; }), {}); 155 var dictionary = { 156 'foo': 43, 157 'bar': 11 158 }; 159 deepEqual(base.mapDictionary(dictionary, function(value) { return value - 10; }), { 160 "foo": 33, 161 "bar": 1 162 }); 163 deepEqual(base.mapDictionary(dictionary, function(value) { 164 if (value > 20) 165 return value - 20; 166 }), { 167 "foo": 23, 168 }); 169 }); 170 171 test("filterTree", 2, function() { 172 var tree = { 173 'path': { 174 'to': { 175 'test.html': { 176 'actual': 'PASS', 177 'expected': 'FAIL' 178 } 179 }, 180 'another.html': { 181 'actual': 'TEXT', 182 'expected': 'PASS' 183 } 184 } 185 } 186 187 function isLeaf(node) 188 { 189 return !!node.actual; 190 } 191 192 function actualIsText(node) 193 { 194 return node.actual == 'TEXT'; 195 } 196 197 var all = base.filterTree(tree, isLeaf, function() { return true }); 198 deepEqual(all, { 199 'path/to/test.html': { 200 'actual': 'PASS', 201 'expected': 'FAIL' 202 }, 203 'path/another.html': { 204 'actual': 'TEXT', 205 'expected': 'PASS' 206 } 207 }); 208 209 var text = base.filterTree(tree, isLeaf, actualIsText); 210 deepEqual(text, { 211 'path/another.html': { 212 'actual': 'TEXT', 213 'expected': 'PASS' 214 } 215 }); 216 }); 217 218 test("UpdateTracker", 20, function() { 219 var dict; 220 221 function dumpKeys() 222 { 223 var updates = [] 224 dict.forEach(function(item, key, updated) { 225 updates.push(key); 226 }); 227 return updates; 228 } 229 230 function dumpUpdatedKeys() 231 { 232 var updates = [] 233 dict.forEach(function(item, key, updated) { 234 updated && updates.push(key); 235 }); 236 return updates; 237 } 238 239 240 dict = new base.UpdateTracker(); 241 dict.update("5", {}); 242 deepEqual(dumpUpdatedKeys(), ["5"]); 243 dict.update("6", {}); 244 dict.update("7", {}); 245 deepEqual(dumpUpdatedKeys(), ["5", "6", "7"]); 246 deepEqual(dict.get("6"), {}); 247 ok(dict.exists("7")); 248 dict.purge(); 249 deepEqual(dumpUpdatedKeys(), []); 250 deepEqual(dumpKeys(), ["5", "6", "7"]); 251 dict.update("5", {}); 252 deepEqual(dumpUpdatedKeys(), ["5"]); 253 dict.update("4", {}); 254 deepEqual(dumpUpdatedKeys(), ["4", "5"]); 255 deepEqual(dumpKeys(), ["4", "5", "6", "7"]); 256 dict.purge(); 257 deepEqual(dumpKeys(), ["4", "5"]); 258 deepEqual(dumpUpdatedKeys(), []); 259 dict.purge(); 260 deepEqual(dumpKeys(), []); 261 262 var removeCount = 0; 263 dict.update("one"); 264 deepEqual(dumpUpdatedKeys(), ["one"]); 265 dict.update("two"); 266 deepEqual(dumpUpdatedKeys(), ["one", "two"]); 267 dict.update("three"); 268 dict.purge(); 269 deepEqual(dumpKeys(), ["one", "three", "two"]); 270 dict.update("two"); 271 dict.purge(function() { 272 removeCount++; 273 }); 274 deepEqual(dumpKeys(), ["two"]); 275 equal(removeCount, 2); 276 dict.update("four"); 277 var removeCounter = { count: 0 }; 278 dict.purge(function() { 279 this.count++; 280 }, removeCounter); 281 equal(removeCounter.count, 1); 282 dict.purge(function() { 283 equal(String(this), "four"); 284 }); 285 286 dict = new base.UpdateTracker(); 287 dict.update("one"); 288 var thisObject = {} 289 dict.forEach(function(item) { 290 equal(this, thisObject); 291 }, thisObject); 292 293 }); 294 295 test("extends", 14, function() { 296 297 var LikeDiv = base.extends("div", { 298 init: function() { 299 this.textContent = "awesome"; 300 }, 301 method: function(msg) { 302 return 42; 303 } 304 }); 305 306 var LikeLikeDiv = base.extends(LikeDiv, { 307 init: function() { 308 this.className = "like"; 309 } 310 }); 311 312 var LikeP = base.extends("p", { 313 init: function(content) { 314 this.textContent = content 315 } 316 }); 317 318 var LikeProgress = base.extends("progress", { 319 init: function() { 320 this.max = 100; 321 this.value = 10; 322 } 323 }); 324 325 var LikeLikeProgress = base.extends(LikeProgress, { 326 completed: function() { 327 this.value = 100; 328 } 329 }); 330 331 document.body.appendChild(new LikeDiv()); 332 equals(document.body.lastChild.tagName, "DIV"); 333 equals(document.body.lastChild.innerHTML, "awesome"); 334 equals(document.body.lastChild.method(), 42); 335 document.body.removeChild(document.body.lastChild); 336 337 document.body.appendChild(new LikeLikeDiv()); 338 equals(document.body.lastChild.tagName, "DIV"); 339 equals(document.body.lastChild.innerHTML, "awesome"); 340 equals(document.body.lastChild.method(), 42); 341 equals(document.body.lastChild.className, "like"); 342 document.body.removeChild(document.body.lastChild); 343 344 document.body.appendChild(new LikeP("super")); 345 equals(document.body.lastChild.tagName, "P"); 346 equals(document.body.lastChild.innerHTML, "super"); 347 raises(function() { 348 document.body.lastChild.method(); 349 }); 350 document.body.removeChild(document.body.lastChild); 351 352 document.body.appendChild(new LikeProgress()); 353 equals(document.body.lastChild.tagName, "PROGRESS"); 354 // Safari 5.1 lacks the <progress> element. 355 // equals(document.body.lastChild.position, 0.1); 356 equals(document.body.lastChild.innerHTML, ""); 357 raises(function() { 358 document.body.lastChild.method(); 359 }); 360 document.body.removeChild(document.body.lastChild); 361 362 document.body.appendChild(new LikeLikeProgress()); 363 equals(document.body.lastChild.tagName, "PROGRESS"); 364 // Safari 5.1 lacks the <progress> element. 365 // equals(document.body.lastChild.position, 0.1); 366 document.body.lastChild.completed(); 367 // Safari 5.1 lacks the <progress> element. 368 // equals(document.body.lastChild.position, 1); 369 document.body.removeChild(document.body.lastChild); 370 }); 371 372 test("relativizeTime", 14, function() { 373 var time = new Date(); 374 equals(base.relativizeTime(time), "Just now"); 375 time.setMinutes(time.getMinutes() - 1); 376 equals(base.relativizeTime(time), "1 minute ago"); 377 time.setMinutes(time.getMinutes() - 1); 378 equals(base.relativizeTime(time), "2 minutes ago"); 379 time.setMinutes(time.getMinutes() - 1); 380 equals(base.relativizeTime(time), "3 minutes ago"); 381 time.setMinutes(time.getMinutes() - 56); 382 equals(base.relativizeTime(time), "59 minutes ago"); 383 time.setMinutes(time.getMinutes() - 1); 384 equals(base.relativizeTime(time), "1 hour ago"); 385 time.setMinutes(time.getMinutes() - 29); 386 equals(base.relativizeTime(time), "1 hour ago"); 387 time.setMinutes(time.getMinutes() - 2); 388 equals(base.relativizeTime(time), "2 hours ago"); 389 time.setMinutes(time.getMinutes() - 29); 390 equals(base.relativizeTime(time), "2 hours ago"); 391 time.setHours(time.getHours() - 1); 392 equals(base.relativizeTime(time), "3 hours ago"); 393 time.setHours(time.getHours() - 20); 394 equals(base.relativizeTime(time), "23 hours ago"); 395 time.setHours(time.getHours() - 1); 396 equals(base.relativizeTime(time), "1 day ago"); 397 time.setDate(time.getDate() - 1); 398 equals(base.relativizeTime(time), "2 days ago"); 399 time.setDate(time.getDate() - 998); 400 equals(base.relativizeTime(time), "1000 days ago"); 401 }); 402 403 test("getURLParameter", 1, function() { 404 ok(!base.getURLParameter('non-existant')); 405 }); 406 407 test("parseJSONP", 6, function() { 408 deepEqual(base.parseJSONP(""), {}); 409 deepEqual(base.parseJSONP('p({"key": "value"})'), {"key": "value"}); 410 deepEqual(base.parseJSONP('ADD_RESULTS({"dummy":"data"});'), {"dummy":"data"}); 411 deepEqual(base.parseJSONP('{"dummy":"data"}'), {"dummy":"data"}); 412 deepEqual(base.parseJSONP('ADD_RESULTS({"builder(1)":"data"});'), {"builder(1)":"data"}); 413 deepEqual(base.parseJSONP('{"builder(1)":"data"}'), {"builder(1)":"data"}); 414 }); 415 416 })(); 417