reign
Version:
A persistent, typed-objects implementation.
514 lines (441 loc) • 13.9 kB
JavaScript
;
var _ = require("../..");
var _2 = require("./");
var _symbols = require("../../symbols");
describeRealm('StructType', function (options) {
let realm;
let StructType;
let T;
let RGBA;
before(() => {
realm = options.realm;
StructType = realm.StructType;
T = realm.T;
});
it('StructType should be an instance of realm.TypeClass', function () {
StructType.should.be.an.instanceOf(realm.TypeClass);
});
describe('Simple', function () {
let struct;
let SimpleStruct;
it('should create a new struct type', function () {
SimpleStruct = new StructType({
value: T.Uint8
});
});
it('SimpleStruct should be an instance of StructType', function () {
SimpleStruct.should.be.an.instanceOf(StructType);
});
it('should create an instance', function () {
struct = new SimpleStruct({ value: 33 });
});
it('struct should be an instance of SimpleStruct', function () {
struct.should.be.an.instanceOf(SimpleStruct);
});
it('should get a field value', function () {
struct.value.should.equal(33);
});
it('should set a field value', function () {
struct.value = 77;
});
it('should get a field value again', function () {
struct.value.should.equal(77);
});
it('should convert the struct to JSON', function () {
JSON.parse(JSON.stringify(struct)).should.eql({
value: 77
});
});
it('should clear the struct', function () {
SimpleStruct.clear(struct[_symbols.$Backing], struct[_symbols.$Address]);
});
it('should have reset the value to zero', function () {
struct.value.should.equal(0);
});
it('should create an array of structs', function () {
const arr = new SimpleStruct.Array(5);
arr.length.should.equal(5);
arr[3].value = 12;
JSON.parse(JSON.stringify(arr)).should.eql([{ value: 0 }, { value: 0 }, { value: 0 }, { value: 12 }, { value: 0 }]);
});
});
describe('Multiple fields', function () {
let struct;
it('should create a new struct type', function () {
RGBA = new StructType({
r: T.Uint8,
g: T.Uint8,
b: T.Uint8,
a: T.Uint8
}, {
defaults: {
a: 255
}
});
});
it('RGBA should be an instance of StructType', function () {
RGBA.should.be.an.instanceOf(StructType);
});
it('should create an instance with default field values', function () {
struct = new RGBA();
});
it('struct should be an instance of RGBA', function () {
struct.should.be.an.instanceOf(RGBA);
});
it('should have the right initial field values', function () {
struct.r.should.equal(0);
struct.g.should.equal(0);
struct.b.should.equal(0);
struct.a.should.equal(255);
});
it('should create an instance, specifying some initial values', function () {
struct = new RGBA({
r: 127,
g: 127
});
});
it('should have the right initial field values', function () {
struct.r.should.equal(127);
struct.g.should.equal(127);
struct.b.should.equal(0);
struct.a.should.equal(255);
});
it('should create an instance, overriding a default value', function () {
struct = new RGBA({
a: 5
});
});
it('should have the right initial field values', function () {
struct.r.should.equal(0);
struct.g.should.equal(0);
struct.b.should.equal(0);
struct.a.should.equal(5);
});
it('should create an instance, specifying all field values', function () {
struct = new RGBA({
r: 127,
g: 127,
b: 127,
a: 230
});
});
it('should have the right initial field values', function () {
struct.r.should.equal(127);
struct.g.should.equal(127);
struct.b.should.equal(127);
struct.a.should.equal(230);
});
it('should set field values', function () {
struct.r = 12;;
struct.g = 127;;
struct.b = 230;;
struct.a = 255;;
});
it('should get a field value', function () {
struct.r.should.equal(12);
struct.g.should.equal(127);
struct.b.should.equal(230);
struct.a.should.equal(255);
});
it('should convert the struct to JSON', function () {
JSON.parse(JSON.stringify(struct)).should.eql({
r: 12,
g: 127,
b: 230,
a: 255
});
});
it('should clear the struct', function () {
RGBA.clear(struct[_symbols.$Backing], struct[_symbols.$Address]);
});
it('should have reset the field values to zero', function () {
struct.r.should.equal(0);
struct.g.should.equal(0);
struct.b.should.equal(0);
struct.a.should.equal(0);
});
describe('.hashValue()', function () {
it('should hash a struct', function () {
const hash = RGBA.hashValue(struct);
RGBA.hashValue(struct).should.equal(hash);
struct.g = 56;
RGBA.hashValue(struct).should.not.equal(hash);
});
});
describe('.randomValue()', function () {
it('should create a random value', function () {
const pixel = RGBA.randomValue();
pixel.should.be.an.instanceOf(RGBA);
});
});
describe('.compareValues()', function () {
it('should compare the same pixel', function () {
const a = new RGBA();
RGBA.compareValues(a, a).should.equal(0);
});
it('should compare two identical pixels', function () {
const a = new RGBA();
const b = new RGBA();
RGBA.compareValues(a, b).should.equal(0);
});
it('should compare two different pixels, with the same fields different', function () {
const a = new RGBA({ r: 1 });
const b = new RGBA({ r: 2 });
RGBA.compareValues(a, b).should.equal(-1);
});
it('should compare two different pixels, with different fields', function () {
const a = new RGBA({ r: 1, g: 2, b: 3 });
const b = new RGBA({ r: 1, g: 2, b: 2 });
RGBA.compareValues(a, b).should.equal(1);
});
});
describe('.compareAddresses()', function () {
it('should compare the same pixel', function () {
const a = new RGBA();
RGBA.compareAddresses(a[_symbols.$Backing], a[_symbols.$Address], a[_symbols.$Address]).should.equal(0);
});
it('should compare two identical pixels', function () {
const a = new RGBA();
const b = new RGBA();
RGBA.compareAddresses(a[_symbols.$Backing], a[_symbols.$Address], b[_symbols.$Address]).should.equal(0);
});
it('should compare two different pixels, with the same fields different', function () {
const a = new RGBA({ r: 1 });
const b = new RGBA({ r: 2 });
RGBA.compareAddresses(a[_symbols.$Backing], a[_symbols.$Address], b[_symbols.$Address]).should.equal(-1);
});
it('should compare two different pixels, with different fields', function () {
const a = new RGBA({ r: 1, g: 2, b: 3 });
const b = new RGBA({ r: 1, g: 2, b: 2 });
RGBA.compareAddresses(a[_symbols.$Backing], a[_symbols.$Address], b[_symbols.$Address]).should.equal(1);
});
});
describe('.compareAddressValue()', function () {
it('should compare the same pixel', function () {
const a = new RGBA();
RGBA.compareAddressValue(a[_symbols.$Backing], a[_symbols.$Address], a).should.equal(0);
});
it('should compare two identical pixels', function () {
const a = new RGBA();
const b = new RGBA();
RGBA.compareAddressValue(a[_symbols.$Backing], a[_symbols.$Address], b).should.equal(0);
});
it('should compare two different pixels, with the same fields different', function () {
const a = new RGBA({ r: 1 });
const b = new RGBA({ r: 2 });
RGBA.compareAddressValue(a[_symbols.$Backing], a[_symbols.$Address], b).should.equal(-1);
});
it('should compare two different pixels, with different fields', function () {
const a = new RGBA({ r: 1, g: 2, b: 3 });
const b = new RGBA({ r: 1, g: 2, b: 2 });
RGBA.compareAddressValue(a[_symbols.$Backing], a[_symbols.$Address], b).should.equal(1);
});
});
});
describe('Struct list', function () {
let Column, Screen;
let display;
it('should create a Column of pixels', function () {
Column = new StructType(RGBA, 640);
});
it('should create a Screen of Columns', function () {
Screen = new StructType(Column, 480);
});
it('should create a new screen instance', function () {
display = new Screen();
});
it('display should have columns', function () {
for (let i = 0; i < 480; i++) {
display[i].should.be.an.instanceOf(Column);
}
});
it('columns should have pixels', function () {
for (let i = 0; i < 480; i++) {
const col = display[i];
for (let j = 0; j < 480; j++) {
const pixel = col[j];
pixel.should.be.an.instanceOf(RGBA);
}
}
});
it('should reach into a screen and set some pixels', function () {
display[10][10].r = 32;
display[10][10].g = 32;
display[10][10].b = 32;
});
});
describe('Struct within a struct', function () {
let Box;
let struct;
it('should create a new struct type', function () {
Box = new StructType([['top', RGBA], ['right', RGBA], ['bottom', RGBA], ['left', RGBA]]);
});
it('Box should be an instance of StructType', function () {
Box.should.be.an.instanceOf(StructType);
});
it('should have the right size', function () {
Box.byteLength.should.equal(16);
});
it('should create an instance with default field values', function () {
struct = new Box();
});
it('struct should be an instance of Box', function () {
struct.should.be.an.instanceOf(Box);
});
it('should have the right initial field values', function () {
struct.top.toJSON().should.eql({
r: 0,
g: 0,
b: 0,
a: 255
});
struct.right.toJSON().should.eql({
r: 0,
g: 0,
b: 0,
a: 255
});
struct.bottom.toJSON().should.eql({
r: 0,
g: 0,
b: 0,
a: 255
});
struct.left.toJSON().should.eql({
r: 0,
g: 0,
b: 0,
a: 255
});
});
it('should convert the whole structure to JSON', function () {
JSON.parse(JSON.stringify(struct)).should.eql({
top: {
r: 0,
g: 0,
b: 0,
a: 255
},
right: {
r: 0,
g: 0,
b: 0,
a: 255
},
bottom: {
r: 0,
g: 0,
b: 0,
a: 255
},
left: {
r: 0,
g: 0,
b: 0,
a: 255
}
});
});
});
describe('Struct with self-referential pointers', function () {
let Tree;
let root;
let vanilla;
it('should define a Tree struct, but delay finalization', function () {
Tree = new StructType();
});
it('should not allow instantiation until the struct is finalized', function () {
(() => new Tree()).should.throw(ReferenceError);
});
it('should finalize the struct', function () {
Tree.finalize({
value: T.Uint32,
left: Tree.ref,
right: Tree.ref
});
});
it('should create a root node', function () {
root = new Tree({ value: 5 });
});
it('root should be an instance of Tree', function () {
root.should.be.an.instanceOf(Tree);
});
it('should have the right initial structure', function () {
root.value.should.equal(5);
(root.left === null).should.equal(true);
(root.right === null).should.equal(true);
});
it('should add branches to the node', function () {
root.left = { value: 1 };
root.right = { value: 10 };
});
it('should have the right structure after adding branches', function () {
JSON.parse(JSON.stringify(root)).should.eql({
value: 5,
left: {
value: 1,
left: null,
right: null
},
right: {
value: 10,
left: null,
right: null
}
});
});
it('should add deeper branches', function () {
root.left.left = { value: root.left.value };
root.left.value = 3;
root.right.right = { value: 100 };
});
it('should have the right structure after adding deeper branches', function () {
vanilla = JSON.parse(JSON.stringify(root));
vanilla.should.eql({
value: 5,
left: {
value: 3,
left: {
value: 1,
left: null,
right: null
},
right: null
},
right: {
value: 10,
left: null,
right: {
value: 100,
left: null,
right: null
}
}
});
});
benchmark('Read struct values', 100000, {
Struct: function Struct() {
return root.value;
},
Object: function Object() {
return vanilla.value;
}
});
benchmark('Read nested struct values', 100000, {
Struct: function Struct() {
return root.left.value;
},
Object: function Object() {
return vanilla.left.value;
}
});
benchmark('Read deeply nested struct values', 10000, {
Struct: function Struct() {
return root.right.right.value;
},
Object: function Object() {
return vanilla.right.right.value;
}
});
});
});