struffer
Version:
Struct + Buffer = Struffer
451 lines • 17.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const alsatian_1 = require("alsatian");
const base_1 = require("../src/base");
const os_1 = require("os");
const common_1 = require("../src/common");
const util_1 = require("util");
// tslint:disable-next-line:max-line-length
exports.CommonAPITestCase = alsatian_1.TestCase('foobar', 'bar', 'foo', 'something', 'UTF-8-Up-Next...', '👍');
/* istanbul ignore next */
class TestsBase {
get factory() {
return () => base_1.default;
}
get defaultSize() {
return 8;
}
}
class FactoryTestsBase extends TestsBase {
basicGeneration({ byteLength, bitLength, types }) {
const Test = this.factory('Basic', types.map((type, i) => {
return [type, `member${i}`];
}));
alsatian_1.Expect(Test.byteLength).toBe(byteLength);
alsatian_1.Expect(Test.bitLength).toBe(bitLength);
}
instantiation(name, offset, types) {
const Test = this.factory(name, types.map((type, i) => {
return [type, `member${i}`];
}));
const buffer = Buffer.alloc(Test.byteLength + ((offset !== null) ? offset : 0));
const struff = new Test(buffer, (offset !== null) ? offset : undefined);
alsatian_1.Expect(struff.kind).toBe(name);
alsatian_1.Expect(struff.offset).toBe((offset !== null) ? offset : 0);
alsatian_1.Expect(struff.size).toBe(types.length);
alsatian_1.Expect(struff[Symbol.toStringTag]).toBe(`${struff.constructor.name}<${name}>`);
}
}
exports.FactoryTestsBase = FactoryTestsBase;
class APITestsBase extends TestsBase {
retrievalBase(bufferData, stuff) {
const Test = this.factory('Test', stuff.map(([type], i) => {
return [type, `member${i}`];
}));
const buf = Buffer.alloc(Test.byteLength);
buf.set(bufferData);
return new Test(buf);
}
assignmentBase(stuff) {
const Test = this.factory('Test', stuff.map(([type], i) => {
return [type, `member${i}`];
}));
const buf = Buffer.alloc(Test.byteLength);
return new Test(buf);
}
otherBase(names, size = this.defaultSize) {
const Test = this.factory('Test', names.map(name => [`u${size}`, name]));
const buf = Buffer.alloc(Test.byteLength);
return new Test(buf);
}
}
class ObjectAPITestsBase extends APITestsBase {
retrieval(bufferData, stuff) {
const struff = super.retrievalBase(bufferData, stuff);
for (const [i, [, value]] of stuff.entries()) {
alsatian_1.Expect(struff.structure[`member${i}`]).toBe(value);
}
alsatian_1.Expect(struff.structure.someNonexistentMember).not.toBeDefined();
}
// technically, this test also includes retrieval but ¯\_(ツ)_/¯
assignment(stuff) {
const struff = super.assignmentBase(stuff);
for (const [i, [, value]] of stuff.entries()) {
alsatian_1.Expect(() => struff.structure[`member${i}`] = value).not.toThrow();
alsatian_1.Expect(struff.structure[`member${i}`]).toBe(value);
}
alsatian_1.Expect(() => struff.structure.someNonexistentMember = 1).toThrow();
}
presence(...names) {
const struff = super.otherBase(names);
for (const name of names) {
alsatian_1.Expect(name in struff.structure).toBe(true);
}
alsatian_1.Expect('someNonexistentMember' in struff.structure).toBe(false);
}
deletion(...names) {
const struff = super.otherBase(names);
struff.buffer.fill(1);
for (const name of names) {
/*
* in strict mode (which typescript enables by default), `delete` returning
* `false` causes a `TypeError` to be thrown
*/
alsatian_1.Expect(() => alsatian_1.Expect(delete struff.structure[name]).toBe(true)).not.toThrow();
alsatian_1.Expect(struff.structure[name]).toBe(0);
}
// same here
alsatian_1.Expect(() => alsatian_1.Expect(delete struff.structure.someNonexistentMember).toBe(false)).toThrow();
}
enumeration(...names) {
const struff = super.otherBase(names);
let i = 0;
for (const member of Object.keys(struff.structure)) {
alsatian_1.Expect(member).toBe(names[i]);
i++;
}
}
propertyDescription(...names) {
const struff = super.otherBase(names);
for (const name of names) {
let desc = Object.getOwnPropertyDescriptor(struff.structure, name);
alsatian_1.Expect(desc).toBeDefined();
desc = desc;
alsatian_1.Expect(desc.configurable).toBe(true);
alsatian_1.Expect(desc.enumerable).toBe(true);
alsatian_1.Expect(desc.writable).toBe(true);
}
const desc = Object.getOwnPropertyDescriptor(struff.structure, 'someNonexistentMember');
alsatian_1.Expect(desc).not.toBeDefined();
}
}
exports.ObjectAPITestsBase = ObjectAPITestsBase;
class MapAPITestsBase extends APITestsBase {
retrieval(bufferData, stuff) {
const struff = super.retrievalBase(bufferData, stuff);
for (const [i, [, value]] of stuff.entries()) {
alsatian_1.Expect(struff.get(`member${i}`)).toBe(value);
}
alsatian_1.Expect(struff.get('someNonexistentMember')).not.toBeDefined();
}
// technically, this test also includes retrieval but ¯\_(ツ)_/¯
assignment(stuff) {
const struff = super.assignmentBase(stuff);
for (const [i, [, value]] of stuff.entries()) {
alsatian_1.Expect(() => struff.set(`member${i}`, value)).not.toThrow();
alsatian_1.Expect(struff.get(`member${i}`)).toBe(value);
}
alsatian_1.Expect(() => struff.set('someNonexistentMember', 1)).toThrow();
}
presence(...names) {
const struff = super.otherBase(names);
for (const name of names) {
alsatian_1.Expect(struff.has(name)).toBe(true);
}
alsatian_1.Expect(struff.has('someNonexistentMember')).toBe(false);
}
deletion(...names) {
const struff = super.otherBase(names);
struff.buffer.fill(1);
for (const name of names) {
alsatian_1.Expect(struff.delete(name)).toBe(true);
alsatian_1.Expect(struff.get(name)).toBe(0);
}
alsatian_1.Expect(struff.delete('someNonexistentMember')).toBe(false);
}
enumeration(...names) {
const struff = super.otherBase(names);
let i = 0;
for (const member of struff.keys()) {
alsatian_1.Expect(member).toBe(names[i]);
i++;
}
}
clearance(...names) {
const struff = super.otherBase(names);
struff.buffer.fill(1);
struff.clear();
for (const name of names) {
alsatian_1.Expect(struff.get(name)).toBe(0);
}
}
iteration(thisArg = undefined, ...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let i = 0;
struff.forEach(function (value, key, map) {
alsatian_1.Expect(key).toBe(names[i]);
alsatian_1.Expect(value).toBe(1);
alsatian_1.Expect(map).toBe(struff);
alsatian_1.Expect(this).toBe(thisArg);
i++;
}, thisArg);
}
valueEnumeration(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let i = 0;
for (const val of struff.values()) {
alsatian_1.Expect(val).toBe(1);
i++;
}
}
entryEnumeration(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let i = 0;
for (const [name, value] of struff.entries()) {
alsatian_1.Expect(name).toBe(names[i]);
alsatian_1.Expect(value).toBe(1);
i++;
}
}
automaticIteration(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let i = 0;
for (const [name, value] of struff) {
alsatian_1.Expect(name).toBe(names[i]);
alsatian_1.Expect(value).toBe(1);
i++;
}
}
}
exports.MapAPITestsBase = MapAPITestsBase;
class BatchAPITestsBase extends APITestsBase {
retrieval(bufferData, stuff) {
const struff = super.retrievalBase(bufferData, stuff);
const members = stuff.filter((_, i) => i % 2 === 0).map((_, i) => `member${i}`);
const dict = struff.getMany(members);
for (const name of Object.keys(dict)) {
const i = Number(name.slice(6));
alsatian_1.Expect(dict[name]).toBe(stuff[i][1]);
}
const all = struff.getMany();
for (const name of Object.keys(dict)) {
const i = Number(name.slice(6));
alsatian_1.Expect(all[name]).toBe(stuff[i][1]);
}
}
// technically, this test also includes retrieval but ¯\_(ツ)_/¯
assignment(stuff) {
const struff = super.assignmentBase(stuff);
const dict = {};
for (const [i, [, value]] of stuff.entries()) {
dict[`member${i}`] = value;
}
struff.setMany(dict);
for (const [i, [, value]] of stuff.entries()) {
alsatian_1.Expect(struff.get(`member${i}`)).toBe(value);
}
}
presence(...names) {
const struff = super.otherBase(names);
const present = struff.hasMany(names.concat('someNonexistentMember'));
for (const name of names) {
alsatian_1.Expect(present[name]).toBe(true);
}
alsatian_1.Expect(present.someNonexistentMember).toBe(false);
}
deletion(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
const toDelete = names.filter((_, i) => i % 2 === 0);
const result = struff.deleteMany(toDelete);
alsatian_1.Expect(result).toBe(true);
for (const name of names) {
if (toDelete.includes(name)) {
alsatian_1.Expect(struff.get(name)).toBe(0);
}
else {
alsatian_1.Expect(struff.get(name)).not.toBe(0);
}
}
const wrongDelete = names.filter(n => !toDelete.includes(n))
.concat('someNonexistentMember')
.concat(names[0]);
const result2 = struff.deleteMany(wrongDelete);
alsatian_1.Expect(result2).toBe(false);
for (const name of names) {
alsatian_1.Expect(struff.get(name)).toBe(0);
}
}
}
exports.BatchAPITestsBase = BatchAPITestsBase;
class MiscellaneousTestsBase extends APITestsBase {
stringRepresentation(factoryName, name, members) {
let rep = `${factoryName}<${name}> {\n`;
for (const [type, name, value] of members) {
const typeInfo = common_1.parseType(type);
rep += ' ';
rep += name;
rep += ': ';
rep += (typeInfo.signature === common_1.MemberSignature.Signed) ? 'i' : 'u';
rep += typeInfo.bitSize;
rep += (typeInfo.endianness === common_1.MemberEndianness.BigEndian) ? 'be' : '';
rep += ' = ';
rep += value;
rep += ';\n';
}
rep += '}';
return rep;
}
pad(arr, signature = 'u', endianness = 'le') {
let result = arr.join('');
if (signature === 'u') {
if (endianness === 'le') {
result = result.padStart(this.defaultSize, '0');
}
else {
result = result.padEnd(this.defaultSize, '0');
}
}
else {
if (endianness === 'le') {
result = result.padStart(this.defaultSize, String(arr[0]));
}
else {
result = result.padEnd(this.defaultSize, String(arr[arr.length - 1]));
}
}
return result.split('').map(i => (i === '0') ? 0 : 1);
}
bitEnumeration(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let expected = [];
expected = '1'.padStart(this.defaultSize, '0').split('').map(i => (i === '0') ? 0 : 1);
/* istanbul ignore next */
if (os_1.endianness() === 'BE') {
expected.reverse();
}
for (const bits of struff.bits()) {
alsatian_1.Expect(bits).toEqual(expected);
}
}
bitEntryEnumeration(...names) {
const struff = super.otherBase(names);
for (const name of names) {
struff.set(name, 1);
}
let expected = [];
expected = '1'.padStart(this.defaultSize, '0').split('').map(i => (i === '0') ? 0 : 1);
/* istanbul ignore next */
if (os_1.endianness() === 'BE') {
expected.reverse();
}
let i = 0;
for (const [name, bits] of struff.bitEntries()) {
alsatian_1.Expect(name).toBe(names[i]);
alsatian_1.Expect(bits).toEqual(expected);
i++;
}
}
getBits() {
const Test = this.factory('Test', [
[`u${this.defaultSize}`, 'foo'],
[`i${this.defaultSize}`, 'bar'],
[`u${this.defaultSize}be`, 'some'],
[`i${this.defaultSize}be`, 'thing'],
]);
const buf = Buffer.alloc(Test.byteLength);
const struff = new Test(buf);
struff.setMany({
foo: 1,
bar: -2,
some: 1,
thing: -2,
});
const expected = {
foo: this.pad([1]),
bar: this.pad([1, 0], 'i'),
some: this.pad([1], 'u', 'be'),
thing: this.pad([0, 1], 'i', 'be'),
};
for (const name of ['foo', 'bar', 'some', 'thing']) {
alsatian_1.Expect(struff.getBits(name)).toEqual(expected[name]);
}
alsatian_1.Expect(() => struff.getBits('someNonexistentMember')).toThrow();
}
setBits() {
const Test = this.factory('Test', [
[`u${this.defaultSize}`, 'foo'],
[`i${this.defaultSize}`, 'bar'],
[`u${this.defaultSize}be`, 'some'],
[`i${this.defaultSize}be`, 'thing'],
]);
const buf = Buffer.alloc(Test.byteLength);
const struff = new Test(buf);
const members = ['foo', 'bar', 'some', 'thing'];
const values = {
foo: this.pad([1]),
bar: this.pad([1, 0], 'i'),
some: this.pad([1], 'u', 'be'),
thing: this.pad([0, 1], 'i', 'be'),
};
for (const name of members) {
struff.setBits(name, values[name]);
}
const expected = {
foo: 1,
bar: -2,
some: 1,
thing: -2,
};
const result = struff.getMany(members);
alsatian_1.Expect(result).toEqual(expected);
alsatian_1.Expect(() => struff.setBits('someNonexistentMember', [1, 1])).toThrow();
}
toString(name, members) {
const Test = this.factory(name, members.map(([type, name]) => {
return [type, name];
}));
const buf = Buffer.alloc(Test.byteLength);
const struff = new Test(buf);
struff.setMany(members.reduce((obj, [, name, value]) => {
obj[name] = value;
return obj;
}, {}));
alsatian_1.Expect(struff.toString()).toBe(this.stringRepresentation(struff.constructor.name, name, members));
}
coercion(name, members) {
const Test = this.factory(name, members.map(([type, name]) => {
return [type, name];
}));
const buf = Buffer.alloc(Test.byteLength);
const struff = new Test(buf);
struff.setMany(members.reduce((obj, [, name, value]) => {
obj[name] = value;
return obj;
}, {}));
alsatian_1.Expect(() => +struff).toThrow();
// tslint:disable-next-line:max-line-length
alsatian_1.Expect(`${struff}foobar`).toBe(`${this.stringRepresentation(struff.constructor.name, name, members)}foobar`);
}
inspection(name, members) {
const Test = this.factory(name, members.map(([type, name]) => {
return [type, name];
}));
const buf = Buffer.alloc(Test.byteLength);
const struff = new Test(buf);
struff.setMany(members.reduce((obj, [, name, value]) => {
obj[name] = value;
return obj;
}, {}));
alsatian_1.Expect(util_1.inspect(struff)).toBe(this.stringRepresentation(struff.constructor.name, name, members));
}
}
exports.MiscellaneousTestsBase = MiscellaneousTestsBase;
//# sourceMappingURL=common.js.map