Merge pull request #33 from thisandagain/tests

[WIP] Add initial test suite
This commit is contained in:
Andrew Sliwinski 2019-05-24 12:11:33 -04:00 committed by GitHub
commit 7055d1e95a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 589 additions and 17 deletions

View file

@ -14,7 +14,6 @@
"scripts": {
"build": "npm run docs && webpack --progress --colors --bail",
"commitmsg": "commitlint -e $GIT_PARAMS",
"coverage": "tap ./test/{unit,integration}/*.js --coverage --coverage-report=lcov",
"deploy": "touch playground/.nojekyll && gh-pages -t -d playground -m \"Build for $(git log --pretty=format:%H -n1)\"",
"docs": "jsdoc -c .jsdoc.json",
"lint": "eslint .",
@ -25,6 +24,7 @@
"test:ci": "npm run test:ci:build && tap ./dist/test-tmp/test",
"test:unit": "tap --node-arg=--require --node-arg=@babel/register ./test/unit",
"test:integration": "tap --node-arg=--require --node-arg=@babel/register ./test/integration",
"test:coverage": "tap --node-arg=--require --node-arg=@babel/register ./test/{unit,integration}/*.js --coverage --coverage-report=lcov",
"test": "npm run lint && npm run docs && npm run test:unit && npm run test:integration",
"watch": "webpack --progress --colors --watch",
"semantic-release": "semantic-release"

BIN
test/fixtures/valid/bouncing-music-balls.sb vendored Executable file

Binary file not shown.

BIN
test/fixtures/valid/default.sb vendored Normal file

Binary file not shown.

BIN
test/fixtures/valid/ewe-and-me.sb vendored Executable file

Binary file not shown.

View file

@ -0,0 +1,84 @@
const fs = require('fs');
const path = require('path');
const test = require('tap').test;
const {SB1File} = require('../..');
test('default', t => {
const uri = path.resolve(__dirname, '../fixtures/valid/default.sb');
const file = fs.readFileSync(uri);
const sb1 = new SB1File(file);
const json = sb1.json;
t.type(json, Object);
t.deepEqual(json.variables, []);
t.deepEqual(json.lists, []);
t.deepEqual(json.scripts, []);
t.true(Array.isArray(json.costumes));
t.equal(json.costumes[0].costumeName, 'background1');
t.equal(json.costumes[0].baseLayerID, 0);
t.equal(json.costumes[0].baseLayerMD5, 'be2aa84eeac485ab8d9ca51294cd926e.png');
t.equal(json.costumes[0].bitmapResolution, 1);
t.equal(json.costumes[0].rotationCenterX, 240);
t.equal(json.costumes[0].rotationCenterY, 180);
t.true(Array.isArray(json.sounds));
t.equal(json.sounds[0].soundName, 'pop');
t.equal(json.sounds[0].soundID, 0);
t.equal(json.sounds[0].md5, '83a9787d4cb6f3b7632b4ddfebf74367.wav');
t.equal(json.sounds[0].sampleCount, 258);
t.equal(json.sounds[0].rate, 11025);
t.equal(json.sounds[0].format, '');
t.true(Array.isArray(json.children));
t.equal(json.children[0].objName, 'Sprite1');
t.equal(json.children[0].currentCostumeIndex, 0);
t.equal(json.children[0].scratchX, 0);
t.equal(json.children[0].scratchY, 0);
t.equal(json.children[0].scale, 1);
t.equal(json.children[0].direction, -270);
t.equal(json.children[0].rotationStyle, 'normal');
t.equal(json.children[0].isDraggable, false);
t.equal(json.children[0].indexInLibrary, 0);
t.equal(json.children[0].visible, true);
t.deepEqual(json.children[0].variables, []);
t.deepEqual(json.children[0].lists, []);
t.deepEqual(json.children[0].scripts, []);
t.deepEqual(json.children[0].costumes, [
{
baseLayerID: 1,
baseLayerMD5: '87b6d14fce8842fb56155dc7f6496308.png',
bitmapResolution: 1,
costumeName: 'costume1',
rotationCenterX: 47,
rotationCenterY: 55
},
{
baseLayerID: 2,
baseLayerMD5: '07a12efdb3cd7ffc94b55563268367b1.png',
bitmapResolution: 1,
costumeName: 'costume2',
rotationCenterX: 47,
rotationCenterY: 55
}
]);
t.deepEqual(json.children[0].sounds, [
{
format: '',
md5: '83c36d806dc92327b9e7049a565c6bff.wav',
rate: 22050,
sampleCount: 18688,
soundID: 1,
soundName: 'meow'
}
]);
t.equal(json.tempoBPM, 60);
t.equal(json.currentCostumeIndex, 0);
t.equal(json.videoAlpha, 0.5);
t.type(json.info, Object);
t.end();
});

View file

@ -1,8 +0,0 @@
const test = require('tap').test;
const SB1 = require('../..');
test('loads package', t => {
t.type(SB1, Object);
t.end();
});

123
test/integration/valid.js Normal file
View file

@ -0,0 +1,123 @@
const fs = require('fs');
const path = require('path');
const test = require('tap').test;
const {SB1File} = require('../..');
test('bouncing-music-balls', t => {
const uri = path.resolve(__dirname, '../fixtures/valid/bouncing-music-balls.sb');
const file = fs.readFileSync(uri);
const sb1 = new SB1File(file);
const json = sb1.json;
t.type(json, Object);
t.true(Array.isArray(json.variables));
t.equal(json.variables.length, 34);
t.deepEqual(json.variables[0], {
isPersistent: false,
name: 'decrease',
value: 0
});
t.deepEqual(json.lists, []);
t.true(Array.isArray(json.scripts));
t.equal(json.scripts.length, 5);
t.equal(json.scripts[0][0], 113);
t.equal(json.scripts[0][1], 53);
t.equal(json.scripts[0][2][0][0], 'whenGreenFlag');
t.true(Array.isArray(json.costumes));
t.equal(json.costumes[0].costumeName, 'openEdges');
t.equal(json.costumes[0].baseLayerID, 1);
t.equal(json.costumes[0].baseLayerMD5, '4c9df7bf7300ef254616a47d98eac474.png');
t.equal(json.costumes[0].bitmapResolution, 1);
t.equal(json.costumes[0].rotationCenterX, 240);
t.equal(json.costumes[0].rotationCenterY, 180);
t.true(Array.isArray(json.sounds));
t.equal(json.sounds[0].soundName, 'pop');
t.equal(json.sounds[0].soundID, 0);
t.equal(json.sounds[0].md5, '83a9787d4cb6f3b7632b4ddfebf74367.wav');
t.equal(json.sounds[0].sampleCount, 258);
t.equal(json.sounds[0].rate, 11025);
t.equal(json.sounds[0].format, '');
t.true(Array.isArray(json.children));
t.equal(json.children[0].objName, 'Emitter');
t.equal(json.children[0].currentCostumeIndex, 0);
t.equal(json.children[0].scratchX, -217);
t.equal(json.children[0].scratchY, 98);
t.equal(json.children[0].scale, 1);
t.equal(json.children[0].direction, 38);
t.equal(json.children[0].rotationStyle, 'normal');
t.equal(json.children[0].isDraggable, false);
t.equal(json.children[0].indexInLibrary, 0);
t.equal(json.children[0].visible, true);
t.deepEqual(json.children[0].variables, []);
t.deepEqual(json.children[0].lists, []);
t.true(Array.isArray(json.children[0].scripts));
t.equal(json.children[0].scripts.length, 14);
t.true(Array.isArray(json.children[0].costumes));
t.equal(json.children[0].costumes.length, 1);
t.equal(json.tempoBPM, 100);
t.equal(json.currentCostumeIndex, 1);
t.equal(json.videoAlpha, 0.5);
t.type(json.info, Object);
t.end();
});
test('ewe-and-me', t => {
const uri = path.resolve(__dirname, '../fixtures/valid/ewe-and-me.sb');
const file = fs.readFileSync(uri);
const sb1 = new SB1File(file);
const json = sb1.json;
t.type(json, Object);
t.deepEqual(json.variables, []);
t.deepEqual(json.lists, []);
t.deepEqual(json.scripts, []);
t.true(Array.isArray(json.costumes));
t.equal(json.costumes[0].costumeName, 'background1');
t.equal(json.costumes[0].baseLayerID, 0);
t.equal(json.costumes[0].baseLayerMD5, '477e98a9e6b26f4d5bbf58f9e135eb45.png');
t.equal(json.costumes[0].bitmapResolution, 1);
t.equal(json.costumes[0].rotationCenterX, 240);
t.equal(json.costumes[0].rotationCenterY, 180);
t.true(Array.isArray(json.sounds));
t.equal(json.sounds[0].soundName, 'pop');
t.equal(json.sounds[0].soundID, 0);
t.equal(json.sounds[0].md5, '83a9787d4cb6f3b7632b4ddfebf74367.wav');
t.equal(json.sounds[0].sampleCount, 258);
t.equal(json.sounds[0].rate, 11025);
t.equal(json.sounds[0].format, '');
t.true(Array.isArray(json.children));
t.equal(json.children[0].objName, 'animation');
t.equal(json.children[0].currentCostumeIndex, 0);
t.equal(json.children[0].scratchX, 2);
t.equal(json.children[0].scratchY, -1);
t.equal(json.children[0].scale, 1.5);
t.equal(json.children[0].direction, -270);
t.equal(json.children[0].rotationStyle, 'normal');
t.equal(json.children[0].isDraggable, false);
t.equal(json.children[0].indexInLibrary, 0);
t.equal(json.children[0].visible, true);
t.deepEqual(json.children[0].variables, []);
t.deepEqual(json.children[0].lists, []);
t.true(Array.isArray(json.children[0].scripts));
t.equal(json.children[0].scripts.length, 3);
t.true(Array.isArray(json.children[0].costumes));
t.equal(json.children[0].costumes.length, 23);
t.equal(json.tempoBPM, 100);
t.equal(json.currentCostumeIndex, 0);
t.equal(json.videoAlpha, 0.5);
t.type(json.info, Object);
t.end();
});

19
test/unit/adler32.js Normal file
View file

@ -0,0 +1,19 @@
const test = require('tap').test;
const {Adler32} = require('../../src/coders/adler32');
test('spec', t => {
const instance = new Adler32();
t.type(Adler32, 'function');
t.type(instance.update, 'function');
t.type(instance.digest, 'number');
t.end();
});
test('digest', t => {
const instance = new Adler32();
const buf = new Uint8Array(128);
instance.update(buf, 0, buf.length);
t.equal(instance.digest, 8388609);
t.end();
});

76
test/unit/byte-packets.js Normal file
View file

@ -0,0 +1,76 @@
const test = require('tap').test;
const {Packet} = require('../../src/coders/byte-packets');
const {Uint8, Uint16LE} = require('../../src/coders/byte-primitives');
test('spec', t => {
t.type(Packet, 'function');
t.type(Packet.initConstructor, 'function');
t.type(Packet.extend, 'function');
const uint8a = new Uint8Array(128);
const instance = new Packet(uint8a, 0);
t.type(instance.uint8a, 'object');
t.type(instance.offset, 'number');
t.type(instance.equals, 'function');
t.type(instance.view, 'function');
t.end();
});
test('equals (true)', t => {
const packet = new Packet();
t.true(packet.equals({
offset: 0
}));
t.end();
});
test('equals (false)', t => {
const packet = new Packet();
t.false(packet.equals({
offset: 1
}));
t.end();
});
test('equals (undefined)', t => {
const packet = new Packet();
t.false(packet.equals({
foo: 'bar'
}));
t.end();
});
test('view', t => {
const packet = new Packet();
const view = packet.view();
t.type(view, 'object');
t.type(view.toString, 'function');
t.type(view.toString(), 'string');
t.end();
});
test('extend (valid)', t => {
class TestPacket extends Packet.extend({
binaryType: Uint8,
value: Uint16LE
}) {}
Packet.initConstructor(TestPacket);
const packet = new TestPacket();
t.type(packet, 'object');
t.end();
});
test('extend (invalid)', t => {
const shouldThrow = function () {
Uint8.size = 0;
class TestPacket extends Packet.extend({
binaryType: Uint8,
value: Uint16LE
}) {}
t.type(TestPacket, 'undefined');
};
t.throws(shouldThrow);
t.end();
});

View file

@ -0,0 +1,162 @@
const test = require('tap').test;
const {
BytePrimitive,
Uint8,
Uint16BE,
Uint16LE,
Uint32BE,
Uint32LE,
Int16BE,
Int32BE,
DoubleBE,
FixedAsciiString
} = require('../../src/coders/byte-primitives');
test('spec', t => {
t.type(BytePrimitive, 'function');
const instance = new BytePrimitive({size: 1});
t.type(instance, 'object');
t.type(instance.asPropertyObject, 'function');
t.end();
});
test('Uint8', t => {
t.type(Uint8, 'object');
t.type(Uint8.size, 'number');
t.type(Uint8.read, 'function');
t.type(Uint8.write, 'function');
t.type(Uint8.toBytes, 'object');
const bytes = new Uint8Array(2);
t.equal(Uint8.write(bytes, 0, 255), 255);
t.equal(Uint8.read(bytes, 0), 255);
t.equal(Uint8.read(bytes, 1), 0);
t.end();
});
test('Uint16BE', t => {
t.type(Uint16BE, 'object');
t.type(Uint16BE.size, 'number');
t.type(Uint16BE.read, 'function');
t.type(Uint16BE.write, 'function');
t.type(Uint16BE.toBytes, 'object');
const bytes = new Uint8Array(3);
t.equal(Uint16BE.write(bytes, 0, 65535), 65535);
t.equal(Uint16BE.read(bytes, 0), 65535);
t.equal(Uint16BE.read(bytes, 1), 65280);
t.equal(Uint16BE.read(bytes, 2), 0);
t.end();
});
test('Uint16LE', t => {
t.type(Uint16LE, 'object');
t.type(Uint16LE.size, 'number');
t.type(Uint16LE.read, 'function');
t.type(Uint16LE.write, 'function');
t.type(Uint16LE.toBytes, 'object');
const bytes = new Uint8Array(3);
t.equal(Uint16LE.write(bytes, 0, 65535), 65535);
t.equal(Uint16LE.read(bytes, 0), 65535);
t.equal(Uint16LE.read(bytes, 1), 255);
t.equal(Uint16LE.read(bytes, 2), 0);
t.end();
});
test('Uint32BE', t => {
t.type(Uint32BE, 'object');
t.type(Uint32BE.size, 'number');
t.type(Uint32BE.read, 'function');
t.type(Uint32BE.write, 'function');
t.type(Uint32BE.toBytes, 'object');
const bytes = new Uint8Array(5);
t.equal(Uint32BE.write(bytes, 0, 4294967295), 4294967295);
t.equal(Uint32BE.read(bytes, 0), 4294967295);
t.equal(Uint32BE.read(bytes, 1), 4294967040);
t.equal(Uint32BE.read(bytes, 2), 4294901760);
t.equal(Uint32BE.read(bytes, 3), 4278190080);
t.equal(Uint32BE.read(bytes, 4), 0);
t.end();
});
test('Uint32LE', t => {
t.type(Uint32LE, 'object');
t.type(Uint32LE.size, 'number');
t.type(Uint32LE.read, 'function');
t.type(Uint32LE.write, 'function');
t.type(Uint32LE.toBytes, 'object');
const bytes = new Uint8Array(5);
t.equal(Uint32LE.write(bytes, 0, 4294967295), 4294967295);
t.equal(Uint32LE.read(bytes, 0), 4294967295);
t.equal(Uint32LE.read(bytes, 1), 16777215);
t.equal(Uint32LE.read(bytes, 2), 65535);
t.equal(Uint32LE.read(bytes, 3), 255);
t.equal(Uint32LE.read(bytes, 4), 0);
t.end();
});
test('Int16BE', t => {
t.type(Int16BE, 'object');
t.type(Int16BE.size, 'number');
t.type(Int16BE.read, 'function');
t.type(Int16BE.write, 'function');
t.type(Int16BE.toBytes, 'object');
const bytes = new Uint8Array(3);
t.equal(Int16BE.write(bytes, 0, 65535), 65535);
t.equal(Int16BE.read(bytes, 0), -1);
t.equal(Int16BE.read(bytes, 1), -256);
t.equal(Int16BE.read(bytes, 2), 0);
t.end();
});
test('Int32BE', t => {
t.type(Int32BE, 'object');
t.type(Int32BE.size, 'number');
t.type(Int32BE.read, 'function');
t.type(Int32BE.write, 'function');
t.type(Int32BE.toBytes, 'object');
const bytes = new Uint8Array(5);
t.equal(Int32BE.write(bytes, 0, 4294967295), 4294967295);
t.equal(Int32BE.read(bytes, 0), -1);
t.equal(Int32BE.read(bytes, 1), -256);
t.equal(Int32BE.read(bytes, 2), -65536);
t.equal(Int32BE.read(bytes, 3), -16777216);
t.equal(Int32BE.read(bytes, 4), 0);
t.end();
});
test('DoubleBE', t => {
t.type(DoubleBE, 'object');
t.type(DoubleBE.size, 'number');
t.type(DoubleBE.read, 'function');
t.type(DoubleBE.write, 'function');
t.type(DoubleBE.toBytes, 'object');
const bytes = new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0]);
t.true(DoubleBE.read(bytes, 0) > 0);
t.throws(() => {
DoubleBE.write(bytes, 0, -1);
});
t.end();
});
test('FixedAsciiString', t => {
const instance = new FixedAsciiString(3);
t.type(instance, 'object');
t.type(instance.size, 'number');
t.type(instance.read, 'function');
t.type(instance.write, 'function');
t.type(instance.toBytes, 'object');
const bytes = new Uint8Array(3);
t.equal(instance.write(bytes, 0, 'foo'), 'foo');
t.equal(instance.read(bytes, 0), 'foo');
t.end();
});

