Merge branch 'tests' of https://github.com/tlwr/CyberChef into tlwr-tests

This commit is contained in:
n1474335 2017-02-28 13:05:03 +00:00
commit 6e5ea5d75f
13 changed files with 1702 additions and 8 deletions

View File

@ -9,10 +9,14 @@ module.exports = function(grunt) {
"A persistent task which creates a development build whenever source files are modified.",
["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
grunt.registerTask("test",
"A task which runs all the tests in test/tests.",
["clean:test", "concat:jsTest", "copy:htmlTest", "chmod:build", "exec:tests"]);
grunt.registerTask("prod",
"Creates a production-ready build. Use the --msg flag to add a compile message.",
["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
"copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod"]);
"copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod", "test"]);
grunt.registerTask("docs",
"Compiles documentation in the /docs directory.",
@ -50,7 +54,7 @@ module.exports = function(grunt) {
// JS includes
var jsFiles = [
var jsIncludes = [
// Third party framework libraries
"src/js/lib/jquery-2.1.1.js",
"src/js/lib/bootstrap-3.3.6.js",
@ -134,6 +138,7 @@ module.exports = function(grunt) {
"src/js/lib/vkbeautify.js",
"src/js/lib/Sortable.js",
"src/js/lib/bootstrap-colorpicker.js",
"src/js/lib/es6-promise.auto.js",
"src/js/lib/xpath.js",
// Custom libraries
@ -154,10 +159,25 @@ module.exports = function(grunt) {
"src/js/views/html/*.js",
"!src/js/views/html/main.js",
// Start the app!
"src/js/views/html/main.js",
];
var jsAppFiles = [].concat(
jsIncludes,
[
// Start the main app!
"src/js/views/html/main.js",
]
);
var jsTestFiles = [].concat(
jsIncludes,
[
"test/TestRegister.js",
"test/tests/**/*.js",
"test/TestRunner.js",
]
);
var banner = '/**\n\
* CyberChef - The Cyber Swiss Army Knife\n\
*\n\
@ -198,6 +218,11 @@ module.exports = function(grunt) {
config: ["src/js/config/**/*.js"],
views: ["src/js/views/**/*.js"],
operations: ["src/js/operations/**/*.js"],
tests: [
"test/**/*.js",
"!test/PhantomRunner.js",
"!test/NodeRunner.js",
],
},
jsdoc: {
options: {
@ -216,6 +241,7 @@ module.exports = function(grunt) {
},
clean: {
dev: ["build/dev/*"],
test: ["build/test/*"],
prod: ["build/prod/*"],
docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
},
@ -243,8 +269,15 @@ module.exports = function(grunt) {
options: {
banner: '"use strict";\n'
},
src: jsFiles,
src: jsAppFiles,
dest: "build/dev/scripts.js"
},
jsTest: {
options: {
banner: '"use strict";\n'
},
src: jsTestFiles,
dest: "build/test/tests.js"
}
},
copy: {
@ -257,6 +290,15 @@ module.exports = function(grunt) {
src: "src/html/index.html",
dest: "build/dev/index.html"
},
htmlTest: {
options: {
process: function(content, srcpath) {
return grunt.template.process(content, templateOptions);
}
},
src: "src/html/test.html",
dest: "build/test/index.html"
},
htmlProd: {
options: {
process: function(content, srcpath) {
@ -409,6 +451,9 @@ module.exports = function(grunt) {
}
},
exec: {
tests: {
command: "node test/NodeRunner.js",
},
repoSize: {
command: [
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",

View File

@ -39,6 +39,7 @@
"grunt-exec": "~1.0.1",
"grunt-inline-alt": "~0.3.10",
"grunt-jsdoc": "^2.1.0",
"ink-docstrap": "^1.1.4"
"ink-docstrap": "^1.1.4",
"phantomjs-prebuilt": "^2.1.14"
}
}

34
src/html/test.html Executable file
View File

@ -0,0 +1,34 @@
<!-- htmlmin:ignore --><!--
CyberChef - The Cyber Swiss Army Knife
@author tlwr [toby@toby.codes]
@copyright Crown Copyright 2017
@license Apache-2.0
Copyright 2017 Crown Copyright
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- htmlmin:ignore -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CyberChef</title>
</head>
<body>
<main style="white-space: pre"></main>
<script type="application/javascript" src="tests.js"></script>
</body>
</html>

View File

@ -109,6 +109,10 @@
"OutputWaiter": false,
"RecipeWaiter": false,
"SeasonalWaiter": false,
"WindowWaiter": false
"WindowWaiter": false,
/* tests */
"TestRegister": false,
"TestRunner": false
}
}
}

File diff suppressed because it is too large Load Diff

8
src/js/lib/vuejs/vue.min.js vendored Normal file

File diff suppressed because one or more lines are too long

24
test/NodeRunner.js Normal file
View File

@ -0,0 +1,24 @@
/**
* NodeRunner.js
*
* The purpose of this file is to execute via PhantomJS the file
* PhantomRunner.js, because PhantomJS is managed by node.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
var path = require("path");
var phantomjs = require("phantomjs-prebuilt");
var phantomEntryPoint = path.join(__dirname, "PhantomRunner.js");
var program = phantomjs.exec(phantomEntryPoint);
program.stdout.pipe(process.stdout);
program.stderr.pipe(process.stderr);
program.on("exit", function(status) {
process.exit(status);
});

80
test/PhantomRunner.js Normal file
View File

@ -0,0 +1,80 @@
/**
* PhantomRunner.js
*
* This file navigates to build/test/index.html and logs the test results.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
var page = require("webpage").create();
var allTestsPassing = true;
var testStatusCounts = {
total: 0,
};
function statusToIcon(status) {
var icons = {
erroring: "🔥",
failing: "❌",
passing: "✔️️",
};
return icons[status] || "?";
}
page.onCallback = function(messageType) {
if (messageType === "testResult") {
var testResult = arguments[1];
allTestsPassing = allTestsPassing && testResult.status === "passing";
var newCount = (testStatusCounts[testResult.status] || 0) + 1;
testStatusCounts[testResult.status] = newCount;
testStatusCounts.total += 1;
console.log([
statusToIcon(testResult.status),
testResult.test.name
].join(" "));
if (testResult.output) {
console.log(
testResult.output
.trim()
.replace(/^/, "\t")
.replace(/\n/g, "\n\t")
);
}
} else if (messageType === "exit") {
console.log("\n");
for (var testStatus in testStatusCounts) {
var count = testStatusCounts[testStatus];
if (count > 0) {
console.log(testStatus.toUpperCase(), count);
}
}
if (!allTestsPassing) {
console.log("\n")
console.log("Not all tests are passing");
}
phantom.exit(allTestsPassing ? 0 : 1);
}
};
page.open("file:///home/toby/Code/CyberChef/build/test/index.html", function(status) {
if (status !== "success") {
console.log("STATUS", status);
phantom.exit(1);
}
});
setTimeout(function() {
// Timeout
phantom.exit(1);
}, 10 * 1000);

96
test/TestRegister.js Normal file
View File

@ -0,0 +1,96 @@
/**
* TestRegister.js
*
* This is so individual files can register their tests in one place, and
* ensure that they will get run by the frontend.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
(function() {
/**
* Add a list of tests to the register.
*
* @class
*/
function TestRegister() {
this.tests = [];
}
/**
* Add a list of tests to the register.
*
* @param {Object[]} tests
*/
TestRegister.prototype.addTests = function(tests) {
this.tests = this.tests.concat(tests);
};
/**
* Returns the list of tests.
*
* @returns {Object[]} tests
*/
TestRegister.prototype.getTests = function() {
return this.tests;
};
/**
* Runs all the tests in the register.
*
*/
TestRegister.prototype.runTests = function() {
return Promise.all(
this.tests.map(function(test, i) {
var chef = new Chef();
return Promise.resolve(chef.bake(
test.input,
test.recipeConfig,
{},
0,
0
))
.then(function(result) {
var ret = {
test: test,
status: null,
output: null,
};
if (result.error) {
if (test.expectedError) {
ret.status = "passing";
} else {
ret.status = "erroring";
ret.output = result.error.displayStr;
}
} else {
if (test.expectedError) {
ret.status = "failing";
ret.output = "Expected an error but did not receive one.";
} else if (result.result === test.expectedOutput) {
ret.status = "passing";
} else {
ret.status = "failing";
ret.output = [
"Expected",
"\t" + test.expectedOutput.replace(/\n/g, "\n\t"),
"Received",
"\t" + result.result.replace(/\n/g, "\n\t"),
].join("\n");
}
}
return ret;
});
})
);
};
// Singleton TestRegister, keeping things simple and obvious.
window.TestRegister = new TestRegister();
})();

38
test/TestRunner.js Normal file
View File

@ -0,0 +1,38 @@
/**
* TestRunner.js
*
* This is for actually running the tests in the test register.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
(function() {
document.addEventListener("DOMContentLoaded", function() {
TestRegister.runTests()
.then(function(results) {
results.forEach(function(testResult) {
if (typeof window.callPhantom === "function") {
window.callPhantom(
"testResult",
testResult
);
} else {
var output = [
"----------",
testResult.test.name,
testResult.status,
testResult.output,
].join("<br>");
document.body.innerHTML += "<div>" + output + "</div>";
}
});
if (typeof window.callPhantom === "function") {
window.callPhantom("exit");
}
});
});
})();

95
test/tests/core.js Normal file
View File

@ -0,0 +1,95 @@
/**
* Core tests.
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
TestRegister.addTests([
//{
// name: "Example error",
// input: "1\n2\na\n4",
// expectedOutput: "1\n2\n3\n4",
// recipeConfig: [
// {
// op: "Fork",
// args: ["\n", "\n", false],
// },
// {
// op: "To Base",
// args: [16],
// },
// ],
//},
//{
// name: "Example non-error when error was expected",
// input: "1",
// expectedError: true,
// recipeConfig: [
// {
// op: "To Base",
// args: [16],
// },
// ],
//},
//{
// name: "Example fail",
// input: "1\n2\na\n4",
// expectedOutput: "1\n2\n3\n4",
// recipeConfig: [
// {
// op: "Fork",
// args: ["\n", "\n", true],
// },
// {
// op: "To Base",
// args: [16],
// },
// ],
//},
{
name: "Fork: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "Fork",
args: ["\n", "\n", false],
},
],
},
{
name: "Fork, Merge: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "Fork",
args: ["\n", "\n", false],
},
{
op: "Merge",
args: [],
},
],
},
{
name: "Fork, (expect) Error, Merge",
input: "1\n2\na\n4",
expectedError: true,
recipeConfig: [
{
op: "Fork",
args: ["\n", "\n", false],
},
{
op: "To Base",
args: [16],
},
{
op: "Merge",
args: [],
},
],
},
]);

View File

@ -0,0 +1,77 @@
/**
* Base58 tests.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
TestRegister.addTests([
{
name: "To Base58 (Bitcoin): nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Base58",
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
},
],
},
{
name: "To Base58 (Ripple): nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Base58",
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
},
],
},
{
name: "To Base58 (Bitcoin): 'hello world'",
input: "hello world",
expectedOutput: "StV1DL6CwTryKyV",
recipeConfig: [
{
op: "To Base58",
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
},
],
},
{
name: "To Base58 (Ripple): 'hello world'",
input: "hello world",
expectedOutput: "StVrDLaUATiyKyV",
recipeConfig: [
{
op: "To Base58",
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
},
],
},
{
name: "From Base58 (Bitcoin): 'StV1DL6CwTryKyV'",
input: "StV1DL6CwTryKyV",
expectedOutput: "hello world",
recipeConfig: [
{
op: "From Base58",
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
},
],
},
{
name: "From Base58 (Ripple): 'StVrDLaUATiyKyV'",
input: "StVrDLaUATiyKyV",
expectedOutput: "hello world",
recipeConfig: [
{
op: "From Base58",
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
},
],
},
]);

View File

@ -0,0 +1,33 @@
/**
* Base58 tests.
*
* @author tlwr [toby@toby.codes
*
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
*/
TestRegister.addTests([
{
name: "To Morse Code: 'SOS'",
input: "SOS",
expectedOutput: "... --- ...",
recipeConfig: [
{
op: "To Morse Code",
args: ["-/.", "Space", "Line feed"],
},
],
},
{
name: "From Morse Code '... --- ...'",
input: "... --- ...",
expectedOutput: "SOS",
recipeConfig: [
{
op: "From Morse Code",
args: ["Space", "Line feed"],
},
],
},
]);