mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-24 06:52:40 -05:00
Merge pull request #310 from thisandagain/bugfix/coverage
Improve Test Coverage
This commit is contained in:
commit
e35a46fdf1
8 changed files with 342 additions and 18 deletions
|
@ -4,3 +4,4 @@ node_modules/*
|
||||||
playground/*
|
playground/*
|
||||||
vm.js
|
vm.js
|
||||||
vm.min.js
|
vm.min.js
|
||||||
|
coverage/*
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
"prepublish": "npm run build",
|
"prepublish": "npm run build",
|
||||||
"prepublish-watch": "npm run watch",
|
"prepublish-watch": "npm run watch",
|
||||||
"start": "./node_modules/.bin/webpack-dev-server",
|
"start": "./node_modules/.bin/webpack-dev-server",
|
||||||
"tap-integration": "./node_modules/.bin/tap ./test/integration/*.js",
|
"tap": "./node_modules/.bin/tap ./test/{unit,integration}/*.js",
|
||||||
"tap-unit": "./node_modules/.bin/tap ./test/unit/*.js",
|
"test": "npm run lint && npm run tap",
|
||||||
"test": "npm run lint && npm run tap-unit && npm run tap-integration",
|
|
||||||
"watch": "./node_modules/.bin/webpack --progress --colors --watch",
|
"watch": "./node_modules/.bin/webpack --progress --colors --watch",
|
||||||
"version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\""
|
"version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\""
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,6 +18,7 @@ var Keyboard = function (runtime) {
|
||||||
* Convert a Scratch key name to a DOM keyCode.
|
* Convert a Scratch key name to a DOM keyCode.
|
||||||
* @param {Any} keyName Scratch key argument.
|
* @param {Any} keyName Scratch key argument.
|
||||||
* @return {number} Key code corresponding to a DOM event.
|
* @return {number} Key code corresponding to a DOM event.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
Keyboard.prototype._scratchKeyToKeyCode = function (keyName) {
|
Keyboard.prototype._scratchKeyToKeyCode = function (keyName) {
|
||||||
if (typeof keyName === 'number') {
|
if (typeof keyName === 'number') {
|
||||||
|
@ -37,6 +38,12 @@ Keyboard.prototype._scratchKeyToKeyCode = function (keyName) {
|
||||||
return keyString.toUpperCase().charCodeAt(0);
|
return keyString.toUpperCase().charCodeAt(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a DOM keyCode into a Scratch key name.
|
||||||
|
* @param {number} keyCode Key code from DOM event.
|
||||||
|
* @return {Any} Scratch key argument.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
Keyboard.prototype._keyCodeToScratchKey = function (keyCode) {
|
Keyboard.prototype._keyCodeToScratchKey = function (keyCode) {
|
||||||
if (keyCode >= 48 && keyCode <= 90) {
|
if (keyCode >= 48 && keyCode <= 90) {
|
||||||
// Standard letter.
|
// Standard letter.
|
||||||
|
@ -52,6 +59,10 @@ Keyboard.prototype._keyCodeToScratchKey = function (keyCode) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keyboard DOM event handler.
|
||||||
|
* @param {object} data Data from DOM event.
|
||||||
|
*/
|
||||||
Keyboard.prototype.postData = function (data) {
|
Keyboard.prototype.postData = function (data) {
|
||||||
if (data.keyCode) {
|
if (data.keyCode) {
|
||||||
var index = this._keysPressed.indexOf(data.keyCode);
|
var index = this._keysPressed.indexOf(data.keyCode);
|
||||||
|
@ -74,6 +85,11 @@ Keyboard.prototype.postData = function (data) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get key down state for a specified Scratch key name.
|
||||||
|
* @param {Any} key Scratch key argument.
|
||||||
|
* @return {boolean} Is the specified key down?
|
||||||
|
*/
|
||||||
Keyboard.prototype.getKeyIsDown = function (key) {
|
Keyboard.prototype.getKeyIsDown = function (key) {
|
||||||
if (key === 'any') {
|
if (key === 'any') {
|
||||||
return this._keysPressed.length > 0;
|
return this._keysPressed.length > 0;
|
||||||
|
|
|
@ -12,21 +12,12 @@ var Mouse = function (runtime) {
|
||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
Mouse.prototype.postData = function (data) {
|
/**
|
||||||
if (data.x) {
|
* Activate "event_whenthisspriteclicked" hats if needed.
|
||||||
this._x = data.x - (data.canvasWidth / 2);
|
* @param {number} x X position to be sent to the renderer.
|
||||||
}
|
* @param {number} y Y position to be sent to the renderer.
|
||||||
if (data.y) {
|
* @private
|
||||||
this._y = data.y - (data.canvasHeight / 2);
|
*/
|
||||||
}
|
|
||||||
if (typeof data.isDown !== 'undefined') {
|
|
||||||
this._isDown = data.isDown;
|
|
||||||
if (this._isDown) {
|
|
||||||
this._activateClickHats(data.x, data.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Mouse.prototype._activateClickHats = function (x, y) {
|
Mouse.prototype._activateClickHats = function (x, y) {
|
||||||
if (this.runtime.renderer) {
|
if (this.runtime.renderer) {
|
||||||
var drawableID = this.runtime.renderer.pick(x, y);
|
var drawableID = this.runtime.renderer.pick(x, y);
|
||||||
|
@ -42,14 +33,45 @@ Mouse.prototype._activateClickHats = function (x, y) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mouse DOM event handler.
|
||||||
|
* @param {object} data Data from DOM event.
|
||||||
|
*/
|
||||||
|
Mouse.prototype.postData = function (data) {
|
||||||
|
if (data.x) {
|
||||||
|
this._x = data.x - data.canvasWidth / 2;
|
||||||
|
}
|
||||||
|
if (data.y) {
|
||||||
|
this._y = data.y - data.canvasHeight / 2;
|
||||||
|
}
|
||||||
|
if (typeof data.isDown !== 'undefined') {
|
||||||
|
this._isDown = data.isDown;
|
||||||
|
if (this._isDown) {
|
||||||
|
this._activateClickHats(data.x, data.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the X position of the mouse.
|
||||||
|
* @return {number} Clamped X position of the mouse cursor.
|
||||||
|
*/
|
||||||
Mouse.prototype.getX = function () {
|
Mouse.prototype.getX = function () {
|
||||||
return MathUtil.clamp(this._x, -240, 240);
|
return MathUtil.clamp(this._x, -240, 240);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Y position of the mouse.
|
||||||
|
* @return {number} Clamped Y position of the mouse cursor.
|
||||||
|
*/
|
||||||
Mouse.prototype.getY = function () {
|
Mouse.prototype.getY = function () {
|
||||||
return MathUtil.clamp(-this._y, -180, 180);
|
return MathUtil.clamp(-this._y, -180, 180);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the down state of the mouse.
|
||||||
|
* @return {boolean} Is the mouse down?
|
||||||
|
*/
|
||||||
Mouse.prototype.getIsDown = function () {
|
Mouse.prototype.getIsDown = function () {
|
||||||
return this._isDown;
|
return this._isDown;
|
||||||
};
|
};
|
||||||
|
|
130
test/unit/blocks_control.js
Normal file
130
test/unit/blocks_control.js
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var Control = require('../../src/blocks/scratch3_control');
|
||||||
|
var Runtime = require('../../src/engine/runtime');
|
||||||
|
|
||||||
|
test('getPrimitives', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
t.type(c.getPrimitives(), 'object');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('repeat', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
|
||||||
|
// Test harness (mocks `util`)
|
||||||
|
var i = 0;
|
||||||
|
var repeat = 10;
|
||||||
|
var util = {
|
||||||
|
stackFrame: Object.create(null),
|
||||||
|
startBranch: function () {
|
||||||
|
i++;
|
||||||
|
c.repeat({TIMES: repeat}, util);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
c.repeat({TIMES: 10}, util);
|
||||||
|
t.strictEqual(util.stackFrame.loopCounter, -1);
|
||||||
|
t.strictEqual(i, repeat);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('repeatUntil', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
|
||||||
|
// Test harness (mocks `util`)
|
||||||
|
var i = 0;
|
||||||
|
var repeat = 10;
|
||||||
|
var util = {
|
||||||
|
stackFrame: Object.create(null),
|
||||||
|
startBranch: function () {
|
||||||
|
i++;
|
||||||
|
c.repeatUntil({CONDITION: (i === repeat)}, util);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
c.repeatUntil({CONDITION: (i === repeat)}, util);
|
||||||
|
t.strictEqual(i, repeat);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('forever', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
|
||||||
|
// Test harness (mocks `util`)
|
||||||
|
var i = 0;
|
||||||
|
var util = {
|
||||||
|
startBranch: function (branchNum, isLoop) {
|
||||||
|
i++;
|
||||||
|
t.strictEqual(branchNum, 1);
|
||||||
|
t.strictEqual(isLoop, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
c.forever(null, util);
|
||||||
|
t.strictEqual(i, 1);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('if / ifElse', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
|
||||||
|
// Test harness (mocks `util`)
|
||||||
|
var i = 0;
|
||||||
|
var util = {
|
||||||
|
startBranch: function (branchNum) {
|
||||||
|
i += branchNum;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
c.if({CONDITION: true}, util);
|
||||||
|
t.strictEqual(i, 1);
|
||||||
|
c.if({CONDITION: false}, util);
|
||||||
|
t.strictEqual(i, 1);
|
||||||
|
c.ifElse({CONDITION: true}, util);
|
||||||
|
t.strictEqual(i, 2);
|
||||||
|
c.ifElse({CONDITION: false}, util);
|
||||||
|
t.strictEqual(i, 4);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('stop', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Control(rt);
|
||||||
|
|
||||||
|
// Test harness (mocks `util`)
|
||||||
|
var state = {
|
||||||
|
stopAll: 0,
|
||||||
|
stopOtherTargetThreads: 0,
|
||||||
|
stopThread: 0
|
||||||
|
};
|
||||||
|
var util = {
|
||||||
|
stopAll: function () {
|
||||||
|
state.stopAll++;
|
||||||
|
},
|
||||||
|
stopOtherTargetThreads: function () {
|
||||||
|
state.stopOtherTargetThreads++;
|
||||||
|
},
|
||||||
|
stopThread: function () {
|
||||||
|
state.stopThread++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute test
|
||||||
|
c.stop({STOP_OPTION: 'all'}, util);
|
||||||
|
c.stop({STOP_OPTION: 'other scripts in sprite'}, util);
|
||||||
|
c.stop({STOP_OPTION: 'other scripts in stage'}, util);
|
||||||
|
c.stop({STOP_OPTION: 'this script'}, util);
|
||||||
|
t.strictEqual(state.stopAll, 1);
|
||||||
|
t.strictEqual(state.stopOtherTargetThreads, 2);
|
||||||
|
t.strictEqual(state.stopThread, 1);
|
||||||
|
t.end();
|
||||||
|
});
|
34
test/unit/io_clock.js
Normal file
34
test/unit/io_clock.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var Clock = require('../../src/io/clock');
|
||||||
|
var Runtime = require('../../src/engine/runtime');
|
||||||
|
|
||||||
|
test('spec', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Clock(rt);
|
||||||
|
|
||||||
|
t.type(Clock, 'function');
|
||||||
|
t.type(c, 'object');
|
||||||
|
t.type(c.projectTimer, 'function');
|
||||||
|
t.type(c.pause, 'function');
|
||||||
|
t.type(c.resume, 'function');
|
||||||
|
t.type(c.resetProjectTimer, 'function');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('cycle', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var c = new Clock(rt);
|
||||||
|
|
||||||
|
t.ok(c.projectTimer() <= 0.1);
|
||||||
|
setTimeout(function () {
|
||||||
|
c.resetProjectTimer();
|
||||||
|
setTimeout(function () {
|
||||||
|
t.ok(c.projectTimer() > 0);
|
||||||
|
c.pause();
|
||||||
|
t.ok(c.projectTimer() > 0);
|
||||||
|
c.resume();
|
||||||
|
t.ok(c.projectTimer() > 0);
|
||||||
|
t.end();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
73
test/unit/io_keyboard.js
Normal file
73
test/unit/io_keyboard.js
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var Keyboard = require('../../src/io/keyboard');
|
||||||
|
var Runtime = require('../../src/engine/runtime');
|
||||||
|
|
||||||
|
test('spec', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var k = new Keyboard(rt);
|
||||||
|
|
||||||
|
t.type(k, 'object');
|
||||||
|
t.type(k.postData, 'function');
|
||||||
|
t.type(k.getKeyIsDown, 'function');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('space', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var k = new Keyboard(rt);
|
||||||
|
|
||||||
|
k.postData({
|
||||||
|
keyCode: 32,
|
||||||
|
isDown: true
|
||||||
|
});
|
||||||
|
t.strictDeepEquals(k._keysPressed, [32]);
|
||||||
|
t.strictEquals(k.getKeyIsDown('space'), true);
|
||||||
|
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('letter', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var k = new Keyboard(rt);
|
||||||
|
|
||||||
|
k.postData({
|
||||||
|
keyCode: 65,
|
||||||
|
isDown: true
|
||||||
|
});
|
||||||
|
t.strictDeepEquals(k._keysPressed, [65]);
|
||||||
|
t.strictEquals(k.getKeyIsDown('a'), true);
|
||||||
|
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('number', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var k = new Keyboard(rt);
|
||||||
|
|
||||||
|
k.postData({
|
||||||
|
keyCode: 49,
|
||||||
|
isDown: true
|
||||||
|
});
|
||||||
|
t.strictDeepEquals(k._keysPressed, [49]);
|
||||||
|
t.strictEquals(k.getKeyIsDown(49), true);
|
||||||
|
t.strictEquals(k.getKeyIsDown('any'), true);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keyup', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var k = new Keyboard(rt);
|
||||||
|
|
||||||
|
k.postData({
|
||||||
|
keyCode: 37,
|
||||||
|
isDown: true
|
||||||
|
});
|
||||||
|
k.postData({
|
||||||
|
keyCode: 37,
|
||||||
|
isDown: false
|
||||||
|
});
|
||||||
|
t.strictDeepEquals(k._keysPressed, []);
|
||||||
|
t.strictEquals(k.getKeyIsDown(37), false);
|
||||||
|
t.strictEquals(k.getKeyIsDown('any'), false);
|
||||||
|
t.end();
|
||||||
|
});
|
49
test/unit/io_mouse.js
Normal file
49
test/unit/io_mouse.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var Mouse = require('../../src/io/mouse');
|
||||||
|
var Runtime = require('../../src/engine/runtime');
|
||||||
|
|
||||||
|
test('spec', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var m = new Mouse(rt);
|
||||||
|
|
||||||
|
t.type(m, 'object');
|
||||||
|
t.type(m.postData, 'function');
|
||||||
|
t.type(m.getX, 'function');
|
||||||
|
t.type(m.getY, 'function');
|
||||||
|
t.type(m.getIsDown, 'function');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mouseUp', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var m = new Mouse(rt);
|
||||||
|
|
||||||
|
m.postData({
|
||||||
|
x: 1,
|
||||||
|
y: 10,
|
||||||
|
isDown: false,
|
||||||
|
canvasWidth: 480,
|
||||||
|
canvasHeight: 360
|
||||||
|
});
|
||||||
|
t.strictEquals(m.getX(), -239);
|
||||||
|
t.strictEquals(m.getY(), 170);
|
||||||
|
t.strictEquals(m.getIsDown(), false);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mouseDown', function (t) {
|
||||||
|
var rt = new Runtime();
|
||||||
|
var m = new Mouse(rt);
|
||||||
|
|
||||||
|
m.postData({
|
||||||
|
x: 10,
|
||||||
|
y: 100,
|
||||||
|
isDown: true,
|
||||||
|
canvasWidth: 480,
|
||||||
|
canvasHeight: 360
|
||||||
|
});
|
||||||
|
t.strictEquals(m.getX(), -230);
|
||||||
|
t.strictEquals(m.getY(), 80);
|
||||||
|
t.strictEquals(m.getIsDown(), true);
|
||||||
|
t.end();
|
||||||
|
});
|
Loading…
Reference in a new issue