94
test/unit/byte-stream.js Normal file
View file

@ -0,0 +1,94 @@
const test = require('tap').test;
const {ByteStream} = require('../../src/coders/byte-stream');
const {Packet} = require('../../src/coders/byte-packets');
const {Uint8} = require('../../src/coders/byte-primitives');
test('spec', t => {
t.type(ByteStream, 'function');
const buffer = new ArrayBuffer(128);
const instance = new ByteStream(buffer, 0);
t.type(instance.buffer, 'object');
t.type(instance.position, 'number');
t.type(instance.uint8a, 'object');
t.type(instance.read, 'function');
t.type(instance.readStruct, 'function');
t.type(instance.resize, 'function');
t.type(instance.write, 'function');
t.type(instance.writeStruct, 'function');
t.type(instance.writeBytes, 'function');
t.end();
});
test('read', t => {
const buffer = new Uint8Array([0, 1, 255]).buffer;
const instance = new ByteStream(buffer);
t.equal(instance.read(Uint8), 0);
t.equal(instance.read(Uint8), 1);
t.equal(instance.read(Uint8), 255);
t.type(instance.read(Uint8), 'undefined');
t.end();
});
test('readStruct', t => {
const buffer = new Uint8Array([0, 1, 10, 255]).buffer;
const instance = new ByteStream(buffer);
const result = instance.readStruct(Packet);
t.type(result, 'object');
// @todo This should use a "Packet" subclass and validate the contents of
// the returned packet
t.end();
});
test('resize', t => {
const buffer = new Uint8Array([]).buffer;
const instance = new ByteStream(buffer);
t.equal(instance.buffer.byteLength, 0);
instance.resize(8);
t.equal(instance.buffer.byteLength, 8);
instance.resize(2);
t.equal(instance.buffer.byteLength, 8);
t.end();
});
test('write', t => {
const buffer = new Uint8Array([0, 1, 255]).buffer;
const instance = new ByteStream(buffer);
t.equal(instance.read(Uint8), 0);
t.equal(instance.read(Uint8), 1);
t.equal(instance.read(Uint8), 255);
t.equal(instance.write(Uint8, 255), 255);
t.type(instance.read(Uint8), 'undefined');
t.end();
});
test('writeStruct', t => {
const buffer = new Uint8Array([0, 1, 255]).buffer;
const bytes = new Uint8Array([0, 0, 0]);
const instance = new ByteStream(buffer);
const result = instance.writeStruct(Packet, bytes);
t.type(result, 'object');
// @todo This should use a "Packet" subclass and validate the contents of
// the returned packet
t.end();
});
test('writeBytes', t => {
const buffer = new Uint8Array([0, 1, 255]).buffer;
const bytes = new Uint8Array([0, 0, 0]);
const instance = new ByteStream(buffer);
const result = instance.writeBytes(bytes);
t.type(result, 'object');
t.equal(result, bytes);
t.end();
});
test('writeBytes (invalid)', t => {
const buffer = new Uint8Array([0, 1, 255]).buffer;
const instance = new ByteStream(buffer);
t.throws(() => {
instance.writeBytes([0, 0, 0]);
});
t.end();
});

19
test/unit/crc32.js Normal file
View file

@ -0,0 +1,19 @@
const test = require('tap').test;
const {CRC32} = require('../../src/coders/crc32');
test('spec', t => {
const instance = new CRC32();
t.type(CRC32, 'function');
t.type(instance.update, 'function');
t.type(instance.digest, 'number');
t.end();
});
test('digest', t => {
const instance = new CRC32();
const buf = new Uint8Array(128);
instance.update(buf, 0, buf.length);
t.equal(instance.digest, 3265854109);
t.end();
});

View file

@ -1,8 +0,0 @@
const test = require('tap').test;
const SB1 = require('../..');
test('loads package', t => {
t.type(SB1, Object);
t.end();
});

11
test/unit/spec.js Normal file
View file

@ -0,0 +1,11 @@
const test = require('tap').test;
const SB1 = require('../..');
test('spec', t => {
t.type(SB1, Object);
t.type(SB1.SB1File, Function);
t.type(SB1.AssertionError, Function);
t.type(SB1.ValidationError, Function);
t.end();
});