Skip to content

Commit

Permalink
implemented threaded comparison testing
Browse files Browse the repository at this point in the history
  • Loading branch information
liabru committed Jan 1, 2020
1 parent 82bb415 commit 285d70d
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 159 deletions.
8 changes: 4 additions & 4 deletions examples/avalanche.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
var Example = Example || {};

Matter.use(
'matter-wrap'
);

Example.avalanche = function() {
Matter.use(
'matter-wrap'
);

var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Expand Down
8 changes: 4 additions & 4 deletions examples/ballPool.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
var Example = Example || {};

Matter.use(
'matter-wrap'
);

Example.ballPool = function() {
Matter.use(
'matter-wrap'
);

var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"gulp-tag-version": "^1.3.0",
"gulp-util": "^3.0.8",
"jest": "^24.9.0",
"jest-worker": "^24.9.0",
"json-stringify-pretty-compact": "^2.0.0",
"run-sequence": "^1.1.4",
"webpack": "^4.39.3",
Expand All @@ -38,10 +39,11 @@
"build": "webpack --mode=production & webpack --mode=production --env.MINIMIZE",
"build-alpha": "webpack --mode=production --env.EDGE & webpack --mode=production --env.MINIMIZE --env.EDGE",
"build-examples": "webpack --config webpack.examples.config.js --mode=production --env.EDGE & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE --env.EDGE",
"lint": "eslint 'src/**/*.js' 'demo/js/Demo.js' 'demo/js/Compare.js' 'examples/*.js' 'test/*.spec.js' 'webpack.*.js' 'Gulpfile.js'",
"lint": "eslint 'src/**/*.js' 'demo/js/Demo.js' 'demo/js/Compare.js' 'examples/*.js' 'webpack.*.js' 'Gulpfile.js'",
"doc": "gulp doc",
"test": "jest",
"compare": "COMPARE=true jest"
"test-save": "SAVE=true jest",
"test-watch": "jest --watch"
},
"dependencies": {},
"files": [
Expand Down
2 changes: 1 addition & 1 deletion src/factory/Bodies.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ var Vector = require('../geometry/Vector');
* @return {body}
*/
Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea) {
var decomp = typeof decomp !== 'undefined' ? decomp : require('poly-decomp'),
var decomp = global.decomp || require('poly-decomp'),
body,
parts,
isConvex,
Expand Down
61 changes: 61 additions & 0 deletions test/ExampleWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* eslint-env es6 */
/* eslint no-global-assign: 0 */
"use strict";

const stubBrowserFeatures = M => {
const noop = () => ({ collisionFilter: {}, mouse: {} });
M.Render.create = () => ({ options: {}, bounds: { min: { x: 0, y: 0 }, max: { x: 800, y: 600 }}});
M.Render.run = M.Render.lookAt = noop;
M.Runner.create = M.Runner.run = noop;
M.MouseConstraint.create = M.Mouse.create = noop;
M.Common.log = M.Common.info = M.Common.warn = noop;
return M;
};

const reset = M => {
M.Common._nextId = M.Common._seed = 0;
M.Body._nextCollidingGroupId = 1;
M.Body._nextNonCollidingGroupId = -1;
M.Body._nextCategory = 0x0001;
};

const { engineCapture } = require('./TestTools');
const MatterDev = stubBrowserFeatures(require('../src/module/main'));
const MatterBuild = stubBrowserFeatures(require('../build/Matter'));
const Example = require('../examples/index');
const decomp = require('../demo/lib/decomp');

const runExample = options => {
const Matter = options.useDev ? MatterDev : MatterBuild;
const consoleOriginal = global.console;

global.console = { log: () => {} };
global.document = {};
global.decomp = decomp;
global.Matter = Matter;

reset(Matter);

const example = Example[options.name]();
const engine = example.engine;
const startTime = process.hrtime();

for (let i = 0; i < options.totalUpdates; i += 1) {
Matter.Engine.update(engine, 1000 / 60);
}

const duration = process.hrtime(startTime);

global.console = consoleOriginal;
global.document = undefined;
global.decomp = undefined;
global.Matter = undefined;

return {
name: options.name,
duration: duration[0] * 1e9 + duration[1],
...engineCapture(engine)
};
};

module.exports = { runExample };
95 changes: 47 additions & 48 deletions test/Examples.spec.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,72 @@
/* eslint-env es6 */
/* eslint no-global-assign: 0 */
"use strict";

const {
stubBrowserFeatures, engineSnapshot, toMatchExtrinsics, toMatchIntrinsics
} = require('./TestTools');
jest.setTimeout(30 * 1000);

const totalUpdates = 120;
const isCompare = process.env.COMPARE === 'true';
const excludeExamples = ['stress', 'stress2', 'svg', 'terrain'];
const { comparisonReport, toMatchExtrinsics, toMatchIntrinsics } = require('./TestTools');

const Example = require('../examples/index');
const MatterBuild = require('../build/matter');
const MatterDev = require('../src/module/main');
const Worker = require('jest-worker').default;

jest.mock('matter-wrap', () => require('../demo/lib/matter-wrap'), { virtual: true });
jest.mock('poly-decomp', () => require('../demo/lib/decomp'), { virtual: true });
const testComparison = process.env.COMPARE === 'true';
const saveComparison = process.env.SAVE === 'true';
const excludeExamples = [ 'svg', 'terrain' ];
const examples = Object.keys(Example).filter(key => !excludeExamples.includes(key));

const runExamples = (matter) => {
let snapshots = {};
matter = stubBrowserFeatures(matter);
global.Matter = matter;
matter.use(require('matter-wrap'));

const Example = require('../examples/index');
const examples = Object.keys(Example).filter(key => !excludeExamples.includes(key));

const consoleOriginal = global.console;
global.console = { log: () => {} };

for (name of examples) {
matter.Common._nextId = matter.Common._seed = 0;
const runExamples = async useDev => {
const worker = new Worker(require.resolve('./ExampleWorker'), {
enableWorkerThreads: true
});

const example = Example[name]();
const engine = example.engine;
const result = await Promise.all(examples.map(name => worker.runExample({
name,
useDev,
totalUpdates: 120
})));

for (let i = 0; i < totalUpdates; i += 1) {
matter.Engine.update(engine, 1000 / 60);
}

snapshots[name] = isCompare ? engineSnapshot(engine) : {};
}
await worker.end();

global.console = consoleOriginal;
global.Matter = undefined;
return snapshots;
return result.reduce((out, capture) => (out[capture.name] = capture, out), {});
};

const snapshotsDev = runExamples(MatterDev);
const snapshotsBuild = runExamples(MatterBuild);
const examples = Object.keys(snapshotsDev);
const capturesDev = runExamples(true);
const capturesBuild = runExamples(false);

afterAll(async () => {
// Report experimental capture comparison.
const dev = await capturesDev;
const build = await capturesBuild;
console.log(comparisonReport(dev, build, MatterBuild.version, saveComparison));
});

describe(`Integration tests (${examples.length})`, () => {
test(`Examples run without throwing`, () => {
expect(Object.keys(snapshotsDev)).toEqual(examples);
expect(Object.keys(snapshotsBuild)).toEqual(examples);
describe(`Integration checks (${examples.length})`, () => {
test(`Examples run without throwing`, async () => {
const dev = await capturesDev;
const build = await capturesBuild;
expect(Object.keys(dev)).toEqual(examples);
expect(Object.keys(build)).toEqual(examples);
});
});

if (isCompare) {
describe(`Regression tests (${examples.length})`, () => {
// Experimental regression comparison checks.
if (testComparison) {
describe(`Regression checks (${examples.length})`, () => {
expect.extend(toMatchExtrinsics);
expect.extend(toMatchIntrinsics);

test(`Examples match properties with release build`, () => {
expect(snapshotsDev).toMatchIntrinsics(snapshotsBuild, totalUpdates);
test(`Examples match intrinsic properties with release build`, async () => {
const dev = await capturesDev;
const build = await capturesBuild;
// compare mass, inertia, friction etc.
expect(dev).toMatchIntrinsics(build);
});

test(`Examples match positions and velocities with release build`, () => {
expect(snapshotsDev).toMatchExtrinsics(snapshotsBuild, totalUpdates);
test(`Examples match extrinsic positions and velocities with release build`, async () => {
const dev = await capturesDev;
const build = await capturesBuild;
// compare position, linear and angular velocity
expect(dev).toMatchExtrinsics(build);
});
});
}
Loading

0 comments on commit 285d70d

Please sign in to comment.