mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 748684 - GCLI shouldn't require removeCommand before addCommand; r=dcamp
This commit is contained in:
parent
51b9398894
commit
06ccc2d4b5
@ -98,7 +98,7 @@ define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite'], fu
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testCli', 'gclitest/testCompletion', 'gclitest/testExec', 'gclitest/testHelp', 'gclitest/testHistory', 'gclitest/testInputter', 'gclitest/testIntro', 'gclitest/testJs', 'gclitest/testKeyboard', 'gclitest/testPref', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testScratchpad', 'gclitest/testSettings', 'gclitest/testSpell', 'gclitest/testSplit', 'gclitest/testTokenize', 'gclitest/testTooltip', 'gclitest/testTypes', 'gclitest/testUtil'], function(require, exports, module) {
|
||||
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testCanon', 'gclitest/testCli', 'gclitest/testCompletion', 'gclitest/testExec', 'gclitest/testHelp', 'gclitest/testHistory', 'gclitest/testInputter', 'gclitest/testIntro', 'gclitest/testJs', 'gclitest/testKeyboard', 'gclitest/testPref', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testScratchpad', 'gclitest/testSettings', 'gclitest/testSpell', 'gclitest/testSplit', 'gclitest/testTokenize', 'gclitest/testTooltip', 'gclitest/testTypes', 'gclitest/testUtil'], function(require, exports, module) {
|
||||
|
||||
// We need to make sure GCLI is initialized before we begin testing it
|
||||
require('gcli/index');
|
||||
@ -108,6 +108,7 @@ define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/e
|
||||
// It's tempting to want to unify these strings and make addSuite() do the
|
||||
// call to require(), however that breaks the build system which looks for
|
||||
// the strings passed to require
|
||||
examiner.addSuite('gclitest/testCanon', require('gclitest/testCanon'));
|
||||
examiner.addSuite('gclitest/testCli', require('gclitest/testCli'));
|
||||
examiner.addSuite('gclitest/testCompletion', require('gclitest/testCompletion'));
|
||||
examiner.addSuite('gclitest/testExec', require('gclitest/testExec'));
|
||||
@ -554,6 +555,278 @@ define('test/assert', ['require', 'exports', 'module' ], function(require, expor
|
||||
exports.is = is;
|
||||
exports.log = info;
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/testCanon', ['require', 'exports', 'module' , 'gclitest/helpers', 'gcli/canon', 'test/assert'], function(require, exports, module) {
|
||||
|
||||
var helpers = require('gclitest/helpers');
|
||||
var canon = require('gcli/canon');
|
||||
var test = require('test/assert');
|
||||
|
||||
exports.testAddRemove = function(options) {
|
||||
var startCount = canon.getCommands().length;
|
||||
var events = 0;
|
||||
|
||||
var canonChange = function(ev) {
|
||||
events++;
|
||||
};
|
||||
canon.onCanonChange.add(canonChange);
|
||||
|
||||
canon.addCommand({
|
||||
name: 'testadd',
|
||||
exec: function() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
test.is(canon.getCommands().length, startCount + 1, 'add command success');
|
||||
test.is(events, 1, 'add event');
|
||||
helpers.exec(options, {
|
||||
typed: 'testadd',
|
||||
outputMatch: /^1$/
|
||||
});
|
||||
|
||||
canon.addCommand({
|
||||
name: 'testadd',
|
||||
exec: function() {
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
|
||||
test.is(canon.getCommands().length, startCount + 1, 'readd command success');
|
||||
test.is(events, 2, 'readd event');
|
||||
helpers.exec(options, {
|
||||
typed: 'testadd',
|
||||
outputMatch: /^2$/
|
||||
});
|
||||
|
||||
canon.removeCommand('testadd');
|
||||
|
||||
test.is(canon.getCommands().length, startCount, 'remove command success');
|
||||
test.is(events, 3, 'remove event');
|
||||
helpers.status(options, {
|
||||
typed: 'testadd',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
canon.addCommand({
|
||||
name: 'testadd',
|
||||
exec: function() {
|
||||
return 3;
|
||||
}
|
||||
});
|
||||
|
||||
test.is(canon.getCommands().length, startCount + 1, 'rereadd command success');
|
||||
test.is(events, 4, 'rereadd event');
|
||||
helpers.exec(options, {
|
||||
typed: 'testadd',
|
||||
outputMatch: /^3$/
|
||||
});
|
||||
|
||||
canon.removeCommand({
|
||||
name: 'testadd'
|
||||
});
|
||||
|
||||
test.is(canon.getCommands().length, startCount, 'reremove command success');
|
||||
test.is(events, 5, 'reremove event');
|
||||
helpers.status(options, {
|
||||
typed: 'testadd',
|
||||
status: 'ERROR'
|
||||
});
|
||||
|
||||
canon.onCanonChange.remove(canonChange);
|
||||
};
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/helpers', ['require', 'exports', 'module' , 'test/assert'], function(require, exports, module) {
|
||||
|
||||
|
||||
var test = require('test/assert');
|
||||
|
||||
/**
|
||||
* Check that we can parse command input.
|
||||
* Doesn't execute the command, just checks that we grok the input properly:
|
||||
*
|
||||
* helpers.status({
|
||||
* // Test inputs
|
||||
* typed: "ech", // Required
|
||||
* cursor: 3, // Optional cursor position
|
||||
*
|
||||
* // Thing to check
|
||||
* status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: [ "<message>" ], // Still to type
|
||||
* directTabText: "o", // Simple completion text
|
||||
* arrowTabText: "", // When the completion is not an extension
|
||||
* markup: "VVVIIIEEE", // What state should the error markup be in
|
||||
* });
|
||||
*/
|
||||
exports.status = function(options, tests) {
|
||||
var requisition = options.display.requisition;
|
||||
var inputter = options.display.inputter;
|
||||
var completer = options.display.completer;
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
else {
|
||||
test.ok(false, "Missing typed for " + JSON.stringify(tests));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tests.cursor) {
|
||||
inputter.setCursor(tests.cursor);
|
||||
}
|
||||
|
||||
if (tests.status) {
|
||||
test.is(requisition.getStatus().toString(), tests.status,
|
||||
"status for " + tests.typed);
|
||||
}
|
||||
|
||||
if (tests.emptyParameters != null) {
|
||||
var realParams = completer.emptyParameters;
|
||||
test.is(realParams.length, tests.emptyParameters.length,
|
||||
'emptyParameters.length for \'' + tests.typed + '\'');
|
||||
|
||||
if (realParams.length === tests.emptyParameters.length) {
|
||||
for (var i = 0; i < realParams.length; i++) {
|
||||
test.is(realParams[i].replace(/\u00a0/g, ' '), tests.emptyParameters[i],
|
||||
'emptyParameters[' + i + '] for \'' + tests.typed + '\'');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.markup) {
|
||||
var cursor = tests.cursor ? tests.cursor.start : tests.typed.length;
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
test.is(tests.markup, actualMarkup, 'markup for ' + tests.typed);
|
||||
}
|
||||
|
||||
if (tests.directTabText) {
|
||||
test.is(completer.directTabText, tests.directTabText,
|
||||
'directTabText for \'' + tests.typed + '\'');
|
||||
}
|
||||
|
||||
if (tests.arrowTabText) {
|
||||
test.is(completer.arrowTabText, ' \u00a0\u21E5 ' + tests.arrowTabText,
|
||||
'arrowTabText for \'' + tests.typed + '\'');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
exports.exec = function(options, tests) {
|
||||
var requisition = options.display.requisition;
|
||||
var inputter = options.display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
function doTest(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
@ -1730,191 +2003,6 @@ define('gclitest/testHelp', ['require', 'exports', 'module' , 'gclitest/helpers'
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/helpers', ['require', 'exports', 'module' , 'test/assert'], function(require, exports, module) {
|
||||
|
||||
|
||||
var test = require('test/assert');
|
||||
|
||||
/**
|
||||
* Check that we can parse command input.
|
||||
* Doesn't execute the command, just checks that we grok the input properly:
|
||||
*
|
||||
* helpers.status({
|
||||
* // Test inputs
|
||||
* typed: "ech", // Required
|
||||
* cursor: 3, // Optional cursor position
|
||||
*
|
||||
* // Thing to check
|
||||
* status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: [ "<message>" ], // Still to type
|
||||
* directTabText: "o", // Simple completion text
|
||||
* arrowTabText: "", // When the completion is not an extension
|
||||
* markup: "VVVIIIEEE", // What state should the error markup be in
|
||||
* });
|
||||
*/
|
||||
exports.status = function(options, tests) {
|
||||
var requisition = options.display.requisition;
|
||||
var inputter = options.display.inputter;
|
||||
var completer = options.display.completer;
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
else {
|
||||
test.ok(false, "Missing typed for " + JSON.stringify(tests));
|
||||
return;
|
||||
}
|
||||
|
||||
if (tests.cursor) {
|
||||
inputter.setCursor(tests.cursor);
|
||||
}
|
||||
|
||||
if (tests.status) {
|
||||
test.is(requisition.getStatus().toString(), tests.status,
|
||||
"status for " + tests.typed);
|
||||
}
|
||||
|
||||
if (tests.emptyParameters != null) {
|
||||
var realParams = completer.emptyParameters;
|
||||
test.is(realParams.length, tests.emptyParameters.length,
|
||||
'emptyParameters.length for \'' + tests.typed + '\'');
|
||||
|
||||
if (realParams.length === tests.emptyParameters.length) {
|
||||
for (var i = 0; i < realParams.length; i++) {
|
||||
test.is(realParams[i].replace(/\u00a0/g, ' '), tests.emptyParameters[i],
|
||||
'emptyParameters[' + i + '] for \'' + tests.typed + '\'');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.markup) {
|
||||
var cursor = tests.cursor ? tests.cursor.start : tests.typed.length;
|
||||
var statusMarkup = requisition.getInputStatusMarkup(cursor);
|
||||
var actualMarkup = statusMarkup.map(function(s) {
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
test.is(tests.markup, actualMarkup, 'markup for ' + tests.typed);
|
||||
}
|
||||
|
||||
if (tests.directTabText) {
|
||||
test.is(completer.directTabText, tests.directTabText,
|
||||
'directTabText for \'' + tests.typed + '\'');
|
||||
}
|
||||
|
||||
if (tests.arrowTabText) {
|
||||
test.is(completer.arrowTabText, ' \u00a0\u21E5 ' + tests.arrowTabText,
|
||||
'arrowTabText for \'' + tests.typed + '\'');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* helpers.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
exports.exec = function(options, tests) {
|
||||
var requisition = options.display.requisition;
|
||||
var inputter = options.display.inputter;
|
||||
|
||||
tests = tests || {};
|
||||
|
||||
if (tests.typed) {
|
||||
inputter.setInput(tests.typed);
|
||||
}
|
||||
|
||||
var typed = inputter.getInputState().typed;
|
||||
var output = requisition.exec({ hidden: true });
|
||||
|
||||
test.is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (tests.completed !== false) {
|
||||
test.ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// test.ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (tests.args != null) {
|
||||
test.is(Object.keys(tests.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
var expectedArg = tests.args[arg];
|
||||
var actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
test.ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
test.is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (var i = 0; i < expectedArg.length; i++) {
|
||||
test.is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.window.document.createElement) {
|
||||
test.log('skipping output tests (missing doc.createElement) for ' + typed);
|
||||
return;
|
||||
}
|
||||
|
||||
var div = options.window.document.createElement('div');
|
||||
output.toDom(div);
|
||||
var displayed = div.textContent.trim();
|
||||
|
||||
if (tests.outputMatch) {
|
||||
function doTest(match, against) {
|
||||
if (!match.test(against)) {
|
||||
test.ok(false, "html output for " + typed + " against " + match.source);
|
||||
console.log("Actual textContent");
|
||||
console.log(against);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(tests.outputMatch)) {
|
||||
tests.outputMatch.forEach(function(match) {
|
||||
doTest(match, displayed);
|
||||
});
|
||||
}
|
||||
else {
|
||||
doTest(tests.outputMatch, displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (tests.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
test.ok(false, "html for " + typed + " (textContent sent to info)");
|
||||
console.log("Actual textContent");
|
||||
console.log(displayed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
@ -4003,12 +4091,13 @@ let testModuleNames = [
|
||||
'gclitest/suite',
|
||||
'test/examiner',
|
||||
'test/assert',
|
||||
'gclitest/testCanon',
|
||||
'gclitest/helpers',
|
||||
'gclitest/testCli',
|
||||
'gclitest/mockCommands',
|
||||
'gclitest/testCompletion',
|
||||
'gclitest/testExec',
|
||||
'gclitest/testHelp',
|
||||
'gclitest/helpers',
|
||||
'gclitest/testHistory',
|
||||
'gclitest/testInputter',
|
||||
'gclitest/testIntro',
|
||||
|
@ -1038,6 +1038,14 @@ canon.Parameter = Parameter;
|
||||
* @return The new command
|
||||
*/
|
||||
canon.addCommand = function addCommand(commandSpec) {
|
||||
if (commands[commandSpec.name] != null) {
|
||||
// Roughly canon.removeCommand() without the event call, which we do later
|
||||
delete commands[commandSpec.name];
|
||||
commandNames = commandNames.filter(function(test) {
|
||||
return test !== commandSpec.name;
|
||||
});
|
||||
}
|
||||
|
||||
var command = new Command(commandSpec);
|
||||
commands[commandSpec.name] = command;
|
||||
commandNames.push(commandSpec.name);
|
||||
@ -1055,6 +1063,8 @@ canon.removeCommand = function removeCommand(commandOrName) {
|
||||
var name = typeof commandOrName === 'string' ?
|
||||
commandOrName :
|
||||
commandOrName.name;
|
||||
|
||||
// See start of canon.addCommand if changing this code
|
||||
delete commands[name];
|
||||
commandNames = commandNames.filter(function(test) {
|
||||
return test !== name;
|
||||
|
Loading…
Reference in New Issue
Block a user