property-manager
Version:
make it easier to manage the properties/attributes of your class.
457 lines (442 loc) • 10.9 kB
JavaScript
import sinonChai from "sinon-chai";
import sinon from "sinon";
import chai from "chai";
var assert = chai.assert;
var expect = chai.expect;
var should = chai.should();
chai.use(sinonChai);
import inherits from 'inherits-ex/lib/inherits';
import createObjectWith from 'inherits-ex/lib/createObjectWith';
import setPrototypeOf from 'inherits-ex/lib/setPrototypeOf';
import extend from 'util-ex/lib/_extend';
import defineProperty from 'util-ex/lib/defineProperty';
import Properties from '../src/properties';
let fnType = null;
const FakeType = (function() {
var ctor;
function FakeType() {
return ctor.apply(this, arguments);
}
ctor = fnType = sinon.spy(function(type) {
if (!(this instanceof FakeType)) {
return createObjectWith(FakeType, arguments);
}
});
FakeType.prototype.isValid = sinon.spy(function() {
return this.valid;
});
FakeType.prototype.errors = [];
return FakeType;
})();
describe('Properties', function() {
var classAttrs, classAttrsDetail;
before(function() {
return Properties.prototype.Type = FakeType;
});
after(function() {
fnType.resetHistory();
return delete Properties.prototype.Type;
});
classAttrs = {
prop1: {
value: 432,
alias: ['pr1', 'p1']
},
prop2: "233",
prop3: void 0,
prop4: null,
_prop5: 'nonExport',
prop6: 'defaultValue',
name: {
name: '名'
},
hidden: {
enumerable: false,
value: 123
},
prop7: {
writable: false,
value: 719
}
};
classAttrsDetail = {
prop1: {
value: 432,
enumerable: true,
assigned: true,
exported: true,
alias: ['pr1', 'p1']
},
prop2: {
value: '233',
enumerable: true,
assigned: true,
exported: true
},
prop3: {
value: void 0,
enumerable: true,
assigned: true,
exported: true
},
prop4: {
value: null,
enumerable: true,
assigned: true,
exported: true
},
'_prop5': {
value: 'nonExport',
enumerable: true,
assigned: true,
exported: false
},
prop6: {
value: 'defaultValue',
enumerable: true,
assigned: true,
exported: true
},
name: {
name: '名',
enumerable: true,
assigned: true,
exported: true
},
hidden: {
enumerable: false,
value: 123,
assigned: false,
exported: false
},
prop7: {
writable: false,
value: 719,
enumerable: true,
assigned: false,
exported: false
}
};
it('should create a properties', function() {
var obj, result;
result = Properties(classAttrs, '_');
obj = {};
result.mergeTo(result, obj).should.be.deep.equal(classAttrsDetail);
});
describe('#assignTo', function() {
it('should assign properties to another', function() {
var c, result;
result = Properties(classAttrs, '_');
c = extend({}, classAttrsDetail);
delete c.prop7;
delete c.hidden;
result.assignTo({}, result).should.be.deep.equal(c);
delete c.prop1;
result.assignTo({}, result, {
exclude: 'prop1'
}).should.be.deep.equal(c);
});
it('should assign exported properties to another', function() {
var c, result;
result = Properties(classAttrs, '_');
c = extend({}, classAttrsDetail);
delete c._prop5;
delete c.hidden;
delete c.prop1;
delete c.prop7;
result.assignTo({}, result, {
isExported: true,
exclude: 'prop1'
}).should.be.deep.equal(c);
});
it('should assign properties to another and skip exists', function() {
var c, result;
result = Properties(classAttrs, '_');
c = extend({}, classAttrsDetail);
delete c.prop7;
delete c.hidden;
c.prop2 = 1;
result.assignTo({
prop2: 1
}, result, {
skipExists: true
}).should.be.deep.equal(c);
});
});
it('should validate value of property via type', function() {
var result;
result = Properties({
test: {
type: 'String'
}
});
FakeType.prototype.errors.push({
name: 'sff',
message: 'hahha'
});
should["throw"](result.assignTo.bind(result, {}, {
test: 123
}));
FakeType.prototype.valid = true;
result.assignTo({}, {
test: 123
}).should.be.deep.equal({
test: 123
});
});
it('should check isDefaultObject', function() {
var obj, result;
result = Properties(classAttrs, '_');
result.isDefaultObject({}).should.be["true"];
result.isDefaultObject({
prop1: 431
}).should.be["false"];
obj = {
p1: 432,
prop2: "233",
prop4: null,
_prop5: 'nonExport',
prop6: 'defaultValue'
};
result.isDefaultObject(obj).should.be["true"];
obj.p1 = 431;
result.isDefaultObject(obj).should.be["false"];
});
it('should throw a hint error when clone object failed', function() {
var DontClone, props, result;
DontClone = (function() {
function DontClone() {}
DontClone.prototype.clone = function() {
throw new Error('disable clone');
};
return DontClone;
})();
props = Properties({
obj: {
value: new DontClone()
}
});
result = {};
expect(props.initializeTo.bind(props, result)).to.be["throw"]('the attribute "obj" can not be cloned, set descriptor "clone" to false');
});
it('should initializeTo with src', function() {
var props, result;
props = Properties({
num: {
value: 1
},
undef: {
value: void 0
},
unnull: {
value: null
}
});
result = {};
props.initializeTo(result, {
num: 34
});
expect(result.num).to.be.equal(34);
expect(result).to.have.property('undef');
expect(result).to.have.property('unnull');
});
it('should initializeTo with src and skip undefined or null', function() {
var props, result;
props = Properties({
num: {
value: 1
},
undef: {
value: void 0
},
unnull: {
value: null
}
});
result = {
num: 12
};
props.initializeTo(result, {}, {
skipUndefined: true,
skipNull: true
});
expect(result.num).to.be.equal(12);
expect(result).to.not.have.property('undef');
expect(result).to.not.have.property('unnull');
});
it('should initializeTo with src and overwrite', function() {
var props, result;
props = Properties({
num: {
value: 1
}
});
result = {
num: 12
};
props.initializeTo(result, {}, {
overwrite: true
});
expect(result.num).to.be.equal(1);
});
describe('smart assign', function() {
it('should smart assign readonly property value', function() {
var props, result;
props = Properties({
num: {
value: 1,
assigned: '__num',
writable: false
}
});
result = {};
props.initializeTo(result);
var err
try {result.num = 12;} catch(e) {err = e}
expect(err).to.be.exist
expect(result.num).to.be.equal(1);
});
it('should add the getter/setter to the smart assign attribute automatically', function() {
var props, result;
props = Properties({
obj: {
value: console,
clone: false,
assigned: '__oConsole',
assign: function(value, dest, src, name) {
expect(dest).be.equal(result);
expect(src).be.equal(result);
expect(name).be.equal('__oConsole');
return value;
}
}
});
result = {};
props.initializeTo(result);
result.__oConsole = 12;
expect(result.obj).to.be.equal(12);
result.obj = 66;
return expect(result.__oConsole).to.be.equal(66);
});
it('should call the setter when initilizing the property value', function() {
var props, result, vAssignFn;
vAssignFn = sinon.spy(function(value, dest, src, name) {
return value;
});
props = Properties({
num: {
value: 1,
assigned: '__num',
assign: vAssignFn
}
});
result = {};
props.initializeTo(result);
expect(result.num).to.be.equal(1);
expect(vAssignFn).to.be.calledOnce;
result.num = 2;
expect(vAssignFn).to.be.calledTwice;
});
it('should not clone object', function() {
var props, result, vAssignFn;
vAssignFn = sinon.spy(function(value, dest, src, name) {
return value;
});
props = Properties({
o: {
value: console,
assigned: '',
assign: vAssignFn
}
});
result = {};
props.initializeTo(result);
expect(result.o).to.be.equal(console);
result.o = console;
expect(vAssignFn).to.be.calledTwice;
});
});
describe('#getValue()', function() {
it('should get value from attribute', function() {
var props, result;
props = Properties({
str: {
type: 'String'
}
});
result = props.getValue({
str: '1234'
}, 'str');
expect(result).to.be.equal('1234');
});
it('should get value from attribute name', function() {
var props, result;
props = Properties({
str: {
name: 'Str1',
type: 'String'
}
});
result = props.getValue({
Str1: '1234'
}, 'str');
expect(result).to.be.equal('1234');
});
it('should get value from attribute alias string', function() {
var props, result;
props = Properties({
str: {
alias: 'Str1',
type: 'String'
}
});
result = props.getValue({
Str1: '1234'
}, 'str');
expect(result).to.be.equal('1234');
});
it('should get value from attribute alias array', function() {
var props, result;
props = Properties({
str: {
alias: ['Str1'],
type: 'String'
}
});
result = props.getValue({
Str1: '1234'
}, 'str');
expect(result).to.be.equal('1234');
});
});
describe('#extends', function() {
it('should inherit properties', function() {
var obj, result;
result = Properties({
a: {
value: 1
}
});
result = result["extends"]({
b: {
value: 2
}
});
obj = {};
result.mergeTo(result, obj).should.be.deep.equal({
b: {
value: 2,
enumerable: true,
assigned: true,
exported: true
},
a: {
value: 1,
enumerable: true,
assigned: true,
exported: true
}
});
});
});
});