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);
|