| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 | /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */"use strict";const { Trait } = require('sdk/deprecated/traits');exports['test:simple compose'] = function(assert) {  let List = Trait.compose({    _list: null,    constructor: function List() {      this._list = [];    },    list: function list() this._list.slice(0),    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  assert.notEqual(undefined, List, 'should not be undefined');  assert.equal('function', typeof List, 'type should be function');  assert.equal(    Trait.compose,    List.compose,    'should inherit static compose'  );  assert.equal(    Trait.override,    List.override,    'should inherit static override'  );  assert.equal(    Trait.required,    List.required,    'should inherit static required'  );  assert.equal(    Trait.resolve,    List.resolve,    'should inherit static resolve'  );  assert.ok(    !('_list' in List.prototype),    'should not expose private API'  );}exports['test: compose trait instance and create instance'] = function(assert) {  let List = Trait.compose({    constructor: function List(options) {      this._list = [];      this._public.publicMember = options.publicMember;    },    _privateMember: true,    get privateMember() this._privateMember,    get list() this._list.slice(0),    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list      let index = list.indexOf(item)      if (0 <= index) list.slice(index, 1)    }  });  let list = List({ publicMember: true });  assert.equal('object', typeof list, 'should return an object')  assert.equal(    true,    list instanceof List,    'should be instance of a List'  );  assert.equal(    undefined,    list._privateMember,    'instance should not expose private API'  );  assert.equal(    true,    list.privateMember,    'privates are accessible by  public API'  );  list._privateMember = false;  assert.equal(    true,    list.privateMember,    'property changes on instance must not affect privates'  );  assert.ok(    !('_list' in list),    'instance should not expose private members'  );  assert.equal(    true,    list.publicMember,    'public members are exposed'  )  assert.equal(    'function',    typeof list.add,    'should be function'  )  assert.equal(    'function',    typeof list.remove,    'should be function'  );  list.add(1);  assert.equal(    1,    list.list[0],    'exposed public API should be able of modifying privates'  )};exports['test:instances must not be hackable'] = function(assert) {  let SECRET = 'There is no secret!',      secret = null;  let Class = Trait.compose({    _secret: null,    protect: function(data) this._secret = data  });  let i1 = Class();  i1.protect(SECRET);  assert.equal(    undefined,    (function() this._secret).call(i1),    'call / apply can\'t access private state'  );  let proto = Object.getPrototypeOf(i1);  try {    proto.reveal = function() this._secret;    secret = i1.reveal();  } catch(e) {}  assert.notEqual(    SECRET,    secret,    'public __proto__ changes should not affect privates'  );  secret = null;  let Class2 = Trait.compose({    _secret: null,    protect: function(data) this._secret = data  });  let i2 = Class2();  i2.protect(SECRET);  try {    Object.prototype.reveal = function() this._secret;    secret = i2.reveal();  } catch(e) {}  assert.notEqual(    SECRET,    secret,    'Object.prototype changes must not affect instances'  );}exports['test:instanceof'] = function(assert) {  const List = Trait.compose({    // private API:    _list: null,    // public API    constructor: function List() {      this._list = []    },    get length() this._list.length,    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  assert.ok(List() instanceof List, 'Must be instance of List');  assert.ok(new List() instanceof List, 'Must be instance of List');};exports['test:privates are unaccessible'] = function(assert) {  const List = Trait.compose({    // private API:    _list: null,    // public API    constructor: function List() {      this._list = [];    },    get length() this._list.length,    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  let list = List();  assert.ok(!('_list' in list), 'no privates on instance');  assert.ok(    !('_list' in List.prototype),    'no privates on prototype'  );};exports['test:public API can access private API'] = function(assert) {  const List = Trait.compose({    // private API:    _list: null,    // public API    constructor: function List() {      this._list = [];    },    get length() this._list.length,    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  let list = List();  list.add('test');  assert.equal(    1,    list.length,    'should be able to add element and access it from public getter'  );};exports['test:required'] = function(assert) {  const Enumerable = Trait.compose({    list: Trait.required,    forEach: function forEach(consumer) {      return this.list.forEach(consumer);    }  });  try {    let i = Enumerable();    assert.fail('should throw when creating instance with required properties');  } catch(e) {    assert.equal(      'Error: Missing required property: list',      e.toString(),      'required prop error'    );  }};exports['test:compose with required'] = function(assert) {  const List = Trait.compose({    // private API:    _list: null,    // public API    constructor: function List() {      this._list = [];    },    get length() this._list.length,    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  const Enumerable = Trait.compose({    list: Trait.required,    forEach: function forEach(consumer) {      return this.list.forEach(consumer);    }  });  const EnumerableList = Enumerable.compose({    get list() this._list.slice(0)  }, List);  let array = [1,2, 'ab']  let l = EnumerableList(array);  array.forEach(function(element) l.add(element));  let number = 0;  l.forEach(function(element, index) {    number ++;    assert.equal(array[index], element, 'should mach array element')  });  assert.equal(    array.length,    number,    'should perform as many asserts as elements in array'  );};exports['test:resolve'] = function(assert) {  const List = Trait.compose({    // private API:    _list: null,    // public API    constructor: function List() {      this._list = [];    },    get length() this._list.length,    add: function add(item) this._list.push(item),    remove: function remove(item) {      let list = this._list;      let index = list.indexOf(item);      if (0 <= index) list.slice(index, 1);    }  });  const Range = List.resolve({    constructor: null,    add: '_add',  }).compose({    min: null,    max: null,    get list() this._list.slice(0),    constructor: function Range(min, max) {      this.min = min;      this.max = max;      this._list = [];    },    add: function(item) {      if (item <= this.max && item >= this.min)        this._add(item)    }  });  let r = Range(0, 10);  assert.equal(    0,    r.min,    'constructor must have set min'  );  assert.equal(    10,    r.max,    'constructor must have set max'  );  assert.equal(    0,    r.length,    'should not contain any elements'  );  r.add(5);  assert.equal(    1,    r.length,    'should add `5` to list'  );  r.add(12);  assert.equal(    1,    r.length,    'should not add `12` to list'  );};exports['test:custom iterator'] = function(assert) {  let Sub = Trait.compose({    foo: "foo",    bar: "bar",    baz: "baz",    __iterator__: function() {      yield 1;      yield 2;      yield 3;    }  });  let (i = 0, sub = Sub()) {    for (let item in sub)    assert.equal(++i, item, "iterated item has the right value");  };};require('sdk/test').run(exports);
 |