Merge pull request #74 from redsquirrel/unit-testing

Instrumenting project for unit testing
pull/1/head
chriseth 9 years ago committed by GitHub
commit aa54d3d8b0
  1. 2
      .travis.yml
  2. 3
      package.json
  3. 15
      src/app.js
  4. 26
      src/app/compiler.js
  5. 28
      src/app/editor.js
  6. 7
      src/app/execution-context.js
  7. 22
      src/app/gist-handler.js
  8. 28
      src/app/query-params.js
  9. 6
      src/app/renderer.js
  10. 17
      test/compiler-test.js
  11. 69
      test/gist-handler-test.js
  12. 3
      test/index.js
  13. 21
      test/query-params-test.js

@ -1,7 +1,7 @@
language: node_js
node_js:
- stable
script: npm run lint && npm run build
script: npm run lint && npm run test && npm run build
addons:
sauce_connect:
username: "chriseth"

@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Minimalistic browser-based Solidity IDE",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "node test/index.js",
"build": "mkdir -p build; browserify src/index.js -o build/app.js",
"lint": "semistandard"
},
@ -19,6 +19,7 @@
"jquery": "^2.2.0",
"js-base64": "^2.1.9",
"semistandard": "^7.0.0",
"tape": "^4.5.1",
"web3": "^0.15.3",
"webworkify": "^1.2.1"
},

