addon-sdk/source/test/traits/object-tests.js

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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
michael@0 5 "use strict";
michael@0 6
michael@0 7 var Trait = require("sdk/deprecated/light-traits").Trait;
michael@0 8 var utils = require("./utils");
michael@0 9 var Data = utils.Data;
michael@0 10 var Method = utils.Method;
michael@0 11 var Accessor = utils.Accessor;
michael@0 12 var Required = utils.Required;
michael@0 13 var Conflict = utils.Conflict;
michael@0 14
michael@0 15 function method() {}
michael@0 16
michael@0 17 exports.Assert = require("./assert").Assert;
michael@0 18
michael@0 19 exports["test empty trait"] = function (assert) {
michael@0 20 assert.equalTraits(Trait({}), {});
michael@0 21 };
michael@0 22
michael@0 23 exports["test simple trait"] = function (assert) {
michael@0 24 var expected = {
michael@0 25 a: Data(0, true, true, true),
michael@0 26 b: Method(method, true, true, true)
michael@0 27 };
michael@0 28
michael@0 29 assert.equalTraits(Trait({ a: 0, b: method }), expected);
michael@0 30 };
michael@0 31
michael@0 32 exports["test simple trait with Trait.required property"] = function (assert) {
michael@0 33 var actual = Trait({ a: Trait.required, b: 1 });
michael@0 34 var expected = { a: Required("a"), b: Data(1) };
michael@0 35
michael@0 36 assert.equalTraits(actual, expected);
michael@0 37 };
michael@0 38
michael@0 39 exports["test ordering of trait properties is irrelevant"] = function (assert) {
michael@0 40 var actual = Trait({ a: 0, b: 1, c: Trait.required });
michael@0 41 var expected = Trait({ b: 1, c: Trait.required, a: 0 });
michael@0 42
michael@0 43 assert.equalTraits(actual, expected);
michael@0 44 };
michael@0 45
michael@0 46 exports["test trait with accessor property"] = function (assert) {
michael@0 47 var record = { get a() {}, set a(v) {} };
michael@0 48 var get = Object.getOwnPropertyDescriptor(record, "a").get;
michael@0 49 var set = Object.getOwnPropertyDescriptor(record, "a").set;
michael@0 50
michael@0 51 assert.equalTraits(Trait(record), { a: Accessor(get, set) });
michael@0 52 };
michael@0 53
michael@0 54 exports["test simple composition"] = function (assert) {
michael@0 55 var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ c: 2, d: method }));
michael@0 56 var expected = { a: Data(0), b: Data(1), c: Data(2), d: Method(method) };
michael@0 57
michael@0 58 assert.equalTraits(actual, expected);
michael@0 59 };
michael@0 60
michael@0 61 exports["test composition with conflict"] = function (assert) {
michael@0 62 var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ a: 2, c: method }));
michael@0 63 var expected = { a: Conflict("a"), b: Data(1), c: Method(method) };
michael@0 64
michael@0 65 assert.equalTraits(actual, expected);
michael@0 66 };
michael@0 67
michael@0 68 exports["test composition of identical props does not cause conflict"] = function (assert) {
michael@0 69 var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ a: 0, c: method }));
michael@0 70
michael@0 71 assert.equalTraits(actual, { a: Data(0), b: Data(1), c: Method(method) });
michael@0 72 };
michael@0 73
michael@0 74 exports["test composition with identical Trait.required props"] = function (assert) {
michael@0 75 var actual = Trait.compose(Trait({ a: Trait.required, b: 1 }),
michael@0 76 Trait({ a: Trait.required, c: method }));
michael@0 77
michael@0 78 assert.equalTraits(actual, { a: Required(), b: Data(1), c: Method(method) });
michael@0 79 };
michael@0 80
michael@0 81 exports["test composition satisfying a Trait.required prop"] = function (assert) {
michael@0 82 var actual = Trait.compose(Trait({ a: Trait.required, b: 1 }),
michael@0 83 Trait({ a: method }));
michael@0 84
michael@0 85 assert.equalTraits(actual, { a: Method(method), b: Data(1) });
michael@0 86 };
michael@0 87
michael@0 88 exports["test compose is neutral wrt conflicts"] = function (assert) {
michael@0 89 var actual = Trait.compose(Trait.compose(Trait({ a: 1 }), Trait({ a: 2 })),
michael@0 90 Trait({ b: 0 }));
michael@0 91
michael@0 92 assert.equalTraits(actual, { a: Conflict("a"), b: Data(0) });
michael@0 93 };
michael@0 94
michael@0 95 exports["test conflicting prop overrides Trait.required prop"] = function (assert) {
michael@0 96 var actual = Trait.compose(Trait.compose(Trait({ a: 1 }),
michael@0 97 Trait({ a: 2 })),
michael@0 98 Trait({ a: Trait.required }));
michael@0 99
michael@0 100 assert.equalTraits(actual, { a: Conflict("a") });
michael@0 101 };
michael@0 102
michael@0 103 exports["test compose is commutative"] = function (assert) {
michael@0 104 var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ c: 2, d: method }));
michael@0 105 var expected = Trait.compose(Trait({ c: 2, d: method }),
michael@0 106 Trait({ a: 0, b: 1 }));
michael@0 107
michael@0 108 assert.equalTraits(actual, expected);
michael@0 109 };
michael@0 110
michael@0 111 exports["test compose is commutative, also for Trait.required/conflicting props"] = function (assert) {
michael@0 112 var actual = Trait.compose(Trait({ a: 0, b: 1, c: 3, e: Trait.required }),
michael@0 113 Trait({ c: 2, d: method }));
michael@0 114
michael@0 115 var expected = Trait.compose(Trait({ c: 2, d: method }),
michael@0 116 Trait({ a: 0, b: 1, c: 3, e: Trait.required }));
michael@0 117
michael@0 118 assert.equalTraits(actual, expected);
michael@0 119 };
michael@0 120
michael@0 121 exports["test compose is associative"] = function (assert) {
michael@0 122 var actual = Trait.compose(Trait({ a: 0, b: 1, c: 3, d: Trait.required }),
michael@0 123 Trait.compose(Trait({ c: 3, d: Trait.required }),
michael@0 124 Trait({ c: 2, d: method,
michael@0 125 e: "foo" })));
michael@0 126
michael@0 127 var expected = Trait.compose(
michael@0 128 Trait.compose(Trait({ a: 0, b: 1, c: 3, d: Trait.required }),
michael@0 129 Trait({ c: 3, d: Trait.required })),
michael@0 130 Trait({ c: 2, d: method, e: "foo" }));
michael@0 131
michael@0 132 assert.equalTraits(actual, expected);
michael@0 133 };
michael@0 134
michael@0 135 exports["test diamond import of same prop does not generate conflict"] = function (assert) {
michael@0 136 var actual = Trait.compose(Trait.compose(Trait({ b: 2 }), Trait({ a: 1 })),
michael@0 137 Trait.compose(Trait({ c: 3 }), Trait({ a: 1 })),
michael@0 138 Trait({ d: 4 }));
michael@0 139 var expected = { a: Data(1), b: Data(2), c: Data(3), d: Data(4) };
michael@0 140
michael@0 141 assert.equalTraits(actual, expected);
michael@0 142 };
michael@0 143
michael@0 144 exports["test resolve with empty resolutions has no effect"] = function (assert) {
michael@0 145 assert.equalTraits(Trait({ a: 1, b: Trait.required, c: method }).resolve({}),
michael@0 146 { a: Data(1), b: Required(), c: Method(method) });
michael@0 147 };
michael@0 148
michael@0 149 exports["test resolve: renaming"] = function (assert) {
michael@0 150 var actual = Trait({ a: 1, b: Trait.required, c: method });
michael@0 151
michael@0 152 assert.equalTraits(actual.resolve({ a: "A", c: "C" }),
michael@0 153 { A: Data(1), b: Required(), C: Method(method),
michael@0 154 a: Required(), c: Required() });
michael@0 155 };
michael@0 156
michael@0 157 exports["test resolve: renaming to conflicting name causes conflict, order 1"] = function (assert) {
michael@0 158 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "b" }),
michael@0 159 { b: Conflict("b"), a: Required() });
michael@0 160 };
michael@0 161
michael@0 162 exports["test resolve: renaming to conflicting name causes conflict, order 2"] = function (assert) {
michael@0 163 assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ a: "b" }),
michael@0 164 { b: Conflict("b"), a: Required() });
michael@0 165 };
michael@0 166
michael@0 167 exports["test resolve: simple exclusion"] = function (assert) {
michael@0 168 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined }),
michael@0 169 { a: Required(), b: Data(2) });
michael@0 170 };
michael@0 171
michael@0 172 exports["test resolve: exclusion to empty trait"] = function (assert) {
michael@0 173 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: null, b: undefined }),
michael@0 174 { a: Required(), b: Required() });
michael@0 175 };
michael@0 176
michael@0 177 exports["test resolve: exclusion and renaming of disjoint props"] = function (assert) {
michael@0 178 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined, b: "c" }),
michael@0 179 { a: Required(), c: Data(2), b: Required() });
michael@0 180 };
michael@0 181
michael@0 182 exports["test resolve: exclusion and renaming of overlapping props"] = function (assert) {
michael@0 183 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined, b: "a" }),
michael@0 184 { a: Data(2), b: Required() });
michael@0 185 };
michael@0 186
michael@0 187 exports["test resolve: renaming to a common alias causes conflict"] = function (assert) {
michael@0 188 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "c", b: "c" }),
michael@0 189 { c: Conflict("c"), a: Required(), b: Required() });
michael@0 190 };
michael@0 191
michael@0 192 exports["test resolve: renaming overrides Trait.required target"] = function (assert) {
michael@0 193 assert.equalTraits(Trait({ a: Trait.required, b: 2 }).resolve({ b: "a" }),
michael@0 194 { a: Data(2), b: Required() });
michael@0 195 };
michael@0 196
michael@0 197 exports["test resolve: renaming Trait.required properties has no effect"] = function (assert) {
michael@0 198 assert.equalTraits(Trait({ a: 2, b: Trait.required }).resolve({ b: "a" }),
michael@0 199 { a: Data(2), b: Required() });
michael@0 200 };
michael@0 201
michael@0 202 exports["test resolve: renaming of non-existent props has no effect"] = function (assert) {
michael@0 203 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "c", d: "c" }),
michael@0 204 { c: Data(1), b: Data(2), a: Required() });
michael@0 205 };
michael@0 206
michael@0 207 exports["test resolve: exclusion of non-existent props has no effect"] = function (assert) {
michael@0 208 assert.equalTraits(Trait({ a: 1 }).resolve({ b: undefined }), { a: Data(1) });
michael@0 209 };
michael@0 210
michael@0 211 exports["test resolve is neutral w.r.t. Trait.required properties"] = function (assert) {
michael@0 212 var actual = Trait({ a: Trait.required, b: Trait.required, c: "foo", d: 1 });
michael@0 213 var expected = { a: Required(), b: Required(), c: Data("foo"), d: Data(1) };
michael@0 214 assert.equalTraits(actual.resolve({ a: "c", b: undefined }), expected);
michael@0 215 };
michael@0 216
michael@0 217 exports["test resolve supports swapping of property names, ordering 1"] = function (assert) {
michael@0 218 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "b", b: "a" }),
michael@0 219 { a: Data(2), b: Data(1) });
michael@0 220 };
michael@0 221
michael@0 222 exports["test resolve supports swapping of property names, ordering 2"] = function (assert) {
michael@0 223 assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ b: "a", a: "b" }),
michael@0 224 { a: Data(2), b: Data(1) });
michael@0 225 };
michael@0 226
michael@0 227 exports["test resolve supports swapping of property names, ordering 3"] = function (assert) {
michael@0 228 assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ b: "a", a: "b" }),
michael@0 229 { a: Data(2), b: Data(1) });
michael@0 230 };
michael@0 231
michael@0 232 exports["test resolve supports swapping of property names, ordering 4"] = function (assert) {
michael@0 233 assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ a: "b", b: "a" }),
michael@0 234 { a: Data(2), b: Data(1) });
michael@0 235 };
michael@0 236
michael@0 237 exports["test create simple"] = function (assert) {
michael@0 238 var o1 = Trait({
michael@0 239 a: 1,
michael@0 240 b: function () {
michael@0 241 return this.a;
michael@0 242 }
michael@0 243 }).create(Object.prototype);
michael@0 244
michael@0 245 assert.equal(Object.getPrototypeOf(o1), Object.prototype, "o1 prototype");
michael@0 246 assert.equal(1, o1.a, "o1.a");
michael@0 247 assert.equal(1, o1.b(), "o1.b()");
michael@0 248 assert.equal(Object.keys(o1).length, 2, "Object.keys(o1).length === 2");
michael@0 249 };
michael@0 250
michael@0 251 exports["test create with Array.prototype"] = function (assert) {
michael@0 252 var o2 = Trait({}).create(Array.prototype);
michael@0 253 assert.equal(Object.getPrototypeOf(o2), Array.prototype, "o2 prototype");
michael@0 254 };
michael@0 255
michael@0 256 exports["test exception for incomplete required properties"] = function (assert) {
michael@0 257 assert.throws(function () {
michael@0 258 Trait({ foo: Trait.required }).create(Object.prototype);
michael@0 259 }, /Missing required property: `foo`/, "required prop error");
michael@0 260 };
michael@0 261
michael@0 262 exports["test exception for unresolved conflicts"] = function (assert) {
michael@0 263 assert.throws(function () {
michael@0 264 Trait.compose(Trait({ a: 0 }), Trait({ a: 1 })).create({});
michael@0 265 }, /Remaining conflicting property: `a`/, "conflicting prop error");
michael@0 266 };
michael@0 267
michael@0 268 exports["test verify that required properties are present but undefined"] = function (assert) {
michael@0 269 var o4 = Object.create(Object.prototype, Trait({ foo: Trait.required }));
michael@0 270
michael@0 271 assert.ok("foo" in o4, "required property present");
michael@0 272 assert.throws(function () {
michael@0 273 o4.foo;
michael@0 274 }, /Missing required property: `foo`/, "required prop error");
michael@0 275 };
michael@0 276
michael@0 277 exports["test verify that conflicting properties are present"] = function (assert) {
michael@0 278 var o5 = Object.create(Object.prototype, Trait.compose(Trait({ a: 0 }),
michael@0 279 Trait({ a: 1 })));
michael@0 280
michael@0 281 assert.ok("a" in o5, "conflicting property present");
michael@0 282 assert.throws(function () {
michael@0 283 o5.a;
michael@0 284 }, /Remaining conflicting property: `a`/, "conflicting prop access error");
michael@0 285 };
michael@0 286
michael@0 287 exports["test diamond with conflicts"] = function (assert) {
michael@0 288 function makeT1(x) {
michael@0 289 return Trait({
michael@0 290 m: function () {
michael@0 291 return x
michael@0 292 }
michael@0 293 })
michael@0 294 };
michael@0 295
michael@0 296 function makeT2(x) {
michael@0 297 return Trait.compose(Trait({
michael@0 298 t2: "foo"
michael@0 299 }), makeT1(x));
michael@0 300 };
michael@0 301
michael@0 302 function makeT3(x) {
michael@0 303 return Trait.compose(Trait({
michael@0 304 t3: "bar"
michael@0 305 }), makeT1(x));
michael@0 306 };
michael@0 307
michael@0 308 var T4 = Trait.compose(makeT2(5), makeT3(5));
michael@0 309
michael@0 310 assert.throws(function () {
michael@0 311 T4.create(Object.prototype);
michael@0 312 }, /Remaining conflicting property: `m`/, "diamond prop conflict");
michael@0 313 };
michael@0 314
michael@0 315 exports["test providing requirements through proto"] = function (assert) {
michael@0 316 var t = Trait({ required: Trait.required }).create({ required: "test" });
michael@0 317 assert.equal(t.required, "test", "property from proto is inherited");
michael@0 318 };
michael@0 319
michael@0 320 if (module == require.main)
michael@0 321 require("test").run(exports);

mercurial