diff options
Diffstat (limited to 'toolkit/devtools/commandline')
99 files changed, 16714 insertions, 0 deletions
diff --git a/toolkit/devtools/commandline/commandline.css b/toolkit/devtools/commandline/commandline.css new file mode 100644 index 000000000..a2180b3c2 --- /dev/null +++ b/toolkit/devtools/commandline/commandline.css @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +.gcli-help-name { + text-align: end; +} + +.gcli-out-shortcut, +.gcli-help-synopsis { + cursor: pointer; + display: inline-block; +} + +.gcli-out-shortcut:before, +.gcli-help-synopsis:before { + content: '\bb'; +} + +.gcli-menu-template { + white-space: nowrap; + width: 290px; + display: flex; +} + +.gcli-menu-names { + white-space: nowrap; + flex-grow: 0; + flex-shrink: 0; +} + +.gcli-menu-descs { + flex-grow: 1; + flex-shrink: 1; +} + +.gcli-menu-name, +.gcli-menu-desc { + white-space: nowrap; +} + +.gcli-menu-name { + -moz-padding-end: 10px; +} + +.gcli-menu-desc { + text-overflow: ellipsis; + overflow: hidden; +} + +.gcli-menu-name, +.gcli-out-shortcut, +.gcli-help-synopsis { + direction: ltr; +} + +.gcli-cookielist-list { + list-style-type: none; + padding-left: 0; +} + +.gcli-cookielist-detail { + padding-left: 20px; + padding-bottom: 10px; +} + +.gcli-appcache-list { + list-style-type: none; + padding-left: 0; +} + +.gcli-appcache-detail { + padding-left: 20px; + padding-bottom: 10px; +} + +.gcli-row-out .nowrap { + white-space: nowrap; +} diff --git a/toolkit/devtools/commandline/commandlineoutput.xhtml b/toolkit/devtools/commandline/commandlineoutput.xhtml new file mode 100644 index 000000000..88b7607f8 --- /dev/null +++ b/toolkit/devtools/commandline/commandlineoutput.xhtml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/> + <link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/> + <link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/> +</head> +<body class="gcli-body"> +<div id="gcli-output-root"></div> +</body> +</html> diff --git a/toolkit/devtools/commandline/commandlinetooltip.xhtml b/toolkit/devtools/commandline/commandlinetooltip.xhtml new file mode 100644 index 000000000..1c0231e69 --- /dev/null +++ b/toolkit/devtools/commandline/commandlinetooltip.xhtml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/> + <link rel="stylesheet" href="chrome://browser/content/devtools/commandline.css" type="text/css"/> + <link rel="stylesheet" href="chrome://browser/skin/devtools/commandline.css" type="text/css"/> +</head> +<body class="gcli-body"> +<div id="gcli-tooltip-root"></div> +<div id="gcli-tooltip-connector"></div> +</body> +</html> diff --git a/toolkit/devtools/commandline/commands-index.js b/toolkit/devtools/commandline/commands-index.js new file mode 100644 index 000000000..63a4f7516 --- /dev/null +++ b/toolkit/devtools/commandline/commands-index.js @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const gcli = require("gcli/index"); + +const commandModules = [ + "devtools/tilt/tilt-commands", + "gcli/commands/addon", + "gcli/commands/appcache", + "gcli/commands/calllog", + "gcli/commands/cmd", + "gcli/commands/cookie", + "gcli/commands/csscoverage", + "gcli/commands/folder", + "gcli/commands/highlight", + "gcli/commands/inject", + "gcli/commands/jsb", + "gcli/commands/listen", + "gcli/commands/media", + "gcli/commands/pagemod", + "gcli/commands/paintflashing", + "gcli/commands/qsa", + "gcli/commands/restart", + "gcli/commands/screenshot", + "gcli/commands/tools", +]; + +gcli.addItemsByModule(commandModules, { delayedLoad: true }); + +const defaultTools = require("main").defaultTools; +for (let definition of defaultTools) { + if (definition.commands) { + gcli.addItemsByModule(definition.commands, { delayedLoad: true }); + } +} + +const { mozDirLoader } = require("gcli/commands/cmd"); + +gcli.addItemsByModule("mozcmd", { delayedLoad: true, loader: mozDirLoader }); diff --git a/toolkit/devtools/commandline/moz.build b/toolkit/devtools/commandline/moz.build new file mode 100644 index 000000000..bad0b4a14 --- /dev/null +++ b/toolkit/devtools/commandline/moz.build @@ -0,0 +1,9 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXTRA_JS_MODULES.devtools.commandline += [ + 'commands-index.js' +] + +BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/toolkit/devtools/commandline/test/browser.ini b/toolkit/devtools/commandline/test/browser.ini new file mode 100644 index 000000000..4a2d3ea1a --- /dev/null +++ b/toolkit/devtools/commandline/test/browser.ini @@ -0,0 +1,111 @@ +[DEFAULT] +skip-if = e10s # Bug ?????? - devtools tests disabled with e10s +subsuite = devtools +support-files = + head.js + helpers.js + mockCommands.js + +[browser_cmd_addon.js] +skip-if = buildapp == 'mulet' +[browser_cmd_calllog.js] +skip-if = true || e10s # Bug 845831 +[browser_cmd_calllog_chrome.js] +skip-if = true || e10s # Bug 845831 +[browser_cmd_appcache_invalid.js] +support-files = + browser_cmd_appcache_invalid_appcache.appcache + browser_cmd_appcache_invalid_appcache.appcache^headers^ + browser_cmd_appcache_invalid_index.html + browser_cmd_appcache_invalid_page1.html + browser_cmd_appcache_invalid_page2.html + browser_cmd_appcache_invalid_page3.html + browser_cmd_appcache_invalid_page3.html^headers^ +[browser_cmd_appcache_valid.js] +support-files = + browser_cmd_appcache_valid_appcache.appcache + browser_cmd_appcache_valid_appcache.appcache^headers^ + browser_cmd_appcache_valid_index.html + browser_cmd_appcache_valid_page1.html + browser_cmd_appcache_valid_page2.html + browser_cmd_appcache_valid_page3.html +[browser_cmd_commands.js] +[browser_cmd_cookie.js] +support-files = + browser_cmd_cookie.html +[browser_cmd_csscoverage_oneshot.js] +support-files = + browser_cmd_csscoverage_page1.html + browser_cmd_csscoverage_page2.html + browser_cmd_csscoverage_page3.html + browser_cmd_csscoverage_sheetA.css + browser_cmd_csscoverage_sheetB.css + browser_cmd_csscoverage_sheetC.css + browser_cmd_csscoverage_sheetD.css +[browser_cmd_csscoverage_startstop.js] +support-files = + browser_cmd_csscoverage_page1.html + browser_cmd_csscoverage_page2.html + browser_cmd_csscoverage_page3.html + browser_cmd_csscoverage_sheetA.css + browser_cmd_csscoverage_sheetB.css + browser_cmd_csscoverage_sheetC.css + browser_cmd_csscoverage_sheetD.css +[browser_cmd_folder.js] +[browser_cmd_highlight_01.js] +[browser_cmd_highlight_02.js] +[browser_cmd_inject.js] +support-files = + browser_cmd_inject.html +[browser_cmd_csscoverage_util.js] +[browser_cmd_jsb.js] +support-files = + browser_cmd_jsb_script.jsi +[browser_cmd_media.js] +support-files = + browser_cmd_media.html +[browser_cmd_pagemod_export.js] +support-files = + browser_cmd_pagemod_export.html +[browser_cmd_pref1.js] +[browser_cmd_pref2.js] +[browser_cmd_pref3.js] +[browser_cmd_restart.js] +[browser_cmd_screenshot.js] +support-files = + browser_cmd_screenshot.html +[browser_cmd_settings.js] +[browser_gcli_async.js] +[browser_gcli_canon.js] +[browser_gcli_cli1.js] +[browser_gcli_cli2.js] +[browser_gcli_completion1.js] +[browser_gcli_completion2.js] +[browser_gcli_date.js] +skip-if = true || e10s # Disabled until TZ bug is fixed +[browser_gcli_exec.js] +[browser_gcli_fail.js] +[browser_gcli_file.js] +[browser_gcli_focus.js] +[browser_gcli_history.js] +[browser_gcli_incomplete.js] +[browser_gcli_inputter.js] +skip-if = true # Bug 1093205 - Test does not run in Firefox due to missing terminal bug +[browser_gcli_intro.js] +[browser_gcli_js.js] +[browser_gcli_keyboard1.js] +[browser_gcli_keyboard2.js] +[browser_gcli_keyboard3.js] +[browser_gcli_keyboard4.js] +[browser_gcli_keyboard5.js] +[browser_gcli_menu.js] +[browser_gcli_node.js] +[browser_gcli_resource.js] +[browser_gcli_short.js] +[browser_gcli_spell.js] +[browser_gcli_split.js] +[browser_gcli_tokenize.js] +[browser_gcli_tooltip.js] +skip-if = true # Bug 1093205 - Test does not run in Firefox due to missing terminal +[browser_gcli_types.js] +[browser_gcli_union.js] diff --git a/toolkit/devtools/commandline/test/browser_cmd_addon.js b/toolkit/devtools/commandline/test/browser_cmd_addon.js new file mode 100644 index 000000000..14fb93e44 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_addon.js @@ -0,0 +1,134 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the addon commands works as they should + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab("about:blank"); + yield helpers.openToolbar(options); + + yield helpers.audit(options, [ + { + setup: 'addon list dictionary', + check: { + input: 'addon list dictionary', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: 'There are no add-ons of that type installed.' + } + }, + { + setup: 'addon list extension', + check: { + input: 'addon list extension', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: [/The following/, /Mochitest/, /Special Powers/] + } + }, + { + setup: 'addon list locale', + check: { + input: 'addon list locale', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: 'There are no add-ons of that type installed.' + } + }, + { + setup: 'addon list plugin', + check: { + input: 'addon list plugin', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: [/Test Plug-in/, /Second Test Plug-in/] + } + }, + { + setup: 'addon list theme', + check: { + input: 'addon list theme', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: [/following themes/, /Default/] + } + }, + { + setup: 'addon list all', + check: { + input: 'addon list all', + hints: '', + markup: 'VVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: [/The following/, /Default/, /Mochitest/, /Test Plug-in/, + /Second Test Plug-in/, /Special Powers/] + } + }, + { + setup: 'addon disable Test_Plug-in_1.0.0.0', + check: { + input: 'addon disable Test_Plug-in_1.0.0.0', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: 'Test Plug-in 1.0.0.0 disabled.' + } + }, + { + setup: 'addon disable WRONG', + check: { + input: 'addon disable WRONG', + hints: '', + markup: 'VVVVVVVVVVVVVVEEEEE', + status: 'ERROR' + } + }, + { + setup: 'addon enable Test_Plug-in_1.0.0.0', + check: { + input: 'addon enable Test_Plug-in_1.0.0.0', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + command: { name: 'addon enable' }, + addon: { + value: function(addon) { + is(addon.name, 'Test Plug-in', 'test plugin name'); + }, + status: 'VALID' + } + } + }, + exec: { + output: 'Test Plug-in 1.0.0.0 enabled.' + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js new file mode 100644 index 000000000..15cade68a --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js @@ -0,0 +1,134 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the appcache validate works as they should with an invalid +// manifest. + +const TEST_URI = "http://sub1.test1.example.com/browser/browser/devtools/commandline/" + + "test/browser_cmd_appcache_invalid_index.html"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let lines = [ + 'Manifest has a character encoding of ISO-8859-1. Manifests must have the ' + + 'utf-8 character encoding.', + 'The first line of the manifest must be "CACHE MANIFEST" at line 1.', + '"CACHE MANIFEST" is only valid on the first line but was found at line 3.', + 'images/sound-icon.png points to a resource that is not available at line 9.', + 'images/background.png points to a resource that is not available at line 10.', + '/checking.cgi points to a resource that is not available at line 13.', + 'Asterisk (*) incorrectly used in the NETWORK section at line 14. If a line ' + + 'in the NETWORK section contains only a single asterisk character, then any ' + + 'URI not listed in the manifest will be treated as if the URI was listed in ' + + 'the NETWORK section. Otherwise such URIs will be treated as unavailable. ' + + 'Other uses of the * character are prohibited', + '../rel.html points to a resource that is not available at line 17.', + '../../rel.html points to a resource that is not available at line 18.', + '../../../rel.html points to a resource that is not available at line 19.', + '../../../../rel.html points to a resource that is not available at line 20.', + '../../../../../rel.html points to a resource that is not available at line 21.', + '/../ is not a valid URI prefix at line 22.', + '/test.css points to a resource that is not available at line 23.', + '/test.js points to a resource that is not available at line 24.', + 'test.png points to a resource that is not available at line 25.', + '/main/features.js points to a resource that is not available at line 27.', + '/main/settings/index.css points to a resource that is not available at line 28.', + 'http://example.com/scene.jpg points to a resource that is not available at line 29.', + '/section1/blockedbyfallback.html points to a resource that is not available at line 30.', + 'http://example.com/images/world.jpg points to a resource that is not available at line 31.', + '/section2/blockedbyfallback.html points to a resource that is not available at line 32.', + '/main/home points to a resource that is not available at line 34.', + 'main/app.js points to a resource that is not available at line 35.', + '/settings/home points to a resource that is not available at line 37.', + '/settings/app.js points to a resource that is not available at line 38.', + 'The file http://sub1.test1.example.com/browser/browser/devtools/' + + 'commandline/test/browser_cmd_appcache_invalid_page3.html was modified ' + + 'after http://sub1.test1.example.com/browser/browser/devtools/' + + 'commandline/test/browser_cmd_appcache_invalid_appcache.appcache. Unless ' + + 'the text in the manifest file is changed the cached version will be used ' + + 'instead at line 39.', + 'browser_cmd_appcache_invalid_page3.html has cache-control set to no-store. ' + + 'This will prevent the application cache from storing the file at line 39.', + 'http://example.com/logo.png points to a resource that is not available at line 40.', + 'http://example.com/check.png points to a resource that is not available at line 41.', + 'Spaces in URIs need to be replaced with % at line 42.', + 'http://example.com/cr oss.png points to a resource that is not available at line 42.', + 'Asterisk (*) incorrectly used in the CACHE section at line 43. If a line ' + + 'in the NETWORK section contains only a single asterisk character, then ' + + 'any URI not listed in the manifest will be treated as if the URI was ' + + 'listed in the NETWORK section. Otherwise such URIs will be treated as ' + + 'unavailable. Other uses of the * character are prohibited', + 'The SETTINGS section may only contain a single value, "prefer-online" or "fast" at line 47.', + 'FALLBACK section line 50 (/section1/ /offline1.html) prevents caching of ' + + 'line 30 (/section1/blockedbyfallback.html) in the CACHE section.', + '/offline1.html points to a resource that is not available at line 50.', + 'FALLBACK section line 51 (/section2/ offline2.html) prevents caching of ' + + 'line 32 (/section2/blockedbyfallback.html) in the CACHE section.', + 'offline2.html points to a resource that is not available at line 51.', + 'Only two URIs separated by spaces are allowed in the FALLBACK section at line 52.', + 'Asterisk (*) incorrectly used in the FALLBACK section at line 53. URIs ' + + 'in the FALLBACK section simply need to match a prefix of the request URI.', + 'offline3.html points to a resource that is not available at line 53.', + 'Invalid section name (BLAH) at line 55.', + 'Only two URIs separated by spaces are allowed in the FALLBACK section at line 55.' + ]; + + let options = yield helpers.openTab(TEST_URI); + info("window open"); + + // Wait for site to be cached. + yield helpers.listenOnce(gBrowser.contentWindow.applicationCache, 'error'); + info("applicationCache error happened"); + + yield helpers.openToolbar(options); + info("toolbar open"); + + // Pages containing an appcache the notification bar gives options to allow + // or deny permission for the app to save data offline. Let's click Allow. + let notificationID = "offline-app-requested-sub1.test1.example.com"; + let notification = + PopupNotifications.getNotification(notificationID, gBrowser.selectedBrowser); + + if (notification) { + info("Authorizing offline storage."); + notification.mainAction.callback(); + } else { + info("No notification box is available."); + } + + info("Site now cached, running tests."); + yield helpers.audit(options, [ + { + setup: 'appcache validate', + check: { + input: 'appcache validate', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID', + args: {} + }, + exec: { + output: lines.map(getRegexForString) + }, + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} + +/** + * Creates a regular expression that matches a string. This greatly simplifies + * matching and debugging long strings. + * + * @param {String} text + * Text to convert + * @return {RegExp} + * Regular expression matching text + */ +function getRegexForString(str) { + str = str.replace(/(\.|\\|\/|\(|\)|\[|\]|\*|\+|\?|\$|\^|\|)/g, "\\$1"); + return new RegExp(str); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache new file mode 100644 index 000000000..75b5d7bad --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache @@ -0,0 +1,55 @@ +# some comment + +CACHE MANIFEST +# the above is a required line +# this is a comment +# spaces are ignored +# blank lines are ignored + +images/sound-icon.png +images/background.png + +NETWORK: +/checking.cgi +/checking.* + +CACHE: +../rel.html +../../rel.html +../../../rel.html +../../../../rel.html +../../../../../rel.html +/../invalid.html +/test.css +/test.js +test.png +browser_cmd_appcache_invalid_index.html +/main/features.js +/main/settings/index.css +http://example.com/scene.jpg +/section1/blockedbyfallback.html +http://example.com/images/world.jpg +/section2/blockedbyfallback.html +browser_cmd_appcache_invalid_page1.html +/main/home +main/app.js +browser_cmd_appcache_invalid_page2.html +/settings/home +/settings/app.js +browser_cmd_appcache_invalid_page3.html +http://example.com/logo.png +http://example.com/check.png +http://example.com/cr oss.png +/checking*.png + +SETTINGS: +prefer-online +fast + +FALLBACK: +/section1/ /offline1.html +/section2/ offline2.html +dadsdsd +* offline3.html + +BLAH: diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ new file mode 100644 index 000000000..af95ed1f5 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ @@ -0,0 +1,2 @@ +Content-Type: text/cache-manifest; charset=ISO-8859-1 +Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html new file mode 100644 index 000000000..67f9aa675 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_invalid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example index.html</h1> + <br /> + <a href="browser_cmd_appcache_invalid_index.html">Home</a> | + <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html new file mode 100644 index 000000000..5ff36f102 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_invalid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page1.html</h1> + <br /> + <a href="browser_cmd_appcache_invalid_index.html">Home</a> | + <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html new file mode 100644 index 000000000..7d4a0c44d --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_invalid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page2.html</h1> + <br /> + <a href="browser_cmd_appcache_invalid_index.html">Home</a> | + <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html new file mode 100644 index 000000000..6777e59f8 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_invalid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page3.html</h1> + <br /> + <a href="browser_cmd_appcache_invalid_index.html">Home</a> | + <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ new file mode 100644 index 000000000..177130b43 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ @@ -0,0 +1,2 @@ +Cache-Control: no-store, no-cache +Last-Modified: Tue, 23 Apr 9999 11:41:13 GMT diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js new file mode 100644 index 000000000..e9a11ead3 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js @@ -0,0 +1,173 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the appcache commands works as they should + +const TEST_URI = "http://sub1.test2.example.com/browser/browser/devtools/" + + "commandline/test/browser_cmd_appcache_valid_index.html"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + info("adding cache listener."); + + // Wait for site to be cached. + yield helpers.listenOnce(gBrowser.contentWindow.applicationCache, 'cached'); + + // Pages containing an appcache the notification bar gives options to allow + // or deny permission for the app to save data offline. Let's click Allow. + let notificationID = "offline-app-requested-sub1.test2.example.com"; + let notification = PopupNotifications.getNotification(notificationID, gBrowser.selectedBrowser); + + if (notification) { + info("Authorizing offline storage."); + notification.mainAction.callback(); + } else { + info("No notification box is available."); + } + + info("Site now cached, running tests."); + yield helpers.audit(options, [ + { + setup: 'appcache', + check: { + input: 'appcache', + markup: 'IIIIIIII', + status: 'ERROR', + args: {} + }, + }, + + { + setup: function() { + Services.prefs.setBoolPref("browser.cache.disk.enable", false); + return helpers.setInput(options, 'appcache list', 13); + }, + check: { + input: 'appcache list', + markup: 'VVVVVVVVVVVVV', + status: 'VALID', + args: {}, + }, + exec: { + output: [ /cache is disabled/ ] + }, + post: function(output) { + Services.prefs.setBoolPref("browser.cache.disk.enable", true); + } + }, + + { + setup: 'appcache list', + check: { + input: 'appcache list', + markup: 'VVVVVVVVVVVVV', + status: 'VALID', + args: {}, + }, + exec: { + output: [ /index/, /page1/, /page2/, /page3/ ] + }, + }, + + { + setup: 'appcache list page', + check: { + input: 'appcache list page', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + search: { value: 'page' }, + } + }, + exec: { + output: [ /page1/, /page2/, /page3/ ] + }, + post: function(output, text) { + ok(!text.contains("index"), "index is not contained in output"); + } + }, + + { + setup: 'appcache validate', + check: { + input: 'appcache validate', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID', + args: {} + }, + exec: { + output: [ /successfully/ ] + }, + }, + + { + setup: 'appcache validate ' + TEST_URI, + check: { + input: 'appcache validate ' + TEST_URI, + // appcache validate http://sub1.test2.example.com/browser/browser/devtools/commandline/test/browser_cmd_appcache_valid_index.html + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + uri: { + value: TEST_URI + }, + } + }, + exec: { + output: [ /successfully/ ] + }, + }, + + { + setup: 'appcache clear', + check: { + input: 'appcache clear', + markup: 'VVVVVVVVVVVVVV', + status: 'VALID', + args: {}, + }, + exec: { + output: [ /successfully/ ] + }, + }, + + { + setup: 'appcache list', + check: { + input: 'appcache list', + markup: 'VVVVVVVVVVVVV', + status: 'VALID', + args: {}, + }, + exec: { + output: [ /no results/ ] + }, + post: function(output, text) { + ok(!text.contains("index"), "index is not contained in output"); + ok(!text.contains("page1"), "page1 is not contained in output"); + ok(!text.contains("page2"), "page1 is not contained in output"); + ok(!text.contains("page3"), "page1 is not contained in output"); + } + }, + + { + setup: 'appcache viewentry --key ' + TEST_URI, + check: { + input: 'appcache viewentry --key ' + TEST_URI, + // appcache viewentry --key http://sub1.test2.example.com/browser/browser/devtools/commandline/test/browser_cmd_appcache_valid_index.html + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: {} + }, + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache new file mode 100644 index 000000000..4f62825e9 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache @@ -0,0 +1,5 @@ +CACHE MANIFEST +browser_cmd_appcache_valid_index.html +browser_cmd_appcache_valid_page1.html +browser_cmd_appcache_valid_page2.html +browser_cmd_appcache_valid_page3.html diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ new file mode 100644 index 000000000..d1a0abd3f --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ @@ -0,0 +1,2 @@ +Content-Type: text/cache-manifest +Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html new file mode 100644 index 000000000..1ab3f3e31 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_valid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example index.html</h1> + <a href="browser_cmd_appcache_valid_index.html">Home</a> | + <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_valid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html new file mode 100644 index 000000000..e0bb429e7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_valid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page1.html</h1> + <a href="browser_cmd_appcache_valid_index.html">Home</a> | + <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_valid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html new file mode 100644 index 000000000..1ce36b319 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_valid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page2.html</h1> + <a href="browser_cmd_appcache_valid_index.html">Home</a> | + <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_valid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html new file mode 100644 index 000000000..074ff7d41 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html manifest="browser_cmd_appcache_valid_appcache.appcache"> + <head> + <meta charset="UTF-8"> + <head> + <body> + <h1>Example page3.html</h1> + <a href="browser_cmd_appcache_valid_index.html">Home</a> | + <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> | + <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> | + <a href="browser_cmd_appcache_valid_page3.html">Page 3</a> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_calllog.js b/toolkit/devtools/commandline/test/browser_cmd_calllog.js new file mode 100644 index 000000000..2ca225e3d --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_calllog.js @@ -0,0 +1,119 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the calllog commands works as they should + +const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog"; + +let tests = {}; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + yield helpers.runTests(options, tests); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +tests.testCallLogStatus = function(options) { + return helpers.audit(options, [ + { + setup: "calllog", + check: { + input: 'calllog', + hints: '', + markup: 'IIIIIII', + status: 'ERROR' + } + }, + { + setup: "calllog start", + check: { + input: 'calllog start', + hints: '', + markup: 'VVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: "calllog stop", + check: { + input: 'calllog stop', + hints: '', + markup: 'VVVVVVVVVVVV', + status: 'VALID' + } + }, + ]); +}; + +tests.testCallLogExec = function(options) { + var deferred = promise.defer(); + + var onWebConsoleOpen = function(subject) { + Services.obs.removeObserver(onWebConsoleOpen, "web-console-created"); + + subject.QueryInterface(Ci.nsISupportsString); + let hud = HUDService.getHudReferenceById(subject.data); + ok(hud, "console open"); + + helpers.audit(options, [ + { + setup: "calllog stop", + exec: { + output: /Stopped call logging/, + } + }, + { + setup: "console clear", + exec: { + output: "", + }, + post: function() { + let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output"); + is(labels.length, 0, "no output in console"); + } + }, + { + setup: "console close", + exec: { + output: "", + } + }, + ]).then(function() { + deferred.resolve(); + }); + }; + Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false); + + helpers.audit(options, [ + { + setup: "calllog stop", + exec: { + output: /No call logging/, + } + }, + { + name: "calllog start", + setup: function() { + // This test wants to be in a different event + var deferred = promise.defer(); + executeSoon(function() { + helpers.setInput(options, "calllog start").then(() => { + deferred.resolve(); + }); + }); + return deferred.promise; + }, + exec: { + output: /Call logging started/, + }, + }, + ]); + + return deferred.promise; +}; diff --git a/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js b/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js new file mode 100644 index 000000000..1bc9d6106 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js @@ -0,0 +1,116 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the calllog commands works as they should + +const TEST_URI = "data:text/html;charset=utf-8,cmd-calllog-chrome"; + +let tests = {}; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + yield helpers.runTests(options, tests); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +tests.testCallLogStatus = function(options) { + return helpers.audit(options, [ + { + setup: "calllog", + check: { + status: "ERROR", + emptyParameters: [ " " ] + } + }, + { + setup: "calllog chromestop", + check: { + status: "VALID", + emptyParameters: [ " " ] + } + }, + { + setup: "calllog chromestart content-variable window", + check: { + status: "VALID", + emptyParameters: [ " " ] + } + }, + { + setup: "calllog chromestart javascript \"({a1: function() {this.a2()},a2: function() {}});\"", + check: { + status: "VALID", + emptyParameters: [ " " ] + } + }, + ]); +}; + +tests.testCallLogExec = function(options) { + let deferred = promise.defer(); + + function onWebConsoleOpen(subject) { + Services.obs.removeObserver(onWebConsoleOpen, "web-console-created"); + + subject.QueryInterface(Ci.nsISupportsString); + let hud = HUDService.getHudReferenceById(subject.data); + ok(hud, "console open"); + + helpers.audit(options, [ + { + setup: "calllog chromestop", + exec: { + output: /Stopped call logging/, + } + }, + { + setup: "calllog chromestart javascript XXX", + exec: { + output: /following exception/, + } + }, + { + setup: "console clear", + exec: { + output: '', + }, + post: function() { + let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output"); + is(labels.length, 0, "no output in console"); + } + }, + { + setup: "console close", + exec: { + output: '', + }, + }, + ]).then(function() { + deferred.resolve(); + }); + } + Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false); + + helpers.audit(options, [ + { + setup: "calllog chromestop", + exec: { + output: /No call logging/ + } + }, + { + setup: "calllog chromestart javascript \"({a1: function() {this.a2()},a2: function() {}});\"", + exec: { + output: /Call logging started/, + } + }, + ]); + + return deferred.promise; +}; diff --git a/toolkit/devtools/commandline/test/browser_cmd_commands.js b/toolkit/devtools/commandline/test/browser_cmd_commands.js new file mode 100644 index 000000000..78dc0a488 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_commands.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test various GCLI commands + +const TEST_URI = "data:text/html;charset=utf-8,gcli-commands"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + let subjectPromise = helpers.observeOnce("web-console-created"); + + helpers.audit(options, [ + { + setup: "console open", + exec: { } + } + ]); + + let subject = yield subjectPromise; + + subject.QueryInterface(Ci.nsISupportsString); + let hud = HUDService.getHudReferenceById(subject.data); + ok(hud, "console open"); + + let msg = yield hud.jsterm.execute("pprint(window)"); + + ok(msg, "output for pprint(window)"); + + let oncePromise = hud.jsterm.once("messages-cleared"); + + helpers.audit(options, [ + { + setup: "console clear", + exec: { output: "" } + } + ]); + + yield oncePromise; + + let labels = hud.outputNode.querySelectorAll(".message"); + is(labels.length, 0, "no output in console"); + + yield helpers.audit(options, [ + { + setup: "console close", + exec: { output: true } + } + ]); + + ok(!HUDService.getHudReferenceById(hud.hudId), "console closed"); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_cookie.html b/toolkit/devtools/commandline/test/browser_cmd_cookie.html new file mode 100644 index 000000000..e9b385a35 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_cookie.html @@ -0,0 +1,18 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>GCLI cookie command test</title> +</head> +<body> + + <p>Cookie test</p> + <p id=result></p> + <script type="text/javascript"> + document.cookie = "zap=zep"; + document.cookie = "zip=zop"; + document.getElementById("result").innerHTML = document.cookie; + </script> + +</body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_cookie.js b/toolkit/devtools/commandline/test/browser_cmd_cookie.js new file mode 100644 index 000000000..a07b4f350 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_cookie.js @@ -0,0 +1,170 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the cookie commands works as they should + +const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+ + "test/browser_cmd_cookie.html"; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function(options) { + return helpers.audit(options, [ + { + setup: 'cookie', + check: { + input: 'cookie', + hints: ' list', + markup: 'IIIIII', + status: 'ERROR' + }, + }, + { + setup: 'cookie lis', + check: { + input: 'cookie lis', + hints: 't', + markup: 'IIIIIIVIII', + status: 'ERROR' + }, + }, + { + setup: 'cookie list', + check: { + input: 'cookie list', + hints: '', + markup: 'VVVVVVVVVVV', + status: 'VALID' + }, + }, + { + setup: 'cookie remove', + check: { + input: 'cookie remove', + hints: ' <name>', + markup: 'VVVVVVVVVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'cookie set', + check: { + input: 'cookie set', + hints: ' <name> <value> [options]', + markup: 'VVVVVVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'cookie set fruit', + check: { + input: 'cookie set fruit', + hints: ' <value> [options]', + markup: 'VVVVVVVVVVVVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'cookie set fruit ban', + check: { + input: 'cookie set fruit ban', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + name: { value: 'fruit' }, + value: { value: 'ban' }, + secure: { value: false }, + } + }, + }, + { + setup: 'cookie set fruit ban --path ""', + check: { + input: 'cookie set fruit ban --path ""', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + name: { value: 'fruit' }, + value: { value: 'ban' }, + path: { value: '' }, + secure: { value: false }, + } + }, + }, + { + setup: "cookie list", + exec: { + output: [ /zap=zep/, /zip=zop/, /Edit/ ] + } + }, + { + setup: "cookie set zup banana", + check: { + args: { + name: { value: 'zup' }, + value: { value: 'banana' }, + } + }, + exec: { + output: "" + } + }, + { + setup: "cookie list", + exec: { + output: [ /zap=zep/, /zip=zop/, /zup=banana/, /Edit/ ] + } + }, + { + setup: "cookie remove zip", + exec: { }, + }, + { + setup: "cookie list", + exec: { + output: [ /zap=zep/, /zup=banana/, /Edit/ ] + }, + post: function(output, text) { + ok(!text.contains("zip"), ""); + ok(!text.contains("zop"), ""); + } + }, + { + setup: "cookie remove zap", + exec: { }, + }, + { + setup: "cookie list", + exec: { + output: [ /zup=banana/, /Edit/ ] + }, + post: function(output, text) { + ok(!text.contains("zap"), ""); + ok(!text.contains("zep"), ""); + ok(!text.contains("zip"), ""); + ok(!text.contains("zop"), ""); + } + }, + { + setup: "cookie remove zup", + exec: { } + }, + { + setup: "cookie list", + exec: { + output: 'No cookies found for host example.com' + }, + post: function(output, text) { + ok(!text.contains("zap"), ""); + ok(!text.contains("zep"), ""); + ok(!text.contains("zip"), ""); + ok(!text.contains("zop"), ""); + ok(!text.contains("zup"), ""); + ok(!text.contains("banana"), ""); + ok(!text.contains("Edit"), ""); + } + }, + ]); + }).then(finish, helpers.handleError); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js new file mode 100644 index 000000000..bbff0dd16 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js @@ -0,0 +1,318 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the addon commands works as they should + +const csscoverage = require("devtools/server/actors/csscoverage"); + +const PAGE_1 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page1.html"; +const PAGE_2 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page2.html"; +const PAGE_3 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page3.html"; + +const SHEET_A = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetA.css"; +const SHEET_B = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetB.css"; +const SHEET_C = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetC.css"; +const SHEET_D = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetD.css"; + +add_task(function*() { + let options = yield helpers.openTab(PAGE_3); + yield helpers.openToolbar(options); + + let usage = yield csscoverage.getUsage(options.target); + + yield navigate(usage, options); + yield checkPages(usage); + yield checkEditorReport(usage); + // usage.createPageReport is not supported for usage.oneshot data as of + // bug 1035300 because the page report assumed we have preload data which + // oneshot can't gather. The ideal solution is to have a special no-preload + // mode for the page report, but since oneshot isn't needed for the UI to + // function, we're currently not supporting page report for oneshot data + // yield checkPageReport(usage); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +}); + +/** + * Just check current page + */ +function* navigate(usage, options) { + ok(!usage.isRunning(), "csscoverage is not running"); + + yield usage.oneshot(); + + ok(!usage.isRunning(), "csscoverage is still not running"); +} + +/** + * Check the expected pages have been visited + */ +function* checkPages(usage) { + let expectedVisited = [ PAGE_3 ]; + let actualVisited = yield usage._testOnly_visitedPages(); + isEqualJson(actualVisited, expectedVisited, 'Visited'); +} + +/** + * Check that createEditorReport returns the expected JSON + */ +function* checkEditorReport(usage) { + // Page1 + let expectedPage1 = { reports: [] }; + let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0"); + isEqualJson(actualPage1, expectedPage1, 'Page1'); + + // Page2 + let expectedPage2 = { reports: [] }; + let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0"); + isEqualJson(actualPage2, expectedPage2, 'Page2'); + + // Page3a + let expectedPage3a = { + reports: [ + { + selectorText: ".page3-test2", + start: { line: 9, column: 5 }, + } + ] + }; + let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0"); + isEqualJson(actualPage3a, expectedPage3a, 'Page3a'); + + // Page3b + let expectedPage3b = { + reports: [ + { + selectorText: ".page3-test3", + start: { line: 3, column: 5 }, + } + ] + }; + let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1"); + isEqualJson(actualPage3b, expectedPage3b, 'Page3b'); + + // SheetA + let expectedSheetA = { + reports: [ + { + selectorText: ".sheetA-test2", + start: { line: 8, column: 1 }, + }, + { + selectorText: ".sheetA-test3", + start: { line: 12, column: 1 }, + }, + { + selectorText: ".sheetA-test4", + start: { line: 16, column: 1 }, + } + ] + }; + let actualSheetA = yield usage.createEditorReport(SHEET_A); + isEqualJson(actualSheetA, expectedSheetA, 'SheetA'); + + // SheetB + let expectedSheetB = { + reports: [ + { + selectorText: ".sheetB-test2", + start: { line: 6, column: 1 }, + }, + { + selectorText: ".sheetB-test3", + start: { line: 10, column: 1 }, + }, + { + selectorText: ".sheetB-test4", + start: { line: 14, column: 1 }, + } + ] + }; + let actualSheetB = yield usage.createEditorReport(SHEET_B); + isEqualJson(actualSheetB, expectedSheetB, 'SheetB'); + + // SheetC + let expectedSheetC = { + reports: [ + { + selectorText: ".sheetC-test2", + start: { line: 6, column: 1 }, + }, + { + selectorText: ".sheetC-test3", + start: { line: 10, column: 1 }, + }, + { + selectorText: ".sheetC-test4", + start: { line: 14, column: 1 }, + } + ] + }; + let actualSheetC = yield usage.createEditorReport(SHEET_C); + isEqualJson(actualSheetC, expectedSheetC, 'SheetC'); + + // SheetD + let expectedSheetD = { + reports: [ + { + selectorText: ".sheetD-test2", + start: { line: 6, column: 1 }, + }, + { + selectorText: ".sheetD-test3", + start: { line: 10, column: 1 }, + }, + { + selectorText: ".sheetD-test4", + start: { line: 14, column: 1 }, + } + ] + }; + let actualSheetD = yield usage.createEditorReport(SHEET_D); + isEqualJson(actualSheetD, expectedSheetD, 'SheetD'); +} + +/** + * Check that checkPageReport returns the expected JSON + */ +function* checkPageReport(usage) { + let actualReport = yield usage.createPageReport(); + + // Quick check on trivial things. See doc comment for checkRuleProperties + actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties)); + actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties)); + + // Check the summary + let expectedSummary = { "used": 23, "unused": 9, "preload": 0 }; + isEqualJson(actualReport.summary, expectedSummary, 'summary'); + + // Check the preload header + isEqualJson(actualReport.preload.length, 0, 'preload length'); + + // Check the unused header + isEqualJson(actualReport.unused.length, 6, 'unused length'); + + // Check the unused rules + isEqualJson(actualReport.unused[0].url, PAGE_3 + " \u2192 <style> index 0", "unused url 0"); + let expectedUnusedRules0 = [ + { + "url": PAGE_3 + " \u2192 <style> index 0", + "start": { "line": 9, "column": 5 }, + "selectorText": ".page3-test2" + } + ]; + isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0'); + + isEqualJson(actualReport.unused[1].url, PAGE_3 + " \u2192 <style> index 1", "unused url 1"); + let expectedUnusedRules1 = [ + { + "url": PAGE_3 + " \u2192 <style> index 1", + "start": { "line": 3, "column": 5 }, + "selectorText": ".page3-test3" + } + ]; + isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1'); + + isEqualJson(actualReport.unused[2].url, SHEET_A, "unused url 2"); + let expectedUnusedRules2 = [ + { + "url": SHEET_A, + "start": { "line": 8, "column": 1 }, + "selectorText": ".sheetA-test2" + }, + { + "url": SHEET_A, + "start": { "line": 12, "column": 1 }, + "selectorText": ".sheetA-test3" + }, + { + "url": SHEET_A, + "start": { "line": 16, "column": 1 }, + "selectorText": ".sheetA-test4" + } + ]; + isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2'); + + isEqualJson(actualReport.unused[3].url, SHEET_B, "unused url 3"); + let expectedUnusedRules3 = [ + { + "url": SHEET_B, + "start": { "line": 6, "column": 1 }, + "selectorText": ".sheetB-test2" + }, + { + "url": SHEET_B, + "start": { "line": 10, "column": 1 }, + "selectorText": ".sheetB-test3" + }, + { + "url": SHEET_B, + "start": { "line": 14, "column": 1 }, + "selectorText": ".sheetB-test4" + } + ]; + isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3'); + + isEqualJson(actualReport.unused[4].url, SHEET_D, "unused url 4"); + let expectedUnusedRules4 = [ + { + "url": SHEET_D, + "start": { "line": 6, "column": 1 }, + "selectorText": ".sheetD-test2" + }, + { + "url": SHEET_D, + "start": { "line": 10, "column": 1 }, + "selectorText": ".sheetD-test3" + }, + { + "url": SHEET_D, + "start": { "line": 14, "column": 1 }, + "selectorText": ".sheetD-test4" + } + ]; + isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4'); + + isEqualJson(actualReport.unused[5].url, SHEET_C, "unused url 5"); + let expectedUnusedRules5 = [ + { + "url": SHEET_C, + "start": { "line": 6, "column": 1 }, + "selectorText": ".sheetC-test2" + }, + { + "url": SHEET_C, + "start": { "line": 10, "column": 1 }, + "selectorText": ".sheetC-test3" + }, + { + "url": SHEET_C, + "start": { "line": 14, "column": 1 }, + "selectorText": ".sheetC-test4" + } + ]; + isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5'); +} + +/** + * We do basic tests on the shortUrl and formattedCssText because they are + * very derivative, and so make for fragile tests, and having done those quick + * existence checks we remove them so the JSON check later can ignore them + */ +function checkRuleProperties(rule, index) { + is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index); + is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index); + delete rule.shortUrl; + + is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index); + ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index); + delete rule.formattedCssText; +} + +/** + * Utility to compare JSON structures + */ +function isEqualJson(o1, o2, msg) { + is(JSON.stringify(o1), JSON.stringify(o2), msg); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html new file mode 100644 index 000000000..b137ac1e7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html @@ -0,0 +1,85 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <!-- + First page of the css coverage test. + * Contains page2 in an iframe + * Forwards to page2 on a timeout + --> + <title>Page 1</title> + <style> + @import url(browser_cmd_csscoverage_sheetD.css); + /* This should match below */ + .page1-test1 { + color: #011; + } + /* This should not match below */ + .page1-test2 { + color: #012; + } + /* This would match if the mouse was in the right place */ + .page1-test3:hover { + color: #013; + } + /* This can't match because it's illegal */ + .page1-test4:broken { + color: #014; + } + /* This doesn't match until the event fires */ + .page1-test5 { + color: #015; + } + /* TODO: include examples of all CSS rules in + https://developer.mozilla.org/en-US/docs/Web/API/CSSRule + and include tests for rules nested in media rules, etc */ + + /* We're not testing unparable CSS right now */ + </style> + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css"> + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css"> + <script type="application/javascript;version=1.8"> + /* How quickly do we rush through this? */ + let delay = 500; + window.addEventListener("load", () => { + dump('TEST-INFO | load from browser_cmd_csscoverage_page1.html\n'); + setTimeout(() => { + dump('TEST-INFO | timeout from browser_cmd_csscoverage_page1.html\n'); + /* This adds <div class=page1-test5></div> */ + let parent = document.querySelector("#page1-test5-holder"); + let child = document.createElement("div"); + child.classList.add("page1-test5"); + parent.appendChild(child); + + /* Then navigate to the next step */ + window.location.href = "browser_cmd_csscoverage_page3.html" + }, delay); + }); + </script> +</head> +<body> + +<h2>Page 1</h2> + +<div class=page1-test1>.page1-test1</div> +<div class=page1-test3>.page1-test3</div> + +<div id=page1-test5-holder></div> + +<div class=sheetA-test1>.sheetA-test1</div> +<div class=sheetA-test3>.sheetA-test3</div> +<div class=sheetB-test1>.sheetB-test1</div> +<div class=sheetB-test3>.sheetB-test3</div> +<div class=sheetC-test1>.sheetC-test1</div> +<div class=sheetC-test3>.sheetC-test3</div> +<div class=sheetD-test1>.sheetD-test1</div> +<div class=sheetD-test3>.sheetD-test3</div> + +<iframe src=browser_cmd_csscoverage_page2.html></iframe> + +<p> + <a href="browser_cmd_csscoverage_page3.html">Page 3</a> +</p> + +</body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html new file mode 100644 index 000000000..13fa8697c --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Page 2</title> + <style> + @import url(browser_cmd_csscoverage_sheetD.css); + + /* This should match below */ + .page2-test1 { + color: #021; + } + /* This should not match below */ + .page2-test2 { + color: #022; + } + /* This doesn't match until the event fires */ + .page2-test3 { + color: #023; + } + </style> + + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css"> + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css"> + <script type="application/javascript;version=1.8"> + /* How quickly do we rush through this? */ + let delay = 500; + window.addEventListener("load", () => { + dump('TEST-INFO | load from browser_cmd_csscoverage_page2.html\n'); + setTimeout(() => { + dump('TEST-INFO | timeout from browser_cmd_csscoverage_page2.html\n'); + /* This adds <div class=page2-test3></div> */ + let parent = document.querySelector("#page2-test3-holder"); + let child = document.createElement("div"); + child.classList.add("page2-test3"); + parent.appendChild(child); + }, delay); + }); + </script> +</head> +<body> + +<h2>Page 2</h2> + +<div class=page2-test1>.page2-test1</div> + +<div id=page2-test3-holder></div> + +<div class=sheetA-test1>.sheetA-test1</div> +<div class=sheetA-test4>.sheetA-test4</div> +<div class=sheetB-test1>.sheetB-test1</div> +<div class=sheetB-test4>.sheetB-test4</div> +<div class=sheetC-test1>.sheetC-test1</div> +<div class=sheetC-test4>.sheetC-test4</div> +<div class=sheetD-test1>.sheetD-test1</div> +<div class=sheetD-test4>.sheetD-test4</div> + +</body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html new file mode 100644 index 000000000..4dc91d5b2 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Page 3</title> + <style> + @import url(browser_cmd_csscoverage_sheetD.css); + + /* This should match below */ + .page3-test1 { + color: #031; + } + /* This should not match below */ + .page3-test2 { + color: #032; + } + </style> + <style> + /* This also should not match below, but in a second inline sheet */ + .page3-test3 { + color: #033; + } + </style> + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css"> + <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css"> + <script type="application/javascript;version=1.8"> + window.addEventListener("load", () => { + dump('TEST-INFO | load from browser_cmd_csscoverage_page3.html\n'); + }); + </script> +</head> +<body> + +<h2>Page 3</h2> + +<div class=page3-test1>.page3-test1</div> + +<div class=sheetA-test1>.sheetA-test1</div> +<div class=sheetA-test5>.sheetA-test5</div> +<div class=sheetB-test1>.sheetB-test1</div> +<div class=sheetB-test5>.sheetB-test5</div> +<div class=sheetC-test1>.sheetC-test1</div> +<div class=sheetC-test5>.sheetC-test5</div> +<div class=sheetD-test1>.sheetD-test1</div> +<div class=sheetD-test5>.sheetD-test5</div> + +<p> + <a href="browser_cmd_csscoverage_page1.html">Page 1</a> +</p> + +</body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css new file mode 100644 index 000000000..1a3bac926 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css @@ -0,0 +1,22 @@ +@import url(browser_cmd_csscoverage_sheetC.css); + +/* This should match in page 1, 2 and 3 */ +.sheetA-test1 { + color: #0A1; +} +/* This should not match anywhere */ +.sheetA-test2 { + color: #0A2; +} +/* This should match in page 1 only */ +.sheetA-test3 { + color: #0A3; +} +/* This should match in page 2 only */ +.sheetA-test4 { + color: #0A4; +} +/* This should match in page 3 only */ +.sheetA-test5 { + color: #0A5; +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css new file mode 100644 index 000000000..9335bd60d --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css @@ -0,0 +1,20 @@ +/* This should match in page 1, 2 and 3 */ +.sheetB-test1 { + color: #0B1; +} +/* This should not match anywhere */ +.sheetB-test2 { + color: #0B2; +} +/* This should match in page 1 only */ +.sheetB-test3 { + color: #0B3; +} +/* This should match in page 2 only */ +.sheetB-test4 { + color: #0B4; +} +/* This should match in page 3 only */ +.sheetB-test5 { + color: #0B5; +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css new file mode 100644 index 000000000..8c899ead9 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css @@ -0,0 +1,20 @@ +/* This should match in page 1, 2 and 3 */ +.sheetC-test1 { + color: #0C1; +} +/* This should not match anywhere */ +.sheetC-test2 { + color: #0C2; +} +/* This should match in page 1 only */ +.sheetC-test3 { + color: #0C3; +} +/* This should match in page 2 only */ +.sheetC-test4 { + color: #0C4; +} +/* This should match in page 3 only */ +.sheetC-test5 { + color: #0C5; +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css new file mode 100644 index 000000000..60ebb314a --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css @@ -0,0 +1,20 @@ +/* This should match in page 1, 2 and 3 */ +.sheetD-test1 { + color: #0D1; +} +/* This should not match anywhere */ +.sheetD-test2 { + color: #0D2; +} +/* This should match in page 1 only */ +.sheetD-test3 { + color: #0D3; +} +/* This should match in page 2 only */ +.sheetD-test4 { + color: #0D4; +} +/* This should match in page 3 only */ +.sheetD-test5 { + color: #0D5; +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js new file mode 100644 index 000000000..f1527c78b --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js @@ -0,0 +1,457 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the addon commands works as they should + +const csscoverage = require("devtools/server/actors/csscoverage"); + +const PAGE_1 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page1.html"; +const PAGE_2 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page2.html"; +const PAGE_3 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page3.html"; + +const SHEET_A = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetA.css"; +const SHEET_B = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetB.css"; +const SHEET_C = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetC.css"; +const SHEET_D = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetD.css"; + +add_task(function*() { + let options = yield helpers.openTab("about:blank"); + yield helpers.openToolbar(options); + + let usage = yield csscoverage.getUsage(options.target); + + yield navigate(usage, options); + yield checkPages(usage); + yield checkEditorReport(usage); + yield checkPageReport(usage); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +}); + +/** + * Visit all the pages in the test + */ +function* navigate(usage, options) { + yield usage.start(); + + ok(usage.isRunning(), "csscoverage is running"); + + yield helpers.navigate(PAGE_1, options); + + // Wait for the test pages to auto-cycle + let ev = yield helpers.listenOnce(options.browser, "load", true); + is(ev.target.location.href, PAGE_1, "page 1 loaded"); + + ev = yield helpers.listenOnce(options.browser, "load", true); + is(ev.target.location.href, PAGE_3, "page 3 loaded"); + + yield usage.stop(); + + ok(!usage.isRunning(), "csscoverage not is running"); +} + +/** + * Check the expected pages have been visited + */ +function* checkPages(usage) { + // 'load' event order. 'null' is for the initial location + let expectedVisited = [ 'null', PAGE_2, PAGE_1, PAGE_3 ]; + let actualVisited = yield usage._testOnly_visitedPages(); + isEqualJson(actualVisited, expectedVisited, 'Visited'); +} + +/** + * Check that createEditorReport returns the expected JSON + */ +function* checkEditorReport(usage) { + // Page1 + let expectedPage1 = { + reports: [ + { + selectorText: ".page1-test2", + start: { line: 8, column: 5 }, + } + ] + }; + let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0"); + isEqualJson(actualPage1, expectedPage1, 'Page1'); + + // Page2 + let expectedPage2 = { + reports: [ + { + selectorText: ".page2-test2", + start: { line: 9, column: 5 }, + }, + ] + }; + let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0"); + isEqualJson(actualPage2, expectedPage2, 'Page2'); + + // Page3a + let expectedPage3a = { + reports: [ + { + selectorText: ".page3-test2", + start: { line: 9, column: 5 }, + } + ] + }; + let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0"); + isEqualJson(actualPage3a, expectedPage3a, 'Page3a'); + + // Page3b + let expectedPage3b = { + reports: [ + { + selectorText: ".page3-test3", + start: { line: 3, column: 5 }, + } + ] + }; + let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1"); + isEqualJson(actualPage3b, expectedPage3b, 'Page3b'); + + // SheetA + let expectedSheetA = { + reports: [ + { + selectorText: ".sheetA-test2", + start: { line: 8, column: 1 }, + } + ] + }; + let actualSheetA = yield usage.createEditorReport(SHEET_A); + isEqualJson(actualSheetA, expectedSheetA, 'SheetA'); + + // SheetB + let expectedSheetB = { + reports: [ + { + selectorText: ".sheetB-test2", + start: { line: 6, column: 1 }, + } + ] + }; + let actualSheetB = yield usage.createEditorReport(SHEET_B); + isEqualJson(actualSheetB, expectedSheetB, 'SheetB'); + + // SheetC + let expectedSheetC = { + reports: [ + { + selectorText: ".sheetC-test2", + start: { line: 6, column: 1 }, + } + ] + }; + let actualSheetC = yield usage.createEditorReport(SHEET_C); + isEqualJson(actualSheetC, expectedSheetC, 'SheetC'); + + // SheetD + let expectedSheetD = { + reports: [ + { + selectorText: ".sheetD-test2", + start: { line: 6, column: 1 }, + } + ] + }; + let actualSheetD = yield usage.createEditorReport(SHEET_D); + isEqualJson(actualSheetD, expectedSheetD, 'SheetD'); +} + +/** + * Check that checkPageReport returns the expected JSON + */ +function* checkPageReport(usage) { + let actualReport = yield usage.createPageReport(); + + // Quick check on trivial things. See doc comment for checkRuleProperties + actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties)); + actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties)); + + // Check the summary + let expectedSummary = { "used": 92, "unused": 22, "preload": 28 }; + isEqualJson(actualReport.summary, expectedSummary, 'summary'); + + checkPageReportPreload(actualReport); + checkPageReportUnused(actualReport); +} + +/** + * Check that checkPageReport returns the expected preload JSON + */ +function checkPageReportPreload(actualReport) { + // Check the preload header + isEqualJson(actualReport.preload.length, 3, 'preload length'); + + // Check the preload rules + isEqualJson(actualReport.preload[0].url, PAGE_2, 'preload url 0'); + let expectedPreloadRules0 = [ + // TODO: This is already pre-loaded, we should note this + { + url: PAGE_2 + " \u2192 <style> index 0", + start: { line: 5, column: 5 }, + selectorText: ".page2-test1" + }, + { + url: SHEET_A, + start: { line: 4, column: 1 }, + selectorText: ".sheetA-test1" + }, + { + url: SHEET_A, + start: { line: 16, column: 1 }, + selectorText: ".sheetA-test4" + }, + { + url: SHEET_B, + start: { line: 2, column: 1 }, + selectorText: ".sheetB-test1" + }, + { + url: SHEET_B, + start: { line: 14, column: 1 }, + selectorText: ".sheetB-test4" + }, + { + url: SHEET_D, + start: { line: 2, column: 1 }, + selectorText: ".sheetD-test1" + }, + { + url: SHEET_D, + start: { line: 14, column: 1 }, + selectorText: ".sheetD-test4" + }, + { + url: SHEET_C, + start: { line: 2, column: 1 }, + selectorText: ".sheetC-test1" + }, + { + url: SHEET_C, + start: { line: 14, column: 1 }, + selectorText: ".sheetC-test4" + } + ]; + isEqualJson(actualReport.preload[0].rules, expectedPreloadRules0, 'preload rules 0'); + + isEqualJson(actualReport.preload[1].url, PAGE_1, 'preload url 1'); + let expectedPreloadRules1 = [ + { + url: SHEET_A, + start: { line: 4, column: 1 }, + selectorText: ".sheetA-test1" + }, + { + url: SHEET_A, + start: { line: 12, column: 1 }, + selectorText: ".sheetA-test3" + }, + { + url: SHEET_B, + start: { line: 2, column: 1 }, + selectorText: ".sheetB-test1" + }, + { + url: SHEET_B, + start: { line: 10, column: 1 }, + selectorText: ".sheetB-test3" + }, + { + url: SHEET_D, + start: { line: 2, column: 1 }, + selectorText: ".sheetD-test1" + }, + { + url: SHEET_D, + start: { line: 10, column: 1 }, + selectorText: ".sheetD-test3" + }, + { + url: SHEET_C, + start: { line: 2, column: 1 }, + selectorText: ".sheetC-test1" + }, + { + url: SHEET_C, + start: { line: 10, column: 1 }, + selectorText: ".sheetC-test3" + }, + { + url: PAGE_1 + " \u2192 <style> index 0", + start: { line: 4, column: 5 }, + selectorText: ".page1-test1" + }, + { + url: PAGE_1 + " \u2192 <style> index 0", + start: { line: 12, column: 5 }, + selectorText: ".page1-test3:hover" + } + ]; + isEqualJson(actualReport.preload[1].rules, expectedPreloadRules1, 'preload rules 1'); + + isEqualJson(actualReport.preload[2].url, PAGE_3, 'preload url 2'); + let expectedPreloadRules2 = [ + { + url: SHEET_A, + start: { line: 4, column: 1 }, + selectorText: ".sheetA-test1" + }, + { + url: SHEET_A, + start: { line: 20, column: 1 }, + selectorText: ".sheetA-test5" + }, + { + url: SHEET_B, + start: { line: 2, column: 1 }, + selectorText: ".sheetB-test1" + }, + { + url: SHEET_B, + start: { line: 18, column: 1 }, + selectorText: ".sheetB-test5" + }, + { + url: SHEET_D, + start: { line: 2, column: 1 }, + selectorText: ".sheetD-test1" + }, + { + url: SHEET_D, + start: { line: 18, column: 1 }, + selectorText: ".sheetD-test5" + }, + { + url: SHEET_C, + start: { line: 2, column: 1 }, + selectorText: ".sheetC-test1" + }, + { + url: SHEET_C, + start: { line: 18, column: 1 }, + selectorText: ".sheetC-test5" + }, + { + url: PAGE_3 + " \u2192 <style> index 0", + start: { line: 5, column: 5 }, + selectorText: ".page3-test1" + }, + ]; + isEqualJson(actualReport.preload[2].rules, expectedPreloadRules2, 'preload rules 2'); +} + +/** + * Check that checkPageReport returns the expected unused JSON + */ +function checkPageReportUnused(actualReport) { + // Check the unused header + isEqualJson(actualReport.unused.length, 8, 'unused length'); + + // Check the unused rules + isEqualJson(actualReport.unused[0].url, PAGE_2 + " \u2192 <style> index 0", "unused url 0"); + let expectedUnusedRules0 = [ + { + url: PAGE_2 + " \u2192 <style> index 0", + start: { line: 9, column: 5 }, + selectorText: ".page2-test2" + } + ]; + isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0'); + + isEqualJson(actualReport.unused[1].url, SHEET_A, "unused url 1"); + let expectedUnusedRules1 = [ + { + url: SHEET_A, + start: { line: 8, column: 1 }, + selectorText: ".sheetA-test2" + } + ]; + isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1'); + + isEqualJson(actualReport.unused[2].url, SHEET_B, "unused url 2"); + let expectedUnusedRules2 = [ + { + url: SHEET_B, + start: { line: 6, column: 1 }, + selectorText: ".sheetB-test2" + } + ]; + isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2'); + + isEqualJson(actualReport.unused[3].url, SHEET_D, "unused url 3"); + let expectedUnusedRules3 = [ + { + url: SHEET_D, + start: { line: 6, column: 1 }, + selectorText: ".sheetD-test2" + } + ]; + isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3'); + + isEqualJson(actualReport.unused[4].url, SHEET_C, "unused url 4"); + let expectedUnusedRules4 = [ + { + url: SHEET_C, + start: { line: 6, column: 1 }, + selectorText: ".sheetC-test2" + } + ]; + isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4'); + + isEqualJson(actualReport.unused[5].url, PAGE_1 + " \u2192 <style> index 0", "unused url 5"); + let expectedUnusedRules5 = [ + { + url: PAGE_1 + " \u2192 <style> index 0", + start: { line: 8, column: 5 }, + selectorText: ".page1-test2" + } + ]; + isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5'); + + isEqualJson(actualReport.unused[6].url, PAGE_3 + " \u2192 <style> index 0", "unused url 6"); + let expectedUnusedRules6 = [ + { + url: PAGE_3 + " \u2192 <style> index 0", + start: { line: 9, column: 5 }, + selectorText: ".page3-test2" + } + ]; + isEqualJson(actualReport.unused[6].rules, expectedUnusedRules6, 'unused rules 6'); + + isEqualJson(actualReport.unused[7].url, PAGE_3 + " \u2192 <style> index 1", "unused url 7"); + let expectedUnusedRules7 = [ + { + url: PAGE_3 + " \u2192 <style> index 1", + start: { line: 3, column: 5 }, + selectorText: ".page3-test3" + } + ]; + isEqualJson(actualReport.unused[7].rules, expectedUnusedRules7, 'unused rules 7'); +} + +/** + * We do basic tests on the shortUrl and formattedCssText because they are + * very derivative, and so make for fragile tests, and having done those quick + * existence checks we remove them so the JSON check later can ignore them + */ +function checkRuleProperties(rule, index) { + is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index); + is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index); + delete rule.shortUrl; + + is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index); + ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index); + delete rule.formattedCssText; +} + +/** + * Utility to compare JSON structures + */ +function isEqualJson(o1, o2, msg) { + is(JSON.stringify(o1), JSON.stringify(o2), msg); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js new file mode 100644 index 000000000..6890af7c1 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the addon commands works as they should + +const csscoverage = require("devtools/server/actors/csscoverage"); + +add_task(function*() { + testDeconstructRuleId(); +}); + +function testDeconstructRuleId() { + // This is the easy case + let rule = csscoverage.deconstructRuleId("http://thing/blah|10|20"); + is(rule.url, "http://thing/blah", "1 url"); + is(rule.line, 10, "1 line"); + is(rule.column, 20, "1 column"); + + // This is the harder case with a URL containing a '|' + rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22"); + is(rule.url, "http://thing/blah?q=a|b", "2 url"); + is(rule.line, 11, "2 line"); + is(rule.column, 22, "2 column"); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_folder.js b/toolkit/devtools/commandline/test/browser_cmd_folder.js new file mode 100644 index 000000000..9ceb38135 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_folder.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the folder commands works as they should + +const TEST_URI = "data:text/html;charset=utf-8,cmd-folder"; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function(options) { + return helpers.audit(options, [ + { + setup: 'folder', + check: { + input: 'folder', + hints: ' open', + markup: 'IIIIII', + status: 'ERROR' + }, + }, + { + setup: 'folder open', + check: { + input: 'folder open', + hints: ' [path]', + markup: 'VVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'folder open ~', + check: { + input: 'folder open ~', + hints: '', + markup: 'VVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'folder openprofile', + check: { + input: 'folder openprofile', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'folder openprofile WRONG', + check: { + input: 'folder openprofile WRONG', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVEEEEE', + status: 'ERROR' + } + } + ]); + }).then(finish, helpers.handleError); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js b/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js new file mode 100644 index 000000000..a29fd8181 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js @@ -0,0 +1,257 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests the various highlight command parameters and options + +// Creating a test page with many elements to test the --showall option +let TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>"; +for (let i = 0; i < 200; i ++) { + TEST_PAGE += "<li class='item'>" + i + "</li>"; +} +TEST_PAGE += "</ul></body>"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function* spawnTest() { + let options = yield helpers.openTab(TEST_PAGE); + yield helpers.openToolbar(options); + + yield helpers.audit(options, [ + { + setup: 'highlight', + check: { + input: 'highlight', + hints: ' [selector] [options]', + markup: 'VVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '0 nodes highlighted' + } + }, + { + setup: 'highlight bo', + check: { + input: 'highlight bo', + hints: ' [options]', + markup: 'VVVVVVVVVVII', + status: 'ERROR' + }, + exec: { + output: 'Error: No matches' + } + }, + { + setup: 'highlight body', + check: { + input: 'highlight body', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight body --hide', + check: { + input: 'highlight body --hide', + hints: 'guides [options]', + markup: 'VVVVVVVVVVVVVVVIIIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --hideguides', + check: { + input: 'highlight body --hideguides', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight body --show', + check: { + input: 'highlight body --show', + hints: 'infobar [options]', + markup: 'VVVVVVVVVVVVVVVIIIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --showinfobar', + check: { + input: 'highlight body --showinfobar', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight body --showa', + check: { + input: 'highlight body --showa', + hints: 'll [options]', + markup: 'VVVVVVVVVVVVVVVIIIIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --showall', + check: { + input: 'highlight body --showall', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight body --r', + check: { + input: 'highlight body --r', + hints: 'egion [options]', + markup: 'VVVVVVVVVVVVVVVIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --region', + check: { + input: 'highlight body --region', + hints: ' <selection> [options]', + markup: 'VVVVVVVVVVVVVVVIIIIIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Value required for \'region\'.' + } + }, + { + setup: 'highlight body --fi', + check: { + input: 'highlight body --fi', + hints: 'll [options]', + markup: 'VVVVVVVVVVVVVVVIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --fill', + check: { + input: 'highlight body --fill', + hints: ' <string> [options]', + markup: 'VVVVVVVVVVVVVVVIIIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Value required for \'fill\'.' + } + }, + { + setup: 'highlight body --ke', + check: { + input: 'highlight body --ke', + hints: 'ep [options]', + markup: 'VVVVVVVVVVVVVVVIIII', + status: 'ERROR' + }, + exec: { + output: 'Error: Too many arguments' + } + }, + { + setup: 'highlight body --keep', + check: { + input: 'highlight body --keep', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight body --hideguides --showinfobar --showall --region ' + + 'content --fill red --keep', + check: { + input: 'highlight body --hideguides --showinfobar --showall --region ' + + 'content --fill red --keep', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV' + + 'VVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '1 node highlighted' + } + }, + { + setup: 'highlight .item', + check: { + input: 'highlight .item', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '200 nodes matched, but only 100 nodes highlighted. Use ' + + '\'--showall\' to show all' + } + }, + { + setup: 'highlight .item --showall', + check: { + input: 'highlight .item --showall', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + exec: { + output: '200 nodes highlighted' + } + }, + { + setup: 'unhighlight', + check: { + input: 'unhighlight', + hints: '', + markup: 'VVVVVVVVVVV', + status: 'VALID' + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js b/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js new file mode 100644 index 000000000..8670c1282 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js @@ -0,0 +1,44 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the highlight command actually creates a highlighter + +const TEST_PAGE = "data:text/html;charset=utf-8,<div></div>"; + +function test() { + return Task.spawn(function*() { + let options = yield helpers.openTab(TEST_PAGE); + yield helpers.openToolbar(options); + + info("highlighting the body node"); + yield runCommand("highlight body", options); + is(getHighlighterNumber(), 1, "The highlighter element exists for body"); + + info("highlighting the div node"); + yield runCommand("highlight div", options); + is(getHighlighterNumber(), 1, "The highlighter element exists for div"); + + info("highlighting the body node again, asking to keep the div"); + yield runCommand("highlight body --keep", options); + is(getHighlighterNumber(), 2, "2 highlighter elements have been created"); + + info("unhighlighting all nodes"); + yield runCommand("unhighlight", options); + is(getHighlighterNumber(), 0, "All highlighters have been removed"); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +function getHighlighterNumber() { + // Note that this only works as long as gcli tests aren't run with e10s on. + // To make this e10s ready, execute this in a content frame script instead. + return require("gcli/commands/highlight").highlighters.length; +} + +function* runCommand(cmd, options) { + yield helpers.audit(options, [{ setup: cmd, exec: {} }]); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_inject.html b/toolkit/devtools/commandline/test/browser_cmd_inject.html new file mode 100644 index 000000000..ea84be393 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_inject.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <head> + <body> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_inject.js b/toolkit/devtools/commandline/test/browser_cmd_inject.js new file mode 100644 index 000000000..588487b2e --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_inject.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the inject commands works as they should + +const TEST_URI = 'http://example.com/browser/browser/devtools/commandline/'+ + 'test/browser_cmd_inject.html'; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function(options) { + return helpers.audit(options, [ + { + setup: 'inject', + check: { + input: 'inject', + markup: 'VVVVVV', + hints: ' <library>', + status: 'ERROR' + }, + }, + { + setup: 'inject j', + check: { + input: 'inject j', + markup: 'VVVVVVVI', + hints: 'Query', + status: 'ERROR' + }, + }, + { + setup: 'inject notauri', + check: { + input: 'inject notauri', + hints: ' -> http://notauri/', + markup: 'VVVVVVVIIIIIII', + status: 'ERROR', + args: { + library: { + value: undefined, + status: 'INCOMPLETE' + } + } + } + }, + { + setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js', + check: { + input: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + hints: '', + status: 'VALID', + args: { + library: { + value: function(library) { + is(library.type, 'url', 'inject type name'); + is(library.url.origin, 'http://example.com', 'inject url hostname'); + ok(library.url.path.indexOf('_inject.js') != -1, 'inject url path'); + }, + status: 'VALID' + } + } + }, + exec: { + output: [ /http:\/\/example.com\/browser\/browser\/devtools\/commandline\/test\/browser_cmd_inject.js loaded/ ] + } + } + ]); + }).then(finish, helpers.handleError); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_jsb.js b/toolkit/devtools/commandline/test/browser_cmd_jsb.js new file mode 100644 index 000000000..cf2a9da13 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_jsb.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the jsb command works as it should + +const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" + + "test/browser_cmd_jsb_script.jsi"; + +function test() { + return Task.spawn(testTask).then(finish, helpers.handleError); +} + +function testTask() { + let options = yield helpers.openTab("about:blank"); + yield helpers.openToolbar(options); + + let notifyPromise = wwNotifyOnce(); + + helpers.audit(options, [ + { + setup: 'jsb', + check: { + input: 'jsb', + hints: ' <url> [options]', + markup: 'VVV', + status: 'ERROR' + } + }, + { + setup: 'jsb ' + TEST_URI, + // Should result in a new scratchpad window + exec: { } + } + ]); + + let { subject } = yield notifyPromise; + let scratchpadWin = subject.QueryInterface(Ci.nsIDOMWindow); + yield helpers.listenOnce(scratchpadWin, "load"); + + let scratchpad = scratchpadWin.Scratchpad; + + yield observeOnce(scratchpad); + + let result = scratchpad.getText(); + result = result.replace(/[\r\n]]*/g, "\n"); + let correct = "function somefunc() {\n" + + " if (true) // Some comment\n" + + " doSomething();\n" + + " for (let n = 0; n < 500; n++) {\n" + + " if (n % 2 == 1) {\n" + + " console.log(n);\n" + + " console.log(n + 1);\n" + + " }\n" + + " }\n" + + "}"; + is(result, correct, "JS has been correctly prettified"); + + if (scratchpadWin) { + scratchpadWin.close(); + scratchpadWin = null; + } + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} + +/** + * A wrapper for calling Services.ww.[un]registerNotification using promises. + * @return a promise that resolves when the notification service first notifies + * with topic == "domwindowopened". + * The value of the promise is { subject: subject, topic: topic, data: data } + */ +function wwNotifyOnce() { + return new Promise(resolve => { + let onNotify = (subject, topic, data) => { + if (topic == "domwindowopened") { + Services.ww.unregisterNotification(onNotify); + resolve({ subject: subject, topic: topic, data: data }); + } + }; + + Services.ww.registerNotification(onNotify); + }); +} + +/** + * YET ANOTHER WRAPPER for a place where we are using events as poor-man's + * promises. Perhaps this should be promoted to scratchpad? + */ +function observeOnce(scratchpad) { + return new Promise(resolve => { + let observer = { + onReady: function() { + scratchpad.removeObserver(observer); + resolve(); + }, + }; + scratchpad.addObserver(observer); + }); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi b/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi new file mode 100644 index 000000000..dcaac807c --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi @@ -0,0 +1,2 @@ +function somefunc(){if (true) // Some comment +doSomething();for(let n=0;n<500;n++){if(n%2==1){console.log(n);console.log(n+1);}}} diff --git a/toolkit/devtools/commandline/test/browser_cmd_media.html b/toolkit/devtools/commandline/test/browser_cmd_media.html new file mode 100644 index 000000000..9bc1e7aeb --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_media.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> + <head> + <meta charset="utf-8"> + <title>GCLI Test for Bug 819930</title> + <style> + @media braille { + body { + background-color: yellow; + } + } + + @media embossed { + body { + background-color: indigo; + } + } + + @media screen { + body { + background-color: white; + } + } + </style> + </head> + <body> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_media.js b/toolkit/devtools/commandline/test/browser_cmd_media.js new file mode 100644 index 000000000..41973c3f8 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_media.js @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that screenshot command works properly +const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" + + "test/browser_cmd_media.html"; +let tests = { + testInput: function(options) { + return helpers.audit(options, [ + { + setup: "media emulate braille", + check: { + input: "media emulate braille", + markup: "VVVVVVVVVVVVVVVVVVVVV", + status: "VALID", + args: { + type: { value: "braille"}, + } + }, + }, + { + setup: "media reset", + check: { + input: "media reset", + markup: "VVVVVVVVVVV", + status: "VALID", + args: { + } + }, + }, + ]); + }, + + testEmulateMedia: function(options) { + return helpers.audit(options, [ + { + setup: "media emulate braille", + check: { + args: { + type: { value: "braille"} + } + }, + exec: { + output: "" + }, + post: function() { + let body = options.window.document.body; + let style = options.window.getComputedStyle(body); + is(style.backgroundColor, "rgb(255, 255, 0)", "media correctly emulated"); + } + } + ]); + }, + + testEndMediaEmulation: function(options) { + return helpers.audit(options, [ + { + setup: function() { + let mDV = options.browser.markupDocumentViewer; + mDV.emulateMedium("embossed"); + return helpers.setInput(options, "media reset"); + }, + exec: { + output: "" + }, + post: function() { + let body = options.window.document.body; + let style = options.window.getComputedStyle(body); + is(style.backgroundColor, "rgb(255, 255, 255)", "media reset"); + } + } + ]); + } +}; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + yield helpers.runTests(options, tests); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html new file mode 100644 index 000000000..a7d28828c --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html @@ -0,0 +1,25 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>GCLI inspect command test</title> +</head> +<body> + + <!-- This is a list of 0 h1 elements --> + + <!-- This is a list of 1 div elements --> + <div>Hello, I'm a div</div> + + <!-- This is a list of 2 span elements --> + <span>Hello, I'm a span</span> + <span>And me</span> + + <!-- This is a collection of various things that match only once --> + <p class="someclass">.someclass</p> + <p id="someid">#someid</p> + <button disabled>button[disabled]</button> + <p><strong>p>strong</strong></p> + +</body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js new file mode 100644 index 000000000..c405a29c7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js @@ -0,0 +1,390 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the inspect command works as it should + +const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+ + "test/browser_cmd_pagemod_export.html"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + const documentElement = options.document.documentElement; + const initialHtml = documentElement.innerHTML; + function resetContent() { + options.document.documentElement.innerHTML = initialHtml; + } + + // Test exporting HTML + let oldOpen = options.window.open; + let openURL = ""; + options.window.open = function(url) { + // The URL is a data: URL that contains the document source + openURL = decodeURIComponent(url); + }; + + yield helpers.audit(options, [ + { + setup: 'export html', + skipIf: true, + check: { + input: 'export html', + hints: ' [destination]', + markup: 'VVVVVVVVVVV', + status: 'VALID', + }, + exec: { + output: '' + }, + post: function() { + isnot(openURL.indexOf('<html lang="en">'), -1, "export html works: <html>"); + isnot(openURL.indexOf("<title>GCLI"), -1, "export html works: <title>"); + isnot(openURL.indexOf('<p id="someid">#'), -1, "export html works: <p>"); + } + }, + { + setup: 'export html stdout', + check: { + input: 'export html stdout', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + destination: { value: "stdout" } + }, + }, + exec: { + output: [ + /<html lang="en">/, + /<title>GCLI/, + /<p id="someid">#/ + ] + } + } + ]); + + options.window.open = oldOpen; + oldOpen = undefined; + + // Test 'pagemod replace' + yield helpers.audit(options, [ + { + setup: 'pagemod replace', + check: { + input: 'pagemod replace', + hints: ' <search> <replace> [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]', + markup: 'VVVVVVVVVVVVVVV', + status: 'ERROR' + } + }, + { + setup: 'pagemod replace some foo', + check: { + input: 'pagemod replace some foo', + hints: ' [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'pagemod replace some foo true', + check: { + input: 'pagemod replace some foo true', + hints: ' [selector] [root] [attrOnly] [contentOnly] [attributes]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'pagemod replace some foo true --attrOnly', + check: { + input: 'pagemod replace some foo true --attrOnly', + hints: ' [selector] [root] [contentOnly] [attributes]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + } + }, + { + setup: 'pagemod replace sOme foOBar', + exec: { + output: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "no change in the page"); + } + }, + { + setup: 'pagemod replace sOme foOBar true', + exec: { + output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + isnot(html.indexOf('<p class="foOBarclass">.foOBarclass'), -1, + ".someclass changed to .foOBarclass"); + isnot(html.indexOf('<p id="foOBarid">#foOBarid'), -1, + "#someid changed to #foOBarid"); + + resetContent(); + } + }, + { + setup: 'pagemod replace some foobar --contentOnly', + exec: { + output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + isnot(html.indexOf('<p class="someclass">.foobarclass'), -1, + ".someclass changed to .foobarclass (content only)"); + isnot(html.indexOf('<p id="someid">#foobarid'), -1, + "#someid changed to #foobarid (content only)"); + + resetContent(); + } + }, + { + setup: 'pagemod replace some foobar --attrOnly', + exec: { + output: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + isnot(html.indexOf('<p class="foobarclass">.someclass'), -1, + ".someclass changed to .foobarclass (attr only)"); + isnot(html.indexOf('<p id="foobarid">#someid'), -1, + "#someid changed to #foobarid (attr only)"); + + resetContent(); + } + }, + { + setup: 'pagemod replace some foobar --root head', + exec: { + output: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed"); + } + }, + { + setup: 'pagemod replace some foobar --selector .someclass,div,span', + exec: { + output: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + isnot(html.indexOf('<p class="foobarclass">.foobarclass'), -1, + ".someclass changed to .foobarclass"); + isnot(html.indexOf('<p id="someid">#someid'), -1, + "#someid did not change"); + + resetContent(); + } + }, + ]); + + // Test 'pagemod remove element' + yield helpers.audit(options, [ + { + setup: 'pagemod remove', + check: { + input: 'pagemod remove', + hints: ' attribute', + markup: 'IIIIIIIVIIIIII', + status: 'ERROR' + }, + }, + { + setup: 'pagemod remove element', + check: { + input: 'pagemod remove element', + hints: ' <search> [root] [stripOnly] [ifEmptyOnly]', + markup: 'VVVVVVVVVVVVVVVVVVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'pagemod remove element foo', + check: { + input: 'pagemod remove element foo', + hints: ' [root] [stripOnly] [ifEmptyOnly]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + }, + { + setup: 'pagemod remove element p', + exec: { + output: /^[^:]+: 3\. [^:]+: 3\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + is(html.indexOf('<p class="someclass">'), -1, "p.someclass removed"); + is(html.indexOf('<p id="someid">'), -1, "p#someid removed"); + is(html.indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed"); + isnot(html.indexOf("<span>"), -1, "<span> not removed"); + + resetContent(); + } + }, + { + setup: 'pagemod remove element p head', + exec: { + output: /^[^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed in the page"); + } + }, + { + setup: 'pagemod remove element p --ifEmptyOnly', + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed in the page"); + } + }, + { + setup: 'pagemod remove element meta,title --ifEmptyOnly', + exec: { + output: /^[^:]+: 2\. [^:]+: 1\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + is(html.indexOf("<meta charset="), -1, "<meta> removed"); + isnot(html.indexOf("<title>"), -1, "<title> not removed"); + + resetContent(); + } + }, + { + setup: 'pagemod remove element p --stripOnly', + exec: { + output: /^[^:]+: 3\. [^:]+: 3\.\s*$/ + }, + post: function() { + let html = documentElement.innerHTML; + + is(html.indexOf('<p class="someclass">'), -1, "p.someclass removed"); + is(html.indexOf('<p id="someid">'), -1, "p#someid removed"); + is(html.indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed"); + isnot(html.indexOf(".someclass"), -1, ".someclass still exists"); + isnot(html.indexOf("#someid"), -1, "#someid still exists"); + isnot(html.indexOf("<strong>p"), -1, "<strong> still exists"); + + resetContent(); + } + }, + ]); + + // Test 'pagemod remove attribute' + yield helpers.audit(options, [ + { + setup: 'pagemod remove attribute', + check: { + input: 'pagemod remove attribute', + hints: ' <searchAttributes> <searchElements> [root] [ignoreCase]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + status: 'ERROR', + args: { + searchAttributes: { value: undefined, status: 'INCOMPLETE' }, + searchElements: { value: undefined, status: 'INCOMPLETE' }, + root: { value: undefined }, + ignoreCase: { value: false }, + } + }, + }, + { + setup: 'pagemod remove attribute foo bar', + check: { + input: 'pagemod remove attribute foo bar', + hints: ' [root] [ignoreCase]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + searchAttributes: { value: 'foo' }, + searchElements: { value: 'bar' }, + root: { value: undefined }, + ignoreCase: { value: false }, + } + }, + post: function() { + return new Promise(resolve => { + executeSoon(resolve); + }); + } + }, + { + setup: 'pagemod remove attribute foo bar', + exec: { + output: /^[^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed in the page"); + } + }, + { + setup: 'pagemod remove attribute foo p', + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed in the page"); + } + }, + { + setup: 'pagemod remove attribute id p,span', + exec: { + output: /^[^:]+: 5\. [^:]+: 1\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML.indexOf('<p id="someid">#someid'), -1, + "p#someid attribute removed"); + isnot(documentElement.innerHTML.indexOf("<p>#someid"), -1, + "p with someid content still exists"); + + resetContent(); + } + }, + { + setup: 'pagemod remove attribute Class p', + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML, initialHtml, "nothing changed in the page"); + } + }, + { + setup: 'pagemod remove attribute Class p --ignoreCase', + exec: { + output: /^[^:]+: 3\. [^:]+: 1\.\s*$/ + }, + post: function() { + is(documentElement.innerHTML.indexOf('<p class="someclass">.someclass'), -1, + "p.someclass attribute removed"); + isnot(documentElement.innerHTML.indexOf("<p>.someclass"), -1, + "p with someclass content still exists"); + + resetContent(); + } + }, + ]); + + // Shutdown + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref1.js b/toolkit/devtools/commandline/test/browser_cmd_pref1.js new file mode 100644 index 000000000..4e2aa41e5 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_pref1.js @@ -0,0 +1,154 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the pref commands work + +let prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +const TEST_URI = "data:text/html;charset=utf-8,gcli-pref1"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + let tiltEnabledOrig = prefBranch.getBoolPref("devtools.tilt.enabled"); + info("originally: devtools.tilt.enabled = " + tiltEnabledOrig); + + yield helpers.audit(options, [ + { + setup: 'pref', + check: { + input: 'pref', + hints: ' reset', + markup: 'IIII', + status: 'ERROR' + }, + }, + { + setup: 'pref s', + check: { + input: 'pref s', + hints: 'et', + markup: 'IIIIVI', + status: 'ERROR' + }, + }, + { + setup: 'pref sh', + check: { + input: 'pref sh', + hints: 'ow', + markup: 'IIIIVII', + status: 'ERROR' + }, + }, + { + setup: 'pref show ', + check: { + input: 'pref show ', + markup: 'VVVVVVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'pref show usetexttospeech', + check: { + input: 'pref show usetexttospeech', + hints: ' -> accessibility.usetexttospeech', + markup: 'VVVVVVVVVVIIIIIIIIIIIIIII', + status: 'ERROR' + }, + }, + { + setup: 'pref show devtools.til', + check: { + input: 'pref show devtools.til', + hints: 't.enabled', + markup: 'VVVVVVVVVVIIIIIIIIIIII', + status: 'ERROR', + tooltipState: 'true:importantFieldFlag', + args: { + setting: { value: undefined, status: 'INCOMPLETE' }, + } + }, + }, + { + setup: 'pref reset devtools.tilt.enabled', + check: { + input: 'pref reset devtools.tilt.enabled', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID' + }, + }, + { + setup: 'pref show devtools.tilt.enabled 4', + check: { + input: 'pref show devtools.tilt.enabled 4', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE', + status: 'ERROR' + }, + }, + { + setup: 'pref set devtools.tilt.enabled 4', + check: { + input: 'pref set devtools.tilt.enabled 4', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE', + status: 'ERROR', + args: { + setting: { arg: ' devtools.tilt.enabled' }, + value: { status: 'ERROR', message: 'Can\'t use \'4\'.' }, + } + }, + }, + { + setup: 'pref set devtools.editor.tabsize 4', + check: { + input: 'pref set devtools.editor.tabsize 4', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + setting: { arg: ' devtools.editor.tabsize' }, + value: { value: 4 }, + } + }, + }, + { + setup: 'pref list', + check: { + input: 'pref list', + hints: ' -> pref set', + markup: 'IIIIVIIII', + status: 'ERROR' + }, + }, + { + setup: 'pref show devtools.tilt.enabled', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.tilt.enabled") + } + }, + }, + exec: { + output: "devtools.tilt.enabled: " + tiltEnabledOrig, + }, + post: function() { + prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig); + } + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref2.js b/toolkit/devtools/commandline/test/browser_cmd_pref2.js new file mode 100644 index 000000000..74ed916a3 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_pref2.js @@ -0,0 +1,105 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the pref commands work + +let prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +const TEST_URI = "data:text/html;charset=utf-8,gcli-pref2"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + let tabSizeOrig = prefBranch.getIntPref("devtools.editor.tabsize"); + info("originally: devtools.editor.tabsize = " + tabSizeOrig); + + yield helpers.audit(options, [ + { + setup: 'pref show devtools.editor.tabsize', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.editor.tabsize") + } + }, + }, + exec: { + output: "devtools.editor.tabsize: " + tabSizeOrig, + }, + }, + { + setup: 'pref set devtools.editor.tabsize 20', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.editor.tabsize") + }, + value: { value: 20 } + }, + }, + exec: { + output: '', + }, + post: function() { + is(prefBranch.getIntPref("devtools.editor.tabsize"), 20, + "devtools.editor.tabsize is 20"); + } + }, + { + setup: 'pref show devtools.editor.tabsize', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.editor.tabsize") + } + }, + }, + exec: { + output: "devtools.editor.tabsize: 20", + } + }, + { + setup: 'pref set devtools.editor.tabsize 1', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.editor.tabsize") + }, + value: { value: 1 } + }, + }, + exec: { + output: '', + }, + }, + { + setup: 'pref show devtools.editor.tabsize', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.editor.tabsize") + } + }, + }, + exec: { + output: "devtools.editor.tabsize: 1", + }, + post: function() { + is(prefBranch.getIntPref("devtools.editor.tabsize"), 1, + "devtools.editor.tabsize is 1"); + } + }, + ]); + + prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref3.js b/toolkit/devtools/commandline/test/browser_cmd_pref3.js new file mode 100644 index 000000000..fea31d948 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_pref3.js @@ -0,0 +1,113 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the pref commands work + +let prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +let supportsString = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + +const TEST_URI = "data:text/html;charset=utf-8,gcli-pref3"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + let remoteHostOrig = prefBranch.getComplexValue("devtools.debugger.remote-host", + Ci.nsISupportsString).data; + info("originally: devtools.debugger.remote-host = " + remoteHostOrig); + + yield helpers.audit(options, [ + { + setup: 'pref show devtools.debugger.remote-host', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.debugger.remote-host") + } + }, + }, + exec: { + output: new RegExp("^devtools\.debugger\.remote-host: " + remoteHostOrig + "$"), + }, + }, + { + setup: 'pref set devtools.debugger.remote-host e.com', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.debugger.remote-host") + }, + value: { value: "e.com" } + }, + }, + exec: { + output: '', + }, + }, + { + setup: 'pref show devtools.debugger.remote-host', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.debugger.remote-host") + } + }, + }, + exec: { + output: new RegExp("^devtools\.debugger\.remote-host: e.com$"), + }, + post: function() { + var ecom = prefBranch.getComplexValue("devtools.debugger.remote-host", + Ci.nsISupportsString).data; + is(ecom, "e.com", "devtools.debugger.remote-host is e.com"); + } + }, + { + setup: 'pref set devtools.debugger.remote-host moz.foo', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.debugger.remote-host") + }, + value: { value: "moz.foo" } + }, + }, + exec: { + output: '', + }, + }, + { + setup: 'pref show devtools.debugger.remote-host', + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.debugger.remote-host") + } + }, + }, + exec: { + output: new RegExp("^devtools\.debugger\.remote-host: moz.foo$"), + }, + post: function() { + var mozfoo = prefBranch.getComplexValue("devtools.debugger.remote-host", + Ci.nsISupportsString).data; + is(mozfoo, "moz.foo", "devtools.debugger.remote-host is moz.foo"); + } + }, + ]); + + supportsString.data = remoteHostOrig; + prefBranch.setComplexValue("devtools.debugger.remote-host", + Ci.nsISupportsString, supportsString); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_restart.js b/toolkit/devtools/commandline/test/browser_cmd_restart.js new file mode 100644 index 000000000..ad93326cb --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_restart.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that restart command works properly (input wise) + +const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart"; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function(options) { + return helpers.audit(options, [ + { + setup: 'restart', + check: { + input: 'restart', + markup: 'VVVVVVV', + status: 'VALID', + args: { + nocache: { value: false }, + safemode: { value: false }, + } + }, + }, + { + setup: 'restart --nocache', + check: { + input: 'restart --nocache', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + nocache: { value: true }, + safemode: { value: false }, + } + }, + }, + { + setup: 'restart --safemode', + check: { + input: 'restart --safemode', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + nocache: { value: false }, + safemode: { value: true }, + } + }, + }, + { + setup: 'restart --safemode --nocache', + check: { + input: 'restart --safemode --nocache', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + nocache: { value: true }, + safemode: { value: true }, + } + }, + }, + ]); + }).then(finish, helpers.handleError); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_screenshot.html b/toolkit/devtools/commandline/test/browser_cmd_screenshot.html new file mode 100644 index 000000000..8e30016f1 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_screenshot.html @@ -0,0 +1,6 @@ +<html> + <head></head> + <body> + <img id="testImage" ></img> + </body> +</html> diff --git a/toolkit/devtools/commandline/test/browser_cmd_screenshot.js b/toolkit/devtools/commandline/test/browser_cmd_screenshot.js new file mode 100644 index 000000000..437daa99f --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_screenshot.js @@ -0,0 +1,181 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that screenshot command works properly +const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" + + "test/browser_cmd_screenshot.html"; + +let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + waitForExplicitFinish(); + + info("RUN TEST: non-private window"); + let normWin = yield addWindow({ private: false }); + yield addTabWithToolbarRunTests(normWin); + normWin.close(); + + info("RUN TEST: private window"); + let pbWin = yield addWindow({ private: true }); + yield addTabWithToolbarRunTests(pbWin); + pbWin.close(); +} + +function addTabWithToolbarRunTests(win) { + let options = yield helpers.openTab(TEST_URI, { chromeWindow: win }); + yield helpers.openToolbar(options); + + // Test input status + yield helpers.audit(options, [ + { + setup: 'screenshot', + check: { + input: 'screenshot', + markup: 'VVVVVVVVVV', + status: 'VALID', + args: { + } + }, + }, + { + setup: 'screenshot abc.png', + check: { + input: 'screenshot abc.png', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + filename: { value: "abc.png"}, + } + }, + }, + { + setup: 'screenshot --fullpage', + check: { + input: 'screenshot --fullpage', + markup: 'VVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + fullpage: { value: true}, + } + }, + }, + { + setup: 'screenshot abc --delay 5', + check: { + input: 'screenshot abc --delay 5', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + filename: { value: "abc"}, + delay: { value: 5 }, + } + }, + }, + { + setup: 'screenshot --selector img#testImage', + check: { + input: 'screenshot --selector img#testImage', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + selector: { + value: options.window.document.getElementById("testImage") + }, + } + }, + }, + ]); + + // Test capture to file + let file = FileUtils.getFile("TmpD", [ "TestScreenshotFile.png" ]); + + yield helpers.audit(options, [ + { + setup: 'screenshot ' + file.path, + check: { + args: { + filename: { value: "" + file.path }, + fullpage: { value: false }, + clipboard: { value: false }, + chrome: { value: false }, + }, + }, + exec: { + output: new RegExp("^Saved to "), + }, + post: function() { + // Bug 849168: screenshot command tests fail in try but not locally + // ok(file.exists(), "Screenshot file exists"); + + if (file.exists()) { + file.remove(false); + } + } + }, + ]); + + // Test capture to clipboard + let clipid = Ci.nsIClipboard; + let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid); + let trans = Cc["@mozilla.org/widget/transferable;1"] + .createInstance(Ci.nsITransferable); + trans.init(null); + trans.addDataFlavor("image/png"); + + yield helpers.audit(options, [ + { + setup: 'screenshot --fullpage --clipboard', + check: { + args: { + fullpage: { value: true }, + clipboard: { value: true }, + chrome: { value: false }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: function() { + try { + clip.getData(trans, clipid.kGlobalClipboard); + let str = new Object(); + let strLength = new Object(); + trans.getTransferData("image/png", str, strLength); + + ok(str.value, "screenshot exists"); + ok(strLength.value > 0, "screenshot has length"); + } + finally { + Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true); + + // Recent PB changes to the test I'm modifying removed the 'pb' + // variable, but left this line in tact. This seems so obviously + // wrong that I'm leaving this in in case the analysis is wrong + // pb.privateBrowsingEnabled = true; + } + } + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} + +function addWindow(windowOptions) { + return new Promise(resolve => { + let win = OpenBrowserWindow(windowOptions); + + // This feels hacky, we should refactor it + whenDelayedStartupFinished(win, () => { + // Would like to get rid of this executeSoon, but without it the url + // (TEST_URI) provided in addTabWithToolbarRunTests hasn't loaded + executeSoon(() => { + resolve(win); + }); + }); + }); +} diff --git a/toolkit/devtools/commandline/test/browser_cmd_settings.js b/toolkit/devtools/commandline/test/browser_cmd_settings.js new file mode 100644 index 000000000..8b4e27225 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_cmd_settings.js @@ -0,0 +1,120 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the pref commands work + +let prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +let supportsString = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + +const TEST_URI = "data:text/html;charset=utf-8,gcli-settings"; + +function test() { + return Task.spawn(spawnTest).then(finish, helpers.handleError); +} + +function spawnTest() { + // Setup + let options = yield helpers.openTab(TEST_URI); + + require("devtools/commandline/commands-index"); + let gcli = require("gcli/index"); + yield gcli.load(); + let settings = gcli.settings; + + let hideIntroEnabled = settings.get("devtools.gcli.hideIntro"); + let tabSize = settings.get("devtools.editor.tabsize"); + let remoteHost = settings.get("devtools.debugger.remote-host"); + + let hideIntroOrig = prefBranch.getBoolPref("devtools.gcli.hideIntro"); + let tabSizeOrig = prefBranch.getIntPref("devtools.editor.tabsize"); + let remoteHostOrig = prefBranch.getComplexValue( + "devtools.debugger.remote-host", + Components.interfaces.nsISupportsString).data; + + info("originally: devtools.gcli.hideIntro = " + hideIntroOrig); + info("originally: devtools.editor.tabsize = " + tabSizeOrig); + info("originally: devtools.debugger.remote-host = " + remoteHostOrig); + + // Actual tests + is(hideIntroEnabled.value, hideIntroOrig, "hideIntroEnabled default"); + is(tabSize.value, tabSizeOrig, "tabSize default"); + is(remoteHost.value, remoteHostOrig, "remoteHost default"); + + hideIntroEnabled.setDefault(); + tabSize.setDefault(); + remoteHost.setDefault(); + + let hideIntroEnabledDefault = hideIntroEnabled.value; + let tabSizeDefault = tabSize.value; + let remoteHostDefault = remoteHost.value; + + hideIntroEnabled.value = false; + tabSize.value = 42; + remoteHost.value = "example.com"; + + is(hideIntroEnabled.value, false, "hideIntroEnabled basic"); + is(tabSize.value, 42, "tabSize basic"); + is(remoteHost.value, "example.com", "remoteHost basic"); + + function hideIntroEnabledCheck(ev) { + is(ev.setting, hideIntroEnabled, "hideIntroEnabled event setting"); + is(ev.value, true, "hideIntroEnabled event value"); + is(ev.setting.value, true, "hideIntroEnabled event setting value"); + } + hideIntroEnabled.onChange.add(hideIntroEnabledCheck); + hideIntroEnabled.value = true; + is(hideIntroEnabled.value, true, "hideIntroEnabled change"); + + function tabSizeCheck(ev) { + is(ev.setting, tabSize, "tabSize event setting"); + is(ev.value, 1, "tabSize event value"); + is(ev.setting.value, 1, "tabSize event setting value"); + } + tabSize.onChange.add(tabSizeCheck); + tabSize.value = 1; + is(tabSize.value, 1, "tabSize change"); + + function remoteHostCheck(ev) { + is(ev.setting, remoteHost, "remoteHost event setting"); + is(ev.value, "y.com", "remoteHost event value"); + is(ev.setting.value, "y.com", "remoteHost event setting value"); + } + remoteHost.onChange.add(remoteHostCheck); + remoteHost.value = "y.com"; + is(remoteHost.value, "y.com", "remoteHost change"); + + hideIntroEnabled.onChange.remove(hideIntroEnabledCheck); + tabSize.onChange.remove(tabSizeCheck); + remoteHost.onChange.remove(remoteHostCheck); + + function remoteHostReCheck(ev) { + is(ev.setting, remoteHost, "remoteHost event reset"); + is(ev.value, null, "remoteHost event revalue"); + is(ev.setting.value, null, "remoteHost event setting revalue"); + } + remoteHost.onChange.add(remoteHostReCheck); + + hideIntroEnabled.setDefault(); + tabSize.setDefault(); + remoteHost.setDefault(); + + remoteHost.onChange.remove(remoteHostReCheck); + + is(hideIntroEnabled.value, hideIntroEnabledDefault, "hideIntroEnabled reset"); + is(tabSize.value, tabSizeDefault, "tabSize reset"); + is(remoteHost.value, remoteHostDefault, "remoteHost reset"); + + // Cleanup + prefBranch.setBoolPref("devtools.gcli.hideIntro", hideIntroOrig); + prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig); + supportsString.data = remoteHostOrig; + prefBranch.setComplexValue("devtools.debugger.remote-host", + Components.interfaces.nsISupportsString, + supportsString); + + yield helpers.closeTab(options); +} diff --git a/toolkit/devtools/commandline/test/browser_gcli_async.js b/toolkit/devtools/commandline/test/browser_gcli_async.js new file mode 100644 index 000000000..590bb2cc8 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_async.js @@ -0,0 +1,128 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testAsync.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + setup: 'tsslo', + check: { + input: 'tsslo', + hints: 'w', + markup: 'IIIII', + cursor: 5, + current: '__command', + status: 'ERROR', + predictions: ['tsslow'], + unassigned: [ ] + } + }, + { + setup: 'tsslo<TAB>', + check: { + input: 'tsslow ', + hints: 'Shalom', + markup: 'VVVVVVV', + cursor: 7, + current: 'hello', + status: 'ERROR', + predictions: [ + 'Shalom', 'Namasté', 'Hallo', 'Dydd-da', 'Chào', 'Hej', + 'Saluton', 'Sawubona' + ], + unassigned: [ ], + args: { + command: { name: 'tsslow' }, + hello: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + }, + } + } + }, + { + setup: 'tsslow S', + check: { + input: 'tsslow S', + hints: 'halom', + markup: 'VVVVVVVI', + cursor: 8, + current: 'hello', + status: 'ERROR', + predictions: [ 'Shalom', 'Saluton', 'Sawubona', 'Namasté' ], + unassigned: [ ], + args: { + command: { name: 'tsslow' }, + hello: { + value: undefined, + arg: ' S', + status: 'INCOMPLETE' + }, + } + } + }, + { + setup: 'tsslow S<TAB>', + check: { + input: 'tsslow Shalom ', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'hello', + status: 'VALID', + predictions: [ 'Shalom' ], + unassigned: [ ], + args: { + command: { name: 'tsslow' }, + hello: { + value: 'Shalom', + arg: ' Shalom ', + status: 'VALID', + message: '' + }, + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_canon.js b/toolkit/devtools/commandline/test/browser_gcli_canon.js new file mode 100644 index 000000000..613e5b2d4 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_canon.js @@ -0,0 +1,280 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCanon.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var Commands = require('gcli/commands/commands').Commands; + +var startCount; +var events; + +var commandsChange = function(ev) { + events++; +}; + +exports.setup = function(options) { + startCount = options.requisition.system.commands.getAll().length; + events = 0; +}; + +exports.shutdown = function(options) { + startCount = undefined; + events = undefined; +}; + +exports.testAddRemove1 = function(options) { + var commands = options.requisition.system.commands; + + return helpers.audit(options, [ + { + name: 'testadd add', + setup: function() { + commands.onCommandsChange.add(commandsChange); + + commands.add({ + name: 'testadd', + exec: function() { + return 1; + } + }); + + assert.is(commands.getAll().length, + startCount + 1, + 'add command success'); + assert.is(events, 1, 'add event'); + + return helpers.setInput(options, 'testadd'); + }, + check: { + input: 'testadd', + hints: '', + markup: 'VVVVVVV', + cursor: 7, + current: '__command', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { } + }, + exec: { + output: /^1$/ + } + }, + { + name: 'testadd alter', + setup: function() { + commands.add({ + name: 'testadd', + exec: function() { + return 2; + } + }); + + assert.is(commands.getAll().length, + startCount + 1, + 'read command success'); + assert.is(events, 2, 'read event'); + + return helpers.setInput(options, 'testadd'); + }, + check: { + input: 'testadd', + hints: '', + markup: 'VVVVVVV', + }, + exec: { + output: '2' + } + }, + { + name: 'testadd remove', + setup: function() { + commands.remove('testadd'); + + assert.is(commands.getAll().length, + startCount, + 'remove command success'); + assert.is(events, 3, 'remove event'); + + return helpers.setInput(options, 'testadd'); + }, + check: { + typed: 'testadd', + cursor: 7, + current: '__command', + status: 'ERROR', + unassigned: [ ], + } + } + ]); +}; + +exports.testAddRemove2 = function(options) { + var commands = options.requisition.system.commands; + + commands.add({ + name: 'testadd', + exec: function() { + return 3; + } + }); + + assert.is(commands.getAll().length, + startCount + 1, + 'rereadd command success'); + assert.is(events, 4, 'rereadd event'); + + return helpers.audit(options, [ + { + setup: 'testadd', + exec: { + output: /^3$/ + }, + post: function() { + commands.remove({ + name: 'testadd' + }); + + assert.is(commands.getAll().length, + startCount, + 'reremove command success'); + assert.is(events, 5, 'reremove event'); + } + }, + { + setup: 'testadd', + check: { + typed: 'testadd', + status: 'ERROR' + } + } + ]); +}; + +exports.testAddRemove3 = function(options) { + var commands = options.requisition.system.commands; + + commands.remove({ name: 'nonexistant' }); + assert.is(commands.getAll().length, + startCount, + 'nonexistant1 command success'); + assert.is(events, 5, 'nonexistant1 event'); + + commands.remove('nonexistant'); + assert.is(commands.getAll().length, + startCount, + 'nonexistant2 command success'); + assert.is(events, 5, 'nonexistant2 event'); + + commands.onCommandsChange.remove(commandsChange); +}; + +exports.testAltCommands = function(options) { + var commands = options.requisition.system.commands; + var altCommands = new Commands(options.requisition.system.types); + + var tss = { + name: 'tss', + params: [ + { name: 'str', type: 'string' }, + { name: 'num', type: 'number' }, + { name: 'opt', type: { name: 'selection', data: [ '1', '2', '3' ] } }, + ], + exec: function(args, context) { + return context.commandName + ':' + + args.str + ':' + args.num + ':' + args.opt; + } + }; + altCommands.add(tss); + + var commandSpecs = altCommands.getCommandSpecs(); + assert.is(JSON.stringify(commandSpecs), + '[{"item":"command","name":"tss","params":[' + + '{"name":"str","type":"string"},' + + '{"name":"num","type":"number"},' + + '{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}' + + '],"isParent":false}]', + 'JSON.stringify(commandSpecs)'); + + var remoter = function(args, context) { + assert.is(context.commandName, 'tss', 'commandName is tss'); + + var cmd = altCommands.get(context.commandName); + return cmd.exec(args, context); + }; + + commands.addProxyCommands(commandSpecs, remoter, 'proxy', 'test'); + + var parent = commands.get('proxy'); + assert.is(parent.name, 'proxy', 'Parent command called proxy'); + + var child = commands.get('proxy tss'); + assert.is(child.name, 'proxy tss', 'child command called proxy tss'); + + return helpers.audit(options, [ + { + setup: 'proxy tss foo 6 3', + check: { + input: 'proxy tss foo 6 3', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + status: 'VALID', + args: { + str: { value: 'foo', status: 'VALID' }, + num: { value: 6, status: 'VALID' }, + opt: { value: '3', status: 'VALID' } + } + }, + exec: { + output: 'tss:foo:6:3' + }, + post: function() { + commands.remove('proxy'); + commands.remove('proxy tss'); + + assert.is(commands.get('proxy'), undefined, 'remove proxy'); + assert.is(commands.get('proxy tss'), undefined, 'remove proxy tss'); + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_cli1.js b/toolkit/devtools/commandline/test/browser_gcli_cli1.js new file mode 100644 index 000000000..cb4d52e7a --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_cli1.js @@ -0,0 +1,544 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCli1.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testBlank = function(options) { + return helpers.audit(options, [ + { + setup: '', + check: { + input: '', + hints: '', + markup: '', + cursor: 0, + current: '__command', + status: 'ERROR' + }, + post: function() { + assert.is(options.requisition.commandAssignment.value, undefined); + } + }, + { + setup: ' ', + check: { + input: ' ', + hints: '', + markup: 'V', + cursor: 1, + current: '__command', + status: 'ERROR' + }, + post: function() { + assert.is(options.requisition.commandAssignment.value, undefined); + } + }, + { + name: '| ', + setup: function() { + return helpers.setInput(options, ' ', 0); + }, + check: { + input: ' ', + hints: '', + markup: 'V', + cursor: 0, + current: '__command', + status: 'ERROR' + }, + post: function() { + assert.is(options.requisition.commandAssignment.value, undefined); + } + } + ]); +}; + +exports.testDelete = function(options) { + return helpers.audit(options, [ + { + setup: 'x<BACKSPACE>', + check: { + input: '', + hints: '', + markup: '', + cursor: 0, + current: '__command', + status: 'ERROR' + }, + post: function() { + assert.is(options.requisition.commandAssignment.value, undefined); + } + } + ]); +}; + +exports.testIncompleteMultiMatch = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn ex', + check: { + input: 'tsn ex', + hints: 't', + markup: 'IIIVII', + cursor: 6, + current: '__command', + status: 'ERROR', + predictionsContains: [ + 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' + ] + } + } + ]); +}; + +exports.testIncompleteSingleMatch = function(options) { + return helpers.audit(options, [ + { + setup: 'tselar', + check: { + input: 'tselar', + hints: 'r', + markup: 'IIIIII', + cursor: 6, + current: '__command', + status: 'ERROR', + predictions: [ 'tselarr' ], + unassigned: [ ] + } + } + ]); +}; + +exports.testTsv = function(options) { + return helpers.audit(options, [ + { + setup: 'tsv', + check: { + input: 'tsv', + hints: ' <optionType> <optionValue>', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { arg: '', status: 'INCOMPLETE' }, + optionValue: { arg: '', status: 'INCOMPLETE' } + } + } + }, + { + setup: 'tsv ', + check: { + input: 'tsv ', + hints: 'option1 <optionValue>', + markup: 'VVVV', + cursor: 4, + current: 'optionType', + status: 'ERROR', + predictions: [ 'option1', 'option2', 'option3' ], + unassigned: [ ], + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tsv' }, + optionType: { arg: '', status: 'INCOMPLETE' }, + optionValue: { arg: '', status: 'INCOMPLETE' } + } + } + }, + { + name: 'ts|v', + setup: function() { + return helpers.setInput(options, 'tsv ', 2); + }, + check: { + input: 'tsv ', + hints: '<optionType> <optionValue>', + markup: 'VVVV', + cursor: 2, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { arg: '', status: 'INCOMPLETE' }, + optionValue: { arg: '', status: 'INCOMPLETE' } + } + } + }, + { + setup: 'tsv o', + check: { + input: 'tsv o', + hints: 'ption1 <optionValue>', + markup: 'VVVVI', + cursor: 5, + current: 'optionType', + status: 'ERROR', + predictions: [ 'option1', 'option2', 'option3' ], + unassigned: [ ], + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tsv' }, + optionType: { + value: undefined, + arg: ' o', + status: 'INCOMPLETE', + message: 'Value required for \'optionType\'.' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + setup: 'tsv option', + check: { + input: 'tsv option', + hints: '1 <optionValue>', + markup: 'VVVVIIIIII', + cursor: 10, + current: 'optionType', + status: 'ERROR', + predictions: [ 'option1', 'option2', 'option3' ], + unassigned: [ ], + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tsv' }, + optionType: { + value: undefined, + arg: ' option', + status: 'INCOMPLETE', + message: 'Value required for \'optionType\'.' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + skipRemainingIf: options.isNoDom, + name: '|tsv option', + setup: function() { + return helpers.setInput(options, 'tsv option', 0); + }, + check: { + input: 'tsv option', + hints: ' <optionValue>', + markup: 'VVVVEEEEEE', + cursor: 0, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: undefined, + arg: ' option', + status: 'INCOMPLETE', + message: 'Value required for \'optionType\'.' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + setup: 'tsv option ', + check: { + input: 'tsv option ', + hints: '<optionValue>', + markup: 'VVVVEEEEEEV', + cursor: 11, + current: 'optionValue', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'false:default', + args: { + command: { name: 'tsv' }, + optionType: { + value: undefined, + arg: ' option ', + status: 'ERROR', + message: 'Can\'t use \'option\'.' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + setup: 'tsv option1', + check: { + input: 'tsv option1', + hints: ' <optionValue>', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'optionType', + status: 'ERROR', + predictions: [ 'option1' ], + unassigned: [ ], + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tsv' }, + optionType: { + value: 'string', + arg: ' option1', + status: 'VALID', + message: '' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + setup: 'tsv option1 ', + check: { + input: 'tsv option1 ', + hints: '<optionValue>', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'optionValue', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: 'string', + arg: ' option1 ', + status: 'VALID', + message: '' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + }, + { + setup: 'tsv option2', + check: { + input: 'tsv option2', + hints: ' <optionValue>', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'optionType', + status: 'ERROR', + predictions: [ 'option2' ], + unassigned: [ ], + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tsv' }, + optionType: { + value: 'number', + arg: ' option2', + status: 'VALID', + message: '' + }, + optionValue: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'optionValue\'.' + } + } + } + } + ]); +}; + +exports.testTsvValues = function(options) { + return helpers.audit(options, [ + { + setup: 'tsv option1 6', + check: { + input: 'tsv option1 6', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'optionValue', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: 'string', + arg: ' option1', + status: 'VALID', + message: '' + }, + optionValue: { + arg: ' 6', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsv option2 6', + check: { + input: 'tsv option2 6', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'optionValue', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: 'number', + arg: ' option2', + status: 'VALID', + message: '' + }, + optionValue: { + arg: ' 6', + status: 'VALID', + message: '' + } + } + } + }, + // Delegated remote types can't transfer value types so we only test for + // the value of 'value' when we're local + { + skipIf: options.isRemote, + setup: 'tsv option1 6', + check: { + args: { + optionValue: { value: '6' } + } + } + }, + { + skipIf: options.isRemote, + setup: 'tsv option2 6', + check: { + args: { + optionValue: { value: 6 } + } + } + } + ]); +}; + +exports.testInvalid = function(options) { + return helpers.audit(options, [ + { + setup: 'zxjq', + check: { + input: 'zxjq', + hints: '', + markup: 'EEEE', + cursor: 4, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError' + } + }, + { + setup: 'zxjq ', + check: { + input: 'zxjq ', + hints: '', + markup: 'EEEEV', + cursor: 5, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError' + } + }, + { + setup: 'zxjq one', + check: { + input: 'zxjq one', + hints: '', + markup: 'EEEEVEEE', + cursor: 8, + current: '__unassigned', + status: 'ERROR', + predictions: [ ], + unassigned: [ ' one' ], + tooltipState: 'true:isError' + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_cli2.js b/toolkit/devtools/commandline/test/browser_gcli_cli2.js new file mode 100644 index 000000000..f1a0a9e98 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_cli2.js @@ -0,0 +1,825 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCli2.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +var nodetype = require('gcli/types/node'); + +exports.setup = function(options) { + if (options.window) { + nodetype.setDocument(options.window.document); + } +}; + +exports.shutdown = function(options) { + nodetype.unsetDocument(); +}; + +exports.testSingleString = function(options) { + return helpers.audit(options, [ + { + setup: 'tsr', + check: { + input: 'tsr', + hints: ' <text>', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'ERROR', + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsr ', + check: { + input: 'tsr ', + hints: '<text>', + markup: 'VVVV', + cursor: 4, + current: 'text', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsr h', + check: { + input: 'tsr h', + hints: '', + markup: 'VVVVV', + cursor: 5, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'h', + arg: ' h', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsr "h h"', + check: { + input: 'tsr "h h"', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'h h', + arg: ' "h h"', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsr h h h', + check: { + input: 'tsr h h h', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'h h h', + arg: ' h h h', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testSingleNumber = function(options) { + return helpers.audit(options, [ + { + setup: 'tsu', + check: { + input: 'tsu', + hints: ' <num>', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'num\'.' + } + } + } + }, + { + setup: 'tsu ', + check: { + input: 'tsu ', + hints: '<num>', + markup: 'VVVV', + cursor: 4, + current: 'num', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'num\'.' + } + } + } + }, + { + setup: 'tsu 1', + check: { + input: 'tsu 1', + hints: '', + markup: 'VVVVV', + cursor: 5, + current: 'num', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { value: 1, arg: ' 1', status: 'VALID', message: '' } + } + } + }, + { + setup: 'tsu x', + check: { + input: 'tsu x', + hints: '', + markup: 'VVVVE', + cursor: 5, + current: 'num', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError', + args: { + command: { name: 'tsu' }, + num: { + value: undefined, + arg: ' x', + status: 'ERROR', + message: 'Can\'t convert "x" to a number.' + } + } + } + }, + { + setup: 'tsu 1.5', + check: { + input: 'tsu 1.5', + hints: '', + markup: 'VVVVEEE', + cursor: 7, + current: 'num', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { + value: undefined, + arg: ' 1.5', + status: 'ERROR', + message: 'Can\'t convert "1.5" to an integer.' + } + } + } + } + ]); +}; + +exports.testSingleFloat = function(options) { + return helpers.audit(options, [ + { + setup: 'tsf', + check: { + input: 'tsf', + hints: ' <num>', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'ERROR', + error: '', + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'num\'.' + } + } + } + }, + { + setup: 'tsf 1', + check: { + input: 'tsf 1', + hints: '', + markup: 'VVVVV', + cursor: 5, + current: 'num', + status: 'VALID', + error: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { value: 1, arg: ' 1', status: 'VALID', message: '' } + } + } + }, + { + setup: 'tsf 1.', + check: { + input: 'tsf 1.', + hints: '', + markup: 'VVVVVV', + cursor: 6, + current: 'num', + status: 'VALID', + error: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { value: 1, arg: ' 1.', status: 'VALID', message: '' } + } + } + }, + { + setup: 'tsf 1.5', + check: { + input: 'tsf 1.5', + hints: '', + markup: 'VVVVVVV', + cursor: 7, + current: 'num', + status: 'VALID', + error: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { value: 1.5, arg: ' 1.5', status: 'VALID', message: '' } + } + } + }, + { + setup: 'tsf 1.5x', + check: { + input: 'tsf 1.5x', + hints: '', + markup: 'VVVVVVVV', + cursor: 8, + current: 'num', + status: 'VALID', + error: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { value: 1.5, arg: ' 1.5x', status: 'VALID', message: '' } + } + } + }, + { + skipRemainingIf: options.isNoDom, + name: 'tsf x (cursor=4)', + setup: function() { + return helpers.setInput(options, 'tsf x', 4); + }, + check: { + input: 'tsf x', + hints: '', + markup: 'VVVVE', + cursor: 4, + current: 'num', + status: 'ERROR', + error: 'Can\'t convert "x" to a number.', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsf' }, + num: { + value: undefined, + arg: ' x', + status: 'ERROR', + message: 'Can\'t convert "x" to a number.' + } + } + } + } + ]); +}; + +exports.testElementWeb = function(options) { + var inputElement = options.isNoDom ? + null : + options.window.document.getElementById('gcli-input'); + + return helpers.audit(options, [ + { + skipIf: function gcliInputElementExists() { + return inputElement == null; + }, + setup: 'tse #gcli-input', + check: { + input: 'tse #gcli-input', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVV', + cursor: 15, + current: 'node', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tse' }, + node: { + value: inputElement, + arg: ' #gcli-input', + status: 'VALID', + message: '' + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + } + ]); +}; + +exports.testElement = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isNoDom, + setup: 'tse', + check: { + input: 'tse', + hints: ' <node> [options]', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'ERROR', + predictions: [ 'tse', 'tselarr' ], + unassigned: [ ], + args: { + command: { name: 'tse' }, + node: { value: undefined, arg: '', status: 'INCOMPLETE' }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tse #gcli-nomatch', + check: { + input: 'tse #gcli-nomatch', + hints: ' [options]', + markup: 'VVVVIIIIIIIIIIIII', + cursor: 17, + current: 'node', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'true:isError', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' #gcli-nomatch', + // This is somewhat debatable because this input can't be corrected + // simply by typing so it's and error rather than incomplete, + // however without digging into the CSS engine we can't tell that + // so we default to incomplete + status: 'INCOMPLETE', + message: 'No matches' + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tse #', + check: { + input: 'tse #', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' #', + status: 'ERROR', + message: 'Syntax error in CSS query' + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tse .', + check: { + input: 'tse .', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' .', + status: 'ERROR', + message: 'Syntax error in CSS query' + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tse *', + check: { + input: 'tse *', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' *', + status: 'ERROR', + message: /^Too many matches \([0-9]*\)/ + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: '', status: 'VALID', message: '' }, + } + } + } + ]); +}; + +exports.testNestedCommand = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn', + check: { + input: 'tsn', + hints: ' deep down nested cmd', + markup: 'III', + cursor: 3, + current: '__command', + status: 'ERROR', + predictionsInclude: [ + 'tsn deep', 'tsn deep down', 'tsn deep down nested', + 'tsn deep down nested cmd', 'tsn dif' + ], + unassigned: [ ], + args: { + command: { name: 'tsn' } + } + } + }, + { + setup: 'tsn ', + check: { + input: 'tsn ', + hints: ' deep down nested cmd', + markup: 'IIIV', + cursor: 4, + current: '__command', + status: 'ERROR', + unassigned: [ ] + } + }, + { + skipIf: options.isPhantomjs, + setup: 'tsn x', + check: { + input: 'tsn x', + hints: ' -> tsn ext', + markup: 'IIIVI', + cursor: 5, + current: '__command', + status: 'ERROR', + predictions: [ 'tsn ext' ], + unassigned: [ ] + } + }, + { + setup: 'tsn dif', + check: { + input: 'tsn dif', + hints: ' <text>', + markup: 'VVVVVVV', + cursor: 7, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn dif' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsn dif ', + check: { + input: 'tsn dif ', + hints: '<text>', + markup: 'VVVVVVVV', + cursor: 8, + current: 'text', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn dif' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsn dif x', + check: { + input: 'tsn dif x', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn dif' }, + text: { value: 'x', arg: ' x', status: 'VALID', message: '' } + } + } + }, + { + setup: 'tsn ext', + check: { + input: 'tsn ext', + hints: ' <text>', + markup: 'VVVVVVV', + cursor: 7, + current: '__command', + status: 'ERROR', + predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ], + unassigned: [ ], + args: { + command: { name: 'tsn ext' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsn exte', + check: { + input: 'tsn exte', + hints: ' <text>', + markup: 'VVVVVVVV', + cursor: 8, + current: '__command', + status: 'ERROR', + predictions: [ 'tsn exte', 'tsn exten', 'tsn extend' ], + unassigned: [ ], + args: { + command: { name: 'tsn exte' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsn exten', + check: { + input: 'tsn exten', + hints: ' <text>', + markup: 'VVVVVVVVV', + cursor: 9, + current: '__command', + status: 'ERROR', + predictions: [ 'tsn exten', 'tsn extend' ], + unassigned: [ ], + args: { + command: { name: 'tsn exten' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'tsn extend', + check: { + input: 'tsn extend', + hints: ' <text>', + markup: 'VVVVVVVVVV', + cursor: 10, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn extend' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'text\'.' + } + } + } + }, + { + setup: 'ts ', + check: { + input: 'ts ', + hints: '', + markup: 'EEV', + cursor: 3, + current: '__command', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + tooltipState: 'true:isError' + } + }, + ]); +}; + +// From Bug 664203 +exports.testDeeplyNested = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn deep down nested', + check: { + input: 'tsn deep down nested', + hints: ' cmd', + markup: 'IIIVIIIIVIIIIVIIIIII', + cursor: 20, + current: '__command', + status: 'ERROR', + predictions: [ 'tsn deep down nested cmd' ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'false:default', + args: { + command: { name: 'tsn deep down nested' }, + } + } + }, + { + setup: 'tsn deep down nested cmd', + check: { + input: 'tsn deep down nested cmd', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 24, + current: '__command', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn deep down nested cmd' }, + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_completion1.js b/toolkit/devtools/commandline/test/browser_gcli_completion1.js new file mode 100644 index 000000000..0df796265 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_completion1.js @@ -0,0 +1,292 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCompletion1.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testActivate = function(options) { + return helpers.audit(options, [ + { + setup: '', + check: { + hints: '' + } + }, + { + setup: ' ', + check: { + hints: '' + } + }, + { + setup: 'tsr', + check: { + hints: ' <text>' + } + }, + { + setup: 'tsr ', + check: { + hints: '<text>' + } + }, + { + setup: 'tsr b', + check: { + hints: '' + } + }, + { + setup: 'tsb', + check: { + hints: ' [toggle]' + } + }, + { + setup: 'tsm', + check: { + hints: ' <abc> <txt> <num>' + } + }, + { + setup: 'tsm ', + check: { + hints: 'a <txt> <num>' + } + }, + { + setup: 'tsm a', + check: { + hints: ' <txt> <num>' + } + }, + { + setup: 'tsm a ', + check: { + hints: '<txt> <num>' + } + }, + { + setup: 'tsm a ', + check: { + hints: '<txt> <num>' + } + }, + { + setup: 'tsm a d', + check: { + hints: ' <num>' + } + }, + { + setup: 'tsm a "d d"', + check: { + hints: ' <num>' + } + }, + { + setup: 'tsm a "d ', + check: { + hints: ' <num>' + } + }, + { + setup: 'tsm a "d d" ', + check: { + hints: '<num>' + } + }, + { + setup: 'tsm a "d d ', + check: { + hints: ' <num>' + } + }, + { + setup: 'tsm d r', + check: { + hints: ' <num>' + } + }, + { + setup: 'tsm a d ', + check: { + hints: '<num>' + } + }, + { + setup: 'tsm a d 4', + check: { + hints: '' + } + }, + { + setup: 'tsg', + check: { + hints: ' <solo> [options]' + } + }, + { + setup: 'tsg ', + check: { + hints: 'aaa [options]' + } + }, + { + setup: 'tsg a', + check: { + hints: 'aa [options]' + } + }, + { + setup: 'tsg b', + check: { + hints: 'bb [options]' + } + }, + { + skipIf: options.isPhantomjs, + setup: 'tsg d', + check: { + hints: ' [options] -> ccc' + } + }, + { + setup: 'tsg aa', + check: { + hints: 'a [options]' + } + }, + { + setup: 'tsg aaa', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsg aaa ', + check: { + hints: '[options]' + } + }, + { + setup: 'tsg aaa d', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsg aaa dddddd', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsg aaa dddddd ', + check: { + hints: '[options]' + } + }, + { + setup: 'tsg aaa "d', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsg aaa "d d', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsg aaa "d d"', + check: { + hints: ' [options]' + } + }, + { + setup: 'tsn ex ', + check: { + hints: '' + } + }, + { + setup: 'selarr', + check: { + hints: ' -> tselarr' + } + }, + { + setup: 'tselar 1', + check: { + hints: '' + } + }, + { + name: 'tselar |1', + setup: function() { + return helpers.setInput(options, 'tselar 1', 7); + }, + check: { + hints: '' + } + }, + { + name: 'tselar| 1', + setup: function() { + return helpers.setInput(options, 'tselar 1', 6); + }, + check: { + hints: ' -> tselarr' + } + }, + { + name: 'tsela|r 1', + setup: function() { + return helpers.setInput(options, 'tselar 1', 5); + }, + check: { + hints: ' -> tselarr' + } + }, + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_completion2.js b/toolkit/devtools/commandline/test/browser_gcli_completion2.js new file mode 100644 index 000000000..b27b8e747 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_completion2.js @@ -0,0 +1,279 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCompletion2.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testLong = function(options) { + return helpers.audit(options, [ + { + setup: 'tslong --sel', + check: { + input: 'tslong --sel', + hints: ' <selection> <msg> [options]', + markup: 'VVVVVVVIIIII' + } + }, + { + setup: 'tslong --sel<TAB>', + check: { + input: 'tslong --sel ', + hints: 'space <msg> [options]', + markup: 'VVVVVVVIIIIIV' + } + }, + { + setup: 'tslong --sel ', + check: { + input: 'tslong --sel ', + hints: 'space <msg> [options]', + markup: 'VVVVVVVIIIIIV' + } + }, + { + setup: 'tslong --sel s', + check: { + input: 'tslong --sel s', + hints: 'pace <msg> [options]', + markup: 'VVVVVVVIIIIIVI' + } + }, + { + setup: 'tslong --num ', + check: { + input: 'tslong --num ', + hints: '<number> <msg> [options]', + markup: 'VVVVVVVIIIIIV' + } + }, + { + setup: 'tslong --num 42', + check: { + input: 'tslong --num 42', + hints: ' <msg> [options]', + markup: 'VVVVVVVVVVVVVVV' + } + }, + { + setup: 'tslong --num 42 ', + check: { + input: 'tslong --num 42 ', + hints: '<msg> [options]', + markup: 'VVVVVVVVVVVVVVVV' + } + }, + { + setup: 'tslong --num 42 --se', + check: { + input: 'tslong --num 42 --se', + hints: 'l <msg> [options]', + markup: 'VVVVVVVVVVVVVVVVIIII' + } + }, + { + setup: 'tslong --num 42 --se<TAB>', + check: { + input: 'tslong --num 42 --sel ', + hints: 'space <msg> [options]', + markup: 'VVVVVVVVVVVVVVVVIIIIIV' + } + }, + { + setup: 'tslong --num 42 --se<TAB><TAB>', + check: { + input: 'tslong --num 42 --sel space ', + hints: '<msg> [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV' + } + }, + { + setup: 'tslong --num 42 --sel ', + check: { + input: 'tslong --num 42 --sel ', + hints: 'space <msg> [options]', + markup: 'VVVVVVVVVVVVVVVVIIIIIV' + } + }, + { + setup: 'tslong --num 42 --sel space ', + check: { + input: 'tslong --num 42 --sel space ', + hints: '<msg> [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV' + } + } + ]); +}; + +exports.testNoTab = function(options) { + return helpers.audit(options, [ + { + setup: 'tss<TAB>', + check: { + input: 'tss ', + markup: 'VVVV', + hints: '' + } + }, + { + setup: 'tss<TAB><TAB>', + check: { + input: 'tss ', + markup: 'VVVV', + hints: '' + } + }, + { + setup: 'xxxx', + check: { + input: 'xxxx', + markup: 'EEEE', + hints: '' + } + }, + { + skipIf: options.isNoDom, + name: '<TAB>', + setup: function() { + // Doing it this way avoids clearing the input buffer + return helpers.pressTab(options); + }, + check: { + input: 'xxxx', + markup: 'EEEE', + hints: '' + } + } + ]); +}; + +exports.testOutstanding = function(options) { + // See bug 779800 + /* + return helpers.audit(options, [ + { + setup: 'tsg --txt1 ddd ', + check: { + input: 'tsg --txt1 ddd ', + hints: 'aaa [options]', + markup: 'VVVVVVVVVVVVVVV' + } + }, + ]); + */ +}; + +exports.testCompleteIntoOptional = function(options) { + // From bug 779816 + return helpers.audit(options, [ + { + setup: 'tso ', + check: { + typed: 'tso ', + hints: '[text]', + markup: 'VVVV', + status: 'VALID' + } + }, + { + setup: 'tso<TAB>', + check: { + typed: 'tso ', + hints: '[text]', + markup: 'VVVV', + status: 'VALID' + } + } + ]); +}; + +exports.testSpaceComplete = function(options) { + return helpers.audit(options, [ + { + setup: 'tslong --sel2 wit', + check: { + input: 'tslong --sel2 wit', + hints: 'h space <msg> [options]', + markup: 'VVVVVVVIIIIIIVIII', + cursor: 17, + current: 'sel2', + status: 'ERROR', + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tslong' }, + msg: { status: 'INCOMPLETE' }, + num: { status: 'VALID' }, + sel: { status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + num2: { status: 'VALID' }, + bool2: { value: false, status: 'VALID' }, + sel2: { arg: ' --sel2 wit', status: 'INCOMPLETE' } + } + } + }, + { + setup: 'tslong --sel2 wit<TAB>', + check: { + input: 'tslong --sel2 \'with space\' ', + hints: '<msg> [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 27, + current: 'sel2', + status: 'ERROR', + tooltipState: 'true:importantFieldFlag', + args: { + command: { name: 'tslong' }, + msg: { status: 'INCOMPLETE' }, + num: { status: 'VALID' }, + sel: { status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + num2: { status: 'VALID' }, + bool2: { value: false, status: 'VALID' }, + sel2: { + value: 'with space', + arg: ' --sel2 \'with space\' ', + status: 'VALID' + } + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_context.js b/toolkit/devtools/commandline/test/browser_gcli_context.js new file mode 100644 index 000000000..1aed2851e --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_context.js @@ -0,0 +1,254 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testContext.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testBaseline = function(options) { + return helpers.audit(options, [ + // These 3 establish a baseline for comparison when we have used the + // context command + { + setup: 'ext', + check: { + input: 'ext', + hints: ' -> context', + markup: 'III', + message: '', + predictions: [ 'context', 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ], + unassigned: [ ], + } + }, + { + setup: 'ext test', + check: { + input: 'ext test', + hints: '', + markup: 'IIIVEEEE', + status: 'ERROR', + message: 'Too many arguments', + unassigned: [ ' test' ], + } + }, + { + setup: 'tsn', + check: { + input: 'tsn', + hints: ' deep down nested cmd', + markup: 'III', + cursor: 3, + current: '__command', + status: 'ERROR', + predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ], + args: { + command: { name: 'tsn' }, + } + } + } + ]); +}; + +exports.testContext = function(options) { + return helpers.audit(options, [ + // Use the 'tsn' context + { + setup: 'context tsn', + check: { + input: 'context tsn', + hints: ' deep down nested cmd', + markup: 'VVVVVVVVVVV', + message: '', + predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ], + args: { + command: { name: 'context' }, + prefix: { + value: options.requisition.system.commands.get('tsn'), + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Using tsn as a command prefix' + } + }, + // For comparison with earlier + { + setup: 'ext', + check: { + input: 'ext', + hints: ' <text>', + markup: 'VVV', + predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ], + args: { + command: { name: 'tsn ext' }, + text: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: 'ext test', + check: { + input: 'ext test', + hints: '', + markup: 'VVVVVVVV', + args: { + command: { name: 'tsn ext' }, + text: { + value: 'test', + arg: ' test', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsnExt text=test' + } + }, + { + setup: 'tsn', + check: { + input: 'tsn', + hints: ' deep down nested cmd', + markup: 'III', + message: '', + predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ], + args: { + command: { name: 'tsn' }, + } + } + }, + // Does it actually work? + { + setup: 'tsb true', + check: { + input: 'tsb true', + hints: '', + markup: 'VVVVVVVV', + options: [ 'true' ], + message: '', + predictions: [ 'true' ], + unassigned: [ ], + args: { + command: { name: 'tsb' }, + toggle: { value: true, arg: ' true', status: 'VALID', message: '' } + } + } + }, + { + // Bug 866710 - GCLI should allow argument merging for non-string parameters + setup: 'context tsn ext', + skip: true + }, + { + setup: 'context "tsn ext"', + check: { + input: 'context "tsn ext"', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + message: '', + predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { + value: options.requisition.system.commands.get('tsn ext'), + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Can\'t use \'tsn ext\' as a prefix because it is not a parent command.', + error: true + } + }, + /* + { + setup: 'context "tsn deep"', + check: { + input: 'context "tsn deep"', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVV', + status: 'ERROR', + message: '', + predictions: [ 'tsn deep' ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { + value: options.requisition.system.commands.get('tsn deep'), + status: 'VALID', + message: '' + } + } + }, + exec: { + output: '' + } + }, + */ + { + setup: 'context', + check: { + input: 'context', + hints: ' [prefix]', + markup: 'VVVVVVV', + status: 'VALID', + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { value: undefined, arg: '', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Command prefix is unset', + type: 'string', + error: false + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_date.js b/toolkit/devtools/commandline/test/browser_gcli_date.js new file mode 100644 index 000000000..352679cc1 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_date.js @@ -0,0 +1,373 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testDate.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +var Status = require('gcli/types/types').Status; + +exports.testParse = function(options) { + var date = options.requisition.system.types.createType('date'); + return date.parseString('now').then(function(conversion) { + // Date comparison - these 2 dates may not be the same, but how close is + // close enough? If this test takes more than 30secs to run the it will + // probably time out, so we'll assume that these 2 values must be within + // 1 min of each other + var gap = new Date().getTime() - conversion.value.getTime(); + assert.ok(gap < 60000, 'now is less than a minute away'); + + assert.is(conversion.getStatus(), Status.VALID, 'now parse'); + }); +}; + +exports.testMaxMin = function(options) { + var max = new Date(); + var min = new Date(); + var types = options.requisition.system.types; + var date = types.createType({ name: 'date', max: max, min: min }); + assert.is(date.getMax(), max, 'max setup'); + + var incremented = date.increment(min); + assert.is(incremented, max, 'incremented'); +}; + +exports.testIncrement = function(options) { + var date = options.requisition.system.types.createType('date'); + return date.parseString('now').then(function(conversion) { + var plusOne = date.increment(conversion.value); + var minusOne = date.decrement(plusOne); + + // See comments in testParse + var gap = new Date().getTime() - minusOne.getTime(); + assert.ok(gap < 60000, 'now is less than a minute away'); + }); +}; + +exports.testInput = function(options) { + return helpers.audit(options, [ + { + setup: 'tsdate 2001-01-01 1980-01-03', + check: { + input: 'tsdate 2001-01-01 1980-01-03', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + assert.is(d1.getFullYear(), 2001, 'd1 year'); + assert.is(d1.getMonth(), 0, 'd1 month'); + assert.is(d1.getDate(), 1, 'd1 date'); + assert.is(d1.getHours(), 0, 'd1 hours'); + assert.is(d1.getMinutes(), 0, 'd1 minutes'); + assert.is(d1.getSeconds(), 0, 'd1 seconds'); + assert.is(d1.getMilliseconds(), 0, 'd1 millis'); + }, + arg: ' 2001-01-01', + status: 'VALID', + message: '' + }, + d2: { + value: function(d2) { + assert.is(d2.getFullYear(), 1980, 'd2 year'); + assert.is(d2.getMonth(), 0, 'd2 month'); + assert.is(d2.getDate(), 3, 'd2 date'); + assert.is(d2.getHours(), 0, 'd2 hours'); + assert.is(d2.getMinutes(), 0, 'd2 minutes'); + assert.is(d2.getSeconds(), 0, 'd2 seconds'); + assert.is(d2.getMilliseconds(), 0, 'd2 millis'); + }, + arg: ' 1980-01-03', + status: 'VALID', + message: '' + }, + } + }, + exec: { + output: [ /^Exec: tsdate/, /2001/, /1980/ ], + type: 'string', + error: false + } + }, + { + setup: 'tsdate 2001/01/01 1980/01/03', + check: { + input: 'tsdate 2001/01/01 1980/01/03', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + assert.is(d1.getFullYear(), 2001, 'd1 year'); + assert.is(d1.getMonth(), 0, 'd1 month'); + assert.is(d1.getDate(), 1, 'd1 date'); + assert.is(d1.getHours(), 0, 'd1 hours'); + assert.is(d1.getMinutes(), 0, 'd1 minutes'); + assert.is(d1.getSeconds(), 0, 'd1 seconds'); + assert.is(d1.getMilliseconds(), 0, 'd1 millis'); + }, + arg: ' 2001/01/01', + status: 'VALID', + message: '' + }, + d2: { + value: function(d2) { + assert.is(d2.getFullYear(), 1980, 'd2 year'); + assert.is(d2.getMonth(), 0, 'd2 month'); + assert.is(d2.getDate(), 3, 'd2 date'); + assert.is(d2.getHours(), 0, 'd2 hours'); + assert.is(d2.getMinutes(), 0, 'd2 minutes'); + assert.is(d2.getSeconds(), 0, 'd2 seconds'); + assert.is(d2.getMilliseconds(), 0, 'd2 millis'); + }, + arg: ' 1980/01/03', + status: 'VALID', + message: '' + }, + } + }, + exec: { + output: [ /^Exec: tsdate/, /2001/, /1980/ ], + type: 'string', + error: false + } + }, + { + setup: 'tsdate now today', + check: { + input: 'tsdate now today', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + // How long should we allow between d1 and now? Mochitest will + // time out after 30 secs, so that seems like a decent upper + // limit, although 30 ms should probably do it. I don't think + // reducing the limit from 30 secs will find any extra bugs + assert.ok(d1.getTime() - new Date().getTime() < 30 * 1000, + 'd1 time'); + }, + arg: ' now', + status: 'VALID', + message: '' + }, + d2: { + value: function(d2) { + // See comment for d1 above + assert.ok(d2.getTime() - new Date().getTime() < 30 * 1000, + 'd2 time'); + }, + arg: ' today', + status: 'VALID', + message: '' + }, + } + }, + exec: { + output: [ /^Exec: tsdate/, new Date().getFullYear() ], + type: 'string', + error: false + } + }, + { + setup: 'tsdate yesterday tomorrow', + check: { + input: 'tsdate yesterday tomorrow', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + var compare = new Date().getTime() - (24 * 60 * 60 * 1000); + // See comment for d1 in the test for 'tsdate now today' + assert.ok(d1.getTime() - compare < 30 * 1000, + 'd1 time'); + }, + arg: ' yesterday', + status: 'VALID', + message: '' + }, + d2: { + value: function(d2) { + var compare = new Date().getTime() + (24 * 60 * 60 * 1000); + // See comment for d1 in the test for 'tsdate now today' + assert.ok(d2.getTime() - compare < 30 * 1000, + 'd2 time'); + }, + arg: ' tomorrow', + status: 'VALID', + message: '' + }, + } + }, + exec: { + output: [ /^Exec: tsdate/, new Date().getFullYear() ], + type: 'string', + error: false + } + } + ]); +}; + +exports.testIncrDecr = function(options) { + return helpers.audit(options, [ + { + // createRequisitionAutomator doesn't fake UP/DOWN well enough + skipRemainingIf: options.isNoDom, + setup: 'tsdate 2001-01-01<UP>', + check: { + input: 'tsdate 2001-01-02', + hints: ' <d2>', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + assert.is(d1.getFullYear(), 2001, 'd1 year'); + assert.is(d1.getMonth(), 0, 'd1 month'); + assert.is(d1.getDate(), 2, 'd1 date'); + assert.is(d1.getHours(), 0, 'd1 hours'); + assert.is(d1.getMinutes(), 0, 'd1 minutes'); + assert.is(d1.getSeconds(), 0, 'd1 seconds'); + assert.is(d1.getMilliseconds(), 0, 'd1 millis'); + }, + arg: ' 2001-01-02', + status: 'VALID', + message: '' + }, + d2: { + value: undefined, + status: 'INCOMPLETE' + }, + } + } + }, + { + // Check wrapping on decrement + setup: 'tsdate 2001-02-01<DOWN>', + check: { + input: 'tsdate 2001-01-31', + hints: ' <d2>', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + assert.is(d1.getFullYear(), 2001, 'd1 year'); + assert.is(d1.getMonth(), 0, 'd1 month'); + assert.is(d1.getDate(), 31, 'd1 date'); + assert.is(d1.getHours(), 0, 'd1 hours'); + assert.is(d1.getMinutes(), 0, 'd1 minutes'); + assert.is(d1.getSeconds(), 0, 'd1 seconds'); + assert.is(d1.getMilliseconds(), 0, 'd1 millis'); + }, + arg: ' 2001-01-31', + status: 'VALID', + message: '' + }, + d2: { + value: undefined, + status: 'INCOMPLETE' + }, + } + } + }, + { + // Check 'max' value capping on increment + setup: 'tsdate 2001-02-01 "27 feb 2000"<UP>', + check: { + input: 'tsdate 2001-02-01 "2000-02-28"', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsdate' }, + d1: { + value: function(d1) { + assert.is(d1.getFullYear(), 2001, 'd1 year'); + assert.is(d1.getMonth(), 1, 'd1 month'); + assert.is(d1.getDate(), 1, 'd1 date'); + assert.is(d1.getHours(), 0, 'd1 hours'); + assert.is(d1.getMinutes(), 0, 'd1 minutes'); + assert.is(d1.getSeconds(), 0, 'd1 seconds'); + assert.is(d1.getMilliseconds(), 0, 'd1 millis'); + }, + arg: ' 2001-02-01', + status: 'VALID', + message: '' + }, + d2: { + value: function(d2) { + assert.is(d2.getFullYear(), 2000, 'd2 year'); + assert.is(d2.getMonth(), 1, 'd2 month'); + assert.is(d2.getDate(), 28, 'd2 date'); + assert.is(d2.getHours(), 0, 'd2 hours'); + assert.is(d2.getMinutes(), 0, 'd2 minutes'); + assert.is(d2.getSeconds(), 0, 'd2 seconds'); + assert.is(d2.getMilliseconds(), 0, 'd2 millis'); + }, + arg: ' "2000-02-28"', + status: 'VALID', + message: '' + }, + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_exec.js b/toolkit/devtools/commandline/test/browser_gcli_exec.js new file mode 100644 index 000000000..0b1f47ddc --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_exec.js @@ -0,0 +1,659 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testExec.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var nodetype = require('gcli/types/node'); + +var mockBody = { + style: {} +}; + +var mockEmptyNodeList = { + length: 0, + item: function() { return null; } +}; + +var mockRootNodeList = { + length: 1, + item: function(i) { return mockBody; } +}; + +var mockDoc = { + querySelectorAll: function(css) { + return (css === ':root') ? mockRootNodeList : mockEmptyNodeList; + } +}; + +exports.testParamGroup = function(options) { + var tsg = options.requisition.system.commands.get('tsg'); + + assert.is(tsg.params[0].groupName, null, 'tsg param 0 group null'); + assert.is(tsg.params[1].groupName, 'First', 'tsg param 1 group First'); + assert.is(tsg.params[2].groupName, 'First', 'tsg param 2 group First'); + assert.is(tsg.params[3].groupName, 'Second', 'tsg param 3 group Second'); + assert.is(tsg.params[4].groupName, 'Second', 'tsg param 4 group Second'); +}; + +exports.testWithHelpers = function(options) { + return helpers.audit(options, [ + { + setup: 'tss', + check: { + input: 'tss', + hints: '', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'VALID', + unassigned: [ ], + args: { + command: { name: 'tss' }, + } + }, + exec: { + output: /^Exec: tss/, + } + }, + { + setup: 'tsv option1 10', + check: { + input: 'tsv option1 10', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'optionValue', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: 'string', + arg: ' option1', + status: 'VALID', + message: '' + }, + optionValue: { + arg: ' 10', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsv optionType=string, optionValue=10' + } + }, + { + setup: 'tsv option2 10', + check: { + input: 'tsv option2 10', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'optionValue', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsv' }, + optionType: { + value: 'number', + arg: ' option2', + status: 'VALID', + message: '' + }, + optionValue: { + arg: ' 10', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsv optionType=number, optionValue=10' + } + }, + // Delegated remote types can't transfer value types so we only test for + // the value of optionValue when we're local + { + skipIf: options.isRemote, + setup: 'tsv option1 10', + check: { + args: { optionValue: { value: '10' } } + }, + exec: { + output: 'Exec: tsv optionType=string, optionValue=10' + } + }, + { + skipIf: options.isRemote, + setup: 'tsv option2 10', + check: { + args: { optionValue: { value: 10 } } + }, + exec: { + output: 'Exec: tsv optionType=number, optionValue=10' + } + } + ]); +}; + +exports.testExecText = function(options) { + return helpers.audit(options, [ + { + setup: 'tsr fred', + check: { + input: 'tsr fred', + hints: '', + markup: 'VVVVVVVV', + cursor: 8, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'fred', + arg: ' fred', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsr text=fred' + } + }, + { + setup: 'tsr fred bloggs', + check: { + input: 'tsr fred bloggs', + hints: '', + markup: 'VVVVVVVVVVVVVVV', + cursor: 15, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'fred bloggs', + arg: ' fred bloggs', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsr text=fred bloggs' + } + }, + { + setup: 'tsr "fred bloggs"', + check: { + input: 'tsr "fred bloggs"', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'fred bloggs', + arg: ' "fred bloggs"', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsr text=fred bloggs' + } + }, + { + setup: 'tsr "fred bloggs', + check: { + input: 'tsr "fred bloggs', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + cursor: 16, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsr' }, + text: { + value: 'fred bloggs', + arg: ' "fred bloggs', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsr text=fred bloggs' + } + } + ]); +}; + +exports.testExecBoolean = function(options) { + return helpers.audit(options, [ + { + setup: 'tsb', + check: { + input: 'tsb', + hints: ' [toggle]', + markup: 'VVV', + cursor: 3, + current: '__command', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsb' }, + toggle: { + value: false, + arg: '', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsb toggle=false' + } + }, + { + setup: 'tsb --toggle', + check: { + input: 'tsb --toggle', + hints: '', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'toggle', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + outputState: 'false:default', + args: { + command: { name: 'tsb' }, + toggle: { + value: true, + arg: ' --toggle', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsb toggle=true' + } + } + ]); +}; + +exports.testExecNumber = function(options) { + return helpers.audit(options, [ + { + setup: 'tsu 10', + check: { + input: 'tsu 10', + hints: '', + markup: 'VVVVVV', + cursor: 6, + current: 'num', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { value: 10, arg: ' 10', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Exec: tsu num=10' + } + }, + { + setup: 'tsu --num 10', + check: { + input: 'tsu --num 10', + hints: '', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'num', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsu' }, + num: { value: 10, arg: ' --num 10', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Exec: tsu num=10' + } + } + ]); +}; + +exports.testExecScript = function(options) { + return helpers.audit(options, [ + { + // Bug 704829 - Enable GCLI Javascript parameters + // The answer to this should be 2 + setup: 'tsj { 1 + 1 }', + check: { + input: 'tsj { 1 + 1 }', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsj' }, + javascript: { + value: '1 + 1', + arg: ' { 1 + 1 }', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Exec: tsj javascript=1 + 1' + } + } + ]); +}; + +exports.testExecNode = function(options) { + var origDoc = nodetype.getDocument(); + nodetype.setDocument(mockDoc); + + return helpers.audit(options, [ + { + skipIf: options.isNoDom, + setup: 'tse :root', + check: { + input: 'tse :root', + hints: ' [options]', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'node', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tse' }, + node: { + value: mockBody, + arg: ' :root', + status: 'VALID', + message: '' + }, + nodes: { + value: mockEmptyNodeList, + arg: '', + status: 'VALID', + message: '' + }, + nodes2: { + value: mockEmptyNodeList, + arg: '', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: /^Exec: tse/ + }, + post: function() { + nodetype.setDocument(origDoc); + } + } + ]); +}; + +exports.testExecSubCommand = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn dif fred', + check: { + input: 'tsn dif fred', + hints: '', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn dif' }, + text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Exec: tsnDif text=fred' + } + }, + { + setup: 'tsn exten fred', + check: { + input: 'tsn exten fred', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn exten' }, + text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tsnExten text=fred' + } + }, + { + setup: 'tsn extend fred', + check: { + input: 'tsn extend fred', + hints: '', + markup: 'VVVVVVVVVVVVVVV', + cursor: 15, + current: 'text', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsn extend' }, + text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tsnExtend text=fred' + } + } + ]); +}; + +exports.testExecArray = function(options) { + return helpers.audit(options, [ + { + setup: 'tselarr 1', + check: { + input: 'tselarr 1', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'num', + status: 'VALID', + predictions: ['1'], + unassigned: [ ], + outputState: 'false:default', + args: { + command: { name: 'tselarr' }, + num: { value: '1', arg: ' 1', status: 'VALID', message: '' }, + arr: { /*value:,*/ arg: '{}', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tselarr num=1, arr=' + } + }, + { + setup: 'tselarr 1 a', + check: { + input: 'tselarr 1 a', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'arr', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tselarr' }, + num: { value: '1', arg: ' 1', status: 'VALID', message: '' }, + arr: { /*value:a,*/ arg: '{ a}', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tselarr num=1, arr=a' + } + }, + { + setup: 'tselarr 1 a b', + check: { + input: 'tselarr 1 a b', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'arr', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tselarr' }, + num: { value: '1', arg: ' 1', status: 'VALID', message: '' }, + arr: { /*value:a,b,*/ arg: '{ a, b}', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tselarr num=1, arr=a,b' + } + } + ]); +}; + +exports.testExecMultiple = function(options) { + return helpers.audit(options, [ + { + setup: 'tsm a 10 10', + check: { + input: 'tsm a 10 10', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'num', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tsm' }, + abc: { value: 'a', arg: ' a', status: 'VALID', message: '' }, + txt: { value: '10', arg: ' 10', status: 'VALID', message: '' }, + num: { value: 10, arg: ' 10', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tsm abc=a, txt=10, num=10' + } + } + ]); +}; + +exports.testExecDefaults = function(options) { + return helpers.audit(options, [ + { + // Bug 707009 - GCLI doesn't always fill in default parameters properly + setup: 'tsg aaa', + check: { + input: 'tsg aaa', + hints: ' [options]', + markup: 'VVVVVVV', + cursor: 7, + current: 'solo', + status: 'VALID', + predictions: ['aaa'], + unassigned: [ ], + args: { + command: { name: 'tsg' }, + solo: { value: 'aaa', arg: ' aaa', status: 'VALID', message: '' }, + txt1: { value: undefined, arg: '', status: 'VALID', message: '' }, + bool: { value: false, arg: '', status: 'VALID', message: '' }, + txt2: { value: undefined, arg: '', status: 'VALID', message: '' }, + num: { value: undefined, arg: '', status: 'VALID', message: '' }, + } + }, + exec: { + output: 'Exec: tsg solo=aaa, txt1=null, bool=false, txt2=d, num=42' + } + } + ]); + +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_fail.js b/toolkit/devtools/commandline/test/browser_gcli_fail.js new file mode 100644 index 000000000..c0b94f492 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_fail.js @@ -0,0 +1,88 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFail.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + setup: 'tsfail reject', + exec: { + output: 'rejected promise', + type: 'error', + error: true + } + }, + { + setup: 'tsfail rejecttyped', + exec: { + output: '54', + type: 'number', + error: true + } + }, + { + setup: 'tsfail throwerror', + exec: { + output: /thrown error$/, + type: 'error', + error: true + } + }, + { + setup: 'tsfail throwstring', + exec: { + output: 'thrown string', + type: 'error', + error: true + } + }, + { + setup: 'tsfail noerror', + exec: { + output: 'no error', + type: 'string', + error: false + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_file.js b/toolkit/devtools/commandline/test/browser_gcli_file.js new file mode 100644 index 000000000..1317d9c7d --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_file.js @@ -0,0 +1,839 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFile.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +var local = false; + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + // These tests require us to be using node directly or to be in + // PhantomJS connected to an execute enabled node server or to be in + // firefox. + skipRemainingIf: options.isPhantomjs || options.isFirefox, + setup: 'tsfile open /', + check: { + input: 'tsfile open /', + hints: '', + markup: 'VVVVVVVVVVVVI', + cursor: 13, + current: 'p1', + status: 'ERROR', + message: '\'/\' is not a file', + args: { + command: { name: 'tsfile open' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' is not a file' + } + } + } + }, + { + setup: 'tsfile open /zxcv', + check: { + input: 'tsfile open /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVIIIII', + cursor: 17, + current: 'p1', + status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile open' }, + p1: { + value: undefined, + arg: ' /zxcv', + status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile open /mach_kernel', + check: { + input: 'tsfile open /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 24, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile open' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile saveas /', + check: { + input: 'tsfile saveas /', + hints: '', + markup: 'VVVVVVVVVVVVVVI', + cursor: 15, + current: 'p1', + status: 'ERROR', + message: '\'/\' already exists', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' already exists' + } + } + } + }, + { + setup: 'tsfile saveas /zxcv', + check: { + input: 'tsfile saveas /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVVVVVVVV', + cursor: 19, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile saveas /mach_kernel', + check: { + input: 'tsfile saveas /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII', + cursor: 26, + current: 'p1', + status: 'ERROR', + message: '\'/mach_kernel\' already exists', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: undefined, + arg: ' /mach_kernel', + status: 'INCOMPLETE', + message: '\'/mach_kernel\' already exists' + } + } + } + }, + { + setup: 'tsfile save /', + check: { + input: 'tsfile save /', + hints: '', + markup: 'VVVVVVVVVVVVI', + cursor: 13, + current: 'p1', + status: 'ERROR', + message: '\'/\' is not a file', + args: { + command: { name: 'tsfile save' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' is not a file' + } + } + } + }, + { + setup: 'tsfile save /zxcv', + check: { + input: 'tsfile save /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile save' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile save /mach_kernel', + check: { + input: 'tsfile save /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 24, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile save' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile cd /', + check: { + input: 'tsfile cd /', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: '/', + arg: ' /', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile cd /zxcv', + check: { + input: 'tsfile cd /zxcv', + // hints: ' -> /dev/', + markup: 'VVVVVVVVVVIIIII', + cursor: 15, + current: 'p1', + status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: undefined, + arg: ' /zxcv', + status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: true || !local, + setup: 'tsfile cd /etc/passwd', + check: { + input: 'tsfile cd /etc/passwd', + hints: ' -> /etc/pam.d/', + markup: 'VVVVVVVVVVIIIIIIIIIII', + cursor: 21, + current: 'p1', + status: 'ERROR', + message: '\'/etc/passwd\' is not a directory', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: undefined, + arg: ' /etc/passwd', + status: 'INCOMPLETE', + message: '\'/etc/passwd\' is not a directory' + } + } + } + }, + { + setup: 'tsfile mkdir /', + check: { + input: 'tsfile mkdir /', + hints: '', + markup: 'VVVVVVVVVVVVVI', + cursor: 14, + current: 'p1', + status: 'ERROR', + message: ''/' already exists', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' already exists' + } + } + } + }, + { + setup: 'tsfile mkdir /zxcv', + check: { + input: 'tsfile mkdir /zxcv', + // hints: ' -> /dev/', + markup: 'VVVVVVVVVVVVVVVVVV', + cursor: 18, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile mkdir /mach_kernel', + check: { + input: 'tsfile mkdir /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVIIIIIIIIIIII', + cursor: 25, + current: 'p1', + status: 'ERROR', + message: '\'/mach_kernel\' already exists', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: undefined, + arg: ' /mach_kernel', + status: 'INCOMPLETE', + message: '\'/mach_kernel\' already exists' + } + } + } + }, + { + setup: 'tsfile rm /', + check: { + input: 'tsfile rm /', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: '/', + arg: ' /', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile rm /zxcv', + check: { + input: 'tsfile rm /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVIIIII', + cursor: 15, + current: 'p1', + status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: undefined, + arg: ' /zxcv', + status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile rm /mach_kernel', + check: { + input: 'tsfile rm /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVV', + cursor: 22, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testFirefoxBasic = function(options) { + return helpers.audit(options, [ + { + // These tests are just like the ones above tailored for running in + // Firefox + skipRemainingIf: true, + // skipRemainingIf: !options.isFirefox, + skipIf: true, + setup: 'tsfile open /', + check: { + input: 'tsfile open /', + hints: '', + markup: 'VVVVVVVVVVVVI', + cursor: 13, + current: 'p1', + status: 'ERROR', + message: '\'/\' is not a file', + args: { + command: { name: 'tsfile open' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' is not a file' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile open /zxcv', + check: { + input: 'tsfile open /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVIIIII', + cursor: 17, + current: 'p1', + status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile open' }, + p1: { + value: undefined, + arg: ' /zxcv', + status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile open /mach_kernel', + check: { + input: 'tsfile open /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 24, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile open' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile saveas /', + check: { + input: 'tsfile saveas /', + hints: '', + markup: 'VVVVVVVVVVVVVVI', + cursor: 15, + current: 'p1', + status: 'ERROR', + message: '\'/\' already exists', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' already exists' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile saveas /zxcv', + check: { + input: 'tsfile saveas /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVVVVVVVV', + cursor: 19, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile saveas /mach_kernel', + check: { + input: 'tsfile saveas /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII', + cursor: 26, + current: 'p1', + status: 'ERROR', + message: '\'/mach_kernel\' already exists', + args: { + command: { name: 'tsfile saveas' }, + p1: { + value: undefined, + arg: ' /mach_kernel', + status: 'INCOMPLETE', + message: '\'/mach_kernel\' already exists' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile save /', + check: { + input: 'tsfile save /', + hints: '', + markup: 'VVVVVVVVVVVVI', + cursor: 13, + current: 'p1', + status: 'ERROR', + message: '\'/\' is not a file', + args: { + command: { name: 'tsfile save' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' is not a file' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile save /zxcv', + check: { + input: 'tsfile save /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile save' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile save /mach_kernel', + check: { + input: 'tsfile save /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 24, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile save' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile cd /', + check: { + input: 'tsfile cd /', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: '/', + arg: ' /', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsfile cd /zxcv', + check: { + input: 'tsfile cd /zxcv', + // hints: ' -> /dev/', + // markup: 'VVVVVVVVVVIIIII', + cursor: 15, + current: 'p1', + // status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: undefined, + arg: ' /zxcv', + // status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: true || !local, + setup: 'tsfile cd /etc/passwd', + check: { + input: 'tsfile cd /etc/passwd', + hints: ' -> /etc/pam.d/', + markup: 'VVVVVVVVVVIIIIIIIIIII', + cursor: 21, + current: 'p1', + status: 'ERROR', + message: '\'/etc/passwd\' is not a directory', + args: { + command: { name: 'tsfile cd' }, + p1: { + value: undefined, + arg: ' /etc/passwd', + status: 'INCOMPLETE', + message: '\'/etc/passwd\' is not a directory' + } + } + } + }, + { + setup: 'tsfile mkdir /', + check: { + input: 'tsfile mkdir /', + hints: '', + markup: 'VVVVVVVVVVVVVI', + cursor: 14, + current: 'p1', + status: 'ERROR', + message: ''/' already exists', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: undefined, + arg: ' /', + status: 'INCOMPLETE', + message: '\'/\' already exists' + } + } + } + }, + { + setup: 'tsfile mkdir /zxcv', + check: { + input: 'tsfile mkdir /zxcv', + // hints: ' -> /dev/', + markup: 'VVVVVVVVVVVVVVVVVV', + cursor: 18, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: '/zxcv', + arg: ' /zxcv', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile mkdir /mach_kernel', + check: { + input: 'tsfile mkdir /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVIIIIIIIIIIII', + cursor: 25, + current: 'p1', + status: 'ERROR', + message: '\'/mach_kernel\' already exists', + args: { + command: { name: 'tsfile mkdir' }, + p1: { + value: undefined, + arg: ' /mach_kernel', + status: 'INCOMPLETE', + message: '\'/mach_kernel\' already exists' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile rm /', + check: { + input: 'tsfile rm /', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: '/', + arg: ' /', + status: 'VALID', + message: '' + } + } + } + }, + { + skipIf: true, + setup: 'tsfile rm /zxcv', + check: { + input: 'tsfile rm /zxcv', + // hints: ' -> /etc/', + markup: 'VVVVVVVVVVIIIII', + cursor: 15, + current: 'p1', + status: 'ERROR', + message: '\'/zxcv\' doesn\'t exist', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: undefined, + arg: ' /zxcv', + status: 'INCOMPLETE', + message: '\'/zxcv\' doesn\'t exist' + } + } + } + }, + { + skipIf: !local, + setup: 'tsfile rm /mach_kernel', + check: { + input: 'tsfile rm /mach_kernel', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVV', + cursor: 22, + current: 'p1', + status: 'VALID', + message: '', + args: { + command: { name: 'tsfile rm' }, + p1: { + value: '/mach_kernel', + arg: ' /mach_kernel', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_fileparser.js b/toolkit/devtools/commandline/test/browser_gcli_fileparser.js new file mode 100644 index 000000000..219b793a9 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_fileparser.js @@ -0,0 +1,61 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFileparser.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var fileparser = require('gcli/util/fileparser'); + +var local = false; + +exports.testGetPredictor = function(options) { + if (!options.isNode || !local) { + assert.log('Skipping tests due to install differences.'); + return; + } + + var opts = { filetype: 'file', existing: 'yes' }; + var predictor = fileparser.getPredictor('/usr/locl/bin/nmp', opts); + return predictor().then(function(replies) { + assert.is(replies[0].name, + '/usr/local/bin/npm', + 'predict npm'); + }); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_filesystem.js b/toolkit/devtools/commandline/test/browser_gcli_filesystem.js new file mode 100644 index 000000000..23c8dda28 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_filesystem.js @@ -0,0 +1,81 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFilesystem.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var filesystem = require('gcli/util/filesystem'); + +exports.testSplit = function(options) { + if (!options.isNode) { + return; + } + + helpers.arrayIs(filesystem.split('', '/'), + [ '.' ], + 'split <blank>'); + + helpers.arrayIs(filesystem.split('a', '/'), + [ 'a' ], + 'split a'); + + helpers.arrayIs(filesystem.split('a/b/c', '/'), + [ 'a', 'b', 'c' ], + 'split a/b/c'); + + helpers.arrayIs(filesystem.split('/a/b/c/', '/'), + [ 'a', 'b', 'c' ], + 'split a/b/c'); + + helpers.arrayIs(filesystem.split('/a/b///c/', '/'), + [ 'a', 'b', 'c' ], + 'split a/b/c'); +}; + +exports.testJoin = function(options) { + if (!options.isNode) { + return; + } + + assert.is(filesystem.join('usr', 'local', 'bin'), + 'usr/local/bin', + 'join to usr/local/bin'); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_focus.js b/toolkit/devtools/commandline/test/browser_gcli_focus.js new file mode 100644 index 000000000..48def8195 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_focus.js @@ -0,0 +1,82 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFocus.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + name: 'exec setup', + setup: function() { + // Just check that we've got focus, and everything is clear + helpers.focusInput(options); + return helpers.setInput(options, 'echo hi'); + }, + check: { }, + exec: { } + }, + { + setup: 'tsn deep', + check: { + input: 'tsn deep', + hints: ' down nested cmd', + markup: 'IIIVIIII', + cursor: 8, + status: 'ERROR', + outputState: 'false:default', + tooltipState: 'false:default' + } + }, + { + setup: 'tsn deep<TAB>', + check: { + input: 'tsn deep down nested cmd ', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV', + cursor: 25, + status: 'VALID', + outputState: 'false:default', + tooltipState: 'false:default' + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_history.js b/toolkit/devtools/commandline/test/browser_gcli_history.js new file mode 100644 index 000000000..590353cbe --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_history.js @@ -0,0 +1,87 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testHistory.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var History = require('gcli/ui/history').History; + +exports.testSimpleHistory = function (options) { + var history = new History({}); + history.add('foo'); + history.add('bar'); + assert.is(history.backward(), 'bar'); + assert.is(history.backward(), 'foo'); + + // Adding to the history again moves us back to the start of the history. + history.add('quux'); + assert.is(history.backward(), 'quux'); + assert.is(history.backward(), 'bar'); + assert.is(history.backward(), 'foo'); +}; + +exports.testBackwardsPastIndex = function (options) { + var history = new History({}); + history.add('foo'); + history.add('bar'); + assert.is(history.backward(), 'bar'); + assert.is(history.backward(), 'foo'); + + // Moving backwards past recorded history just keeps giving you the last + // item. + assert.is(history.backward(), 'foo'); +}; + +exports.testForwardsPastIndex = function (options) { + var history = new History({}); + history.add('foo'); + history.add('bar'); + assert.is(history.backward(), 'bar'); + assert.is(history.backward(), 'foo'); + + // Going forward through the history again. + assert.is(history.forward(), 'bar'); + + // 'Present' time. + assert.is(history.forward(), ''); + + // Going to the 'future' just keeps giving us the empty string. + assert.is(history.forward(), ''); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_incomplete.js b/toolkit/devtools/commandline/test/browser_gcli_incomplete.js new file mode 100644 index 000000000..c443bbd49 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_incomplete.js @@ -0,0 +1,454 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testIncomplete.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + setup: 'tsu 2 extra', + check: { + args: { + num: { value: 2, type: 'Argument' } + } + }, + post: function() { + var requisition = options.requisition; + + assert.is(requisition._unassigned.length, + 1, + 'single unassigned: tsu 2 extra'); + assert.is(requisition._unassigned[0].param.type.isIncompleteName, + false, + 'unassigned.isIncompleteName: tsu 2 extra'); + } + }, + { + setup: 'tsu', + check: { + args: { + num: { value: undefined, type: 'BlankArgument' } + } + } + }, + { + setup: 'tsg', + check: { + args: { + solo: { type: 'BlankArgument' }, + txt1: { type: 'BlankArgument' }, + bool: { type: 'BlankArgument' }, + txt2: { type: 'BlankArgument' }, + num: { type: 'BlankArgument' } + } + } + } + ]); +}; + +exports.testCompleted = function(options) { + return helpers.audit(options, [ + { + setup: 'tsela<TAB>', + check: { + args: { + command: { name: 'tselarr', type: 'Argument' }, + num: { type: 'BlankArgument' }, + arr: { type: 'ArrayArgument' } + } + } + }, + { + setup: 'tsn dif ', + check: { + input: 'tsn dif ', + hints: '<text>', + markup: 'VVVVVVVV', + cursor: 8, + status: 'ERROR', + args: { + command: { name: 'tsn dif', type: 'MergedArgument' }, + text: { type: 'BlankArgument', status: 'INCOMPLETE' } + } + } + }, + { + setup: 'tsn di<TAB>', + check: { + input: 'tsn dif ', + hints: '<text>', + markup: 'VVVVVVVV', + cursor: 8, + status: 'ERROR', + args: { + command: { name: 'tsn dif', type: 'Argument' }, + text: { type: 'BlankArgument', status: 'INCOMPLETE' } + } + } + }, + // The above 2 tests take different routes to 'tsn dif '. + // The results should be similar. The difference is in args.command.type. + { + setup: 'tsg -', + check: { + input: 'tsg -', + hints: '-txt1 <solo> [options]', + markup: 'VVVVI', + cursor: 5, + status: 'ERROR', + args: { + solo: { value: undefined, status: 'INCOMPLETE' }, + txt1: { value: undefined, status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + txt2: { value: undefined, status: 'VALID' }, + num: { value: undefined, status: 'VALID' } + } + } + }, + { + setup: 'tsg -<TAB>', + check: { + input: 'tsg --txt1 ', + hints: '<string> <solo> [options]', + markup: 'VVVVIIIIIIV', + cursor: 11, + status: 'ERROR', + args: { + solo: { value: undefined, status: 'INCOMPLETE' }, + txt1: { value: undefined, status: 'INCOMPLETE' }, + bool: { value: false, status: 'VALID' }, + txt2: { value: undefined, status: 'VALID' }, + num: { value: undefined, status: 'VALID' } + } + } + }, + { + setup: 'tsg --txt1 fred', + check: { + input: 'tsg --txt1 fred', + hints: ' <solo> [options]', + markup: 'VVVVVVVVVVVVVVV', + status: 'ERROR', + args: { + solo: { value: undefined, status: 'INCOMPLETE' }, + txt1: { value: 'fred', status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + txt2: { value: undefined, status: 'VALID' }, + num: { value: undefined, status: 'VALID' } + } + } + }, + { + setup: 'tscook key value --path path --', + check: { + input: 'tscook key value --path path --', + hints: 'domain [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVII', + status: 'ERROR', + args: { + key: { value: 'key', status: 'VALID' }, + value: { value: 'value', status: 'VALID' }, + path: { value: 'path', status: 'VALID' }, + domain: { value: undefined, status: 'VALID' }, + secure: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tscook key value --path path --domain domain --', + check: { + input: 'tscook key value --path path --domain domain --', + hints: 'secure [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVII', + status: 'ERROR', + args: { + key: { value: 'key', status: 'VALID' }, + value: { value: 'value', status: 'VALID' }, + path: { value: 'path', status: 'VALID' }, + domain: { value: 'domain', status: 'VALID' }, + secure: { value: false, status: 'VALID' } + } + } + } + ]); + +}; + +exports.testCase = function(options) { + return helpers.audit(options, [ + { + setup: 'tsg AA', + check: { + input: 'tsg AA', + hints: ' [options] -> aaa', + markup: 'VVVVII', + status: 'ERROR', + args: { + solo: { value: undefined, text: 'AA', status: 'INCOMPLETE' }, + txt1: { value: undefined, status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + txt2: { value: undefined, status: 'VALID' }, + num: { value: undefined, status: 'VALID' } + } + } + } + ]); +}; + +exports.testIncomplete = function(options) { + return helpers.audit(options, [ + { + setup: 'tsm a a -', + check: { + args: { + abc: { value: 'a', type: 'Argument' }, + txt: { value: 'a', type: 'Argument' }, + num: { value: undefined, arg: ' -', type: 'Argument', status: 'INCOMPLETE' } + } + } + }, + { + setup: 'tsg -', + check: { + args: { + solo: { type: 'BlankArgument' }, + txt1: { type: 'BlankArgument' }, + bool: { type: 'BlankArgument' }, + txt2: { type: 'BlankArgument' }, + num: { type: 'BlankArgument' } + } + }, + post: function() { + var requisition = options.requisition; + + assert.is(requisition._unassigned[0], + requisition.getAssignmentAt(5), + 'unassigned -'); + assert.is(requisition._unassigned.length, + 1, + 'single unassigned - tsg -'); + assert.is(requisition._unassigned[0].param.type.isIncompleteName, + true, + 'unassigned.isIncompleteName: tsg -'); + } + } + ]); +}; + +exports.testRepeated = function(options) { + return helpers.audit(options, [ + { + setup: 'tscook key value --path jjj --path kkk', + check: { + input: 'tscook key value --path jjj --path kkk', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVEEEEEEVEEE', + cursor: 38, + current: '__unassigned', + status: 'ERROR', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ' --path', ' kkk' ], + args: { + command: { name: 'tscook' }, + key: { + value: 'key', + arg: ' key', + status: 'VALID', + message: '' + }, + value: { + value: 'value', + arg: ' value', + status: 'VALID', + message: '' + }, + path: { + value: 'jjj', + arg: ' --path jjj', + status: 'VALID', + message: '' + }, + domain: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + secure: { + value: false, + arg: '', + status: 'VALID', + message: '' + }, + } + } + } + ]); +}; + +exports.testHidden = function(options) { + return helpers.audit(options, [ + { + setup: 'tshidde', + check: { + input: 'tshidde', + hints: ' -> tse', + status: 'ERROR' + } + }, + { + setup: 'tshidden', + check: { + input: 'tshidden', + hints: ' [options]', + markup: 'VVVVVVVV', + status: 'VALID', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --vis', + check: { + input: 'tshidden --vis', + hints: 'ible [options]', + markup: 'VVVVVVVVVIIIII', + status: 'ERROR', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --invisiblestrin', + check: { + input: 'tshidden --invisiblestrin', + hints: ' [options]', + markup: 'VVVVVVVVVEEEEEEEEEEEEEEEE', + status: 'ERROR', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --invisiblestring', + check: { + input: 'tshidden --invisiblestring', + hints: ' <string> [options]', + markup: 'VVVVVVVVVIIIIIIIIIIIIIIIII', + status: 'ERROR', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'INCOMPLETE' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --invisiblestring x', + check: { + input: 'tshidden --invisiblestring x', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: 'x', status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --invisibleboolea', + check: { + input: 'tshidden --invisibleboolea', + hints: ' [options]', + markup: 'VVVVVVVVVEEEEEEEEEEEEEEEEE', + status: 'ERROR', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --invisibleboolean', + check: { + input: 'tshidden --invisibleboolean', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + visible: { value: undefined, status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: true, status: 'VALID' } + } + } + }, + { + setup: 'tshidden --visible xxx', + check: { + input: 'tshidden --visible xxx', + markup: 'VVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + hints: '', + args: { + visible: { value: 'xxx', status: 'VALID' }, + invisiblestring: { value: undefined, status: 'VALID' }, + invisibleboolean: { value: false, status: 'VALID' } + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_inputter.js b/toolkit/devtools/commandline/test/browser_gcli_inputter.js new file mode 100644 index 000000000..e8d1c214a --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_inputter.js @@ -0,0 +1,112 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testInputter.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var KeyEvent = require('gcli/util/util').KeyEvent; + +var latestEvent; +var latestData; + +var outputted = function(ev) { + latestEvent = ev; + + ev.output.promise.then(function() { + latestData = ev.output.data; + }); +}; + + +exports.setup = function(options) { + options.requisition.commandOutputManager.onOutput.add(outputted); +}; + +exports.shutdown = function(options) { + options.requisition.commandOutputManager.onOutput.remove(outputted); +}; + +exports.testOutput = function(options) { + latestEvent = undefined; + latestData = undefined; + + var terminal = options.terminal; + if (!terminal) { + assert.log('Skipping testInputter.testOutput due to lack of terminal.'); + return; + } + + var focusManager = terminal.focusManager; + + terminal.setInput('tss'); + + var ev0 = { keyCode: KeyEvent.DOM_VK_RETURN }; + terminal.onKeyDown(ev0); + + assert.is(terminal.getInputState().typed, + 'tss', + 'terminal should do nothing on RETURN keyDown'); + assert.is(latestEvent, undefined, 'no events this test'); + assert.is(latestData, undefined, 'no data this test'); + + var ev1 = { keyCode: KeyEvent.DOM_VK_RETURN }; + return terminal.handleKeyUp(ev1).then(function() { + assert.ok(latestEvent != null, 'events this test'); + assert.is(latestData, 'Exec: tss ', 'last command is tss'); + + assert.is(terminal.getInputState().typed, + '', + 'terminal should exec on RETURN keyUp'); + + assert.ok(focusManager._recentOutput, 'recent output happened'); + + var ev2 = { keyCode: KeyEvent.DOM_VK_F1 }; + return terminal.handleKeyUp(ev2).then(function() { + assert.ok(!focusManager._recentOutput, 'no recent output happened post F1'); + assert.ok(focusManager._helpRequested, 'F1 = help'); + + var ev3 = { keyCode: KeyEvent.DOM_VK_ESCAPE }; + return terminal.handleKeyUp(ev3).then(function() { + assert.ok(!focusManager._helpRequested, 'ESCAPE = anti help'); + }); + }); + + }); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_intro.js b/toolkit/devtools/commandline/test/browser_gcli_intro.js new file mode 100644 index 000000000..263000e89 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_intro.js @@ -0,0 +1,87 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testIntro.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testIntroStatus = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: function commandIntroMissing() { + return options.requisition.system.commands.get('intro') == null; + }, + setup: 'intro', + check: { + typed: 'intro', + markup: 'VVVVV', + status: 'VALID', + hints: '' + } + }, + { + setup: 'intro foo', + check: { + typed: 'intro foo', + markup: 'VVVVVVEEE', + status: 'ERROR', + hints: '' + } + }, + { + setup: 'intro', + skipIf: options.isNoDom, + check: { + typed: 'intro', + markup: 'VVVVV', + status: 'VALID', + hints: '' + }, + exec: { + output: [ + /command\s*line/, + /help/, + /F1/, + /Escape/ + ] + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_js.js b/toolkit/devtools/commandline/test/browser_gcli_js.js new file mode 100644 index 000000000..4128c4642 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_js.js @@ -0,0 +1,592 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testJs.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var javascript = require('gcli/types/javascript'); + +var tempWindow; + +exports.setup = function(options) { + if (options.isNoDom) { + return; + } + + tempWindow = javascript.getGlobalObject(); + Object.defineProperty(options.window, 'donteval', { + get: function() { + assert.ok(false, 'donteval should not be used'); + return { cant: '', touch: '', 'this': '' }; + }, + enumerable: true, + configurable : true + }); + javascript.setGlobalObject(options.window); +}; + +exports.shutdown = function(options) { + if (options.isNoDom) { + return; + } + + javascript.setGlobalObject(tempWindow); + tempWindow = undefined; + delete options.window.donteval; +}; + +function jsTestAllowed(options) { + return options.isRemote || options.isNoDom || + options.requisition.system.commands.get('{') == null; +} + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: jsTestAllowed, + setup: '{', + check: { + input: '{', + hints: '', + markup: 'V', + cursor: 1, + current: 'javascript', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: undefined, + arg: '{', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ ', + check: { + input: '{ ', + hints: '', + markup: 'VV', + cursor: 2, + current: 'javascript', + status: 'ERROR', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: undefined, + arg: '{ ', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ w', + check: { + input: '{ w', + hints: 'indow', + markup: 'VVI', + cursor: 3, + current: 'javascript', + status: 'ERROR', + predictionsContains: [ 'window' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'w', + arg: '{ w', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ windo', + check: { + input: '{ windo', + hints: 'w', + markup: 'VVIIIII', + cursor: 7, + current: 'javascript', + status: 'ERROR', + predictions: [ 'window' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'windo', + arg: '{ windo', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ window', + check: { + input: '{ window', + hints: '', + markup: 'VVVVVVVV', + cursor: 8, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'window', + arg: '{ window', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: '{ window.do', + check: { + input: '{ window.do', + hints: 'cument', + markup: 'VVIIIIIIIII', + cursor: 11, + current: 'javascript', + status: 'ERROR', + predictionsContains: [ 'window.document' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'window.do', + arg: '{ window.do', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ window.document.title', + check: { + input: '{ window.document.title', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVV', + cursor: 23, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'window.document.title', + arg: '{ window.document.title', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testDocument = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: jsTestAllowed, + setup: '{ docu', + check: { + input: '{ docu', + hints: 'ment', + markup: 'VVIIII', + cursor: 6, + current: 'javascript', + status: 'ERROR', + predictions: [ 'document' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'docu', + arg: '{ docu', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ docu<TAB>', + check: { + input: '{ document', + hints: '', + markup: 'VVVVVVVVVV', + cursor: 10, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'document', + arg: '{ document', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: '{ document.titl', + check: { + input: '{ document.titl', + hints: 'e', + markup: 'VVIIIIIIIIIIIII', + cursor: 15, + current: 'javascript', + status: 'ERROR', + predictions: [ 'document.title' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'document.titl', + arg: '{ document.titl', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ document.titl<TAB>', + check: { + input: '{ document.title ', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'document.title', + arg: '{ document.title ', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: '{ document.title', + check: { + input: '{ document.title', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + cursor: 16, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'document.title', + arg: '{ document.title', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testDonteval = function(options) { + if (!options.isNoDom) { + // nodom causes an eval here, maybe that's node/v8? + assert.ok('donteval' in options.window, 'donteval exists'); + } + + return helpers.audit(options, [ + { + skipRemainingIf: jsTestAllowed, + setup: '{ don', + check: { + input: '{ don', + hints: 'teval', + markup: 'VVIII', + cursor: 5, + current: 'javascript', + status: 'ERROR', + predictions: [ 'donteval' ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'don', + arg: '{ don', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: '{ donteval', + check: { + input: '{ donteval', + hints: '', + markup: 'VVVVVVVVVV', + cursor: 10, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'donteval', + arg: '{ donteval', + status: 'VALID', + message: '' + } + } + } + }, + /* + // This is a controversial test - technically we can tell that it's an error + // because 'donteval.' is a syntax error, however donteval is unsafe so we + // are playing safe by bailing out early. It's enough of a corner case that + // I don't think it warrants fixing + { + setup: '{ donteval.', + check: { + input: '{ donteval.', + hints: '', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'donteval.', + arg: '{ donteval.', + status: 'VALID', + message: '' + } + } + } + }, + */ + { + setup: '{ donteval.cant', + check: { + input: '{ donteval.cant', + hints: '', + markup: 'VVVVVVVVVVVVVVV', + cursor: 15, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'donteval.cant', + arg: '{ donteval.cant', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: '{ donteval.xxx', + check: { + input: '{ donteval.xxx', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'javascript', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: '{' }, + javascript: { + value: 'donteval.xxx', + arg: '{ donteval.xxx', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testExec = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: jsTestAllowed, + setup: '{ 1+1', + check: { + input: '{ 1+1', + hints: '', + markup: 'VVVVV', + cursor: 5, + current: 'javascript', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + javascript: { + value: '1+1', + arg: '{ 1+1', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: '2', + type: 'number', + error: false + } + }, + { + setup: '{ 1+1 }', + check: { + input: '{ 1+1 }', + hints: '', + markup: 'VVVVVVV', + cursor: 7, + current: 'javascript', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + javascript: { + value: '1+1', + arg: '{ 1+1 }', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: '2', + type: 'number', + error: false + } + }, + { + setup: '{ "hello"', + check: { + input: '{ "hello"', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'javascript', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + javascript: { + value: '"hello"', + arg: '{ "hello"', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'hello', + type: 'string', + error: false + } + }, + { + setup: '{ "hello" + 1', + check: { + input: '{ "hello" + 1', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'javascript', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + javascript: { + value: '"hello" + 1', + arg: '{ "hello" + 1', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'hello1', + type: 'string', + error: false + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js new file mode 100644 index 000000000..0de779491 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js @@ -0,0 +1,104 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard1.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +var javascript = require('gcli/types/javascript'); +// var helpers = require('./helpers'); + +var tempWindow; + +exports.setup = function(options) { + tempWindow = javascript.getGlobalObject(); + javascript.setGlobalObject(options.window); +}; + +exports.shutdown = function(options) { + javascript.setGlobalObject(tempWindow); + tempWindow = undefined; +}; + +exports.testSimple = function(options) { + return helpers.audit(options, [ + { + setup: 'tsela<TAB>', + check: { input: 'tselarr ', cursor: 8 } + }, + { + setup: 'tsn di<TAB>', + check: { input: 'tsn dif ', cursor: 8 } + }, + { + setup: 'tsg a<TAB>', + check: { input: 'tsg aaa ', cursor: 8 } + } + ]); +}; + +exports.testScript = function(options) { + return helpers.audit(options, [ + { + skipIf: function commandJsMissing() { + return options.requisition.system.commands.get('{') == null; + }, + setup: '{ wind<TAB>', + check: { input: '{ window' } + }, + { + skipIf: function commandJsMissing() { + return options.requisition.system.commands.get('{') == null; + }, + setup: '{ window.docum<TAB>', + check: { input: '{ window.document' } + } + ]); +}; + +exports.testJsdom = function(options) { + return helpers.audit(options, [ + { + skipIf: function jsDomOrCommandJsMissing() { + return options.requisition.system.commands.get('{') == null; + }, + setup: '{ window.document.titl<TAB>', + check: { input: '{ window.document.title ' } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js new file mode 100644 index 000000000..7f510f08e --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js @@ -0,0 +1,136 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard2.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testIncr = function(options) { + return helpers.audit(options, [ + /* + // We currently refuse to increment/decrement things with a non-valid + // status which makes sense for many cases, and is a decent default. + // However in theory we could do better, these tests are there for then + { + setup: 'tsu -70<UP>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -7<UP>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -6<UP>', + check: { input: 'tsu -5' } + }, + */ + { + setup: 'tsu -5<UP>', + check: { input: 'tsu -3' } + }, + { + setup: 'tsu -4<UP>', + check: { input: 'tsu -3' } + }, + { + setup: 'tsu -3<UP>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu -2<UP>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu -1<UP>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu 0<UP>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 1<UP>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 2<UP>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 3<UP>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 4<UP>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 5<UP>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 6<UP>', + check: { input: 'tsu 9' } + }, + { + setup: 'tsu 7<UP>', + check: { input: 'tsu 9' } + }, + { + setup: 'tsu 8<UP>', + check: { input: 'tsu 9' } + }, + { + setup: 'tsu 9<UP>', + check: { input: 'tsu 10' } + }, + { + setup: 'tsu 10<UP>', + check: { input: 'tsu 10' } + } + /* + // See notes above + { + setup: 'tsu 100<UP>', + check: { input: 'tsu 10' } + } + */ + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js new file mode 100644 index 000000000..c1bfc15fc --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js @@ -0,0 +1,134 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard3.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testDecr = function(options) { + return helpers.audit(options, [ + /* + // See notes at top of testIncr in testKeyboard2.js + { + setup: 'tsu -70<DOWN>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -7<DOWN>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -6<DOWN>', + check: { input: 'tsu -5' } + }, + */ + { + setup: 'tsu -5<DOWN>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -4<DOWN>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -3<DOWN>', + check: { input: 'tsu -5' } + }, + { + setup: 'tsu -2<DOWN>', + check: { input: 'tsu -3' } + }, + { + setup: 'tsu -1<DOWN>', + check: { input: 'tsu -3' } + }, + { + setup: 'tsu 0<DOWN>', + check: { input: 'tsu -3' } + }, + { + setup: 'tsu 1<DOWN>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu 2<DOWN>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu 3<DOWN>', + check: { input: 'tsu 0' } + }, + { + setup: 'tsu 4<DOWN>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 5<DOWN>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 6<DOWN>', + check: { input: 'tsu 3' } + }, + { + setup: 'tsu 7<DOWN>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 8<DOWN>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 9<DOWN>', + check: { input: 'tsu 6' } + }, + { + setup: 'tsu 10<DOWN>', + check: { input: 'tsu 9' } + } + /* + // See notes at top of testIncr + { + setup: 'tsu 100<DOWN>', + check: { input: 'tsu 9' } + } + */ + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js new file mode 100644 index 000000000..5a358f481 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js @@ -0,0 +1,204 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard4.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testIncrFloat = function(options) { + return helpers.audit(options, [ + /* + // See notes at top of testIncr + { + setup: 'tsf -70<UP>', + check: { input: 'tsf -6.5' } + }, + */ + { + setup: 'tsf -6.5<UP>', + check: { input: 'tsf -6' } + }, + { + setup: 'tsf -6<UP>', + check: { input: 'tsf -4.5' } + }, + { + setup: 'tsf -4.5<UP>', + check: { input: 'tsf -3' } + }, + { + setup: 'tsf -4<UP>', + check: { input: 'tsf -3' } + }, + { + setup: 'tsf -3<UP>', + check: { input: 'tsf -1.5' } + }, + { + setup: 'tsf -1.5<UP>', + check: { input: 'tsf 0' } + }, + { + setup: 'tsf 0<UP>', + check: { input: 'tsf 1.5' } + }, + { + setup: 'tsf 1.5<UP>', + check: { input: 'tsf 3' } + }, + { + setup: 'tsf 2<UP>', + check: { input: 'tsf 3' } + }, + { + setup: 'tsf 3<UP>', + check: { input: 'tsf 4.5' } + }, + { + setup: 'tsf 5<UP>', + check: { input: 'tsf 6' } + } + /* + // See notes at top of testIncr + { + setup: 'tsf 100<UP>', + check: { input: 'tsf -6.5' } + } + */ + ]); +}; + +exports.testDecrFloat = function(options) { + return helpers.audit(options, [ + /* + // See notes at top of testIncr + { + setup: 'tsf -70<DOWN>', + check: { input: 'tsf 11.5' } + }, + */ + { + setup: 'tsf -6.5<DOWN>', + check: { input: 'tsf -6.5' } + }, + { + setup: 'tsf -6<DOWN>', + check: { input: 'tsf -6.5' } + }, + { + setup: 'tsf -4.5<DOWN>', + check: { input: 'tsf -6' } + }, + { + setup: 'tsf -4<DOWN>', + check: { input: 'tsf -4.5' } + }, + { + setup: 'tsf -3<DOWN>', + check: { input: 'tsf -4.5' } + }, + { + setup: 'tsf -1.5<DOWN>', + check: { input: 'tsf -3' } + }, + { + setup: 'tsf 0<DOWN>', + check: { input: 'tsf -1.5' } + }, + { + setup: 'tsf 1.5<DOWN>', + check: { input: 'tsf 0' } + }, + { + setup: 'tsf 2<DOWN>', + check: { input: 'tsf 1.5' } + }, + { + setup: 'tsf 3<DOWN>', + check: { input: 'tsf 1.5' } + }, + { + setup: 'tsf 5<DOWN>', + check: { input: 'tsf 4.5' } + } + /* + // See notes at top of testIncr + { + setup: 'tsf 100<DOWN>', + check: { input: 'tsf 11.5' } + } + */ + ]); +}; + +exports.testIncrSelection = function(options) { + /* + // Bug 829516: GCLI up/down navigation over selection is sometimes bizarre + return helpers.audit(options, [ + { + setup: 'tselarr <DOWN>', + check: { hints: '2' }, + exec: {} + }, + { + setup: 'tselarr <DOWN><DOWN>', + check: { hints: '3' }, + exec: {} + }, + { + setup: 'tselarr <DOWN><DOWN><DOWN>', + check: { hints: '1' }, + exec: {} + } + ]); + */ +}; + +exports.testDecrSelection = function(options) { + /* + // Bug 829516: GCLI up/down navigation over selection is sometimes bizarre + return helpers.audit(options, [ + { + setup: 'tselarr <UP>', + check: { hints: '3' } + } + ]); + */ +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js new file mode 100644 index 000000000..41e36a4b9 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js @@ -0,0 +1,72 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard5.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testCompleteDown = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn e<DOWN><DOWN><DOWN><DOWN><DOWN><TAB>', + check: { input: 'tsn exte ' } + }, + { + setup: 'tsn e<DOWN><DOWN><DOWN><DOWN><TAB>', + check: { input: 'tsn ext ' } + }, + { + setup: 'tsn e<DOWN><DOWN><DOWN><TAB>', + check: { input: 'tsn extend ' } + }, + { + setup: 'tsn e<DOWN><DOWN><TAB>', + check: { input: 'tsn exten ' } + }, + { + setup: 'tsn e<DOWN><TAB>', + check: { input: 'tsn exte ' } + }, + { + setup: 'tsn e<TAB>', + check: { input: 'tsn ext ' } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js new file mode 100644 index 000000000..d53a855b3 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js @@ -0,0 +1,80 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard6.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testCompleteUp = function(options) { + return helpers.audit(options, [ + { + setup: 'tsn e<UP><TAB>', + check: { input: 'tsn extend ' } + }, + { + setup: 'tsn e<UP><UP><TAB>', + check: { input: 'tsn exten ' } + }, + { + setup: 'tsn e<UP><UP><UP><TAB>', + check: { input: 'tsn exte ' } + }, + { + setup: 'tsn e<UP><UP><UP><UP><TAB>', + check: { input: 'tsn ext ' } + }, + { + setup: 'tsn e<UP><UP><UP><UP><UP><TAB>', + check: { input: 'tsn extend ' } + }, + { + setup: 'tsn e<UP><UP><UP><UP><UP><UP><TAB>', + check: { input: 'tsn exten ' } + }, + { + setup: 'tsn e<UP><UP><UP><UP><UP><UP><UP><TAB>', + check: { input: 'tsn exte ' } + }, + { + setup: 'tsn e<UP><UP><UP><UP><UP><UP><UP><UP><TAB>', + check: { input: 'tsn ext ' } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_menu.js b/toolkit/devtools/commandline/test/browser_gcli_menu.js new file mode 100644 index 000000000..8e3eb167f --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_menu.js @@ -0,0 +1,66 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testMenu.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testOptions = function(options) { + return helpers.audit(options, [ + { + setup: 'tslong', + check: { + input: 'tslong', + markup: 'VVVVVV', + status: 'ERROR', + hints: ' <msg> [options]', + args: { + msg: { value: undefined, status: 'INCOMPLETE' }, + num: { value: undefined, status: 'VALID' }, + sel: { value: undefined, status: 'VALID' }, + bool: { value: false, status: 'VALID' }, + bool2: { value: false, status: 'VALID' }, + sel2: { value: undefined, status: 'VALID' }, + num2: { value: undefined, status: 'VALID' } + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_node.js b/toolkit/devtools/commandline/test/browser_gcli_node.js new file mode 100644 index 000000000..7be07ba76 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_node.js @@ -0,0 +1,349 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testNode.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var nodetype = require('gcli/types/node'); + +exports.setup = function(options) { + if (options.window) { + nodetype.setDocument(options.window.document); + } +}; + +exports.shutdown = function(options) { + nodetype.unsetDocument(); +}; + +exports.testNode = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isNoDom, + setup: 'tse ', + check: { + input: 'tse ', + hints: '<node> [options]', + markup: 'VVVV', + cursor: 4, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { status: 'INCOMPLETE' }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + }, + { + setup: 'tse :', + check: { + input: 'tse :', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + arg: ' :', + status: 'ERROR', + message: 'Syntax error in CSS query' + }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + }, + { + setup: 'tse #', + check: { + input: 'tse #', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' #', + status: 'ERROR', + message: 'Syntax error in CSS query' + }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + }, + { + setup: 'tse .', + check: { + input: 'tse .', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' .', + status: 'ERROR', + message: 'Syntax error in CSS query' + }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + }, + { + setup: 'tse *', + check: { + input: 'tse *', + hints: ' [options]', + markup: 'VVVVE', + cursor: 5, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' *', + status: 'ERROR' + // message: 'Too many matches (128)' + }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + } + ]); +}; + +exports.testNodeDom = function(options) { + var requisition = options.requisition; + + return helpers.audit(options, [ + { + skipRemainingIf: options.isNoDom, + setup: 'tse :root', + check: { + input: 'tse :root', + hints: ' [options]', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'node', + status: 'VALID', + args: { + command: { name: 'tse' }, + node: { arg: ' :root', status: 'VALID' }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + }, + { + setup: 'tse :root ', + check: { + input: 'tse :root ', + hints: '[options]', + markup: 'VVVVVVVVVV', + cursor: 10, + current: 'node', + status: 'VALID', + args: { + command: { name: 'tse' }, + node: { arg: ' :root ', status: 'VALID' }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + }, + post: function() { + assert.is(requisition.getAssignment('node').value.tagName, + 'HTML', + 'root id'); + } + }, + { + setup: 'tse #gcli-nomatch', + check: { + input: 'tse #gcli-nomatch', + hints: ' [options]', + markup: 'VVVVIIIIIIIIIIIII', + cursor: 17, + current: 'node', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: ' #gcli-nomatch', + status: 'INCOMPLETE', + message: 'No matches' + }, + nodes: { status: 'VALID' }, + nodes2: { status: 'VALID' } + } + } + } + ]); +}; + +exports.testNodes = function(options) { + var requisition = options.requisition; + + return helpers.audit(options, [ + { + skipRemainingIf: options.isNoDom, + setup: 'tse :root --nodes *', + check: { + input: 'tse :root --nodes *', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVV', + current: 'nodes', + status: 'VALID', + args: { + command: { name: 'tse' }, + node: { arg: ' :root', status: 'VALID' }, + nodes: { arg: ' --nodes *', status: 'VALID' }, + nodes2: { status: 'VALID' } + } + }, + post: function() { + assert.is(requisition.getAssignment('node').value.tagName, + 'HTML', + '#gcli-input id'); + } + }, + { + setup: 'tse :root --nodes2 div', + check: { + input: 'tse :root --nodes2 div', + hints: ' [options]', + markup: 'VVVVVVVVVVVVVVVVVVVVVV', + cursor: 22, + current: 'nodes2', + status: 'VALID', + args: { + command: { name: 'tse' }, + node: { arg: ' :root', status: 'VALID' }, + nodes: { status: 'VALID' }, + nodes2: { arg: ' --nodes2 div', status: 'VALID' } + } + }, + post: function() { + assert.is(requisition.getAssignment('node').value.tagName, + 'HTML', + 'root id'); + } + }, + { + setup: 'tse --nodes ffff', + check: { + input: 'tse --nodes ffff', + hints: ' <node> [options]', + markup: 'VVVVIIIIIIIVIIII', + cursor: 16, + current: 'nodes', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + }, + nodes: { + value: undefined, + arg: ' --nodes ffff', + status: 'INCOMPLETE', + message: 'No matches' + }, + nodes2: { arg: '', status: 'VALID', message: '' } + } + }, + post: function() { + /* + assert.is(requisition.getAssignment('nodes2').value.constructor.name, + 'NodeList', + '#gcli-input id'); + */ + } + }, + { + setup: 'tse --nodes2 ffff', + check: { + input: 'tse --nodes2 ffff', + hints: ' <node> [options]', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'nodes2', + status: 'ERROR', + args: { + command: { name: 'tse' }, + node: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + }, + nodes: { arg: '', status: 'VALID', message: '' }, + nodes2: { arg: ' --nodes2 ffff', status: 'VALID', message: '' } + } + }, + post: function() { + /* + assert.is(requisition.getAssignment('nodes').value.constructor.name, + 'NodeList', + '#gcli-input id'); + assert.is(requisition.getAssignment('nodes2').value.constructor.name, + 'NodeList', + '#gcli-input id'); + */ + } + }, + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_pref1.js b/toolkit/devtools/commandline/test/browser_gcli_pref1.js new file mode 100644 index 000000000..ee9c51d5e --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_pref1.js @@ -0,0 +1,180 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testPref1.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testPrefShowStatus = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.requisition.system.commands.get('pref') == null, + setup: 'pref s', + check: { + typed: 'pref s', + hints: 'et', + markup: 'IIIIVI', + status: 'ERROR' + } + }, + { + setup: 'pref show', + check: { + typed: 'pref show', + hints: ' <setting>', + markup: 'VVVVVVVVV', + status: 'ERROR' + } + }, + { + setup: 'pref show ', + check: { + typed: 'pref show ', + hints: 'allowSet', + markup: 'VVVVVVVVVV', + status: 'ERROR' + } + }, + { + setup: 'pref show tempTBo', + check: { + typed: 'pref show tempTBo', + hints: 'ol', + markup: 'VVVVVVVVVVIIIIIII', + status: 'ERROR' + } + }, + { + setup: 'pref show tempTBool', + check: { + typed: 'pref show tempTBool', + markup: 'VVVVVVVVVVVVVVVVVVV', + status: 'VALID', + hints: '' + } + }, + { + setup: 'pref show tempTBool 4', + check: { + typed: 'pref show tempTBool 4', + markup: 'VVVVVVVVVVVVVVVVVVVVE', + status: 'ERROR', + hints: '' + } + }, + { + setup: 'pref show tempNumber 4', + check: { + typed: 'pref show tempNumber 4', + markup: 'VVVVVVVVVVVVVVVVVVVVVE', + status: 'ERROR', + hints: '' + } + } + ]); +}; + +exports.testPrefSetStatus = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.requisition.system.commands.get('pref') == null, + setup: 'pref s', + check: { + typed: 'pref s', + hints: 'et', + markup: 'IIIIVI', + status: 'ERROR' + } + }, + { + setup: 'pref set', + check: { + typed: 'pref set', + hints: ' <setting> <value>', + markup: 'VVVVVVVV', + status: 'ERROR' + } + }, + { + setup: 'pref xxx', + check: { + typed: 'pref xxx', + markup: 'IIIIVIII', + status: 'ERROR' + } + }, + { + setup: 'pref set ', + check: { + typed: 'pref set ', + hints: 'allowSet <value>', + markup: 'VVVVVVVVV', + status: 'ERROR' + } + }, + { + setup: 'pref set tempTBo', + check: { + typed: 'pref set tempTBo', + hints: 'ol <value>', + markup: 'VVVVVVVVVIIIIIII', + status: 'ERROR' + } + }, + { + setup: 'pref set tempTBool 4', + check: { + typed: 'pref set tempTBool 4', + markup: 'VVVVVVVVVVVVVVVVVVVE', + status: 'ERROR', + hints: '' + } + }, + { + setup: 'pref set tempNumber 4', + check: { + typed: 'pref set tempNumber 4', + markup: 'VVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + hints: '' + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_pref2.js b/toolkit/devtools/commandline/test/browser_gcli_pref2.js new file mode 100644 index 000000000..019283077 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_pref2.js @@ -0,0 +1,151 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testPref2.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); +var mockSettings = require('./mockSettings'); + +exports.testPrefExec = function(options) { + if (options.requisition.system.commands.get('pref') == null) { + assert.log('Skipping test; missing pref command.'); + return; + } + + if (options.isRemote) { + assert.log('Skipping test which assumes local settings.'); + return; + } + + var allowSet = settings.getSetting('allowSet'); + var initialAllowSet = allowSet.value; + allowSet.value = false; + + assert.is(mockSettings.tempNumber.value, 42, 'set to 42'); + + return helpers.audit(options, [ + { + // Delegated remote types can't transfer value types so we only test for + // the value of 'value' when we're local + skipIf: options.isRemote, + setup: 'pref set tempNumber 4', + check: { + setting: { value: mockSettings.tempNumber }, + args: { value: { value: 4 } } + } + }, + { + skipRemainingIf: options.isNoDom, + setup: 'pref set tempNumber 4', + check: { + input: 'pref set tempNumber 4', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVV', + cursor: 21, + current: 'value', + status: 'VALID', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'pref set' }, + setting: { + arg: ' tempNumber', + status: 'VALID', + message: '' + }, + value: { + arg: ' 4', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: [ /void your warranty/, /I promise/ ] + }, + post: function() { + assert.is(mockSettings.tempNumber.value, 42, 'still set to 42'); + allowSet.value = true; + } + }, + { + setup: 'pref set tempNumber 4', + exec: { + output: '' + }, + post: function() { + assert.is(mockSettings.tempNumber.value, 4, 'set to 4'); + } + }, + { + setup: 'pref reset tempNumber', + check: { + args: { + command: { name: 'pref reset' }, + setting: { value: mockSettings.tempNumber } + } + }, + exec: { + output: '' + }, + post: function() { + assert.is(mockSettings.tempNumber.value, 42, 'reset to 42'); + + allowSet.value = initialAllowSet; + } + }, + { + skipRemainingIf: function commandPrefListMissing() { + return options.requisition.system.commands.get('pref list') == null; + }, + setup: 'pref list tempNum', + check: { + args: { + command: { name: 'pref list' }, + search: { value: 'tempNum' } + } + }, + exec: { + output: /tempNum/ + } + }, + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_remotews.js b/toolkit/devtools/commandline/test/browser_gcli_remotews.js new file mode 100644 index 000000000..7b9237e19 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_remotews.js @@ -0,0 +1,500 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testRemoteWs.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +// testRemoteWs and testRemoteXhr are virtually identical. +// Changes made here should be made there too. +// They are kept separate to save adding complexity to the test system and so +// to help us select the test that are available in different environments + +exports.testRemoteWebsocket = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isRemote || options.isNode || options.isFirefox, + setup: 'remote ', + check: { + input: 'remote ', + hints: '', + markup: 'EEEEEEV', + cursor: 7, + current: '__command', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'remote\'.', + predictions: [ ], + unassigned: [ ], + } + }, + { + setup: 'connect remote', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + error: false + } + }, + { + setup: 'disconnect remote', + check: { + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + } + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'connect remote --method websocket', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + error: false + } + }, + { + setup: 'disconnect remote', + check: { + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + } + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'connect remote --method websocket', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + output: /^Added [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'remote ', + check: { + input: 'remote ', + // PhantomJS fails on this. Unsure why + // hints: ' {', + markup: 'IIIIIIV', + status: 'ERROR', + optionsIncludes: [ + 'remote', 'remote cd', 'remote context', 'remote echo', + 'remote exec', 'remote exit', 'remote firefox', 'remote help', + 'remote intro', 'remote make' + ], + message: '', + predictionsIncludes: [ 'remote' ], + unassigned: [ ], + } + }, + { + setup: 'remote echo hello world', + check: { + input: 'remote echo hello world', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVV', + cursor: 23, + current: 'message', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote echo' }, + message: { + value: 'hello world', + arg: ' hello world', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'hello world', + type: 'string', + error: false + } + }, + { + setup: 'remote exec ls', + check: { + input: 'remote exec ls', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { + value: 'ls', + arg: ' ls', + status: 'VALID', + message: '' + } + } + }, + exec: { + // output: '', We can't rely on the contents of the FS + type: 'output', + error: false + } + }, + { + setup: 'remote sleep mistake', + check: { + input: 'remote sleep mistake', + hints: '', + markup: 'VVVVVVVVVVVVVEEEEEEE', + cursor: 20, + current: 'length', + status: 'ERROR', + options: [ ], + message: 'Can\'t convert "mistake" to a number.', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote sleep' }, + length: { + value: undefined, + arg: ' mistake', + status: 'ERROR', + message: 'Can\'t convert "mistake" to a number.' + } + } + } + }, + { + setup: 'remote sleep 1', + check: { + input: 'remote sleep 1', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'length', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote sleep' }, + length: { value: 1, arg: ' 1', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Done', + type: 'string', + error: false + } + }, + { + setup: 'remote help ', + skipIf: true, // The help command is not remotable + check: { + input: 'remote help ', + hints: '[search]', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'search', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote help' }, + search: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: '', + type: 'string', + error: false + } + }, + { + setup: 'remote intro', + check: { + input: 'remote intro', + hints: '', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: '__command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote intro' } + } + }, + exec: { + output: [ + /GCLI is an experiment/, + /F1\/Escape/ + ], + type: 'intro', + error: false + } + }, + { + setup: 'context remote', + check: { + input: 'context remote', + // hints: ' {', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'prefix', + status: 'VALID', + optionsContains: [ + 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + 'remote firefox', 'remote help', 'remote intro', 'remote make' + ], + message: '', + // predictionsContains: [ + // 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + // 'remote firefox', 'remote help', 'remote intro', 'remote make', + // 'remote pref' + // ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { + arg: ' remote', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Using remote as a command prefix', + type: 'string', + error: false + } + }, + { + setup: 'exec ls', + check: { + input: 'exec ls', + hints: '', + markup: 'VVVVVVV', + cursor: 7, + current: 'command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { value: 'ls', arg: ' ls', status: 'VALID', message: '' }, + } + }, + exec: { + // output: '', We can't rely on the contents of the filesystem + type: 'output', + error: false + } + }, + { + setup: 'echo hello world', + check: { + input: 'echo hello world', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + cursor: 16, + current: 'message', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote echo' }, + message: { + value: 'hello world', + arg: ' hello world', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: /^hello world$/, + type: 'string', + error: false + } + }, + { + setup: 'context', + check: { + input: 'context', + hints: ' [prefix]', + markup: 'VVVVVVV', + cursor: 7, + current: '__command', + status: 'VALID', + optionsContains: [ + 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + 'remote firefox', 'remote help', 'remote intro', 'remote make' + ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { value: undefined, arg: '', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Command prefix is unset', + type: 'string', + error: false + } + }, + { + setup: 'disconnect ', + check: { + input: 'disconnect ', + hints: 'remote', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'prefix', + status: 'ERROR', + options: [ 'remote' ], + message: '', + predictions: [ 'remote' ], + unassigned: [ ], + args: { + command: { name: 'disconnect' }, + prefix: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'prefix\'.' + } + } + } + }, + { + setup: 'disconnect remote', + check: { + input: 'disconnect remote', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + unassigned: [ ], + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + }, + arg: ' remote', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'remote ', + check: { + input: 'remote ', + hints: '', + markup: 'EEEEEEV', + cursor: 7, + current: '__command', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'remote\'.', + predictions: [ ], + unassigned: [ ], + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js b/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js new file mode 100644 index 000000000..b89b9d52b --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js @@ -0,0 +1,500 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testRemoteXhr.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +// testRemoteWs and testRemoteXhr are virtually identical. +// Changes made here should be made there too. +// They are kept separate to save adding complexity to the test system and so +// to help us select the test that are available in different environments + +exports.testRemoteXhr = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isRemote || options.isNode || options.isFirefox, + setup: 'remote ', + check: { + input: 'remote ', + hints: '', + markup: 'EEEEEEV', + cursor: 7, + current: '__command', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'remote\'.', + predictions: [ ], + unassigned: [ ], + } + }, + { + setup: 'connect remote', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + error: false + } + }, + { + setup: 'disconnect remote', + check: { + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + } + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'connect remote --method xhr', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + error: false + } + }, + { + setup: 'disconnect remote', + check: { + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + } + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'connect remote --method xhr', + check: { + args: { + prefix: { value: 'remote' }, + url: { value: undefined } + } + }, + exec: { + output: /^Added [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'remote ', + check: { + input: 'remote ', + // PhantomJS fails on this. Unsure why + // hints: ' {', + markup: 'IIIIIIV', + status: 'ERROR', + optionsIncludes: [ + 'remote', 'remote cd', 'remote context', 'remote echo', + 'remote exec', 'remote exit', 'remote firefox', 'remote help', + 'remote intro', 'remote make' + ], + message: '', + predictionsIncludes: [ 'remote' ], + unassigned: [ ], + } + }, + { + setup: 'remote echo hello world', + check: { + input: 'remote echo hello world', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVV', + cursor: 23, + current: 'message', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote echo' }, + message: { + value: 'hello world', + arg: ' hello world', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'hello world', + type: 'string', + error: false + } + }, + { + setup: 'remote exec ls', + check: { + input: 'remote exec ls', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { + value: 'ls', + arg: ' ls', + status: 'VALID', + message: '' + } + } + }, + exec: { + // output: '', We can't rely on the contents of the FS + type: 'output', + error: false + } + }, + { + setup: 'remote sleep mistake', + check: { + input: 'remote sleep mistake', + hints: '', + markup: 'VVVVVVVVVVVVVEEEEEEE', + cursor: 20, + current: 'length', + status: 'ERROR', + options: [ ], + message: 'Can\'t convert "mistake" to a number.', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote sleep' }, + length: { + value: undefined, + arg: ' mistake', + status: 'ERROR', + message: 'Can\'t convert "mistake" to a number.' + } + } + } + }, + { + setup: 'remote sleep 1', + check: { + input: 'remote sleep 1', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'length', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote sleep' }, + length: { value: 1, arg: ' 1', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Done', + type: 'string', + error: false + } + }, + { + setup: 'remote help ', + skipIf: true, // The help command is not remotable + check: { + input: 'remote help ', + hints: '[search]', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: 'search', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote help' }, + search: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: '', + type: 'string', + error: false + } + }, + { + setup: 'remote intro', + check: { + input: 'remote intro', + hints: '', + markup: 'VVVVVVVVVVVV', + cursor: 12, + current: '__command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote intro' } + } + }, + exec: { + output: [ + /GCLI is an experiment/, + /F1\/Escape/ + ], + type: 'intro', + error: false + } + }, + { + setup: 'context remote', + check: { + input: 'context remote', + // hints: ' {', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'prefix', + status: 'VALID', + optionsContains: [ + 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + 'remote firefox', 'remote help', 'remote intro', 'remote make' + ], + message: '', + // predictionsContains: [ + // 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + // 'remote firefox', 'remote help', 'remote intro', 'remote make', + // 'remote pref' + // ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { + arg: ' remote', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: 'Using remote as a command prefix', + type: 'string', + error: false + } + }, + { + setup: 'exec ls', + check: { + input: 'exec ls', + hints: '', + markup: 'VVVVVVV', + cursor: 7, + current: 'command', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { value: 'ls', arg: ' ls', status: 'VALID', message: '' }, + } + }, + exec: { + // output: '', We can't rely on the contents of the filesystem + type: 'output', + error: false + } + }, + { + setup: 'echo hello world', + check: { + input: 'echo hello world', + hints: '', + markup: 'VVVVVVVVVVVVVVVV', + cursor: 16, + current: 'message', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'remote echo' }, + message: { + value: 'hello world', + arg: ' hello world', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: /^hello world$/, + type: 'string', + error: false + } + }, + { + setup: 'context', + check: { + input: 'context', + hints: ' [prefix]', + markup: 'VVVVVVV', + cursor: 7, + current: '__command', + status: 'VALID', + optionsContains: [ + 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit', + 'remote firefox', 'remote help', 'remote intro', 'remote make' + ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'context' }, + prefix: { value: undefined, arg: '', status: 'VALID', message: '' } + } + }, + exec: { + output: 'Command prefix is unset', + type: 'string', + error: false + } + }, + { + setup: 'disconnect ', + check: { + input: 'disconnect ', + hints: 'remote', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'prefix', + status: 'ERROR', + options: [ 'remote' ], + message: '', + predictions: [ 'remote' ], + unassigned: [ ], + args: { + command: { name: 'disconnect' }, + prefix: { + value: undefined, + arg: '', + status: 'INCOMPLETE', + message: 'Value required for \'prefix\'.' + } + } + } + }, + { + setup: 'disconnect remote', + check: { + input: 'disconnect remote', + hints: '', + markup: 'VVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + unassigned: [ ], + args: { + prefix: { + value: function(connection) { + assert.is(connection.prefix, 'remote', 'disconnecting remote'); + }, + arg: ' remote', + status: 'VALID', + message: '' + } + } + }, + exec: { + output: /^Removed [0-9]* commands.$/, + type: 'string', + error: false + } + }, + { + setup: 'remote ', + check: { + input: 'remote ', + hints: '', + markup: 'EEEEEEV', + cursor: 7, + current: '__command', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'remote\'.', + predictions: [ ], + unassigned: [ ], + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_resource.js b/toolkit/devtools/commandline/test/browser_gcli_resource.js new file mode 100644 index 000000000..2a23253f7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_resource.js @@ -0,0 +1,169 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testResource.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); + +var Promise = require('gcli/util/promise').Promise; +var util = require('gcli/util/util'); +var resource = require('gcli/types/resource'); +var Status = require('gcli/types/types').Status; + + +var tempDocument; + +exports.setup = function(options) { + tempDocument = resource.getDocument(); + if (options.window) { + resource.setDocument(options.window.document); + } +}; + +exports.shutdown = function(options) { + resource.setDocument(tempDocument); + tempDocument = undefined; +}; + +exports.testAllPredictions1 = function(options) { + if (options.isFirefox || options.isNoDom) { + assert.log('Skipping checks due to firefox document.stylsheets support.'); + return; + } + + var resource = options.requisition.system.types.createType('resource'); + return resource.getLookup().then(function(opts) { + assert.ok(opts.length > 1, 'have all resources'); + + return util.promiseEach(opts, function(prediction) { + return checkPrediction(resource, prediction); + }); + }); +}; + +exports.testScriptPredictions = function(options) { + if (options.isFirefox || options.isNoDom) { + assert.log('Skipping checks due to firefox document.stylsheets support.'); + return; + } + + var types = options.requisition.system.types; + var resource = types.createType({ name: 'resource', include: 'text/javascript' }); + return resource.getLookup().then(function(opts) { + assert.ok(opts.length > 1, 'have js resources'); + + return util.promiseEach(opts, function(prediction) { + return checkPrediction(resource, prediction); + }); + }); +}; + +exports.testStylePredictions = function(options) { + if (options.isFirefox || options.isNoDom) { + assert.log('Skipping checks due to firefox document.stylsheets support.'); + return; + } + + var types = options.requisition.system.types; + var resource = types.createType({ name: 'resource', include: 'text/css' }); + return resource.getLookup().then(function(opts) { + assert.ok(opts.length >= 1, 'have css resources'); + + return util.promiseEach(opts, function(prediction) { + return checkPrediction(resource, prediction); + }); + }); +}; + +exports.testAllPredictions2 = function(options) { + if (options.isNoDom) { + assert.log('Skipping checks due to nodom document.stylsheets support.'); + return; + } + var types = options.requisition.system.types; + + var scriptRes = types.createType({ name: 'resource', include: 'text/javascript' }); + return scriptRes.getLookup().then(function(scriptOptions) { + var styleRes = types.createType({ name: 'resource', include: 'text/css' }); + return styleRes.getLookup().then(function(styleOptions) { + var allRes = types.createType({ name: 'resource' }); + return allRes.getLookup().then(function(allOptions) { + assert.is(scriptOptions.length + styleOptions.length, + allOptions.length, + 'split'); + }); + }); + }); +}; + +exports.testAllPredictions3 = function(options) { + if (options.isNoDom) { + assert.log('Skipping checks due to nodom document.stylsheets support.'); + return; + } + + var types = options.requisition.system.types; + var res1 = types.createType({ name: 'resource' }); + return res1.getLookup().then(function(options1) { + var res2 = types.createType('resource'); + return res2.getLookup().then(function(options2) { + assert.is(options1.length, options2.length, 'type spec'); + }); + }); +}; + +function checkPrediction(res, prediction) { + var name = prediction.name; + var value = prediction.value; + + // resources don't need context so cheat and pass in null + var context = null; + return res.parseString(name, context).then(function(conversion) { + assert.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name); + assert.is(conversion.value, value, 'value for ' + name); + + assert.is(typeof value.loadContents, 'function', 'resource for ' + name); + assert.is(typeof value.element, 'object', 'resource for ' + name); + + return Promise.resolve(res.stringify(value, context)).then(function(strung) { + assert.is(strung, name, 'stringify for ' + name); + }); + }); +} diff --git a/toolkit/devtools/commandline/test/browser_gcli_short.js b/toolkit/devtools/commandline/test/browser_gcli_short.js new file mode 100644 index 000000000..812d6ef5e --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_short.js @@ -0,0 +1,263 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testShort.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testBasic = function(options) { + return helpers.audit(options, [ + { + setup: 'tshidden -v', + check: { + input: 'tshidden -v', + hints: ' <string>', + markup: 'VVVVVVVVVII', + cursor: 11, + current: 'visible', + status: 'ERROR', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tshidden' }, + visible: { + value: undefined, + arg: ' -v', + status: 'INCOMPLETE' + }, + invisiblestring: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: false, + arg: '', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tshidden -v v', + check: { + input: 'tshidden -v v', + hints: '', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'visible', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tshidden' }, + visible: { + value: 'v', + arg: ' -v v', + status: 'VALID', + message: '' + }, + invisiblestring: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: false, + arg: '', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tshidden -i i', + check: { + input: 'tshidden -i i', + hints: ' [options]', + markup: 'VVVVVVVVVVVVV', + cursor: 13, + current: 'invisiblestring', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tshidden' }, + visible: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisiblestring: { + value: 'i', + arg: ' -i i', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: false, + arg: '', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tshidden -b', + check: { + input: 'tshidden -b', + hints: ' [options]', + markup: 'VVVVVVVVVVV', + cursor: 11, + current: 'invisibleboolean', + status: 'VALID', + options: [ ], + message: '', + predictions: [ ], + unassigned: [ ], + args: { + command: { name: 'tshidden' }, + visible: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisiblestring: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: true, + arg: ' -b', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tshidden -j', + check: { + input: 'tshidden -j', + hints: ' [options]', + markup: 'VVVVVVVVVEE', + cursor: 11, + current: '__unassigned', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'-j\'.', + predictions: [ ], + unassigned: [ ' -j' ], + args: { + command: { name: 'tshidden' }, + visible: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisiblestring: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: false, + arg: '', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tshidden -v jj -b --', + check: { + input: 'tshidden -v jj -b --', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVEE', + cursor: 20, + current: '__unassigned', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'--\'.', + predictions: [ ], + unassigned: [ ' --' ], + args: { + command: { name: 'tshidden' }, + visible: { + value: 'jj', + arg: ' -v jj', + status: 'VALID', + message: '' + }, + invisiblestring: { + value: undefined, + arg: '', + status: 'VALID', + message: '' + }, + invisibleboolean: { + value: true, + arg: ' -b', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_spell.js b/toolkit/devtools/commandline/test/browser_gcli_spell.js new file mode 100644 index 000000000..bcd130fee --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_spell.js @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009 Panagiotis Astithas + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testSpell.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var spell = require('gcli/util/spell'); + +exports.testSpellerSimple = function(options) { + var alternatives = [ + 'window', 'document', 'InstallTrigger', 'requirejs', 'require','define', + 'console', 'location', 'constructor', 'getInterface', 'external', 'sidebar' + ]; + + assert.is(spell.correct('document', alternatives), 'document'); + assert.is(spell.correct('documen', alternatives), 'document'); + assert.is(spell.correct('ocument', alternatives), 'document'); + assert.is(spell.correct('odcument', alternatives), 'document'); + + assert.is(spell.correct('=========', alternatives), undefined); +}; + +exports.testRank = function(options) { + var distances = spell.rank('fred', [ 'banana', 'fred', 'ed', 'red', 'FRED' ]); + + assert.is(distances.length, 5, 'rank length'); + + assert.is(distances[0].name, 'fred', 'fred name #0'); + assert.is(distances[1].name, 'FRED', 'FRED name #1'); + assert.is(distances[2].name, 'red', 'red name #2'); + assert.is(distances[3].name, 'ed', 'ed name #3'); + assert.is(distances[4].name, 'banana', 'banana name #4'); + + assert.is(distances[0].dist, 0, 'fred dist 0'); + assert.is(distances[1].dist, 4, 'FRED dist 4'); + assert.is(distances[2].dist, 10, 'red dist 10'); + assert.is(distances[3].dist, 20, 'ed dist 20'); + assert.is(distances[4].dist, 100, 'banana dist 100'); +}; + +exports.testRank2 = function(options) { + var distances = spell.rank('caps', [ 'CAPS', 'false' ]); + assert.is(JSON.stringify(distances), + '[{"name":"CAPS","dist":4},{"name":"false","dist":50}]', + 'spell.rank("caps", [ "CAPS", "false" ]'); +}; + +exports.testDistancePrefix = function(options) { + assert.is(spell.distancePrefix('fred', 'freddy'), 0, 'distancePrefix fred'); + assert.is(spell.distancePrefix('FRED', 'freddy'), 4, 'distancePrefix FRED'); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_split.js b/toolkit/devtools/commandline/test/browser_gcli_split.js new file mode 100644 index 000000000..5e32cbfb8 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_split.js @@ -0,0 +1,82 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testSplit.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); + +var cli = require('gcli/cli'); + +exports.testSplitSimple = function(options) { + var args = cli.tokenize('s'); + options.requisition._split(args); + assert.is(args.length, 0); + assert.is(options.requisition.commandAssignment.arg.text, 's'); +}; + +exports.testFlatCommand = function(options) { + var args = cli.tokenize('tsv'); + options.requisition._split(args); + assert.is(args.length, 0); + assert.is(options.requisition.commandAssignment.value.name, 'tsv'); + + args = cli.tokenize('tsv a b'); + options.requisition._split(args); + assert.is(options.requisition.commandAssignment.value.name, 'tsv'); + assert.is(args.length, 2); + assert.is(args[0].text, 'a'); + assert.is(args[1].text, 'b'); +}; + +exports.testJavascript = function(options) { + if (!options.requisition.system.commands.get('{')) { + assert.log('Skipping testJavascript because { is not registered'); + return; + } + + var args = cli.tokenize('{'); + options.requisition._split(args); + assert.is(args.length, 1); + assert.is(args[0].text, ''); + assert.is(options.requisition.commandAssignment.arg.text, ''); + assert.is(options.requisition.commandAssignment.value.name, '{'); +}; + +// BUG 663081 - add tests for sub commands diff --git a/toolkit/devtools/commandline/test/browser_gcli_string.js b/toolkit/devtools/commandline/test/browser_gcli_string.js new file mode 100644 index 000000000..5f992dfdd --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_string.js @@ -0,0 +1,285 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testString.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var helpers = require('./helpers'); + +exports.testNewLine = function(options) { + return helpers.audit(options, [ + { + setup: 'echo a\\nb', + check: { + input: 'echo a\\nb', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'message', + status: 'VALID', + args: { + command: { name: 'echo' }, + message: { + value: 'a\nb', + arg: ' a\\nb', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testTab = function(options) { + return helpers.audit(options, [ + { + setup: 'echo a\\tb', + check: { + input: 'echo a\\tb', + hints: '', + markup: 'VVVVVVVVV', + cursor: 9, + current: 'message', + status: 'VALID', + args: { + command: { name: 'echo' }, + message: { + value: 'a\tb', + arg: ' a\\tb', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testEscape = function(options) { + return helpers.audit(options, [ + { + // What's typed is actually: + // tsrsrsr a\\ b c + setup: 'tsrsrsr a\\\\ b c', + check: { + input: 'tsrsrsr a\\\\ b c', + hints: '', + markup: 'VVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { value: 'a\\', arg: ' a\\\\', status: 'VALID', message: '' }, + p2: { value: 'b', arg: ' b', status: 'VALID', message: '' }, + p3: { value: 'c', arg: ' c', status: 'VALID', message: '' }, + } + } + }, + { + // What's typed is actually: + // tsrsrsr abc\\ndef asd asd + setup: 'tsrsrsr abc\\\\ndef asd asd', + check: { + input: 'tsrsrsr abc\\\\ndef asd asd', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { + value: 'abc\\ndef', + arg: ' abc\\\\ndef', + status: 'VALID', + message: '' + }, + p2: { value: 'asd', arg: ' asd', status: 'VALID', message: '' }, + p3: { value: 'asd', arg: ' asd', status: 'VALID', message: '' }, + } + } + } + ]); +}; + +exports.testBlank = function(options) { + return helpers.audit(options, [ + { + setup: 'tsrsrsr a "" c', + check: { + input: 'tsrsrsr a "" c', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'p3', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { + value: 'a', + arg: ' a', + status: 'VALID', + message: '' + }, + p2: { + value: undefined, + arg: ' ""', + status: 'INCOMPLETE' + }, + p3: { + value: 'c', + arg: ' c', + status: 'VALID', + message: '' + } + } + } + }, + { + setup: 'tsrsrsr a b ""', + check: { + input: 'tsrsrsr a b ""', + hints: '', + markup: 'VVVVVVVVVVVVVV', + cursor: 14, + current: 'p3', + status: 'VALID', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { + value: 'a', + arg: ' a', + status:'VALID', + message: '' }, + p2: { + value: 'b', + arg: ' b', + status: 'VALID', + message: '' + }, + p3: { + value: '', + arg: ' ""', + status: 'VALID', + message: '' + } + } + } + } + ]); +}; + +exports.testBlankWithParam = function(options) { + return helpers.audit(options, [ + { + setup: 'tsrsrsr a --p3', + check: { + input: 'tsrsrsr a --p3', + hints: ' <string> <p2>', + markup: 'VVVVVVVVVVVVVVV', + cursor: 15, + current: 'p3', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { value: 'a', arg: ' a', status: 'VALID', message: '' }, + p2: { value: undefined, arg: '', status: 'INCOMPLETE' }, + p3: { value: '', arg: ' --p3', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tsrsrsr a --p3 ', + check: { + input: 'tsrsrsr a --p3 ', + hints: '<string> <p2>', + markup: 'VVVVVVVVVVVVVVVV', + cursor: 16, + current: 'p3', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { value: 'a', arg: ' a', status: 'VALID', message: '' }, + p2: { value: undefined, arg: '', status: 'INCOMPLETE' }, + p3: { value: '', arg: ' --p3 ', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tsrsrsr a --p3 "', + check: { + input: 'tsrsrsr a --p3 "', + hints: ' <p2>', + markup: 'VVVVVVVVVVVVVVVVV', + cursor: 17, + current: 'p3', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { value: 'a', arg: ' a', status: 'VALID', message: '' }, + p2: { value: undefined, arg: '', status: 'INCOMPLETE' }, + p3: { value: '', arg: ' --p3 "', status: 'VALID', message: '' }, + } + } + }, + { + setup: 'tsrsrsr a --p3 ""', + check: { + input: 'tsrsrsr a --p3 ""', + hints: ' <p2>', + markup: 'VVVVVVVVVVVVVVVVVV', + cursor: 18, + current: 'p3', + status: 'ERROR', + message: '', + args: { + command: { name: 'tsrsrsr' }, + p1: { value: 'a', arg: ' a', status: 'VALID', message: '' }, + p2: { value: undefined, arg: '', status: 'INCOMPLETE' }, + p3: { value: '', arg: ' --p3 ""', status: 'VALID', message: '' }, + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_tokenize.js b/toolkit/devtools/commandline/test/browser_gcli_tokenize.js new file mode 100644 index 000000000..dae64af84 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_tokenize.js @@ -0,0 +1,305 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTokenize.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var cli = require('gcli/cli'); + +exports.testBlanks = function(options) { + var args; + + args = cli.tokenize(''); + assert.is(args.length, 1); + assert.is(args[0].text, ''); + assert.is(args[0].prefix, ''); + assert.is(args[0].suffix, ''); + + args = cli.tokenize(' '); + assert.is(args.length, 1); + assert.is(args[0].text, ''); + assert.is(args[0].prefix, ' '); + assert.is(args[0].suffix, ''); +}; + +exports.testTokSimple = function(options) { + var args; + + args = cli.tokenize('s'); + assert.is(args.length, 1); + assert.is(args[0].text, 's'); + assert.is(args[0].prefix, ''); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'Argument'); + + args = cli.tokenize('s s'); + assert.is(args.length, 2); + assert.is(args[0].text, 's'); + assert.is(args[0].prefix, ''); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'Argument'); + assert.is(args[1].text, 's'); + assert.is(args[1].prefix, ' '); + assert.is(args[1].suffix, ''); + assert.is(args[1].type, 'Argument'); +}; + +exports.testJavascript = function(options) { + var args; + + args = cli.tokenize('{x}'); + assert.is(args.length, 1); + assert.is(args[0].text, 'x'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{ x }'); + assert.is(args.length, 1); + assert.is(args[0].text, 'x'); + assert.is(args[0].prefix, '{ '); + assert.is(args[0].suffix, ' }'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{x} {y}'); + assert.is(args.length, 2); + assert.is(args[0].text, 'x'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + assert.is(args[1].text, 'y'); + assert.is(args[1].prefix, ' {'); + assert.is(args[1].suffix, '}'); + assert.is(args[1].type, 'ScriptArgument'); + + args = cli.tokenize('{x}{y}'); + assert.is(args.length, 2); + assert.is(args[0].text, 'x'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + assert.is(args[1].text, 'y'); + assert.is(args[1].prefix, '{'); + assert.is(args[1].suffix, '}'); + assert.is(args[1].type, 'ScriptArgument'); + + args = cli.tokenize('{'); + assert.is(args.length, 1); + assert.is(args[0].text, ''); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{ '); + assert.is(args.length, 1); + assert.is(args[0].text, ''); + assert.is(args[0].prefix, '{ '); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{x'); + assert.is(args.length, 1); + assert.is(args[0].text, 'x'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'ScriptArgument'); +}; + +exports.testRegularNesting = function(options) { + var args; + + args = cli.tokenize('{"x"}'); + assert.is(args.length, 1); + assert.is(args[0].text, '"x"'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{\'x\'}'); + assert.is(args.length, 1); + assert.is(args[0].text, '\'x\''); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('"{x}"'); + assert.is(args.length, 1); + assert.is(args[0].text, '{x}'); + assert.is(args[0].prefix, '"'); + assert.is(args[0].suffix, '"'); + assert.is(args[0].type, 'Argument'); + + args = cli.tokenize('\'{x}\''); + assert.is(args.length, 1); + assert.is(args[0].text, '{x}'); + assert.is(args[0].prefix, '\''); + assert.is(args[0].suffix, '\''); + assert.is(args[0].type, 'Argument'); +}; + +exports.testDeepNesting = function(options) { + var args; + + args = cli.tokenize('{{}}'); + assert.is(args.length, 1); + assert.is(args[0].text, '{}'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{{x} {y}}'); + assert.is(args.length, 1); + assert.is(args[0].text, '{x} {y}'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + args = cli.tokenize('{{w} {{{x}}}} {y} {{{z}}}'); + + assert.is(args.length, 3); + + assert.is(args[0].text, '{w} {{{x}}}'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + assert.is(args[1].text, 'y'); + assert.is(args[1].prefix, ' {'); + assert.is(args[1].suffix, '}'); + assert.is(args[1].type, 'ScriptArgument'); + + assert.is(args[2].text, '{{z}}'); + assert.is(args[2].prefix, ' {'); + assert.is(args[2].suffix, '}'); + assert.is(args[2].type, 'ScriptArgument'); + + args = cli.tokenize('{{w} {{{x}}} {y} {{{z}}}'); + + assert.is(args.length, 1); + + assert.is(args[0].text, '{w} {{{x}}} {y} {{{z}}}'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'ScriptArgument'); +}; + +exports.testStrangeNesting = function(options) { + var args; + + // Note: When we get real JS parsing this should break + args = cli.tokenize('{"x}"}'); + + assert.is(args.length, 2); + + assert.is(args[0].text, '"x'); + assert.is(args[0].prefix, '{'); + assert.is(args[0].suffix, '}'); + assert.is(args[0].type, 'ScriptArgument'); + + assert.is(args[1].text, '}'); + assert.is(args[1].prefix, '"'); + assert.is(args[1].suffix, ''); + assert.is(args[1].type, 'Argument'); +}; + +exports.testComplex = function(options) { + var args; + + args = cli.tokenize(' 1234 \'12 34\''); + + assert.is(args.length, 2); + + assert.is(args[0].text, '1234'); + assert.is(args[0].prefix, ' '); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'Argument'); + + assert.is(args[1].text, '12 34'); + assert.is(args[1].prefix, ' \''); + assert.is(args[1].suffix, '\''); + assert.is(args[1].type, 'Argument'); + + args = cli.tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \ + + assert.is(args.length, 3); + + assert.is(args[0].text, '12\'34'); + assert.is(args[0].prefix, ''); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'Argument'); + + assert.is(args[1].text, '12 34'); + assert.is(args[1].prefix, ' "'); + assert.is(args[1].suffix, '"'); + assert.is(args[1].type, 'Argument'); + + assert.is(args[2].text, '\\'); + assert.is(args[2].prefix, ' '); + assert.is(args[2].suffix, ''); + assert.is(args[2].type, 'Argument'); +}; + +exports.testPathological = function(options) { + var args; + + args = cli.tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd + + assert.is(args.length, 4); + + assert.is(args[0].text, 'a\\ b'); + assert.is(args[0].prefix, ''); + assert.is(args[0].suffix, ''); + assert.is(args[0].type, 'Argument'); + + assert.is(args[1].text, '\\t\\n\\r'); + assert.is(args[1].prefix, ' '); + assert.is(args[1].suffix, ''); + assert.is(args[1].type, 'Argument'); + + assert.is(args[2].text, '\\\'x\\"'); + assert.is(args[2].prefix, ' '); + assert.is(args[2].suffix, ''); + assert.is(args[2].type, 'Argument'); + + assert.is(args[3].text, 'd'); + assert.is(args[3].prefix, ' \''); + assert.is(args[3].suffix, ''); + assert.is(args[3].type, 'Argument'); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_tooltip.js b/toolkit/devtools/commandline/test/browser_gcli_tooltip.js new file mode 100644 index 000000000..10aa558d7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_tooltip.js @@ -0,0 +1,152 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTooltip.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testActivate = function(options) { + if (!options.display) { + assert.log('No display. Skipping activate tests'); + return; + } + + return helpers.audit(options, [ + { + setup: ' ', + check: { + input: ' ', + hints: '', + markup: 'V', + cursor: 1, + current: '__command', + status: 'ERROR', + message: '', + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'false:default' + } + }, + { + setup: 'tsb ', + check: { + input: 'tsb ', + hints: 'false', + markup: 'VVVV', + cursor: 4, + current: 'toggle', + status: 'VALID', + options: [ 'false', 'true' ], + message: '', + predictions: [ 'false', 'true' ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'true:importantFieldFlag' + } + }, + { + setup: 'tsb t', + check: { + input: 'tsb t', + hints: 'rue', + markup: 'VVVVI', + cursor: 5, + current: 'toggle', + status: 'ERROR', + options: [ 'true' ], + message: '', + predictions: [ 'true' ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'true:importantFieldFlag' + } + }, + { + setup: 'tsb tt', + check: { + input: 'tsb tt', + hints: ' -> true', + markup: 'VVVVII', + cursor: 6, + current: 'toggle', + status: 'ERROR', + options: [ 'true' ], + message: '', + predictions: [ 'true' ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'true:importantFieldFlag' + } + }, + { + setup: 'wxqy', + check: { + input: 'wxqy', + hints: '', + markup: 'EEEE', + cursor: 4, + current: '__command', + status: 'ERROR', + options: [ ], + message: 'Can\'t use \'wxqy\'.', + predictions: [ ], + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'true:isError' + } + }, + { + setup: '', + check: { + input: '', + hints: '', + markup: '', + cursor: 0, + current: '__command', + status: 'ERROR', + message: '', + unassigned: [ ], + outputState: 'false:default', + tooltipState: 'false:default' + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_types.js b/toolkit/devtools/commandline/test/browser_gcli_types.js new file mode 100644 index 000000000..01c11c39d --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_types.js @@ -0,0 +1,153 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTypes.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +var util = require('gcli/util/util'); +var Promise = require('gcli/util/promise').Promise; +var nodetype = require('gcli/types/node'); + +exports.setup = function(options) { + if (options.window) { + nodetype.setDocument(options.window.document); + } +}; + +exports.shutdown = function(options) { + nodetype.unsetDocument(); +}; + +function forEachType(options, typeSpec, callback) { + var types = options.requisition.system.types; + return util.promiseEach(types.getTypeNames(), function(name) { + typeSpec.name = name; + typeSpec.requisition = options.requisition; + + // Provide some basic defaults to help selection/delegate/array work + if (name === 'selection') { + typeSpec.data = [ 'a', 'b' ]; + } + else if (name === 'delegate') { + typeSpec.delegateType = function() { + return 'string'; + }; + } + else if (name === 'array') { + typeSpec.subtype = 'string'; + } + else if (name === 'remote') { + return; + } + else if (name === 'union') { + typeSpec.alternatives = [{ name: 'string' }]; + } + + var type = types.createType(typeSpec); + var reply = callback(type); + return Promise.resolve(reply).then(function(value) { + // Clean up + delete typeSpec.name; + delete typeSpec.requisition; + delete typeSpec.data; + delete typeSpec.delegateType; + delete typeSpec.subtype; + delete typeSpec.alternatives; + + return value; + }); + }); +} + +exports.testDefault = function(options) { + if (options.isNoDom) { + assert.log('Skipping tests due to issues with resource type.'); + return; + } + + return forEachType(options, {}, function(type) { + var context = options.requisition.executionContext; + var blank = type.getBlank(context).value; + + // boolean and array types are exempt from needing undefined blank values + if (type.name === 'boolean') { + assert.is(blank, false, 'blank boolean is false'); + } + else if (type.name === 'array') { + assert.ok(Array.isArray(blank), 'blank array is array'); + assert.is(blank.length, 0, 'blank array is empty'); + } + else if (type.name === 'nodelist') { + assert.ok(typeof blank.item, 'function', 'blank.item is function'); + assert.is(blank.length, 0, 'blank nodelist is empty'); + } + else { + assert.is(blank, undefined, 'default defined for ' + type.name); + } + }); +}; + +exports.testNullDefault = function(options) { + var context = null; // Is this test still valid with a null context? + + return forEachType(options, { defaultValue: null }, function(type) { + var reply = type.stringify(null, context); + return Promise.resolve(reply).then(function(str) { + assert.is(str, '', 'stringify(null) for ' + type.name); + }); + }); +}; + +exports.testGetSpec = function(options) { + return forEachType(options, {}, function(type) { + if (type.name === 'param') { + return; + } + + var spec = type.getSpec('cmd', 'param'); + assert.ok(spec != null, 'non null spec for ' + type.name); + + var str = JSON.stringify(spec); + assert.ok(str != null, 'serializable spec for ' + type.name); + + var example = options.requisition.system.types.createType(spec); + assert.ok(example != null, 'creatable spec for ' + type.name); + }); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_union.js b/toolkit/devtools/commandline/test/browser_gcli_union.js new file mode 100644 index 000000000..9f3dd08c1 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_union.js @@ -0,0 +1,188 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUnion.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testDefault = function(options) { + return helpers.audit(options, [ + { + setup: 'unionc1', + check: { + input: 'unionc1', + markup: 'VVVVVVV', + hints: ' <first>', + status: 'ERROR', + args: { + first: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: 'unionc1 three', + check: { + input: 'unionc1 three', + markup: 'VVVVVVVVVVVVV', + hints: '', + status: 'VALID', + args: { + first: { + value: function(data) { + assert.is(Object.keys(data).length, 2, 'union3 Object.keys'); + assert.is(data.type, 'string', 'union3 val type'); + assert.is(data.string, 'three', 'union3 val string'); + }, + arg: ' three', + status: 'VALID' + } + } + }, + exec: { + output: [ + /"type": ?"string"/, + /"string": ?"three"/ + ] + }, + post: function(output, text) { + var data = output.data.first; + assert.is(Object.keys(data).length, 2, 'union3 Object.keys'); + assert.is(data.type, 'string', 'union3 val type'); + assert.is(data.string, 'three', 'union3 val string'); + } + }, + { + setup: 'unionc1 one', + check: { + input: 'unionc1 one', + markup: 'VVVVVVVVVVV', + hints: '', + status: 'VALID', + args: { + first: { + value: function(data) { + assert.is(Object.keys(data).length, 2, 'union1 Object.keys'); + assert.is(data.type, 'selection', 'union1 val type'); + assert.is(data.selection, 1, 'union1 val selection'); + }, + arg: ' one', + status: 'VALID' + } + } + }, + exec: { + output: [ + /"type": ?"selection"/, + /"selection": ?1/ + ] + }, + post: function(output, text) { + var data = output.data.first; + assert.is(Object.keys(data).length, 2, 'union1 Object.keys'); + assert.is(data.type, 'selection', 'union1 val type'); + assert.is(data.selection, 1, 'union1 val selection'); + } + }, + { + skipIf: options.isPhantomjs, // Phantom goes weird with predictions + setup: 'unionc1 5', + check: { + input: 'unionc1 5', + markup: 'VVVVVVVVV', + hints: ' -> two', + predictions: [ 'two' ], + status: 'VALID', + args: { + first: { + value: function(data) { + assert.is(Object.keys(data).length, 2, 'union5 Object.keys'); + assert.is(data.type, 'number', 'union5 val type'); + assert.is(data.number, 5, 'union5 val number'); + }, + arg: ' 5', + status: 'VALID' + } + } + }, + exec: { + output: [ + /"type": ?"number"/, + /"number": ?5/ + ] + }, + post: function(output, text) { + var data = output.data.first; + assert.is(Object.keys(data).length, 2, 'union5 Object.keys'); + assert.is(data.type, 'number', 'union5 val type'); + assert.is(data.number, 5, 'union5 val number'); + } + }, + { + skipRemainingIf: options.isPhantomjs, + setup: 'unionc2 on', + check: { + input: 'unionc2 on', + hints: 'e', + markup: 'VVVVVVVVII', + current: 'first', + status: 'ERROR', + predictionsContains: [ + 'one', + 'http://on/', + 'https://on/' + ], + args: { + command: { name: 'unionc2' }, + first: { + value: undefined, + arg: ' on', + status: 'INCOMPLETE', + message: 'Can\'t use \'on\'.' + }, + } + } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/browser_gcli_url.js b/toolkit/devtools/commandline/test/browser_gcli_url.js new file mode 100644 index 000000000..1fec41eb7 --- /dev/null +++ b/toolkit/devtools/commandline/test/browser_gcli_url.js @@ -0,0 +1,122 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +var exports = {}; + +var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUrl.js</p>"; + +function test() { + return Task.spawn(function() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + gcli.addItems(mockCommands.items); + + yield helpers.runTests(options, exports); + + gcli.removeItems(mockCommands.items); + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +// <INJECTED SOURCE:END> + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testDefault = function(options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isPhantomjs, + setup: 'urlc', + check: { + input: 'urlc', + markup: 'VVVV', + hints: ' <url>', + status: 'ERROR', + args: { + url: { + value: undefined, + arg: '', + status: 'INCOMPLETE' + } + } + } + }, + { + setup: 'urlc example', + check: { + input: 'urlc example', + markup: 'VVVVVIIIIIII', + hints: ' -> http://example/', + predictions: [ + 'http://example/', + 'https://example/', + 'http://localhost:9999/example' + ], + status: 'ERROR', + args: { + url: { + value: undefined, + arg: ' example', + status: 'INCOMPLETE' + } + } + }, + }, + { + setup: 'urlc example.com/', + check: { + input: 'urlc example.com/', + markup: 'VVVVVIIIIIIIIIIII', + hints: ' -> http://example.com/', + status: 'ERROR', + args: { + url: { + value: undefined, + arg: ' example.com/', + status: 'INCOMPLETE' + } + } + }, + }, + { + setup: 'urlc http://example.com/index?q=a#hash', + check: { + input: 'urlc http://example.com/index?q=a#hash', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + hints: '', + status: 'VALID', + args: { + url: { + value: function(data) { + assert.is(data.hash, '#hash', 'url hash'); + }, + arg: ' http://example.com/index?q=a#hash', + status: 'VALID' + } + } + }, + exec: { output: /"url": ?/ } + } + ]); +}; diff --git a/toolkit/devtools/commandline/test/head.js b/toolkit/devtools/commandline/test/head.js new file mode 100644 index 000000000..36d6e356a --- /dev/null +++ b/toolkit/devtools/commandline/test/head.js @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/commandline/test/"; +const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/"; + +var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; +var console = require("resource://gre/modules/devtools/Console.jsm").console; + +// Import the GCLI test helper +let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/")); +Services.scriptloader.loadSubScript(testDir + "/helpers.js", this); +Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this); + +gDevTools.testing = true; +SimpleTest.registerCleanupFunction(() => { + gDevTools.testing = false; +}); + +function whenDelayedStartupFinished(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic) { + if (aWindow == aSubject) { + Services.obs.removeObserver(observer, aTopic); + executeSoon(aCallback); + } + }, "browser-delayed-startup-finished", false); +} + +/** + * Force GC on shutdown, because it seems that GCLI can outrun the garbage + * collector in some situations, which causes test failures in later tests + * Bug 774619 is an example. + */ +registerCleanupFunction(function tearDown() { + window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils) + .garbageCollect(); +}); diff --git a/toolkit/devtools/commandline/test/helpers.js b/toolkit/devtools/commandline/test/helpers.js new file mode 100644 index 000000000..dc33b183b --- /dev/null +++ b/toolkit/devtools/commandline/test/helpers.js @@ -0,0 +1,1274 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; + +// A copy of this code exists in firefox mochitests. They should be kept +// in sync. Hence the exports synonym for non AMD contexts. +var { helpers, gcli, assert } = (function() { + +var helpers = {}; + +var TargetFactory = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.TargetFactory; +var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; + +var assert = { ok: ok, is: is, log: info }; +var util = require('gcli/util/util'); +var Promise = require('gcli/util/promise').Promise; +var cli = require('gcli/cli'); +var KeyEvent = require('gcli/util/util').KeyEvent; +var gcli = require('gcli/index'); + +/** + * See notes in helpers.checkOptions() + */ +var createFFDisplayAutomator = function(display) { + var automator = { + setInput: function(typed) { + return display.inputter.setInput(typed); + }, + + setCursor: function(cursor) { + return display.inputter.setCursor(cursor); + }, + + focus: function() { + return display.inputter.focus(); + }, + + fakeKey: function(keyCode) { + var fakeEvent = { + keyCode: keyCode, + preventDefault: function() { }, + timeStamp: new Date().getTime() + }; + + display.inputter.onKeyDown(fakeEvent); + + if (keyCode === KeyEvent.DOM_VK_BACK_SPACE) { + var input = display.inputter.element; + input.value = input.value.slice(0, -1); + } + + return display.inputter.handleKeyUp(fakeEvent); + }, + + getInputState: function() { + return display.inputter.getInputState(); + }, + + getCompleterTemplateData: function() { + return display.completer._getCompleterTemplateData(); + }, + + getErrorMessage: function() { + return display.tooltip.errorEle.textContent; + } + }; + + Object.defineProperty(automator, 'focusManager', { + get: function() { return display.focusManager; }, + enumerable: true + }); + + Object.defineProperty(automator, 'field', { + get: function() { return display.tooltip.field; }, + enumerable: true + }); + + return automator; +}; + +/** + * Warning: For use with Firefox Mochitests only. + * + * Open a new tab at a URL and call a callback on load, and then tidy up when + * the callback finishes. + * The function will be passed a set of test options, and will usually return a + * promise to indicate that the tab can be cleared up. (To be formal, we call + * Promise.resolve() on the return value of the callback function) + * + * The options used by addTab include: + * - chromeWindow: XUL window parent of created tab. a.k.a 'window' in mochitest + * - tab: The new XUL tab element, as returned by gBrowser.addTab() + * - target: The debug target as defined by the devtools framework + * - browser: The XUL browser element for the given tab + * - window: Content window for the created tab. a.k.a 'content' in mochitest + * - isFirefox: Always true. Allows test sharing with GCLI + * + * Normally addTab will create an options object containing the values as + * described above. However these options can be customized by the third + * 'options' parameter. This has the ability to customize the value of + * chromeWindow or isFirefox, and to add new properties. + * + * @param url The URL for the new tab + * @param callback The function to call on page load + * @param options An optional set of options to customize the way the tests run + */ +helpers.addTab = function(url, callback, options) { + waitForExplicitFinish(); + + options = options || {}; + options.chromeWindow = options.chromeWindow || window; + options.isFirefox = true; + + var tabbrowser = options.chromeWindow.gBrowser; + options.tab = tabbrowser.addTab(); + tabbrowser.selectedTab = options.tab; + options.browser = tabbrowser.getBrowserForTab(options.tab); + options.target = TargetFactory.forTab(options.tab); + + var loaded = helpers.listenOnce(options.browser, "load", true).then(function(ev) { + options.document = options.browser.contentDocument; + options.window = options.document.defaultView; + + var reply = callback.call(null, options); + + return Promise.resolve(reply).then(null, function(error) { + ok(false, error); + }).then(function() { + tabbrowser.removeTab(options.tab); + + delete options.window; + delete options.document; + + delete options.target; + delete options.browser; + delete options.tab; + + delete options.chromeWindow; + delete options.isFirefox; + }); + }); + + options.browser.contentWindow.location = url; + return loaded; +}; + +/** + * Open a new tab + * @param url Address of the page to open + * @param options Object to which we add properties describing the new tab. The + * following properties are added: + * - chromeWindow + * - tab + * - browser + * - target + * - document + * - window + * @return A promise which resolves to the options object when the 'load' event + * happens on the new tab + */ +helpers.openTab = function(url, options) { + waitForExplicitFinish(); + + options = options || {}; + options.chromeWindow = options.chromeWindow || window; + options.isFirefox = true; + + var tabbrowser = options.chromeWindow.gBrowser; + options.tab = tabbrowser.addTab(); + tabbrowser.selectedTab = options.tab; + options.browser = tabbrowser.getBrowserForTab(options.tab); + options.target = TargetFactory.forTab(options.tab); + + return helpers.navigate(url, options); +}; + +/** + * Undo the effects of |helpers.openTab| + * @param options The options object passed to |helpers.openTab| + * @return A promise resolved (with undefined) when the tab is closed + */ +helpers.closeTab = function(options) { + options.chromeWindow.gBrowser.removeTab(options.tab); + + delete options.window; + delete options.document; + + delete options.target; + delete options.browser; + delete options.tab; + + delete options.chromeWindow; + delete options.isFirefox; + + return Promise.resolve(undefined); +}; + +/** + * Open the developer toolbar in a tab + * @param options Object to which we add properties describing the developer + * toolbar. The following properties are added: + * - automator + * - requisition + * @return A promise which resolves to the options object when the 'load' event + * happens on the new tab + */ +helpers.openToolbar = function(options) { + options = options || {}; + options.chromeWindow = options.chromeWindow || window; + + return options.chromeWindow.DeveloperToolbar.show(true).then(function() { + var display = options.chromeWindow.DeveloperToolbar.display; + options.automator = createFFDisplayAutomator(display); + options.requisition = display.requisition; + return options; + }); +}; + +/** + * Navigate the current tab to a URL + */ +helpers.navigate = function(url, options) { + options = options || {}; + options.chromeWindow = options.chromeWindow || window; + options.tab = options.tab || options.chromeWindow.gBrowser.selectedTab; + + var tabbrowser = options.chromeWindow.gBrowser; + options.browser = tabbrowser.getBrowserForTab(options.tab); + + var promise = helpers.listenOnce(options.browser, "load", true).then(function() { + options.document = options.browser.contentDocument; + options.window = options.document.defaultView; + return options; + }); + + options.browser.contentWindow.location = url; + + return promise; +}; + +/** + * Undo the effects of |helpers.openToolbar| + * @param options The options object passed to |helpers.openToolbar| + * @return A promise resolved (with undefined) when the toolbar is closed + */ +helpers.closeToolbar = function(options) { + return options.chromeWindow.DeveloperToolbar.hide().then(function() { + delete options.automator; + delete options.requisition; + }); +}; + +/** + * A helper to work with Task.spawn so you can do: + * return Task.spawn(realTestFunc).then(finish, helpers.handleError); + */ +helpers.handleError = function(ex) { + console.error(ex); + ok(false, ex); + finish(); +}; + +/** + * A helper for calling addEventListener and then removeEventListener as soon + * as the event is called, passing the results on as a promise + * @param element The DOM element to listen on + * @param event The name of the event to listen for + * @param useCapture Should we use the capturing phase? + * @return A promise resolved with the event object when the event first happens + */ +helpers.listenOnce = function(element, event, useCapture) { + return new Promise(function(resolve, reject) { + var onEvent = function(ev) { + element.removeEventListener(event, onEvent, useCapture); + resolve(ev); + }; + element.addEventListener(event, onEvent, useCapture); + }.bind(this)); +}; + +/** + * A wrapper for calling Services.obs.[add|remove]Observer using promises. + * @param topic The topic parameter to Services.obs.addObserver + * @param ownsWeak The ownsWeak parameter to Services.obs.addObserver with a + * default value of false + * @return a promise that resolves when the ObserverService first notifies us + * of the topic. The value of the promise is the first parameter to the observer + * function other parameters are dropped. + */ +helpers.observeOnce = function(topic, ownsWeak=false) { + return new Promise(function(resolve, reject) { + let resolver = function(subject) { + Services.obs.removeObserver(resolver, topic); + resolve(subject); + }; + Services.obs.addObserver(resolver, topic, ownsWeak); + }.bind(this)); +}; + +/** + * Takes a function that uses a callback as its last parameter, and returns a + * new function that returns a promise instead + */ +helpers.promiseify = function(functionWithLastParamCallback, scope) { + return function() { + let args = [].slice.call(arguments); + return new Promise(resolve => { + args.push((...results) => { + resolve(results.length > 1 ? results : results[0]); + }); + functionWithLastParamCallback.apply(scope, args); + }); + }; +}; + +/** + * Warning: For use with Firefox Mochitests only. + * + * As addTab, but that also opens the developer toolbar. In addition a new + * 'automator' property is added to the options object with the display from GCLI + * in the developer toolbar + */ +helpers.addTabWithToolbar = function(url, callback, options) { + return helpers.addTab(url, function(innerOptions) { + var win = innerOptions.chromeWindow; + + return win.DeveloperToolbar.show(true).then(function() { + var display = win.DeveloperToolbar.display; + innerOptions.automator = createFFDisplayAutomator(display); + innerOptions.requisition = display.requisition; + + var reply = callback.call(null, innerOptions); + + return Promise.resolve(reply).then(null, function(error) { + ok(false, error); + console.error(error); + }).then(function() { + win.DeveloperToolbar.hide().then(function() { + delete innerOptions.automator; + }); + }); + }); + }, options); +}; + +/** + * Warning: For use with Firefox Mochitests only. + * + * Run a set of test functions stored in the values of the 'exports' object + * functions stored under setup/shutdown will be run at the start/end of the + * sequence of tests. + * A test will be considered finished when its return value is resolved. + * @param options An object to be passed to the test functions + * @param tests An object containing named test functions + * @return a promise which will be resolved when all tests have been run and + * their return values resolved + */ +helpers.runTests = function(options, tests) { + var testNames = Object.keys(tests).filter(function(test) { + return test != "setup" && test != "shutdown"; + }); + + var recover = function(error) { + ok(false, error); + console.error(error); + }; + + info("SETUP"); + var setupDone = (tests.setup != null) ? + Promise.resolve(tests.setup(options)) : + Promise.resolve(); + + var testDone = setupDone.then(function() { + return util.promiseEach(testNames, function(testName) { + info(testName); + var action = tests[testName]; + + if (typeof action === "function") { + var reply = action.call(tests, options); + return Promise.resolve(reply); + } + else if (Array.isArray(action)) { + return helpers.audit(options, action); + } + + return Promise.reject("test action '" + testName + + "' is not a function or helpers.audit() object"); + }); + }, recover); + + return testDone.then(function() { + info("SHUTDOWN"); + return (tests.shutdown != null) ? + Promise.resolve(tests.shutdown(options)) : + Promise.resolve(); + }, recover); +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Ensure that the options object is setup correctly + * options should contain an automator object that looks like this: + * { + * getInputState: function() { ... }, + * setCursor: function(cursor) { ... }, + * getCompleterTemplateData: function() { ... }, + * focus: function() { ... }, + * getErrorMessage: function() { ... }, + * fakeKey: function(keyCode) { ... }, + * setInput: function(typed) { ... }, + * focusManager: ..., + * field: ..., + * } + */ +function checkOptions(options) { + if (options == null) { + console.trace(); + throw new Error('Missing options object'); + } + if (options.requisition == null) { + console.trace(); + throw new Error('options.requisition == null'); + } +} + +/** + * Various functions to return the actual state of the command line + */ +helpers._actual = { + input: function(options) { + return options.automator.getInputState().typed; + }, + + hints: function(options) { + return options.automator.getCompleterTemplateData().then(function(data) { + var emptyParams = data.emptyParameters.join(''); + return (data.directTabText + emptyParams + data.arrowTabText) + .replace(/\u00a0/g, ' ') + .replace(/\u21E5/, '->') + .replace(/ $/, ''); + }); + }, + + markup: function(options) { + var cursor = helpers._actual.cursor(options); + var statusMarkup = options.requisition.getInputStatusMarkup(cursor); + return statusMarkup.map(function(s) { + return new Array(s.string.length + 1).join(s.status.toString()[0]); + }).join(''); + }, + + cursor: function(options) { + return options.automator.getInputState().cursor.start; + }, + + current: function(options) { + var cursor = helpers._actual.cursor(options); + return options.requisition.getAssignmentAt(cursor).param.name; + }, + + status: function(options) { + return options.requisition.status.toString(); + }, + + predictions: function(options) { + var cursor = helpers._actual.cursor(options); + var assignment = options.requisition.getAssignmentAt(cursor); + var context = options.requisition.executionContext; + return assignment.getPredictions(context).then(function(predictions) { + return predictions.map(function(prediction) { + return prediction.name; + }); + }); + }, + + unassigned: function(options) { + return options.requisition._unassigned.map(function(assignment) { + return assignment.arg.toString(); + }.bind(this)); + }, + + outputState: function(options) { + var outputData = options.automator.focusManager._shouldShowOutput(); + return outputData.visible + ':' + outputData.reason; + }, + + tooltipState: function(options) { + var tooltipData = options.automator.focusManager._shouldShowTooltip(); + return tooltipData.visible + ':' + tooltipData.reason; + }, + + options: function(options) { + if (options.automator.field.menu == null) { + return []; + } + return options.automator.field.menu.items.map(function(item) { + return item.name.textContent ? item.name.textContent : item.name; + }); + }, + + message: function(options) { + return options.automator.getErrorMessage(); + } +}; + +function shouldOutputUnquoted(value) { + var type = typeof value; + return value == null || type === 'boolean' || type === 'number'; +} + +function outputArray(array) { + return (array.length === 0) ? + '[ ]' : + '[ \'' + array.join('\', \'') + '\' ]'; +} + +helpers._createDebugCheck = function(options) { + checkOptions(options); + var requisition = options.requisition; + var command = requisition.commandAssignment.value; + var cursor = helpers._actual.cursor(options); + var input = helpers._actual.input(options); + var padding = new Array(input.length + 1).join(' '); + + var hintsPromise = helpers._actual.hints(options); + var predictionsPromise = helpers._actual.predictions(options); + + return Promise.all([ hintsPromise, predictionsPromise ]).then(function(values) { + var hints = values[0]; + var predictions = values[1]; + var output = ''; + + output += 'return helpers.audit(options, [\n'; + output += ' {\n'; + + if (cursor === input.length) { + output += ' setup: \'' + input + '\',\n'; + } + else { + output += ' name: \'' + input + ' (cursor=' + cursor + ')\',\n'; + output += ' setup: function() {\n'; + output += ' return helpers.setInput(options, \'' + input + '\', ' + cursor + ');\n'; + output += ' },\n'; + } + + output += ' check: {\n'; + + output += ' input: \'' + input + '\',\n'; + output += ' hints: ' + padding + '\'' + hints + '\',\n'; + output += ' markup: \'' + helpers._actual.markup(options) + '\',\n'; + output += ' cursor: ' + cursor + ',\n'; + output += ' current: \'' + helpers._actual.current(options) + '\',\n'; + output += ' status: \'' + helpers._actual.status(options) + '\',\n'; + output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n'; + output += ' message: \'' + helpers._actual.message(options) + '\',\n'; + output += ' predictions: ' + outputArray(predictions) + ',\n'; + output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n'; + output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n'; + output += ' tooltipState: \'' + helpers._actual.tooltipState(options) + '\'' + + (command ? ',' : '') +'\n'; + + if (command) { + output += ' args: {\n'; + output += ' command: { name: \'' + command.name + '\' },\n'; + + requisition.getAssignments().forEach(function(assignment) { + output += ' ' + assignment.param.name + ': { '; + + if (typeof assignment.value === 'string') { + output += 'value: \'' + assignment.value + '\', '; + } + else if (shouldOutputUnquoted(assignment.value)) { + output += 'value: ' + assignment.value + ', '; + } + else { + output += '/*value:' + assignment.value + ',*/ '; + } + + output += 'arg: \'' + assignment.arg + '\', '; + output += 'status: \'' + assignment.getStatus().toString() + '\', '; + output += 'message: \'' + assignment.message + '\''; + output += ' },\n'; + }); + + output += ' }\n'; + } + + output += ' },\n'; + output += ' exec: {\n'; + output += ' output: \'\',\n'; + output += ' type: \'string\',\n'; + output += ' error: false\n'; + output += ' }\n'; + output += ' }\n'; + output += ']);'; + + return output; + }.bind(this), util.errorHandler); +}; + +/** + * Simulate focusing the input field + */ +helpers.focusInput = function(options) { + checkOptions(options); + options.automator.focus(); +}; + +/** + * Simulate pressing TAB in the input field + */ +helpers.pressTab = function(options) { + checkOptions(options); + return helpers.pressKey(options, KeyEvent.DOM_VK_TAB); +}; + +/** + * Simulate pressing RETURN in the input field + */ +helpers.pressReturn = function(options) { + checkOptions(options); + return helpers.pressKey(options, KeyEvent.DOM_VK_RETURN); +}; + +/** + * Simulate pressing a key by keyCode in the input field + */ +helpers.pressKey = function(options, keyCode) { + checkOptions(options); + return options.automator.fakeKey(keyCode); +}; + +/** + * A list of special key presses and how to to them, for the benefit of + * helpers.setInput + */ +var ACTIONS = { + '<TAB>': function(options) { + return helpers.pressTab(options); + }, + '<RETURN>': function(options) { + return helpers.pressReturn(options); + }, + '<UP>': function(options) { + return helpers.pressKey(options, KeyEvent.DOM_VK_UP); + }, + '<DOWN>': function(options) { + return helpers.pressKey(options, KeyEvent.DOM_VK_DOWN); + }, + '<BACKSPACE>': function(options) { + return helpers.pressKey(options, KeyEvent.DOM_VK_BACK_SPACE); + } +}; + +/** + * Used in helpers.setInput to cut an input string like 'blah<TAB>foo<UP>' into + * an array like [ 'blah', '<TAB>', 'foo', '<UP>' ]. + * When using this RegExp, you also need to filter out the blank strings. + */ +var CHUNKER = /([^<]*)(<[A-Z]+>)/; + +/** + * Alter the input to <code>typed</code> optionally leaving the cursor at + * <code>cursor</code>. + * @return A promise of the number of key-presses to respond + */ +helpers.setInput = function(options, typed, cursor) { + checkOptions(options); + var inputPromise; + var automator = options.automator; + // We try to measure average keypress time, but setInput can simulate + // several, so we try to keep track of how many + var chunkLen = 1; + + // The easy case is a simple string without things like <TAB> + if (typed.indexOf('<') === -1) { + inputPromise = automator.setInput(typed); + } + else { + // Cut the input up into input strings separated by '<KEY>' tokens. The + // CHUNKS RegExp leaves blanks so we filter them out. + var chunks = typed.split(CHUNKER).filter(function(s) { + return s !== ''; + }); + chunkLen = chunks.length + 1; + + // We're working on this in chunks so first clear the input + inputPromise = automator.setInput('').then(function() { + return util.promiseEach(chunks, function(chunk) { + if (chunk.charAt(0) === '<') { + var action = ACTIONS[chunk]; + if (typeof action !== 'function') { + console.error('Known actions: ' + Object.keys(ACTIONS).join()); + throw new Error('Key action not found "' + chunk + '"'); + } + return action(options); + } + else { + return automator.setInput(automator.getInputState().typed + chunk); + } + }); + }); + } + + return inputPromise.then(function() { + if (cursor != null) { + automator.setCursor({ start: cursor, end: cursor }); + } + + if (automator.focusManager) { + automator.focusManager.onInputChange(); + } + + // Firefox testing is noisy and distant, so logging helps + if (options.isFirefox) { + var cursorStr = (cursor == null ? '' : ', ' + cursor); + log('setInput("' + typed + '"' + cursorStr + ')'); + } + + return chunkLen; + }); +}; + +/** + * Helper for helpers.audit() to ensure that all the 'check' properties match. + * See helpers.audit for more information. + * @param name The name to use in error messages + * @param checks See helpers.audit for a list of available checks + * @return A promise which resolves to undefined when the checks are complete + */ +helpers._check = function(options, name, checks) { + // A test method to check that all args are assigned in some way + var requisition = options.requisition; + requisition._args.forEach(function(arg) { + if (arg.assignment == null) { + assert.ok(false, 'No assignment for ' + arg); + } + }); + + if (checks == null) { + return Promise.resolve(); + } + + var outstanding = []; + var suffix = name ? ' (for \'' + name + '\')' : ''; + + if (!options.isNoDom && 'input' in checks) { + assert.is(helpers._actual.input(options), checks.input, 'input' + suffix); + } + + if (!options.isNoDom && 'cursor' in checks) { + assert.is(helpers._actual.cursor(options), checks.cursor, 'cursor' + suffix); + } + + if (!options.isNoDom && 'current' in checks) { + assert.is(helpers._actual.current(options), checks.current, 'current' + suffix); + } + + if ('status' in checks) { + assert.is(helpers._actual.status(options), checks.status, 'status' + suffix); + } + + if (!options.isNoDom && 'markup' in checks) { + assert.is(helpers._actual.markup(options), checks.markup, 'markup' + suffix); + } + + if (!options.isNoDom && 'hints' in checks) { + var hintCheck = function(actualHints) { + assert.is(actualHints, checks.hints, 'hints' + suffix); + }; + outstanding.push(helpers._actual.hints(options).then(hintCheck)); + } + + if (!options.isNoDom && 'predictions' in checks) { + var predictionsCheck = function(actualPredictions) { + helpers.arrayIs(actualPredictions, + checks.predictions, + 'predictions' + suffix); + }; + outstanding.push(helpers._actual.predictions(options).then(predictionsCheck)); + } + + if (!options.isNoDom && 'predictionsContains' in checks) { + var containsCheck = function(actualPredictions) { + checks.predictionsContains.forEach(function(prediction) { + var index = actualPredictions.indexOf(prediction); + assert.ok(index !== -1, + 'predictionsContains:' + prediction + suffix); + }); + }; + outstanding.push(helpers._actual.predictions(options).then(containsCheck)); + } + + if ('unassigned' in checks) { + helpers.arrayIs(helpers._actual.unassigned(options), + checks.unassigned, + 'unassigned' + suffix); + } + + /* TODO: Fix this + if (!options.isNoDom && 'tooltipState' in checks) { + assert.is(helpers._actual.tooltipState(options), + checks.tooltipState, + 'tooltipState' + suffix); + } + */ + + if (!options.isNoDom && 'outputState' in checks) { + assert.is(helpers._actual.outputState(options), + checks.outputState, + 'outputState' + suffix); + } + + if (!options.isNoDom && 'options' in checks) { + helpers.arrayIs(helpers._actual.options(options), + checks.options, + 'options' + suffix); + } + + if (!options.isNoDom && 'error' in checks) { + assert.is(helpers._actual.message(options), checks.error, 'error' + suffix); + } + + if (checks.args != null) { + Object.keys(checks.args).forEach(function(paramName) { + var check = checks.args[paramName]; + + // We allow an 'argument' called 'command' to be the command itself, but + // what if the command has a parameter called 'command' (for example, an + // 'exec' command)? We default to using the parameter because checking + // the command value is less useful + var assignment = requisition.getAssignment(paramName); + if (assignment == null && paramName === 'command') { + assignment = requisition.commandAssignment; + } + + if (assignment == null) { + assert.ok(false, 'Unknown arg: ' + paramName + suffix); + return; + } + + if ('value' in check) { + if (typeof check.value === 'function') { + try { + check.value(assignment.value); + } + catch (ex) { + assert.ok(false, '' + ex); + } + } + else { + assert.is(assignment.value, + check.value, + 'arg.' + paramName + '.value' + suffix); + } + } + + if ('name' in check) { + assert.is(assignment.value.name, + check.name, + 'arg.' + paramName + '.name' + suffix); + } + + if ('type' in check) { + assert.is(assignment.arg.type, + check.type, + 'arg.' + paramName + '.type' + suffix); + } + + if ('arg' in check) { + assert.is(assignment.arg.toString(), + check.arg, + 'arg.' + paramName + '.arg' + suffix); + } + + if ('status' in check) { + assert.is(assignment.getStatus().toString(), + check.status, + 'arg.' + paramName + '.status' + suffix); + } + + if (!options.isNoDom && 'message' in check) { + if (typeof check.message.test === 'function') { + assert.ok(check.message.test(assignment.message), + 'arg.' + paramName + '.message' + suffix); + } + else { + assert.is(assignment.message, + check.message, + 'arg.' + paramName + '.message' + suffix); + } + } + }); + } + + return Promise.all(outstanding).then(function() { + // Ensure the promise resolves to nothing + return undefined; + }); +}; + +/** + * Helper for helpers.audit() to ensure that all the 'exec' properties work. + * See helpers.audit for more information. + * @param name The name to use in error messages + * @param expected See helpers.audit for a list of available exec checks + * @return A promise which resolves to undefined when the checks are complete + */ +helpers._exec = function(options, name, expected) { + var requisition = options.requisition; + if (expected == null) { + return Promise.resolve({}); + } + + var origLogErrors = cli.logErrors; + if (expected.error) { + cli.logErrors = false; + } + + try { + return requisition.exec({ hidden: true }).then(function(output) { + if ('type' in expected) { + assert.is(output.type, + expected.type, + 'output.type for: ' + name); + } + + if ('error' in expected) { + assert.is(output.error, + expected.error, + 'output.error for: ' + name); + } + + if (!('output' in expected)) { + return { output: output }; + } + + var context = requisition.conversionContext; + var convertPromise; + if (options.isNoDom) { + convertPromise = output.convert('string', context); + } + else { + convertPromise = output.convert('dom', context).then(function(node) { + return node.textContent.trim(); + }); + } + + return convertPromise.then(function(textOutput) { + var doTest = function(match, against) { + // Only log the real textContent if the test fails + if (against.match(match) != null) { + assert.ok(true, 'html output for \'' + name + '\' ' + + 'should match /' + (match.source || match) + '/'); + } else { + assert.ok(false, 'html output for \'' + name + '\' ' + + 'should match /' + (match.source || match) + '/. ' + + 'Actual textContent: "' + against + '"'); + } + }; + + if (typeof expected.output === 'string') { + assert.is(textOutput, + expected.output, + 'html output for ' + name); + } + else if (Array.isArray(expected.output)) { + expected.output.forEach(function(match) { + doTest(match, textOutput); + }); + } + else { + doTest(expected.output, textOutput); + } + + if (expected.error) { + cli.logErrors = origLogErrors; + } + return { output: output, text: textOutput }; + }); + }.bind(this)).then(function(data) { + if (expected.error) { + cli.logErrors = origLogErrors; + } + + return data; + }); + } + catch (ex) { + assert.ok(false, 'Failure executing \'' + name + '\': ' + ex); + util.errorHandler(ex); + + if (expected.error) { + cli.logErrors = origLogErrors; + } + return Promise.resolve({}); + } +}; + +/** + * Helper to setup the test + */ +helpers._setup = function(options, name, audit) { + if (typeof audit.setup === 'string') { + return helpers.setInput(options, audit.setup); + } + + if (typeof audit.setup === 'function') { + return Promise.resolve(audit.setup.call(audit)); + } + + return Promise.reject('\'setup\' property must be a string or a function. Is ' + audit.setup); +}; + +/** + * Helper to shutdown the test + */ +helpers._post = function(name, audit, data) { + if (typeof audit.post === 'function') { + return Promise.resolve(audit.post.call(audit, data.output, data.text)); + } + return Promise.resolve(audit.post); +}; + +/* + * We do some basic response time stats so we can see if we're getting slow + */ +var totalResponseTime = 0; +var averageOver = 0; +var maxResponseTime = 0; +var maxResponseCulprit; +var start; + +/** + * Restart the stats collection process + */ +helpers.resetResponseTimes = function() { + start = new Date().getTime(); + totalResponseTime = 0; + averageOver = 0; + maxResponseTime = 0; + maxResponseCulprit = undefined; +}; + +/** + * Expose an average response time in milliseconds + */ +Object.defineProperty(helpers, 'averageResponseTime', { + get: function() { + return averageOver === 0 ? + undefined : + Math.round(100 * totalResponseTime / averageOver) / 100; + }, + enumerable: true +}); + +/** + * Expose a maximum response time in milliseconds + */ +Object.defineProperty(helpers, 'maxResponseTime', { + get: function() { return Math.round(maxResponseTime * 100) / 100; }, + enumerable: true +}); + +/** + * Expose the name of the test that provided the maximum response time + */ +Object.defineProperty(helpers, 'maxResponseCulprit', { + get: function() { return maxResponseCulprit; }, + enumerable: true +}); + +/** + * Quick summary of the times + */ +Object.defineProperty(helpers, 'timingSummary', { + get: function() { + var elapsed = (new Date().getTime() - start) / 1000; + return 'Total ' + elapsed + 's, ' + + 'ave response ' + helpers.averageResponseTime + 'ms, ' + + 'max response ' + helpers.maxResponseTime + 'ms ' + + 'from \'' + helpers.maxResponseCulprit + '\''; + }, + enumerable: true +}); + +/** + * A way of turning a set of tests into something more declarative, this helps + * to allow tests to be asynchronous. + * @param audits An array of objects each of which contains: + * - setup: string/function to be called to set the test up. + * If audit is a string then it is passed to helpers.setInput(). + * If audit is a function then it is executed. The tests will wait while + * tests that return promises complete. + * - name: For debugging purposes. If name is undefined, and 'setup' + * is a string then the setup value will be used automatically + * - skipIf: A function to define if the test should be skipped. Useful for + * excluding tests from certain environments (e.g. nodom, firefox, etc). + * The name of the test will be used in log messages noting the skip + * See helpers.reason for pre-defined skip functions. The skip function must + * be synchronous, and will be passed the test options object. + * - skipRemainingIf: A function to skip all the remaining audits in this set. + * See skipIf for details of how skip functions work. + * - check: Check data. Available checks: + * - input: The text displayed in the input field + * - cursor: The position of the start of the cursor + * - status: One of 'VALID', 'ERROR', 'INCOMPLETE' + * - hints: The hint text, i.e. a concatenation of the directTabText, the + * emptyParameters and the arrowTabText. The text as inserted into the UI + * will include NBSP and Unicode RARR characters, these should be + * represented using normal space and '->' for the arrow + * - markup: What state should the error markup be in. e.g. 'VVVIIIEEE' + * - args: Maps of checks to make against the arguments: + * - value: i.e. assignment.value (which ignores defaultValue) + * - type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned + * Care should be taken with this since it's something of an + * implementation detail + * - arg: The toString value of the argument + * - status: i.e. assignment.getStatus + * - message: i.e. assignment.message + * - name: For commands - checks assignment.value.name + * - exec: Object to indicate we should execute the command and check the + * results. Available checks: + * - output: A string, RegExp or array of RegExps to compare with the output + * If typeof output is a string then the output should be exactly equal + * to the given string. If the type of output is a RegExp or array of + * RegExps then the output should match all RegExps + * - error: If true, then it is expected that this command will fail (that + * is, return a rejected promise or throw an exception) + * - type: A string documenting the expected type of the return value + * - post: Function to be called after the checks have been run, which will be + * passed 2 parameters: the first being output data (with type, data, and + * error properties), and the second being the converted text version of + * the output data + */ +helpers.audit = function(options, audits) { + checkOptions(options); + var skipReason = null; + return util.promiseEach(audits, function(audit) { + var name = audit.name; + if (name == null && typeof audit.setup === 'string') { + name = audit.setup; + } + + if (assert.testLogging) { + log('- START \'' + name + '\' in ' + assert.currentTest); + } + + if (audit.skipRemainingIf) { + var skipRemainingIf = (typeof audit.skipRemainingIf === 'function') ? + audit.skipRemainingIf(options) : + !!audit.skipRemainingIf; + if (skipRemainingIf) { + skipReason = audit.skipRemainingIf.name ? + 'due to ' + audit.skipRemainingIf.name : + ''; + assert.log('Skipped ' + name + ' ' + skipReason); + + // Tests need at least one pass, fail or todo. Let's create a dummy pass + // in case there are none. + ok(true, "Each test requires at least one pass, fail or todo so here is a pass."); + + return Promise.resolve(undefined); + } + } + + if (audit.skipIf) { + var skip = (typeof audit.skipIf === 'function') ? + audit.skipIf(options) : + !!audit.skipIf; + if (skip) { + var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : ''; + assert.log('Skipped ' + name + ' ' + reason); + return Promise.resolve(undefined); + } + } + + if (skipReason != null) { + assert.log('Skipped ' + name + ' ' + skipReason); + return Promise.resolve(undefined); + } + + var start = new Date().getTime(); + + var setupDone = helpers._setup(options, name, audit); + return setupDone.then(function(chunkLen) { + if (typeof chunkLen !== 'number') { + chunkLen = 1; + } + + // Nasty hack to allow us to auto-skip tests where we're actually testing + // a key-sequence (i.e. targeting terminal.js) when there is no terminal + if (chunkLen === -1) { + assert.log('Skipped ' + name + ' ' + skipReason); + return Promise.resolve(undefined); + } + + if (assert.currentTest) { + var responseTime = (new Date().getTime() - start) / chunkLen; + totalResponseTime += responseTime; + if (responseTime > maxResponseTime) { + maxResponseTime = responseTime; + maxResponseCulprit = assert.currentTest + '/' + name; + } + averageOver++; + } + + var checkDone = helpers._check(options, name, audit.check); + return checkDone.then(function() { + var execDone = helpers._exec(options, name, audit.exec); + return execDone.then(function(data) { + return helpers._post(name, audit, data).then(function() { + if (assert.testLogging) { + log('- END \'' + name + '\' in ' + assert.currentTest); + } + }); + }); + }); + }); + }).then(function() { + return options.automator.setInput(''); + }, function(ex) { + options.automator.setInput(''); + throw ex; + }); +}; + +/** + * Compare 2 arrays. + */ +helpers.arrayIs = function(actual, expected, message) { + assert.ok(Array.isArray(actual), 'actual is not an array: ' + message); + assert.ok(Array.isArray(expected), 'expected is not an array: ' + message); + + if (!Array.isArray(actual) || !Array.isArray(expected)) { + return; + } + + assert.is(actual.length, expected.length, 'array length: ' + message); + + for (var i = 0; i < actual.length && i < expected.length; i++) { + assert.is(actual[i], expected[i], 'member[' + i + ']: ' + message); + } +}; + +/** + * A quick helper to log to the correct place + */ +function log(message) { + if (typeof info === 'function') { + info(message); + } + else { + console.log(message); + } +} + +return { helpers: helpers, gcli: gcli, assert: assert }; +})(); diff --git a/toolkit/devtools/commandline/test/mockCommands.js b/toolkit/devtools/commandline/test/mockCommands.js new file mode 100644 index 000000000..0b9f9343f --- /dev/null +++ b/toolkit/devtools/commandline/test/mockCommands.js @@ -0,0 +1,742 @@ +/* + * Copyright 2012, Mozilla Foundation and contributors + * + * 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. + */ + +'use strict'; +// <INJECTED SOURCE:START> + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// DO NOT EDIT IT DIRECTLY + +// <INJECTED SOURCE:END> + + +var Promise = require('gcli/util/promise').Promise; +var mockCommands = {}; + +// We use an alias for exports here because this module is used in Firefox +// mochitests where we don't have define/require + +/** + * Registration and de-registration. + */ +mockCommands.setup = function(requisition) { + requisition.system.addItems(mockCommands.items); +}; + +mockCommands.shutdown = function(requisition) { + requisition.system.removeItems(mockCommands.items); +}; + +function createExec(name) { + return function(args, executionContext) { + var argsOut = Object.keys(args).map(function(key) { + return key + '=' + args[key]; + }).join(', '); + return 'Exec: ' + name + ' ' + argsOut; + }; +} + +mockCommands.items = [ + { + item: 'converter', + from: 'json', + to: 'string', + exec: function(json, context) { + return JSON.stringify(json, null, ' '); + } + }, + { + item: 'converter', + from: 'json', + to: 'view', + exec: function(json, context) { + var html = JSON.stringify(json, null, ' ').replace(/\n/g, '<br/>'); + return { + html: '<pre>' + html + '</pre>' + }; + } + }, + { + item: 'type', + name: 'optionType', + parent: 'selection', + lookup: [ + { + name: 'option1', + value: 'string' + }, + { + name: 'option2', + value: 'number' + }, + { + name: 'option3', + value: { + name: 'selection', + lookup: [ + { name: 'one', value: 1 }, + { name: 'two', value: 2 }, + { name: 'three', value: 3 } + ] + } + } + ] + }, + { + item: 'type', + name: 'optionValue', + parent: 'delegate', + delegateType: function(executionContext) { + if (executionContext != null) { + var option = executionContext.getArgsObject().optionType; + if (option != null) { + return option; + } + } + return 'blank'; + } + }, + { + item: 'command', + name: 'tsv', + params: [ + { name: 'optionType', type: 'optionType' }, + { name: 'optionValue', type: 'optionValue' } + ], + exec: createExec('tsv') + }, + { + item: 'command', + name: 'tsr', + params: [ { name: 'text', type: 'string' } ], + exec: createExec('tsr') + }, + { + item: 'command', + name: 'tsrsrsr', + params: [ + { name: 'p1', type: 'string' }, + { name: 'p2', type: 'string' }, + { name: 'p3', type: { name: 'string', allowBlank: true} }, + ], + exec: createExec('tsrsrsr') + }, + { + item: 'command', + name: 'tso', + params: [ { name: 'text', type: 'string', defaultValue: null } ], + exec: createExec('tso') + }, + { + item: 'command', + name: 'tse', + params: [ + { name: 'node', type: 'node' }, + { + group: 'options', + params: [ + { name: 'nodes', type: { name: 'nodelist' } }, + { name: 'nodes2', type: { name: 'nodelist', allowEmpty: true } } + ] + } + ], + exec: createExec('tse') + }, + { + item: 'command', + name: 'tsj', + params: [ { name: 'javascript', type: 'javascript' } ], + exec: createExec('tsj') + }, + { + item: 'command', + name: 'tsb', + params: [ { name: 'toggle', type: 'boolean' } ], + exec: createExec('tsb') + }, + { + item: 'command', + name: 'tss', + exec: createExec('tss') + }, + { + item: 'command', + name: 'tsu', + params: [ + { + name: 'num', + type: { + name: 'number', + max: 10, + min: -5, + step: 3 + } + } + ], + exec: createExec('tsu') + }, + { + item: 'command', + name: 'tsf', + params: [ + { + name: 'num', + type: { + name: 'number', + allowFloat: true, + max: 11.5, + min: -6.5, + step: 1.5 + } + } + ], + exec: createExec('tsf') + }, + { + item: 'command', + name: 'tsn' + }, + { + item: 'command', + name: 'tsn dif', + params: [ { name: 'text', type: 'string', description: 'tsn dif text' } ], + exec: createExec('tsnDif') + }, + { + item: 'command', + name: 'tsn hidden', + hidden: true, + exec: createExec('tsnHidden') + }, + { + item: 'command', + name: 'tsn ext', + params: [ { name: 'text', type: 'string' } ], + exec: createExec('tsnExt') + }, + { + item: 'command', + name: 'tsn exte', + params: [ { name: 'text', type: 'string' } ], + exec: createExec('tsnExte') + }, + { + item: 'command', + name: 'tsn exten', + params: [ { name: 'text', type: 'string' } ], + exec: createExec('tsnExten') + }, + { + item: 'command', + name: 'tsn extend', + params: [ { name: 'text', type: 'string' } ], + exec: createExec('tsnExtend') + }, + { + item: 'command', + name: 'tsn deep' + }, + { + item: 'command', + name: 'tsn deep down' + }, + { + item: 'command', + name: 'tsn deep down nested' + }, + { + item: 'command', + name: 'tsn deep down nested cmd', + exec: createExec('tsnDeepDownNestedCmd') + }, + { + item: 'command', + name: 'tshidden', + hidden: true, + params: [ + { + group: 'Options', + params: [ + { + name: 'visible', + type: 'string', + short: 'v', + defaultValue: null, + description: 'visible' + }, + { + name: 'invisiblestring', + type: 'string', + short: 'i', + description: 'invisiblestring', + defaultValue: null, + hidden: true + }, + { + name: 'invisibleboolean', + short: 'b', + type: 'boolean', + description: 'invisibleboolean', + hidden: true + } + ] + } + ], + exec: createExec('tshidden') + }, + { + item: 'command', + name: 'tselarr', + params: [ + { name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } }, + { name: 'arr', type: { name: 'array', subtype: 'string' } } + ], + exec: createExec('tselarr') + }, + { + item: 'command', + name: 'tsm', + description: 'a 3-param test selection|string|number', + params: [ + { name: 'abc', type: { name: 'selection', data: [ 'a', 'b', 'c' ] } }, + { name: 'txt', type: 'string' }, + { name: 'num', type: { name: 'number', max: 42, min: 0 } } + ], + exec: createExec('tsm') + }, + { + item: 'command', + name: 'tsg', + description: 'a param group test', + params: [ + { + name: 'solo', + type: { name: 'selection', data: [ 'aaa', 'bbb', 'ccc' ] }, + description: 'solo param' + }, + { + group: 'First', + params: [ + { + name: 'txt1', + type: 'string', + defaultValue: null, + description: 'txt1 param' + }, + { + name: 'bool', + type: 'boolean', + description: 'bool param' + } + ] + }, + { + name: 'txt2', + type: 'string', + defaultValue: 'd', + description: 'txt2 param', + option: 'Second' + }, + { + name: 'num', + type: { name: 'number', min: 40 }, + defaultValue: 42, + description: 'num param', + option: 'Second' + } + ], + exec: createExec('tsg') + }, + { + item: 'command', + name: 'tscook', + description: 'param group test to catch problems with cookie command', + params: [ + { + name: 'key', + type: 'string', + description: 'tscookKeyDesc' + }, + { + name: 'value', + type: 'string', + description: 'tscookValueDesc' + }, + { + group: 'tscookOptionsDesc', + params: [ + { + name: 'path', + type: 'string', + defaultValue: '/', + description: 'tscookPathDesc' + }, + { + name: 'domain', + type: 'string', + defaultValue: null, + description: 'tscookDomainDesc' + }, + { + name: 'secure', + type: 'boolean', + description: 'tscookSecureDesc' + } + ] + } + ], + exec: createExec('tscook') + }, + { + item: 'command', + name: 'tslong', + description: 'long param tests to catch problems with the jsb command', + params: [ + { + name: 'msg', + type: 'string', + description: 'msg Desc' + }, + { + group: 'Options Desc', + params: [ + { + name: 'num', + short: 'n', + type: 'number', + description: 'num Desc', + defaultValue: 2 + }, + { + name: 'sel', + short: 's', + type: { + name: 'selection', + lookup: [ + { name: 'space', value: ' ' }, + { name: 'tab', value: '\t' } + ] + }, + description: 'sel Desc', + defaultValue: ' ' + }, + { + name: 'bool', + short: 'b', + type: 'boolean', + description: 'bool Desc' + }, + { + name: 'num2', + short: 'm', + type: 'number', + description: 'num2 Desc', + defaultValue: -1 + }, + { + name: 'bool2', + short: 'c', + type: 'boolean', + description: 'bool2 Desc' + }, + { + name: 'sel2', + short: 't', + type: { + name: 'selection', + data: [ 'collapse', 'basic', 'with space', 'with two spaces' ] + }, + description: 'sel2 Desc', + defaultValue: 'collapse' + } + ] + } + ], + exec: createExec('tslong') + }, + { + item: 'command', + name: 'tsdate', + description: 'long param tests to catch problems with the jsb command', + params: [ + { + name: 'd1', + type: 'date', + }, + { + name: 'd2', + type: { + name: 'date', + min: '1 jan 2000', + max: '28 feb 2000', + step: 2 + } + }, + ], + exec: createExec('tsdate') + }, + { + item: 'command', + name: 'tsfail', + description: 'test errors', + params: [ + { + name: 'method', + type: { + name: 'selection', + data: [ + 'reject', 'rejecttyped', + 'throwerror', 'throwstring', 'throwinpromise', + 'noerror' + ] + } + } + ], + exec: function(args, context) { + if (args.method === 'reject') { + return new Promise(function(resolve, reject) { + setTimeout(function() { + reject('rejected promise'); + }, 10); + }); + } + + if (args.method === 'rejecttyped') { + return new Promise(function(resolve, reject) { + setTimeout(function() { + reject(context.typedData('number', 54)); + }, 10); + }); + } + + if (args.method === 'throwinpromise') { + return new Promise(function(resolve, reject) { + setTimeout(function() { + resolve('should be lost'); + }, 10); + }).then(function() { + var t = null; + return t.foo; + }); + } + + if (args.method === 'throwerror') { + throw new Error('thrown error'); + } + + if (args.method === 'throwstring') { + throw 'thrown string'; + } + + return 'no error'; + } + }, + { + item: 'command', + name: 'tsfile', + description: 'test file params', + }, + { + item: 'command', + name: 'tsfile open', + description: 'a file param in open mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'file', + existing: 'yes' + } + } + ], + exec: createExec('tsfile open') + }, + { + item: 'command', + name: 'tsfile saveas', + description: 'a file param in saveas mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'file', + existing: 'no' + } + } + ], + exec: createExec('tsfile saveas') + }, + { + item: 'command', + name: 'tsfile save', + description: 'a file param in save mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'file', + existing: 'maybe' + } + } + ], + exec: createExec('tsfile save') + }, + { + item: 'command', + name: 'tsfile cd', + description: 'a file param in cd mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'directory', + existing: 'yes' + } + } + ], + exec: createExec('tsfile cd') + }, + { + item: 'command', + name: 'tsfile mkdir', + description: 'a file param in mkdir mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'directory', + existing: 'no' + } + } + ], + exec: createExec('tsfile mkdir') + }, + { + item: 'command', + name: 'tsfile rm', + description: 'a file param in rm mode', + params: [ + { + name: 'p1', + type: { + name: 'file', + filetype: 'any', + existing: 'yes' + } + } + ], + exec: createExec('tsfile rm') + }, + { + item: 'command', + name: 'tsslow', + params: [ + { + name: 'hello', + type: { + name: 'selection', + data: function(context) { + return new Promise(function(resolve, reject) { + setTimeout(function() { + resolve([ + 'Shalom', 'Namasté', 'Hallo', 'Dydd-da', + 'Chào', 'Hej', 'Saluton', 'Sawubona' + ]); + }, 10); + }); + } + } + } + ], + exec: function(args, context) { + return 'Test completed'; + } + }, + { + item: 'command', + name: 'urlc', + params: [ + { + name: 'url', + type: 'url' + } + ], + returnType: 'json', + exec: function(args, context) { + return args; + } + }, + { + item: 'command', + name: 'unionc1', + params: [ + { + name: 'first', + type: { + name: 'union', + alternatives: [ + { + name: 'selection', + lookup: [ + { name: 'one', value: 1 }, + { name: 'two', value: 2 }, + ] + }, + 'number', + { name: 'string' } + ] + } + } + ], + returnType: 'json', + exec: function(args, context) { + return args; + } + }, + { + item: 'command', + name: 'unionc2', + params: [ + { + name: 'first', + type: { + name: 'union', + alternatives: [ + { + name: 'selection', + lookup: [ + { name: 'one', value: 1 }, + { name: 'two', value: 2 }, + ] + }, + { + name: 'url' + } + ] + } + } + ], + returnType: 'json', + exec: function(args, context) { + return args; + } + } +]; |