@ -3,12 +3,16 @@
var $ = require('jquery');
var utils = require('./app/utils');
var queryParams = require('./app/query-params');
var gistHandler = require('./app/gist-handler');
var QueryParams = require('./app/query-params');
var queryParams = new QueryParams();
var GistHandler = require('./app/gist-handler');
var gistHandler = new GistHandler();
var StorageHandler = require('./app/storage-handler');
var Editor = require('./app/editor');
var Renderer = require('./app/renderer');
var Compiler = require('./app/compiler');
var ExecutionContext = require('./app/execution-context');
// The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event.
@ -61,7 +65,7 @@ var run = function () {
// ------------------ gist load ----------------
var loadingFromGist = gistHandler.handleLoad(function (gistId) {
var loadingFromGist = gistHandler.handleLoad(queryParams.get(), function (gistId) {
$.ajax({
url: 'https://api.github.com/gists/' + gistId,
jsonp: 'callback',
@ -421,7 +425,10 @@ var run = function () {
return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path, cb);
}
var compiler = new Compiler(editor, handleGithubCall, $('#output'), getHidingRHP, updateFiles);
var executionContext = new ExecutionContext();
var renderer = new Renderer(editor, executionContext, updateFiles);
var compiler = new Compiler(editor, renderer, queryParams, handleGithubCall, $('#output'), getHidingRHP, updateFiles);
executionContext.setCompiler(compiler);
function setVersionText (text) {
$('#version').text(text);

@ -1,18 +1,13 @@
var webworkify = require('webworkify');
var queryParams = require('./query-params');
var utils = require('./utils');
var Renderer = require('./renderer');
var Base64 = require('js-base64').Base64;
function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles) {
var renderer = new Renderer(editor, this, updateFiles);
function Compiler (editor, renderer, queryParams, handleGithubCall, outputField, hidingRHP, updateFiles) {
var compileJSON;
var compilerAcceptsMultipleFiles;
var previousInput = '';
var sourceAnnotations = [];
var cachedRemoteFiles = {};
var worker = null;
@ -39,7 +34,6 @@ function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles
var compile = function (missingInputs) {
editor.clearAnnotations();
sourceAnnotations = [];
outputField.empty();
var input = editor.getValue();
editor.setCacheFileContent(input);
@ -58,10 +52,10 @@ function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles
};
this.compile = compile;
this.addAnnotation = function (annotation) {
sourceAnnotations[sourceAnnotations.length] = annotation;
editor.setAnnotations(sourceAnnotations);
};
function setCompileJSON (_compileJSON) {
compileJSON = _compileJSON;
}
this.setCompileJSON = setCompileJSON; // this is exposed for testing
function onCompilerLoaded (setVersionText, version) {
setVersionText(version);
@ -91,14 +85,14 @@ function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles
compilerAcceptsMultipleFiles = false;
compile = Module.cwrap('compileJSON', 'string', [ 'string', 'number' ]);
}
compileJSON = function (source, optimize, cb) {
setCompileJSON(function (source, optimize, cb) {
try {
var result = compile(source, optimize);
} catch (exception) {
result = JSON.stringify({ error: 'Uncaught JavaScript exception:\n' + exception });
}
compilationFinished(result, missingInputs);
};
});
onCompilerLoaded(setVersionText, Module.cwrap('version', 'string', [])());
}
}
@ -149,7 +143,7 @@ function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles
function loadInternal (url, setVersionText) {
delete window.Module;
// Set a safe fallback until the new one is loaded
compileJSON = function (source, optimize) { compilationFinished('{}'); };
setCompileJSON(function (source, optimize) { compilationFinished('{}'); });
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
@ -183,9 +177,9 @@ function Compiler (editor, handleGithubCall, outputField, hidingRHP, updateFiles
});
worker.onerror = function (msg) { console.log(msg.data); };
worker.addEventListener('error', function (msg) { console.log(msg.data); });
compileJSON = function (source, optimize) {
setCompileJSON(function (source, optimize) {
worker.postMessage({cmd: 'compile', source: source, optimize: optimize});
};
});
worker.postMessage({cmd: 'loadVersion', data: url});
}

@ -6,6 +6,15 @@ var ace = require('brace');
require('../mode-solidity.js');
function Editor (loadingFromGist) {
var SOL_CACHE_UNTITLED = utils.getCacheFilePrefix() + 'Untitled';
var SOL_CACHE_FILE = null;
var editor = ace.edit('input');
var sessions = {};
var sourceAnnotations = [];
setupStuff(getFiles());
this.newFile = function () {
var untitledCount = '';
while (window.localStorage[SOL_CACHE_UNTITLED + untitledCount]) {
@ -58,7 +67,7 @@ function Editor (loadingFromGist) {
return this.getFiles().indexOf(utils.fileKey(name)) !== -1;
};
this.getFiles = function () {
function getFiles () {
var files = [];
for (var f in window.localStorage) {
if (f.indexOf(utils.getCacheFilePrefix(), 0) === 0) {
@ -67,7 +76,8 @@ function Editor (loadingFromGist) {
}
}
return files;
};
}
this.getFiles = getFiles;
this.packageFiles = function () {
var files = {};
@ -100,9 +110,15 @@ function Editor (loadingFromGist) {
};
this.clearAnnotations = function () {
sourceAnnotations = [];
editor.getSession().clearAnnotations();
};
this.addAnnotation = function (annotation) {
sourceAnnotations[sourceAnnotations.length] = annotation;
this.setAnnotations(sourceAnnotations);
};
this.setAnnotations = function (sourceAnnotations) {
editor.getSession().setAnnotations(sourceAnnotations);
};
@ -152,14 +168,6 @@ function Editor (loadingFromGist) {
editor.setSession(sessions[SOL_CACHE_FILE]);
editor.resize(true);
}
var SOL_CACHE_UNTITLED = utils.getCacheFilePrefix() + 'Untitled';
var SOL_CACHE_FILE = null;
var editor = ace.edit('input');
var sessions = {};
setupStuff(this.getFiles());
}
module.exports = Editor;

@ -13,9 +13,14 @@ if (typeof window.web3 !== 'undefined') {
web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
}
function ExecutionContext (compiler) {
function ExecutionContext () {
var compiler;
var executionContext = injectedProvider ? 'injected' : 'vm';
this.setCompiler = function (_compiler) {
compiler = _compiler;
};
this.isVM = function () {
return executionContext === 'vm';
};

@ -1,14 +1,12 @@
/* global prompt */
// Allowing window to be overriden for testing
function GistHandler (_window) {
if (_window === undefined) _window = window;
var queryParams = require('./query-params');
function handleLoad (cb) {
var params = queryParams.get();
this.handleLoad = function (params, cb) {
var loadingFromGist = false;
if (typeof params['gist'] !== undefined) {
var gistId;
if (params['gist'] === '') {
var str = prompt('Enter the URL or ID of the Gist you would like to load.');
var str = _window.prompt('Enter the URL or ID of the Gist you would like to load.');
if (str !== '') {
gistId = getGistId(str);
loadingFromGist = !!gistId;
@ -20,16 +18,14 @@ function handleLoad (cb) {
if (loadingFromGist) {
cb(gistId);
}
}
return loadingFromGist;
}
};
function getGistId (str) {
function getGistId (str) {
var idr = /[0-9A-Fa-f]{8,}/;
var match = idr.exec(str);
return match ? match[0] : null;
}
}
module.exports = {
handleLoad: handleLoad
};
module.exports = GistHandler;

@ -1,10 +1,14 @@
function getQueryParams () {
var qs = window.location.hash.substr(1);
// Allowing window to be overriden for testing
function QueryParams (_window) {
if (_window === undefined) _window = window;
if (window.location.search.length > 0) {
this.get = function () {
var qs = _window.location.hash.substr(1);
if (_window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1);
window.location.search = '';
_window.location.hash = _window.location.search.substr(1);
_window.location.search = '';
}
var params = {};
@ -16,10 +20,10 @@ function getQueryParams () {
}
}
return params;
}
};
function updateQueryParams (params) {
var currentParams = getQueryParams();
this.update = function (params) {
var currentParams = this.get();
var keys = Object.keys(params);
for (var x in keys) {
currentParams[keys[x]] = params[keys[x]];
@ -29,10 +33,8 @@ function updateQueryParams (params) {
for (var y in updatedKeys) {
queryString += updatedKeys[y] + '=' + currentParams[updatedKeys[y]] + '&';
}
window.location.hash = queryString.slice(0, -1);
_window.location.hash = queryString.slice(0, -1);
};
}
module.exports = {
get: getQueryParams,
update: updateQueryParams
};
module.exports = QueryParams;

@ -3,11 +3,9 @@ var $ = require('jquery');
var UniversalDApp = require('../universal-dapp.js');
var utils = require('./utils');
var ExecutionContext = require('./execution-context');
function Renderer (editor, compiler, updateFiles) {
function Renderer (editor, executionContext, updateFiles) {
var detailsOpen = {};
var executionContext = new ExecutionContext(compiler);
function renderError (message) {
var type = utils.errortype(message);
@ -20,7 +18,7 @@ function Renderer (editor, compiler, updateFiles) {
var errLine = parseInt(err[2], 10) - 1;
var errCol = err[4] ? parseInt(err[4], 10) : 0;
if (errFile === '' || errFile === utils.fileNameFromKey(editor.getCacheFile())) {
compiler.addAnnotation({
editor.addAnnotation({
row: errLine,
column: errCol,
text: message,

@ -0,0 +1,17 @@
var test = require('tape');
var Compiler = require('../src/app/compiler');
test('compiler.compile smoke', function (t) {
t.plan(1);
var noop = function () {};
var getCacheFile = function () { return 'fakeCacheFile'; };
var fakeEditor = {onChangeSetup: noop, clearAnnotations: noop, getValue: noop, setCacheFileContent: noop, getCacheFile: getCacheFile};
var fakeOutputField = {empty: noop};
var fakeQueryParams = {get: function () { return {}; }};
var compiler = new Compiler(fakeEditor, null, fakeQueryParams, null, fakeOutputField);
compiler.setCompileJSON(noop);
compiler.compile();
t.ok(compiler);
});

@ -0,0 +1,69 @@
var test = require('tape');
var GistHandler = require('../src/app/gist-handler');
test('gistHandler.handleLoad with no gist param', function (t) {
t.plan(1);
var gistHandler = new GistHandler({});
var params = {};
var result = gistHandler.handleLoad(params, null);
t.equal(result, false);
});
test('gistHandler.handleLoad with blank gist param, and invalid user input', function (t) {
t.plan(3);
var fakeWindow = {prompt: function (message) {
t.ok(message);
t.ok(message.match(/gist/i));
return 'invalid';
}};
var gistHandler = new GistHandler(fakeWindow);
var params = {'gist': ''};
var result = gistHandler.handleLoad(params, null);
t.equal(result, false);
});
test('gistHandler.handleLoad with blank gist param, and valid user input', function (t) {
t.plan(4);
var fakeWindow = {prompt: function (message) {
t.ok(message);
t.ok(message.match(/gist/i));
return 'Beef1234';
}};
var cb = function (gistId) {
t.equal(gistId, 'Beef1234');
};
var gistHandler = new GistHandler(fakeWindow);
var params = {'gist': ''};
var result = gistHandler.handleLoad(params, cb);
t.equal(result, true);
});
test('gistHandler.handleLoad with gist param', function (t) {
t.plan(2);
var gistHandler = new GistHandler({});
var params = {'gist': 'abc'};
var cb = function (gistId) {
t.equal(gistId, 'abc');
};
var result = gistHandler.handleLoad(params, cb);
t.equal(result, true);
});

@ -0,0 +1,3 @@
require('./compiler-test');
require('./gist-handler-test');
require('./query-params-test');

@ -0,0 +1,21 @@
var test = require('tape');
var QueryParams = require('../src/app/query-params');
test('queryParams.get', function (t) {
t.plan(2);
var fakeWindow = {location: {hash: '#wat=sup&foo=bar', search: ''}};
var params = new QueryParams(fakeWindow).get();
t.equal(params.wat, 'sup');
t.equal(params.foo, 'bar');
});
test('queryParams.update', function (t) {
t.plan(1);
var fakeWindow = {location: {hash: '#wat=sup', search: ''}};
var qp = new QueryParams(fakeWindow);
qp.update({foo: 'bar'});
t.equal(fakeWindow.location.hash, '#wat=sup&foo=bar');
});
Loading…
Cancel
Save