addon-sdk/source/test/test-functional.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 "use strict";
michael@0 5
michael@0 6 const { setTimeout } = require('sdk/timers');
michael@0 7 const utils = require('sdk/lang/functional');
michael@0 8 const { invoke, defer, partial, compose, memoize, once, is, isnt,
michael@0 9 delay, wrap, curry, chainable, field, query, isInstance, debounce, throttle
michael@0 10 } = utils;
michael@0 11 const { LoaderWithHookedConsole } = require('sdk/test/loader');
michael@0 12
michael@0 13 exports['test forwardApply'] = function(assert) {
michael@0 14 function sum(b, c) { return this.a + b + c; }
michael@0 15 assert.equal(invoke(sum, [2, 3], { a: 1 }), 6,
michael@0 16 'passed arguments and pseoude-variable are used');
michael@0 17
michael@0 18 assert.equal(invoke(sum.bind({ a: 2 }), [2, 3], { a: 1 }), 7,
michael@0 19 'bounded `this` pseoudo variable is used');
michael@0 20 };
michael@0 21
michael@0 22 exports['test deferred function'] = function(assert, done) {
michael@0 23 let nextTurn = false;
michael@0 24 function sum(b, c) {
michael@0 25 assert.ok(nextTurn, 'enqueued is called in next turn of event loop');
michael@0 26 assert.equal(this.a + b + c, 6,
michael@0 27 'passed arguments an pseoude-variable are used');
michael@0 28 done();
michael@0 29 }
michael@0 30
michael@0 31 let fixture = { a: 1, method: defer(sum) };
michael@0 32 fixture.method(2, 3);
michael@0 33 nextTurn = true;
michael@0 34 };
michael@0 35
michael@0 36 exports['test partial function'] = function(assert) {
michael@0 37 function sum(b, c) { return this.a + b + c; }
michael@0 38
michael@0 39 let foo = { a : 5 };
michael@0 40
michael@0 41 foo.sum7 = partial(sum, 7);
michael@0 42 foo.sum8and4 = partial(sum, 8, 4);
michael@0 43
michael@0 44 assert.equal(foo.sum7(2), 14, 'partial one arguments works');
michael@0 45
michael@0 46 assert.equal(foo.sum8and4(), 17, 'partial both arguments works');
michael@0 47 };
michael@0 48
michael@0 49 exports["test curry defined numeber of arguments"] = function(assert) {
michael@0 50 var sum = curry(function(a, b, c) {
michael@0 51 return a + b + c;
michael@0 52 });
michael@0 53
michael@0 54 assert.equal(sum(2, 2, 1), 5, "sum(2, 2, 1) => 5");
michael@0 55 assert.equal(sum(2, 4)(1), 7, "sum(2, 4)(1) => 7");
michael@0 56 assert.equal(sum(2)(4, 2), 8, "sum(2)(4, 2) => 8");
michael@0 57 assert.equal(sum(2)(4)(3), 9, "sum(2)(4)(3) => 9");
michael@0 58 };
michael@0 59
michael@0 60 exports['test compose'] = function(assert) {
michael@0 61 let greet = function(name) { return 'hi: ' + name; };
michael@0 62 let exclaim = function(sentence) { return sentence + '!'; };
michael@0 63
michael@0 64 assert.equal(compose(exclaim, greet)('moe'), 'hi: moe!',
michael@0 65 'can compose a function that takes another');
michael@0 66
michael@0 67 assert.equal(compose(greet, exclaim)('moe'), 'hi: moe!',
michael@0 68 'in this case, the functions are also commutative');
michael@0 69
michael@0 70 let target = {
michael@0 71 name: 'Joe',
michael@0 72 greet: compose(function exclaim(sentence) {
michael@0 73 return sentence + '!';
michael@0 74 }, function(title) {
michael@0 75 return 'hi : ' + title + ' ' + this.name;
michael@0 76 })
michael@0 77 };
michael@0 78
michael@0 79 assert.equal(target.greet('Mr'), 'hi : Mr Joe!',
michael@0 80 'this can be passed in');
michael@0 81 assert.equal(target.greet.call({ name: 'Alex' }, 'Dr'), 'hi : Dr Alex!',
michael@0 82 'this can be applied');
michael@0 83
michael@0 84 let single = compose(function(value) {
michael@0 85 return value + ':suffix';
michael@0 86 });
michael@0 87
michael@0 88 assert.equal(single('text'), 'text:suffix', 'works with single function');
michael@0 89
michael@0 90 let identity = compose();
michael@0 91 assert.equal(identity('bla'), 'bla', 'works with zero functions');
michael@0 92 };
michael@0 93
michael@0 94 exports['test wrap'] = function(assert) {
michael@0 95 let greet = function(name) { return 'hi: ' + name; };
michael@0 96 let backwards = wrap(greet, function(f, name) {
michael@0 97 return f(name) + ' ' + name.split('').reverse().join('');
michael@0 98 });
michael@0 99
michael@0 100 assert.equal(backwards('moe'), 'hi: moe eom',
michael@0 101 'wrapped the saluation function');
michael@0 102
michael@0 103 let inner = function () { return 'Hello '; };
michael@0 104 let target = {
michael@0 105 name: 'Matteo',
michael@0 106 hi: wrap(inner, function(f) { return f() + this.name; })
michael@0 107 };
michael@0 108
michael@0 109 assert.equal(target.hi(), 'Hello Matteo', 'works with this');
michael@0 110
michael@0 111 function noop() { }
michael@0 112 let wrapped = wrap(noop, function(f) {
michael@0 113 return Array.slice(arguments);
michael@0 114 });
michael@0 115
michael@0 116 let actual = wrapped([ 'whats', 'your' ], 'vector', 'victor');
michael@0 117 assert.deepEqual(actual, [ noop, ['whats', 'your'], 'vector', 'victor' ],
michael@0 118 'works with fancy stuff');
michael@0 119 };
michael@0 120
michael@0 121 exports['test memoize'] = function(assert) {
michael@0 122 const fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2);
michael@0 123 let fibnitro = memoize(fib);
michael@0 124
michael@0 125 assert.equal(fib(10), 55,
michael@0 126 'a memoized version of fibonacci produces identical results');
michael@0 127 assert.equal(fibnitro(10), 55,
michael@0 128 'a memoized version of fibonacci produces identical results');
michael@0 129
michael@0 130 function o(key, value) { return value; }
michael@0 131 let oo = memoize(o), v1 = {}, v2 = {};
michael@0 132
michael@0 133
michael@0 134 assert.equal(oo(1, v1), v1, 'returns value back');
michael@0 135 assert.equal(oo(1, v2), v1, 'memoized by a first argument');
michael@0 136 assert.equal(oo(2, v2), v2, 'returns back value if not memoized');
michael@0 137 assert.equal(oo(2), v2, 'memoized new value');
michael@0 138 assert.notEqual(oo(1), oo(2), 'values do not override');
michael@0 139 assert.equal(o(3, v2), oo(2, 3), 'returns same value as un-memoized');
michael@0 140
michael@0 141 let get = memoize(function(attribute) { return this[attribute]; });
michael@0 142 let target = { name: 'Bob', get: get };
michael@0 143
michael@0 144 assert.equal(target.get('name'), 'Bob', 'has correct `this`');
michael@0 145 assert.equal(target.get.call({ name: 'Jack' }, 'name'), 'Bob',
michael@0 146 'name is memoized');
michael@0 147 assert.equal(get('name'), 'Bob', 'once memoized can be called without this');
michael@0 148 };
michael@0 149
michael@0 150 exports['test delay'] = function(assert, done) {
michael@0 151 let delayed = false;
michael@0 152 delay(function() {
michael@0 153 assert.ok(delayed, 'delayed the function');
michael@0 154 done();
michael@0 155 }, 1);
michael@0 156 delayed = true;
michael@0 157 };
michael@0 158
michael@0 159 exports['test delay with this'] = function(assert, done) {
michael@0 160 let context = {};
michael@0 161 delay.call(context, function(name) {
michael@0 162 assert.equal(this, context, 'this was passed in');
michael@0 163 assert.equal(name, 'Tom', 'argument was passed in');
michael@0 164 done();
michael@0 165 }, 10, 'Tom');
michael@0 166 };
michael@0 167
michael@0 168 exports['test once'] = function(assert) {
michael@0 169 let n = 0;
michael@0 170 let increment = once(function() { n ++; });
michael@0 171
michael@0 172 increment();
michael@0 173 increment();
michael@0 174
michael@0 175 assert.equal(n, 1, 'only incremented once');
michael@0 176
michael@0 177 let target = {
michael@0 178 state: 0,
michael@0 179 update: once(function() {
michael@0 180 return this.state ++;
michael@0 181 })
michael@0 182 };
michael@0 183
michael@0 184 target.update();
michael@0 185 target.update();
michael@0 186
michael@0 187 assert.equal(target.state, 1, 'this was passed in and called only once');
michael@0 188 };
michael@0 189
michael@0 190 exports['test once with argument'] = function(assert) {
michael@0 191 let n = 0;
michael@0 192 let increment = once(a => n++);
michael@0 193
michael@0 194 increment();
michael@0 195 increment('foo');
michael@0 196
michael@0 197 assert.equal(n, 1, 'only incremented once');
michael@0 198
michael@0 199 increment();
michael@0 200 increment('foo');
michael@0 201
michael@0 202 assert.equal(n, 1, 'only incremented once');
michael@0 203 };
michael@0 204
michael@0 205 exports['test complement'] = assert => {
michael@0 206 let { complement } = require("sdk/lang/functional");
michael@0 207
michael@0 208 let isOdd = x => Boolean(x % 2);
michael@0 209
michael@0 210 assert.equal(isOdd(1), true);
michael@0 211 assert.equal(isOdd(2), false);
michael@0 212
michael@0 213 let isEven = complement(isOdd);
michael@0 214
michael@0 215 assert.equal(isEven(1), false);
michael@0 216 assert.equal(isEven(2), true);
michael@0 217
michael@0 218 let foo = {};
michael@0 219 let isFoo = function() { return this === foo; };
michael@0 220 let insntFoo = complement(isFoo);
michael@0 221
michael@0 222 assert.equal(insntFoo.call(foo), false);
michael@0 223 assert.equal(insntFoo.call({}), true);
michael@0 224 };
michael@0 225
michael@0 226 exports['test constant'] = assert => {
michael@0 227 let { constant } = require("sdk/lang/functional");
michael@0 228
michael@0 229 let one = constant(1);
michael@0 230
michael@0 231 assert.equal(one(1), 1);
michael@0 232 assert.equal(one(2), 1);
michael@0 233 };
michael@0 234
michael@0 235 exports['test apply'] = assert => {
michael@0 236 let { apply } = require("sdk/lang/functional");
michael@0 237
michael@0 238 let dashify = (...args) => args.join("-");
michael@0 239
michael@0 240 assert.equal(apply(dashify, 1, [2, 3]), "1-2-3");
michael@0 241 assert.equal(apply(dashify, "a"), "a");
michael@0 242 assert.equal(apply(dashify, ["a", "b"]), "a-b");
michael@0 243 assert.equal(apply(dashify, ["a", "b"], "c"), "a,b-c");
michael@0 244 assert.equal(apply(dashify, [1, 2], [3, 4]), "1,2-3-4");
michael@0 245 };
michael@0 246
michael@0 247 exports['test flip'] = assert => {
michael@0 248 let { flip } = require("sdk/lang/functional");
michael@0 249
michael@0 250 let append = (left, right) => left + " " + right;
michael@0 251 let prepend = flip(append);
michael@0 252
michael@0 253 assert.equal(append("hello", "world"), "hello world");
michael@0 254 assert.equal(prepend("hello", "world"), "world hello");
michael@0 255
michael@0 256 let wrap = function(left, right) {
michael@0 257 return left + " " + this + " " + right;
michael@0 258 };
michael@0 259 let invertWrap = flip(wrap);
michael@0 260
michael@0 261 assert.equal(wrap.call("@", "hello", "world"), "hello @ world");
michael@0 262 assert.equal(invertWrap.call("@", "hello", "world"), "world @ hello");
michael@0 263
michael@0 264 let reverse = flip((...args) => args);
michael@0 265
michael@0 266 assert.deepEqual(reverse(1, 2, 3, 4), [4, 3, 2, 1]);
michael@0 267 assert.deepEqual(reverse(1), [1]);
michael@0 268 assert.deepEqual(reverse(), []);
michael@0 269
michael@0 270 // currying still works
michael@0 271 let prependr = curry(prepend);
michael@0 272
michael@0 273 assert.equal(prependr("hello", "world"), "world hello");
michael@0 274 assert.equal(prependr("hello")("world"), "world hello");
michael@0 275 };
michael@0 276
michael@0 277 exports["test when"] = assert => {
michael@0 278 let { when } = require("sdk/lang/functional");
michael@0 279
michael@0 280 let areNums = (...xs) => xs.every(x => typeof(x) === "number");
michael@0 281
michael@0 282 let sum = when(areNums, (...xs) => xs.reduce((y, x) => x + y, 0));
michael@0 283
michael@0 284 assert.equal(sum(1, 2, 3), 6);
michael@0 285 assert.equal(sum(1, 2, "3"), undefined);
michael@0 286
michael@0 287 let multiply = when(areNums,
michael@0 288 (...xs) => xs.reduce((y, x) => x * y, 1),
michael@0 289 (...xs) => xs);
michael@0 290
michael@0 291 assert.equal(multiply(2), 2);
michael@0 292 assert.equal(multiply(2, 3), 6);
michael@0 293 assert.deepEqual(multiply(2, "4"), [2, "4"]);
michael@0 294
michael@0 295 function Point(x, y) {
michael@0 296 this.x = x;
michael@0 297 this.y = y;
michael@0 298 }
michael@0 299
michael@0 300 let isPoint = x => x instanceof Point;
michael@0 301
michael@0 302 let inc = when(isPoint, ({x, y}) => new Point(x + 1, y + 1));
michael@0 303
michael@0 304 assert.equal(inc({}), undefined);
michael@0 305 assert.deepEqual(inc(new Point(0, 0)), { x: 1, y: 1 });
michael@0 306
michael@0 307 let axis = when(isPoint,
michael@0 308 ({ x, y }) => [x, y],
michael@0 309 _ => [0, 0]);
michael@0 310
michael@0 311 assert.deepEqual(axis(new Point(1, 4)), [1, 4]);
michael@0 312 assert.deepEqual(axis({ foo: "bar" }), [0, 0]);
michael@0 313 };
michael@0 314
michael@0 315 exports["test chainable"] = function(assert) {
michael@0 316 let Player = function () { this.volume = 5; };
michael@0 317 Player.prototype = {
michael@0 318 setBand: chainable(function (band) { return (this.band = band); }),
michael@0 319 incVolume: chainable(function () { return this.volume++; })
michael@0 320 };
michael@0 321 let player = new Player();
michael@0 322 player
michael@0 323 .setBand('Animals As Leaders')
michael@0 324 .incVolume().incVolume().incVolume().incVolume().incVolume().incVolume();
michael@0 325
michael@0 326 assert.equal(player.band, 'Animals As Leaders', 'passes arguments into chained');
michael@0 327 assert.equal(player.volume, 11, 'accepts no arguments in chain');
michael@0 328 };
michael@0 329
michael@0 330 exports["test field"] = assert => {
michael@0 331 let Num = field("constructor", 0);
michael@0 332 assert.equal(Num.name, Number.name);
michael@0 333 assert.ok(typeof(Num), "function");
michael@0 334
michael@0 335 let x = field("x");
michael@0 336
michael@0 337 [
michael@0 338 [field("foo", { foo: 1 }), 1],
michael@0 339 [field("foo")({ foo: 1 }), 1],
michael@0 340 [field("bar", {}), undefined],
michael@0 341 [field("bar")({}), undefined],
michael@0 342 [field("hey", undefined), undefined],
michael@0 343 [field("hey")(undefined), undefined],
michael@0 344 [field("how", null), null],
michael@0 345 [field("how")(null), null],
michael@0 346 [x(1), undefined],
michael@0 347 [x(undefined), undefined],
michael@0 348 [x(null), null],
michael@0 349 [x({ x: 1 }), 1],
michael@0 350 [x({ x: 2 }), 2],
michael@0 351 ].forEach(([actual, expected]) => assert.equal(actual, expected));
michael@0 352 };
michael@0 353
michael@0 354 exports["test query"] = assert => {
michael@0 355 let Num = query("constructor", 0);
michael@0 356 assert.equal(Num.name, Number.name);
michael@0 357 assert.ok(typeof(Num), "function");
michael@0 358
michael@0 359 let x = query("x");
michael@0 360 let xy = query("x.y");
michael@0 361
michael@0 362 [
michael@0 363 [query("foo", { foo: 1 }), 1],
michael@0 364 [query("foo")({ foo: 1 }), 1],
michael@0 365 [query("foo.bar", { foo: { bar: 2 } }), 2],
michael@0 366 [query("foo.bar")({ foo: { bar: 2 } }), 2],
michael@0 367 [query("foo.bar", { foo: 1 }), undefined],
michael@0 368 [query("foo.bar")({ foo: 1 }), undefined],
michael@0 369 [x(1), undefined],
michael@0 370 [x(undefined), undefined],
michael@0 371 [x(null), null],
michael@0 372 [x({ x: 1 }), 1],
michael@0 373 [x({ x: 2 }), 2],
michael@0 374 [xy(1), undefined],
michael@0 375 [xy(undefined), undefined],
michael@0 376 [xy(null), null],
michael@0 377 [xy({ x: 1 }), undefined],
michael@0 378 [xy({ x: 2 }), undefined],
michael@0 379 [xy({ x: { y: 1 } }), 1],
michael@0 380 [xy({ x: { y: 2 } }), 2]
michael@0 381 ].forEach(([actual, expected]) => assert.equal(actual, expected));
michael@0 382 };
michael@0 383
michael@0 384 exports["test isInstance"] = assert => {
michael@0 385 function X() {}
michael@0 386 function Y() {}
michael@0 387 let isX = isInstance(X);
michael@0 388
michael@0 389 [
michael@0 390 isInstance(X, new X()),
michael@0 391 isInstance(X)(new X()),
michael@0 392 !isInstance(X, new Y()),
michael@0 393 !isInstance(X)(new Y()),
michael@0 394 isX(new X()),
michael@0 395 !isX(new Y())
michael@0 396 ].forEach(x => assert.ok(x));
michael@0 397 };
michael@0 398
michael@0 399 exports["test is"] = assert => {
michael@0 400
michael@0 401 assert.deepEqual([ 1, 0, 1, 0, 1 ].map(is(1)),
michael@0 402 [ true, false, true, false, true ],
michael@0 403 "is can be partially applied");
michael@0 404
michael@0 405 assert.ok(is(1, 1));
michael@0 406 assert.ok(!is({}, {}));
michael@0 407 assert.ok(is()(1)()(1), "is is curried");
michael@0 408 assert.ok(!is()(1)()(2));
michael@0 409 };
michael@0 410
michael@0 411 exports["test isnt"] = assert => {
michael@0 412
michael@0 413 assert.deepEqual([ 1, 0, 1, 0, 1 ].map(isnt(0)),
michael@0 414 [ true, false, true, false, true ],
michael@0 415 "is can be partially applied");
michael@0 416
michael@0 417 assert.ok(!isnt(1, 1));
michael@0 418 assert.ok(isnt({}, {}));
michael@0 419 assert.ok(!isnt()(1)()(1));
michael@0 420 assert.ok(isnt()(1)()(2));
michael@0 421 };
michael@0 422
michael@0 423 exports["test debounce"] = (assert, done) => {
michael@0 424 let counter = 0;
michael@0 425 let fn = debounce(() => counter++, 100);
michael@0 426
michael@0 427 new Array(10).join(0).split("").forEach(fn);
michael@0 428
michael@0 429 assert.equal(counter, 0, "debounce does not fire immediately");
michael@0 430 setTimeout(() => {
michael@0 431 assert.equal(counter, 1, "function called after wait time");
michael@0 432 fn();
michael@0 433 setTimeout(() => {
michael@0 434 assert.equal(counter, 2, "function able to be called again after wait");
michael@0 435 done();
michael@0 436 }, 150);
michael@0 437 }, 200);
michael@0 438 };
michael@0 439
michael@0 440 exports["test throttle"] = (assert, done) => {
michael@0 441 let called = 0;
michael@0 442 let attempt = 0;
michael@0 443 let atleast100ms = false;
michael@0 444 let throttledFn = throttle(() => {
michael@0 445 called++;
michael@0 446 if (called === 2) {
michael@0 447 assert.equal(attempt, 10, "called twice, but attempted 10 times");
michael@0 448 fn();
michael@0 449 }
michael@0 450 if (called === 3) {
michael@0 451 assert.ok(atleast100ms, "atleast 100ms have passed");
michael@0 452 assert.equal(attempt, 11, "called third, waits for delay to happen");
michael@0 453 done();
michael@0 454 }
michael@0 455 }, 200);
michael@0 456 let fn = () => ++attempt && throttledFn();
michael@0 457
michael@0 458 setTimeout(() => atleast100ms = true, 100);
michael@0 459
michael@0 460 new Array(11).join(0).split("").forEach(fn);
michael@0 461 };
michael@0 462
michael@0 463 require('test').run(exports);

mercurial