diff options
Diffstat (limited to 'devtools/client/commandline')
107 files changed, 16813 insertions, 0 deletions
diff --git a/devtools/client/commandline/commandline.css b/devtools/client/commandline/commandline.css new file mode 100644 index 000000000..aed2d0e64 --- /dev/null +++ b/devtools/client/commandline/commandline.css @@ -0,0 +1,85 @@ +/* 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 { + padding-inline-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; +} + +.gcli-mdn-url { + text-decoration: underline; + cursor: pointer; +} + diff --git a/devtools/client/commandline/commandlineoutput.xhtml b/devtools/client/commandline/commandlineoutput.xhtml new file mode 100644 index 000000000..c8674c838 --- /dev/null +++ b/devtools/client/commandline/commandlineoutput.xhtml @@ -0,0 +1,17 @@ +<?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://devtools/content/commandline/commandline.css" type="text/css"/> + <link rel="stylesheet" href="chrome://devtools/skin/commandline.css" type="text/css"/> +</head> +<body class="gcli-body"> +<div id="gcli-output-root"></div> +</body> +</html> diff --git a/devtools/client/commandline/commandlinetooltip.xhtml b/devtools/client/commandline/commandlinetooltip.xhtml new file mode 100644 index 000000000..74c831022 --- /dev/null +++ b/devtools/client/commandline/commandlinetooltip.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://devtools/content/commandline/commandline.css" type="text/css"/> + <link rel="stylesheet" href="chrome://devtools/skin/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/devtools/client/commandline/moz.build b/devtools/client/commandline/moz.build new file mode 100644 index 000000000..22fc46624 --- /dev/null +++ b/devtools/client/commandline/moz.build @@ -0,0 +1,5 @@ +# 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/. + +BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] diff --git a/devtools/client/commandline/test/.eslintrc.js b/devtools/client/commandline/test/.eslintrc.js new file mode 100644 index 000000000..815b63a0e --- /dev/null +++ b/devtools/client/commandline/test/.eslintrc.js @@ -0,0 +1,10 @@ +"use strict"; + +module.exports = { + // Extend from the shared list of defined globals for mochitests. + "extends": "../../../.eslintrc.mochitests.js", + "globals": { + "helpers": true, + "assert": true + } +}; diff --git a/devtools/client/commandline/test/browser.ini b/devtools/client/commandline/test/browser.ini new file mode 100644 index 000000000..7ba549418 --- /dev/null +++ b/devtools/client/commandline/test/browser.ini @@ -0,0 +1,124 @@ +[DEFAULT] +skip-if = e10s # Bug 1034511 +tags = devtools +subsuite = devtools +support-files = + head.js + helpers.js + mockCommands.js + +[browser_cmd_addon.js] +[browser_cmd_calllog.js] +skip-if = true # Bug 845831 +[browser_cmd_calllog_chrome.js] +skip-if = true # 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_cookie_host.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] +skip-if = (e10s && debug) # Bug 1034511 (docShell leaks on debug) +[browser_cmd_highlight_01.js] +[browser_cmd_highlight_02.js] +[browser_cmd_highlight_03.js] +[browser_cmd_highlight_04.js] +[browser_cmd_inject.js] +support-files = + browser_cmd_inject.html +[browser_cmd_csscoverage_util.js] +skip-if = (e10s && debug) # Bug 1034511 (docShell leaks on debug) +[browser_cmd_jsb.js] +support-files = + browser_cmd_jsb_script.jsi +[browser_cmd_listen.js] +[browser_cmd_measure.js] +[browser_cmd_media.js] +support-files = + browser_cmd_media.html +[browser_cmd_pagemod_export.js] +support-files = + browser_cmd_pagemod_export.html +[browser_cmd_paintflashing.js] +[browser_cmd_pref1.js] +[browser_cmd_pref2.js] +[browser_cmd_pref3.js] +[browser_cmd_qsa.js] +[browser_cmd_restart.js] +[browser_cmd_rulers.js] +[browser_cmd_screenshot.js] +subsuite = clipboard +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 # Bug 934098 +[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/devtools/client/commandline/test/browser_cmd_addon.js b/devtools/client/commandline/test/browser_cmd_addon.js new file mode 100644 index 000000000..e8cea2e06 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_addon.js @@ -0,0 +1,195 @@ +/* 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." + } + }, + { + setup: "addon ctp Test_Plug-in_1.0.0.0", + check: { + input: "addon ctp Test_Plug-in_1.0.0.0", + hints: "", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID", + args: { + command: { name: "addon ctp" }, + addon: { + value: function (addon) { + is(addon.name, "Test Plug-in", "test plugin name"); + }, + status: "VALID" + } + } + }, + exec: { + output: "Test Plug-in 1.0.0.0 set to click-to-play." + } + }, + { + setup: "addon ctp OpenH264_Video_Codec_provided_by_Cisco_Systems,_Inc._null", + check: { + input: "addon ctp OpenH264_Video_Codec_provided_by_Cisco_Systems,_Inc._null", + hints: "", + status: "VALID", + args: { + command: { name: "addon ctp" }, + addon: { + value: function (addon) { + is(addon.name, "OpenH264 Video Codec provided by Cisco Systems, Inc.", "openh264"); + }, + status: "VALID" + } + } + }, + exec: { + output: "OpenH264 Video Codec provided by Cisco Systems, Inc. null cannot be set to click-to-play." + } + }, + { + setup: "addon ctp Mochitest_1.0", + check: { + input: "addon ctp Mochitest_1.0", + hints: "", + status: "VALID", + args: { + command: { name: "addon ctp" }, + addon: { + value: function (addon) { + is(addon.name, "Mochitest", "mochitest"); + }, + status: "VALID" + } + } + }, + exec: { + output: "Mochitest 1.0 cannot be set to click-to-play because it is not a plugin." + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_appcache_invalid.js b/devtools/client/commandline/test/browser_cmd_appcache_invalid.js new file mode 100644 index 000000000..df87bbc5a --- /dev/null +++ b/devtools/client/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/devtools/client/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 \u201cCACHE MANIFEST\u201d at line 1.", + "\u201cCACHE MANIFEST\u201d 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/devtools/client/" + + "commandline/test/browser_cmd_appcache_invalid_page3.html was modified " + + "after http://sub1.test1.example.com/browser/devtools/client/" + + "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, \u201cprefer-online\u201d or \u201cfast\u201d 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/devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache b/devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache new file mode 100644 index 000000000..75b5d7bad --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ b/devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ new file mode 100644 index 000000000..af95ed1f5 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_index.html b/devtools/client/commandline/test/browser_cmd_appcache_invalid_index.html new file mode 100644 index 000000000..67f9aa675 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_page1.html b/devtools/client/commandline/test/browser_cmd_appcache_invalid_page1.html new file mode 100644 index 000000000..5ff36f102 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_page2.html b/devtools/client/commandline/test/browser_cmd_appcache_invalid_page2.html new file mode 100644 index 000000000..7d4a0c44d --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html b/devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html new file mode 100644 index 000000000..6777e59f8 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ b/devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ new file mode 100644 index 000000000..177130b43 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid.js b/devtools/client/commandline/test/browser_cmd_appcache_valid.js new file mode 100644 index 000000000..83aa9ca8f --- /dev/null +++ b/devtools/client/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/devtools/client/" + + "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); + + info("adding cache listener."); + // Wait for site to be cached. + yield helpers.listenOnce(gBrowser.contentWindow.applicationCache, "cached"); + + yield helpers.openToolbar(options); + + // 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.includes("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/devtools/client/commandline/test/browser_cmd_appcache_valid_index.html + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV", + 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.includes("index"), "index is not contained in output"); + ok(!text.includes("page1"), "page1 is not contained in output"); + ok(!text.includes("page2"), "page1 is not contained in output"); + ok(!text.includes("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/devtools/client/commandline/test/browser_cmd_appcache_valid_index.html + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID", + args: {} + }, + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache b/devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache new file mode 100644 index 000000000..4f62825e9 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ b/devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ new file mode 100644 index 000000000..d1a0abd3f --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid_index.html b/devtools/client/commandline/test/browser_cmd_appcache_valid_index.html new file mode 100644 index 000000000..1ab3f3e31 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid_page1.html b/devtools/client/commandline/test/browser_cmd_appcache_valid_page1.html new file mode 100644 index 000000000..e0bb429e7 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid_page2.html b/devtools/client/commandline/test/browser_cmd_appcache_valid_page2.html new file mode 100644 index 000000000..1ce36b319 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_appcache_valid_page3.html b/devtools/client/commandline/test/browser_cmd_appcache_valid_page3.html new file mode 100644 index 000000000..074ff7d41 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_calllog.js b/devtools/client/commandline/test/browser_cmd_calllog.js new file mode 100644 index 000000000..ebe10165f --- /dev/null +++ b/devtools/client/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"; + +var 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/devtools/client/commandline/test/browser_cmd_calllog_chrome.js b/devtools/client/commandline/test/browser_cmd_calllog_chrome.js new file mode 100644 index 000000000..81d2dfd54 --- /dev/null +++ b/devtools/client/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"; + +var 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/devtools/client/commandline/test/browser_cmd_commands.js b/devtools/client/commandline/test/browser_cmd_commands.js new file mode 100644 index 000000000..6c69034ec --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_commands.js @@ -0,0 +1,63 @@ +/* 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"; +const HUDService = require("devtools/client/webconsole/hudservice"); + +// Use the old webconsole since pprint isn't working on new one (Bug 1304794) +Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false); +registerCleanupFunction(function* () { + Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled"); +}); + +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)"); + + yield helpers.audit(options, [ + { + setup: "console clear", + exec: { output: "" } + } + ]); + + let labels = hud.outputNode.querySelectorAll(".message"); + is(labels.length, 0, "no output in console"); + + yield helpers.audit(options, [ + { + setup: "console close", + exec: { output: "" } + } + ]); + + ok(!HUDService.getHudReferenceById(hud.hudId), "console closed"); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_cookie.html b/devtools/client/commandline/test/browser_cmd_cookie.html new file mode 100644 index 000000000..7688d034a --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_cookie.html @@ -0,0 +1,19 @@ +<!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.cookie = "zig=zag; domain=.mochi.test"; + document.getElementById("result").innerHTML = document.cookie; + </script> + +</body> +</html> diff --git a/devtools/client/commandline/test/browser_cmd_cookie.js b/devtools/client/commandline/test/browser_cmd_cookie.js new file mode 100644 index 000000000..37a8205cb --- /dev/null +++ b/devtools/client/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/devtools/client/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.includes("zip"), ""); + ok(!text.includes("zop"), ""); + } + }, + { + setup: "cookie remove zap", + exec: { }, + }, + { + setup: "cookie list", + exec: { + output: [ /zup=banana/, /Edit/ ] + }, + post: function (output, text) { + ok(!text.includes("zap"), ""); + ok(!text.includes("zep"), ""); + ok(!text.includes("zip"), ""); + ok(!text.includes("zop"), ""); + } + }, + { + setup: "cookie remove zup", + exec: { } + }, + { + setup: "cookie list", + exec: { + output: "No cookies found for host example.com" + }, + post: function (output, text) { + ok(!text.includes("zap"), ""); + ok(!text.includes("zep"), ""); + ok(!text.includes("zip"), ""); + ok(!text.includes("zop"), ""); + ok(!text.includes("zup"), ""); + ok(!text.includes("banana"), ""); + ok(!text.includes("Edit"), ""); + } + }, + ]); + }).then(finish, helpers.handleError); +} diff --git a/devtools/client/commandline/test/browser_cmd_cookie_host.js b/devtools/client/commandline/test/browser_cmd_cookie_host.js new file mode 100644 index 000000000..c20294027 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_cookie_host.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the cookie command works for host with a port specified + +const TEST_URI = "http://mochi.test:8888/browser/devtools/client/commandline/" + + "test/browser_cmd_cookie.html"; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function (options) { + return helpers.audit(options, [ + { + setup: "cookie list", + exec: { + output: [ /zap=zep/, /zip=zop/, /zig=zag/ ], + } + }, + { + setup: "cookie set zup banana", + check: { + args: { + name: { value: "zup" }, + value: { value: "banana" }, + } + }, + exec: { + output: "" + } + }, + { + setup: "cookie list", + exec: { + output: [ /zap=zep/, /zip=zop/, /zig=zag/, /zup=banana/, /Edit/ ] + } + } + ]); + }).then(finish, helpers.handleError); +} + diff --git a/devtools/client/commandline/test/browser_cmd_csscoverage_oneshot.js b/devtools/client/commandline/test/browser_cmd_csscoverage_oneshot.js new file mode 100644 index 000000000..3394045f5 --- /dev/null +++ b/devtools/client/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/shared/fronts/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._testOnlyVisitedPages(); + 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/devtools/client/commandline/test/browser_cmd_csscoverage_page1.html b/devtools/client/commandline/test/browser_cmd_csscoverage_page1.html new file mode 100644 index 000000000..b137ac1e7 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_page2.html b/devtools/client/commandline/test/browser_cmd_csscoverage_page2.html new file mode 100644 index 000000000..13fa8697c --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_page3.html b/devtools/client/commandline/test/browser_cmd_csscoverage_page3.html new file mode 100644 index 000000000..4dc91d5b2 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_sheetA.css b/devtools/client/commandline/test/browser_cmd_csscoverage_sheetA.css new file mode 100644 index 000000000..1a3bac926 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_sheetB.css b/devtools/client/commandline/test/browser_cmd_csscoverage_sheetB.css new file mode 100644 index 000000000..9335bd60d --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_sheetC.css b/devtools/client/commandline/test/browser_cmd_csscoverage_sheetC.css new file mode 100644 index 000000000..8c899ead9 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_sheetD.css b/devtools/client/commandline/test/browser_cmd_csscoverage_sheetD.css new file mode 100644 index 000000000..60ebb314a --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js b/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js new file mode 100644 index 000000000..2bdb86d86 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js @@ -0,0 +1,465 @@ +/* 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/shared/fronts/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(options.chromeWindow, options.target); + + ok(usage.isRunning(), "csscoverage is running"); + + // Load page 1. + options.browser.loadURI(PAGE_1); + // And wait until page 1 and page 2 (an iframe inside page 1) are both loaded. + yield Promise.all([ + BrowserTestUtils.browserLoaded(options.browser, false, PAGE_1), + BrowserTestUtils.browserLoaded(options.browser, true, PAGE_2) + ]); + is(options.browser.currentURI.spec, PAGE_1, "page 1 loaded"); + + // page 2 has JS that navigates to page 3 after a timeout. + yield BrowserTestUtils.browserLoaded(options.browser, false, PAGE_3); + is(options.browser.currentURI.spec, PAGE_3, "page 3 loaded"); + + let toolboxReady = gDevTools.once("toolbox-ready"); + + yield usage.stop(); + + ok(!usage.isRunning(), "csscoverage not is running"); + + yield toolboxReady; +} + +/** + * Check the expected pages have been visited + */ +function* checkPages(usage) { + // 'load' event order. '' is for the initial location + let expectedVisited = [ "", PAGE_2, PAGE_1, PAGE_3 ]; + let actualVisited = yield usage._testOnlyVisitedPages(); + 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/devtools/client/commandline/test/browser_cmd_csscoverage_util.js b/devtools/client/commandline/test/browser_cmd_csscoverage_util.js new file mode 100644 index 000000000..264967a6b --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_folder.js b/devtools/client/commandline/test/browser_cmd_folder.js new file mode 100644 index 000000000..8592d4a78 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_highlight_01.js b/devtools/client/commandline/test/browser_cmd_highlight_01.js new file mode 100644 index 000000000..1d9c151d9 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_highlight_01.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* eslint key-spacing: 0 */ + +// Tests the various highlight command parameters and options + +// Creating a test page with many elements to test the --showall option +var TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>"; +for (let i = 0; i < 101; 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 --hideguides", + check: { + input: "highlight body --hideguides", + hints: " [options]", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID" + }, + exec: { + output: "1 node highlighted" + } + }, + { + setup: "highlight body --showinfobar", + check: { + input: "highlight body --showinfobar", + hints: " [options]", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID" + }, + exec: { + output: "1 node highlighted" + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_highlight_02.js b/devtools/client/commandline/test/browser_cmd_highlight_02.js new file mode 100644 index 000000000..d5a361f43 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_highlight_02.js @@ -0,0 +1,45 @@ +/* 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(yield getHighlighterNumber(), 1, "The highlighter element exists for body"); + + info("highlighting the div node"); + yield runCommand("highlight div", options); + is(yield 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(yield getHighlighterNumber(), 2, "2 highlighter elements have been created"); + + info("unhighlighting all nodes"); + yield runCommand("unhighlight", options); + is(yield getHighlighterNumber(), 0, "All highlighters have been removed"); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); +} + +function getHighlighterNumber() { + return ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + return require("devtools/shared/gcli/commands/highlight").highlighters.length; + }); +} + +function* runCommand(cmd, options) { + yield helpers.audit(options, [{ setup: cmd, exec: {} }]); +} diff --git a/devtools/client/commandline/test/browser_cmd_highlight_03.js b/devtools/client/commandline/test/browser_cmd_highlight_03.js new file mode 100644 index 000000000..75b28af61 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_highlight_03.js @@ -0,0 +1,131 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* eslint key-spacing: 0 */ + +// Tests the various highlight command parameters and options that doesn't +// involve nodes at all. + +var TEST_PAGE = "data:text/html;charset=utf-8,"; + +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 body --hide", + check: { + input: "highlight body --hide", + hints: "guides [options]", + markup: "VVVVVVVVVVVVVVVIIIIII", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + }, + { + 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 --showa", + check: { + input: "highlight body --showa", + hints: "ll [options]", + markup: "VVVVVVVVVVVVVVVIIIIIII", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + }, + { + 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 \u2018region\u2019." + } + }, + { + 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 \u2018fill\u2019." + } + }, + { + setup: "highlight body --ke", + check: { + input: "highlight body --ke", + hints: "ep [options]", + markup: "VVVVVVVVVVVVVVVIIII", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + }, + { + setup: "unhighlight", + check: { + input: "unhighlight", + hints: "", + markup: "VVVVVVVVVVV", + status: "VALID" + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_highlight_04.js b/devtools/client/commandline/test/browser_cmd_highlight_04.js new file mode 100644 index 000000000..108308d8f --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_highlight_04.js @@ -0,0 +1,94 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* eslint key-spacing: 0 */ + +// Tests the various highlight command parameters and options + +// Creating a test page with many elements to test the --showall option +var TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>"; +for (let i = 0; i < 101; 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 body --showall", + check: { + input: "highlight body --showall", + hints: " [options]", + markup: "VVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID" + }, + exec: { + output: "1 node highlighted" + } + }, + { + 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: "101 nodes matched, but only 100 nodes highlighted. Use " + + "\u2018--showall\u2019 to show all" + } + }, + { + setup: "highlight .item --showall", + check: { + input: "highlight .item --showall", + hints: " [options]", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID" + }, + exec: { + output: "101 nodes highlighted" + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_inject.html b/devtools/client/commandline/test/browser_cmd_inject.html new file mode 100644 index 000000000..ea84be393 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_inject.js b/devtools/client/commandline/test/browser_cmd_inject.js new file mode 100644 index 000000000..ec618bb77 --- /dev/null +++ b/devtools/client/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/devtools/client/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/devtools/client/commandline/test/browser_cmd_inject.js", + check: { + input: "inject http://example.com/browser/devtools/client/commandline/test/browser_cmd_inject.js", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV", + 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.pathname.indexOf("_inject.js") != -1, "inject url path"); + }, + status: "VALID" + } + } + }, + exec: { + output: [ /http:\/\/example.com\/browser\/devtools\/client\/commandline\/test\/browser_cmd_inject.js loaded/ ] + } + } + ]); + }).then(finish, helpers.handleError); +} diff --git a/devtools/client/commandline/test/browser_cmd_jsb.js b/devtools/client/commandline/test/browser_cmd_jsb.js new file mode 100644 index 000000000..c27cf151c --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_jsb.js @@ -0,0 +1,103 @@ +/* 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/devtools/client/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: { + output: "", + error: false + } + } + ]); + + 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/devtools/client/commandline/test/browser_cmd_jsb_script.jsi b/devtools/client/commandline/test/browser_cmd_jsb_script.jsi new file mode 100644 index 000000000..dcaac807c --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_listen.js b/devtools/client/commandline/test/browser_cmd_listen.js new file mode 100644 index 000000000..91746c2aa --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_listen.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the listen/unlisten commands work as they should. + +const TEST_URI = "http://example.com/browser/devtools/client/commandline/" + + "test/browser_cmd_cookie.html"; + +function test() { + return Task.spawn(testTask).then(finish, helpers.handleError); +} + +var tests = { + testInput: function (options) { + return helpers.audit(options, [ + { + setup: "listen", + check: { + input: "listen", + markup: "VVVVVV", + status: "VALID" + }, + }, + { + setup: "unlisten", + check: { + input: "unlisten", + markup: "VVVVVVVV", + status: "VALID" + }, + exec: { + output: "All TCP ports closed" + } + }, + { + setup: function () { + return helpers.setInput(options, "listen"); + }, + check: { + input: "listen", + hints: " [port] [protocol]", + markup: "VVVVVV", + status: "VALID" + }, + exec: { + output: "Listening on port " + Services.prefs + .getIntPref("devtools.debugger.remote-port") + } + }, + { + setup: function () { + return helpers.setInput(options, "listen 8000"); + }, + exec: { + output: "Listening on port 8000" + } + }, + { + setup: function () { + return helpers.setInput(options, "unlisten"); + }, + exec: { + output: "All TCP ports closed" + } + } + ]); + }, +}; + +function* testTask() { + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + yield helpers.runTests(options, tests); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + Services.prefs.clearUserPref("devtools.debugger.remote-enabled"); +} diff --git a/devtools/client/commandline/test/browser_cmd_measure.js b/devtools/client/commandline/test/browser_cmd_measure.js new file mode 100644 index 000000000..7dd9bd9c9 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_measure.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests the highlight command, ensure no invalid arguments are given + +const TEST_PAGE = "data:text/html;charset=utf-8,foo"; + +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: "measure", + check: { + input: "measure", + markup: "VVVVVVV", + status: "VALID" + } + }, + { + setup: "measure on", + check: { + input: "measure on", + markup: "VVVVVVVVEE", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + }, + { + setup: "measure --visible", + check: { + input: "measure --visible", + markup: "VVVVVVVVEEEEEEEEE", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_media.html b/devtools/client/commandline/test/browser_cmd_media.html new file mode 100644 index 000000000..9bc1e7aeb --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_media.js b/devtools/client/commandline/test/browser_cmd_media.js new file mode 100644 index 000000000..559370add --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_media.js @@ -0,0 +1,88 @@ +/* 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/devtools/client/commandline/" + + "test/browser_cmd_media.html"; +var 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: Task.async(function* () { + yield ContentTask.spawn(options.browser, {}, function* () { + let color = content.getComputedStyle(content.document.body).backgroundColor; + is(color, "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: Task.async(function* () { + yield ContentTask.spawn(options.browser, {}, function* () { + let color = content.getComputedStyle(content.document.body).backgroundColor; + is(color, "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/devtools/client/commandline/test/browser_cmd_pagemod_export.html b/devtools/client/commandline/test/browser_cmd_pagemod_export.html new file mode 100644 index 000000000..a7d28828c --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_pagemod_export.js b/devtools/client/commandline/test/browser_cmd_pagemod_export.js new file mode 100644 index 000000000..c1053a065 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_pagemod_export.js @@ -0,0 +1,417 @@ +/* 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/devtools/client/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); + + function getHTML() { + return ContentTask.spawn(options.browser, {}, function* () { + return content.document.documentElement.innerHTML; + }); + } + + const initialHtml = yield getHTML(); + + function resetContent() { + return ContentTask.spawn(options.browser, initialHtml, function* (html) { + content.document.documentElement.innerHTML = html; + }); + } + + // Test exporting HTML + yield ContentTask.spawn(options.browser, {}, function* () { + content.wrappedJSObject.oldOpen = content.open; + content.wrappedJSObject.openURL = ""; + content.wrappedJSObject.open = function (url) { + // The URL is a data: URL that contains the document source + content.wrappedJSObject.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: Task.async(function* () { + yield ContentTask.spawn(options.browser, {}, function* () { + let openURL = content.wrappedJSObject.openURL; + 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">#/ + ] + } + } + ]); + + yield ContentTask.spawn(options.browser, {}, function* () { + content.wrappedJSObject.open = content.wrappedJSObject.oldOpen; + delete content.wrappedJSObject.openURL; + delete content.wrappedJSObject.oldOpen; + }); + + // 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: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "no change in the page"); + }) + }, + { + setup: "pagemod replace sOme foOBar true", + exec: { + output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + isnot(html.indexOf('<p class="foOBarclass">.foOBarclass'), -1, + ".someclass changed to .foOBarclass"); + isnot(html.indexOf('<p id="foOBarid">#foOBarid'), -1, + "#someid changed to #foOBarid"); + + yield resetContent(); + }) + }, + { + setup: "pagemod replace some foobar --contentOnly", + exec: { + output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + 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)"); + + yield resetContent(); + }) + }, + { + setup: "pagemod replace some foobar --attrOnly", + exec: { + output: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + 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)"); + + yield resetContent(); + }) + }, + { + setup: "pagemod replace some foobar --root head", + exec: { + output: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed"); + }) + }, + { + setup: "pagemod replace some foobar --selector .someclass,div,span", + exec: { + output: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + isnot(html.indexOf('<p class="foobarclass">.foobarclass'), -1, + ".someclass changed to .foobarclass"); + isnot(html.indexOf('<p id="someid">#someid'), -1, + "#someid did not change"); + + yield 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: Task.async(function* () { + let html = yield getHTML(); + + 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"); + + yield resetContent(); + }) + }, + { + setup: "pagemod remove element p head", + exec: { + output: /^[^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed in the page"); + }) + }, + { + setup: "pagemod remove element p --ifEmptyOnly", + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed in the page"); + }) + }, + { + setup: "pagemod remove element meta,title --ifEmptyOnly", + exec: { + output: /^[^:]+: 2\. [^:]+: 1\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + is(html.indexOf("<meta charset="), -1, "<meta> removed"); + isnot(html.indexOf("<title>"), -1, "<title> not removed"); + + yield resetContent(); + }) + }, + { + setup: "pagemod remove element p --stripOnly", + exec: { + output: /^[^:]+: 3\. [^:]+: 3\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + 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"); + + yield 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 }, // 'root' is a node which is remote + // so we can't see the value in tests + 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 }, // 'root' is a node which is remote + // so we can't see the value in tests + ignoreCase: { value: false }, + } + }, + post: function () { + return new Promise(resolve => { + executeSoon(resolve); + }); + } + }, + { + setup: "pagemod remove attribute foo bar", + exec: { + output: /^[^:]+: 0\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed in the page"); + }) + }, + { + setup: "pagemod remove attribute foo p", + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed in the page"); + }) + }, + { + setup: "pagemod remove attribute id p,span", + exec: { + output: /^[^:]+: 5\. [^:]+: 1\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + is(html.indexOf('<p id="someid">#someid'), -1, "p#someid attribute removed"); + isnot(html.indexOf("<p>#someid"), -1, "p with someid content still exists"); + + yield resetContent(); + }) + }, + { + setup: "pagemod remove attribute Class p", + exec: { + output: /^[^:]+: 3\. [^:]+: 0\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + is(html, initialHtml, "nothing changed in the page"); + }) + }, + { + setup: "pagemod remove attribute Class p --ignoreCase", + exec: { + output: /^[^:]+: 3\. [^:]+: 1\.\s*$/ + }, + post: Task.async(function* () { + let html = yield getHTML(); + + is(html.indexOf('<p class="someclass">.someclass'), -1, + "p.someclass attribute removed"); + isnot(html.indexOf("<p>.someclass"), -1, + "p with someclass content still exists"); + + yield resetContent(); + }) + }, + ]); + + // Shutdown + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_paintflashing.js b/devtools/client/commandline/test/browser_cmd_paintflashing.js new file mode 100644 index 000000000..09d5edc59 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_paintflashing.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the paintflashing command correctly sets its state. + +"use strict"; + +const TEST_URI = "http://example.com/browser/devtools/client/commandline/" + + "test/browser_cmd_cookie.html"; + +function test() { + return Task.spawn(testTask).then(finish, helpers.handleError); +} + +var tests = { + testInput: function (options) { + let toggleCommand = options.requisition.system.commands.get("paintflashing toggle"); + + let _tab = options.tab; + + let actions = [ + { + command: "paintflashing on", + isChecked: true, + label: "checked after on" + }, + { + command: "paintflashing off", + isChecked: false, + label: "unchecked after off" + }, + { + command: "paintflashing toggle", + isChecked: true, + label: "checked after toggle" + }, + { + command: "paintflashing toggle", + isChecked: false, + label: "unchecked after toggle" + } + ]; + + return helpers.audit(options, actions.map(spec => ({ + setup: spec.command, + exec: {}, + post: () => is(toggleCommand.state.isChecked({_tab}), spec.isChecked, spec.label) + }))); + }, +}; + +function* testTask() { + let options = yield helpers.openTab(TEST_URI); + yield helpers.openToolbar(options); + + yield helpers.runTests(options, tests); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_pref1.js b/devtools/client/commandline/test/browser_cmd_pref1.js new file mode 100644 index 000000000..4dc34f7ae --- /dev/null +++ b/devtools/client/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 + +var 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 netmonEnabledOrig = prefBranch.getBoolPref("devtools.netmonitor.enabled"); + info("originally: devtools.netmonitor.enabled = " + netmonEnabledOrig); + + 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.netmoni", + check: { + input: "pref show devtools.netmoni", + hints: "tor.enabled", + markup: "VVVVVVVVVVIIIIIIIIIIIIIIII", + status: "ERROR", + tooltipState: "true:importantFieldFlag", + args: { + setting: { value: undefined, status: "INCOMPLETE" }, + } + }, + }, + { + setup: "pref reset devtools.netmonitor.enabled", + check: { + input: "pref reset devtools.netmonitor.enabled", + hints: "", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV", + status: "VALID" + }, + }, + { + setup: "pref show devtools.netmonitor.enabled 4", + check: { + input: "pref show devtools.netmonitor.enabled 4", + hints: "", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE", + status: "ERROR" + }, + }, + { + setup: "pref set devtools.netmonitor.enabled 4", + check: { + input: "pref set devtools.netmonitor.enabled 4", + hints: "", + markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE", + status: "ERROR", + args: { + setting: { arg: " devtools.netmonitor.enabled" }, + value: { status: "ERROR", message: "Can\u2019t use \u20184\u2019." }, + } + }, + }, + { + 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.netmonitor.enabled", + check: { + args: { + setting: { + value: options.requisition.system.settings.get("devtools.netmonitor.enabled") + } + }, + }, + exec: { + output: "devtools.netmonitor.enabled: " + netmonEnabledOrig, + }, + post: function () { + prefBranch.setBoolPref("devtools.netmonitor.enabled", netmonEnabledOrig); + } + }, + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_pref2.js b/devtools/client/commandline/test/browser_cmd_pref2.js new file mode 100644 index 000000000..44619517e --- /dev/null +++ b/devtools/client/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 + +var 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/devtools/client/commandline/test/browser_cmd_pref3.js b/devtools/client/commandline/test/browser_cmd_pref3.js new file mode 100644 index 000000000..8ce5ffe5a --- /dev/null +++ b/devtools/client/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 + +var prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +var 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/devtools/client/commandline/test/browser_cmd_qsa.js b/devtools/client/commandline/test/browser_cmd_qsa.js new file mode 100644 index 000000000..551d47739 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_qsa.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the qsa commands work as they should.
+
+const TEST_URI = "data:text/html;charset=utf-8,<body></body>";
+
+function test() {
+ helpers.addTabWithToolbar(TEST_URI, function (options) {
+ return helpers.audit(options, [
+ {
+ setup: "qsa",
+ check: {
+ input: "qsa",
+ hints: " [query]",
+ markup: "VVV",
+ status: "VALID"
+ }
+ },
+ {
+ setup: "qsa body",
+ check: {
+ input: "qsa body",
+ hints: "",
+ markup: "VVVVVVVV",
+ status: "VALID"
+ }
+ }
+ ]);
+ }).then(finish, helpers.handleError);
+}
diff --git a/devtools/client/commandline/test/browser_cmd_restart.js b/devtools/client/commandline/test/browser_cmd_restart.js new file mode 100644 index 000000000..cf4c1a5d5 --- /dev/null +++ b/devtools/client/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/devtools/client/commandline/test/browser_cmd_rulers.js b/devtools/client/commandline/test/browser_cmd_rulers.js new file mode 100644 index 000000000..8fc099257 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_rulers.js @@ -0,0 +1,53 @@ +/* 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 + +var TEST_PAGE = "data:text/html;charset=utf-8,foo"; + +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: "rulers", + check: { + input: "rulers", + markup: "VVVVVV", + status: "VALID" + } + }, + { + setup: "rulers on", + check: { + input: "rulers on", + markup: "VVVVVVVEE", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + }, + { + setup: "rulers --visible", + check: { + input: "rulers --visible", + markup: "VVVVVVVEEEEEEEEE", + status: "ERROR" + }, + exec: { + output: "Error: Too many arguments" + } + } + ]); + + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); +} diff --git a/devtools/client/commandline/test/browser_cmd_screenshot.html b/devtools/client/commandline/test/browser_cmd_screenshot.html new file mode 100644 index 000000000..d86966188 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_screenshot.html @@ -0,0 +1,18 @@ +<html> + <head> + <style> + img { + height: 100px; + width: 100px; + } + .overflow { + overflow: scroll; + height: 200%; + width: 200%; + } + </style> + </head> + <body> + <img id="testImage" ></img> + </body> +</html> diff --git a/devtools/client/commandline/test/browser_cmd_screenshot.js b/devtools/client/commandline/test/browser_cmd_screenshot.js new file mode 100644 index 000000000..e7f3d0587 --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_screenshot.js @@ -0,0 +1,374 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* global helpers, btoa, whenDelayedStartupFinished, OpenBrowserWindow */ + +// Test that screenshot command works properly + +"use strict"; + +const TEST_URI = "http://example.com/browser/devtools/client/commandline/" + + "test/browser_cmd_screenshot.html"; + +var FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils; + +function test() { + // This test gets bombarded by a cascade of GCs and often takes 50s so lets be + // safe and give the test 90s to run. + requestLongerTimeout(3); + + 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 }); + let browser = options.browser; + 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", + }, + }, + ]); + + // 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 }, + }, + }, + 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 + yield helpers.audit(options, [ + { + setup: "screenshot --clipboard", + check: { + args: { + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + Assert.equal(imgSize.width, content.innerWidth, + "Image width matches window size"); + Assert.equal(imgSize.height, content.innerHeight, + "Image height matches window size"); + }); + }) + }, + { + setup: "screenshot --fullpage --clipboard", + check: { + args: { + fullpage: { value: true }, + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + Assert.equal(imgSize.width, + content.innerWidth + content.scrollMaxX - content.scrollMinX, + "Image width matches page size"); + Assert.equal(imgSize.height, + content.innerHeight + content.scrollMaxY - content.scrollMinY, + "Image height matches page size"); + }); + }) + }, + { + setup: "screenshot --selector img#testImage --clipboard", + check: { + args: { + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + let img = content.document.querySelector("img#testImage"); + Assert.equal(imgSize.width, img.clientWidth, + "Image width matches element size"); + Assert.equal(imgSize.height, img.clientHeight, + "Image height matches element size"); + }); + }) + }, + ]); + + // Trigger scrollbars by forcing document to overflow + // This only affects results on OSes with scrollbars that reduce document size + // (non-floating scrollbars). With default OS settings, this means Windows + // and Linux are affected, but Mac is not. For Mac to exhibit this behavior, + // change System Preferences -> General -> Show scroll bars to Always. + yield ContentTask.spawn(browser, {}, function* () { + content.document.body.classList.add("overflow"); + }); + + let scrollbarSize = yield ContentTask.spawn(browser, {}, function* () { + const winUtils = content.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let scrollbarHeight = {}; + let scrollbarWidth = {}; + winUtils.getScrollbarSize(true, scrollbarWidth, scrollbarHeight); + return { + width: scrollbarWidth.value, + height: scrollbarHeight.value, + }; + }); + + info(`Scrollbar size: ${scrollbarSize.width}x${scrollbarSize.height}`); + + // Test capture to clipboard in presence of scrollbars + yield helpers.audit(options, [ + { + setup: "screenshot --clipboard", + check: { + args: { + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + imgSize1.scrollbarWidth = scrollbarSize.width; + imgSize1.scrollbarHeight = scrollbarSize.height; + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + Assert.equal(imgSize.width, content.innerWidth - imgSize.scrollbarWidth, + "Image width matches window size minus scrollbar size"); + Assert.equal(imgSize.height, content.innerHeight - imgSize.scrollbarHeight, + "Image height matches window size minus scrollbar size"); + }); + }) + }, + { + setup: "screenshot --fullpage --clipboard", + check: { + args: { + fullpage: { value: true }, + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + imgSize1.scrollbarWidth = scrollbarSize.width; + imgSize1.scrollbarHeight = scrollbarSize.height; + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + Assert.equal(imgSize.width, + (content.innerWidth + content.scrollMaxX - + content.scrollMinX) - imgSize.scrollbarWidth, + "Image width matches page size minus scrollbar size"); + Assert.equal(imgSize.height, + (content.innerHeight + content.scrollMaxY - + content.scrollMinY) - imgSize.scrollbarHeight, + "Image height matches page size minus scrollbar size"); + }); + }) + }, + { + setup: "screenshot --selector img#testImage --clipboard", + check: { + args: { + clipboard: { value: true }, + }, + }, + exec: { + output: new RegExp("^Copied to clipboard.$"), + }, + post: Task.async(function* () { + let imgSize1 = yield getImageSizeFromClipboard(); + yield ContentTask.spawn(browser, imgSize1, function* (imgSize) { + let img = content.document.querySelector("img#testImage"); + Assert.equal(imgSize.width, img.clientWidth, + "Image width matches element size"); + Assert.equal(imgSize.height, img.clientHeight, + "Image height matches element size"); + }); + }) + }, + ]); + + 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); + }); + }); + }); +} + +let getImageSizeFromClipboard = Task.async(function* () { + 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); + let flavor = "image/png"; + trans.init(null); + trans.addDataFlavor(flavor); + + clip.getData(trans, clipid.kGlobalClipboard); + let data = new Object(); + let dataLength = new Object(); + trans.getTransferData(flavor, data, dataLength); + + ok(data.value, "screenshot exists"); + ok(dataLength.value > 0, "screenshot has length"); + + let image = data.value; + let dataURI = `data:${flavor};base64,`; + + // Due to the differences in how images could be stored in the clipboard the + // checks below are needed. The clipboard could already provide the image as + // byte streams, but also as pointer, or as image container. If it's not + // possible obtain a byte stream, the function returns `null`. + if (image instanceof Ci.nsISupportsInterfacePointer) { + image = image.data; + } + + if (image instanceof Ci.imgIContainer) { + image = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .encodeImage(image, flavor); + } + + if (image instanceof Ci.nsIInputStream) { + let binaryStream = Cc["@mozilla.org/binaryinputstream;1"] + .createInstance(Ci.nsIBinaryInputStream); + binaryStream.setInputStream(image); + let rawData = binaryStream.readBytes(binaryStream.available()); + let charCodes = Array.from(rawData, c => c.charCodeAt(0) & 0xff); + let encodedData = String.fromCharCode(...charCodes); + encodedData = btoa(encodedData); + dataURI = dataURI + encodedData; + } else { + throw new Error("Unable to read image data"); + } + + let img = document.createElementNS("http://www.w3.org/1999/xhtml", "img"); + + let loaded = new Promise(resolve => { + img.addEventListener("load", function onLoad() { + img.removeEventListener("load", onLoad); + resolve(); + }); + }); + + img.src = dataURI; + document.documentElement.appendChild(img); + yield loaded; + img.remove(); + + return { + width: img.width, + height: img.height, + }; +}); diff --git a/devtools/client/commandline/test/browser_cmd_settings.js b/devtools/client/commandline/test/browser_cmd_settings.js new file mode 100644 index 000000000..051d81f2f --- /dev/null +++ b/devtools/client/commandline/test/browser_cmd_settings.js @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the pref commands work + +var prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService).getBranch(null) + .QueryInterface(Ci.nsIPrefBranch2); + +var 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); + + const { createSystem } = require("gcli/system"); + const system = createSystem({ location: "server" }); + + const gcliInit = require("devtools/shared/gcli/commands/index"); + gcliInit.addAllItemsByModule(system); + yield system.load(); + + let settings = system.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/devtools/client/commandline/test/browser_gcli_async.js b/devtools/client/commandline/test/browser_gcli_async.js new file mode 100644 index 000000000..4ce564d8a --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_async.js @@ -0,0 +1,110 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_async.js"); +} + +// 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: { + 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: { + 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: { + arg: " Shalom ", + status: "VALID", + message: "" + }, + } + } + } + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_canon.js b/devtools/client/commandline/test/browser_gcli_canon.js new file mode 100644 index 000000000..807244505 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_canon.js @@ -0,0 +1,286 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_canon.js"); +} + +// 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" ] } }, + ], + customProp1: "localValue", + customProp2: true, + customProp3: 42, + 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 customProps = [ "customProp1", "customProp2", "customProp3", ]; + var commandSpecs2 = altCommands.getCommandSpecs(customProps); + assert.is(JSON.stringify(commandSpecs2), + "[{" + + '"item":"command",' + + '"name":"tss",' + + '"params":[' + + '{"name":"str","type":"string"},' + + '{"name":"num","type":"number"},' + + '{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}' + + "]," + + '"isParent":false,' + + '"customProp1":"localValue",' + + '"customProp2":true,' + + '"customProp3":42' + + "}]", + "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/devtools/client/commandline/test/browser_gcli_cli1.js b/devtools/client/commandline/test/browser_gcli_cli1.js new file mode 100644 index 000000000..5c7d75ead --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_cli1.js @@ -0,0 +1,528 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_cli1.js"); +} + +// 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 \u2018optionType\u2019." + }, + optionValue: { + value: undefined, + arg: "", + status: "INCOMPLETE", + message: "Value required for \u2018optionValue\u2019." + } + } + } + }, + { + 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 \u2018optionType\u2019." + }, + optionValue: { + value: undefined, + arg: "", + status: "INCOMPLETE", + message: "Value required for \u2018optionValue\u2019." + } + } + } + }, + { + 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 \u2018optionType\u2019." + }, + optionValue: { + value: undefined, + arg: "", + status: "INCOMPLETE", + message: "Value required for \u2018optionValue\u2019." + } + } + } + }, + { + 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\u2019t use \u2018option\u2019." + }, + optionValue: { + value: undefined, + arg: "", + status: "INCOMPLETE", + message: "Value required for \u2018optionValue\u2019." + } + } + } + }, + { + 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 \u2018optionValue\u2019." + } + } + } + }, + { + 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 \u2018optionValue\u2019." + } + } + } + }, + { + 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 \u2018optionValue\u2019." + } + } + } + } + ]); +}; + +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/devtools/client/commandline/test/browser_gcli_cli2.js b/devtools/client/commandline/test/browser_gcli_cli2.js new file mode 100644 index 000000000..7ae5174d3 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_cli2.js @@ -0,0 +1,788 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_cli2.js"); +} + +// var helpers = require('./helpers'); + +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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018num\u2019." + } + } + } + }, + { + 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 \u2018num\u2019." + } + } + } + }, + { + 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\u2019t convert \u201cx\u201d 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\u2019t convert \u201c1.5\u201d 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 \u2018num\u2019." + } + } + } + }, + { + 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: "" } + } + } + }, + { + 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\u2019t convert \u201cx\u201d to a number.", + predictions: [ ], + unassigned: [ ], + args: { + command: { name: "tsf" }, + num: { + value: undefined, + arg: " x", + status: "ERROR", + message: "Can\u2019t convert \u201cx\u201d to a number." + } + } + } + } + ]); +}; + +exports.testElementWeb = function (options) { + return helpers.audit(options, [ + { + setup: "tse #gcli-root", + check: { + input: "tse #gcli-root", + hints: " [options]", + markup: "VVVVVVVVVVVVVV", + cursor: 14, + current: "node", + status: "VALID", + predictions: [ ], + unassigned: [ ], + args: { + command: { name: "tse" }, + node: { + arg: " #gcli-root", + status: "VALID", + message: "" + }, + nodes: { arg: "", status: "VALID", message: "" }, + nodes2: { arg: "", status: "VALID", message: "" }, + } + } + } + ]); +}; + +exports.testElement = function (options) { + return helpers.audit(options, [ + { + 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: { 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, // PhantomJS gets predictions wrong + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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 \u2018text\u2019." + } + } + } + }, + { + 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/devtools/client/commandline/test/browser_gcli_completion1.js b/devtools/client/commandline/test/browser_gcli_completion1.js new file mode 100644 index 000000000..274f831bc --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_completion1.js @@ -0,0 +1,277 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_completion1.js"); +} + +// 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, // PhantomJS gets predictions wrong + 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/devtools/client/commandline/test/browser_gcli_completion2.js b/devtools/client/commandline/test/browser_gcli_completion2.js new file mode 100644 index 000000000..309070b1f --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_completion2.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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_completion2.js"); +} + +// 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: "" + } + }, + { + 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/devtools/client/commandline/test/browser_gcli_context.js b/devtools/client/commandline/test/browser_gcli_context.js new file mode 100644 index 000000000..499c074aa --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_context.js @@ -0,0 +1,239 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_context.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_date.js b/devtools/client/commandline/test/browser_gcli_date.js new file mode 100644 index 000000000..9d50aebcb --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_date.js @@ -0,0 +1,358 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_date.js"); +} + +// 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.nudge(min, 1); + 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.nudge(conversion.value, 1); + var minusOne = date.nudge(plusOne, -1); + + // 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: "testCommandOutput", + 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: "testCommandOutput", + 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: "testCommandOutput", + 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: "testCommandOutput", + error: false + } + } + ]); +}; + +exports.testIncrDecr = function (options) { + return helpers.audit(options, [ + { + // createRequisitionAutomator doesn't fake UP/DOWN well enough + skipRemainingIf: options.isNode, + 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/devtools/client/commandline/test/browser_gcli_exec.js b/devtools/client/commandline/test/browser_gcli_exec.js new file mode 100644 index 000000000..ef3b9fffe --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_exec.js @@ -0,0 +1,656 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_exec.js"); +} + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +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=option1 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=option2 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=option1 optionValue=10" + } + }, + { + skipIf: options.isRemote, + setup: "tsv option2 10", + check: { + args: { optionValue: { value: 10 } } + }, + exec: { + output: "Exec: tsv optionType=option2 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: { + arg: " { 1 + 1 }", + status: "VALID", + message: "" + } + } + }, + exec: { + output: "Exec: tsj javascript=1 + 1" + } + } + ]); +}; + +exports.testExecNode = function (options) { + return helpers.audit(options, [ + { + skipIf: options.isRemote, + setup: "tse :root", + check: { + input: "tse :root", + hints: " [options]", + markup: "VVVVVVVVV", + cursor: 9, + current: "node", + status: "VALID", + predictions: [ ], + unassigned: [ ], + args: { + command: { name: "tse" }, + node: { + arg: " :root", + status: "VALID", + message: "" + }, + nodes: { + arg: "", + status: "VALID", + message: "" + }, + nodes2: { + arg: "", + status: "VALID", + message: "" + } + } + }, + exec: { + output: /^Exec: tse/ + }, + post: function (output) { + assert.is(output.data.args.node, ":root", "node should be :root"); + assert.is(output.data.args.nodes, "Error", "nodes should be Error"); + assert.is(output.data.args.nodes2, "Error", "nodes2 should be Error"); + } + } + ]); +}; + +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= bool=false txt2=d num=42" + } + } + ]); +}; + +exports.testNested = function (options) { + var commands = options.requisition.system.commands; + commands.add({ + name: "nestorama", + exec: function (args, context) { + return context.updateExec("tsb").then(function (tsbOutput) { + return context.updateExec("tsu 6").then(function (tsuOutput) { + return JSON.stringify({ + tsb: tsbOutput.data, + tsu: tsuOutput.data + }); + }); + }); + } + }); + + return helpers.audit(options, [ + { + setup: "nestorama", + exec: { + output: + "{" + + '"tsb":{' + + '"name":"tsb",' + + '"args":{"toggle":"false"}' + + "}," + + '"tsu":{' + + '"name":"tsu",' + + '"args":{"num":"6"}' + + "}" + + "}" + }, + post: function () { + commands.remove("nestorama"); + } + } + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_fail.js b/devtools/client/commandline/test/browser_gcli_fail.js new file mode 100644 index 000000000..6a9b5e9f5 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_fail.js @@ -0,0 +1,73 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_fail.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_file.js b/devtools/client/commandline/test/browser_gcli_file.js new file mode 100644 index 000000000..4b24ed570 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_file.js @@ -0,0 +1,821 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_file.js"); +} + +// var helpers = require('./helpers'); + +var local = false; + +exports.testBasic = function (options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isFirefox, // No file implementation in Firefox + 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/devtools/client/commandline/test/browser_gcli_fileparser.js b/devtools/client/commandline/test/browser_gcli_fileparser.js new file mode 100644 index 000000000..3b1c76ad5 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_fileparser.js @@ -0,0 +1,46 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_fileparser.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_filesystem.js b/devtools/client/commandline/test/browser_gcli_filesystem.js new file mode 100644 index 000000000..19087b74e --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_filesystem.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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_filesystem.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_focus.js b/devtools/client/commandline/test/browser_gcli_focus.js new file mode 100644 index 000000000..3229a6a19 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_focus.js @@ -0,0 +1,67 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_focus.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_history.js b/devtools/client/commandline/test/browser_gcli_history.js new file mode 100644 index 000000000..e01426031 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_history.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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_history.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_incomplete.js b/devtools/client/commandline/test/browser_gcli_incomplete.js new file mode 100644 index 000000000..38424b745 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_incomplete.js @@ -0,0 +1,439 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_incomplete.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_inputter.js b/devtools/client/commandline/test/browser_gcli_inputter.js new file mode 100644 index 000000000..3fa3e7806 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_inputter.js @@ -0,0 +1,97 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_inputter.js"); +} + +// 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.name, "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/devtools/client/commandline/test/browser_gcli_intro.js b/devtools/client/commandline/test/browser_gcli_intro.js new file mode 100644 index 000000000..0fe640d4c --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_intro.js @@ -0,0 +1,71 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_intro.js"); +} + +// 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", + check: { + typed: "intro", + markup: "VVVVV", + status: "VALID", + hints: "" + }, + exec: { + output: [ + /command\s*line/, + /help/, + /F1/, + /Escape/ + ] + } + } + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_js.js b/devtools/client/commandline/test/browser_gcli_js.js new file mode 100644 index 000000000..4d36cedd8 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_js.js @@ -0,0 +1,570 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_js.js"); +} + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.setup = function (options) { + if (jsTestDisallowed(options)) { + return; + } + + // Check that we're not trespassing on 'donteval' + var win = options.requisition.environment.window; + Object.defineProperty(win, "donteval", { + get: function () { + assert.ok(false, "donteval should not be used"); + console.trace(); + return { cant: "", touch: "", "this": "" }; + }, + enumerable: true, + configurable: true + }); +}; + +exports.shutdown = function (options) { + if (jsTestDisallowed(options)) { + return; + } + + delete options.requisition.environment.window.donteval; +}; + +function jsTestDisallowed(options) { + return options.isRemote || // Altering the environment (which isn't remoted) + options.isNode || + options.requisition.system.commands.get("{") == null; +} + +exports.testBasic = function (options) { + return helpers.audit(options, [ + { + skipRemainingIf: jsTestDisallowed, + 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: jsTestDisallowed, + 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 ', + // Node/JSDom gets this wrong and omits the trailing space. Why? + 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) { + return helpers.audit(options, [ + { + skipRemainingIf: true, // Commented out until we fix non-enumerable props + 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: jsTestDisallowed, + 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/devtools/client/commandline/test/browser_gcli_keyboard1.js b/devtools/client/commandline/test/browser_gcli_keyboard1.js new file mode 100644 index 000000000..a71ac81dd --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard1.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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard1.js"); +} + +var javascript = require("gcli/types/javascript"); +// var helpers = require('./helpers'); + +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, [ + { + skipRemainingIf: options.isRemote || + options.requisition.system.commands.get("{") == null, + setup: "{ wind<TAB>", + check: { input: "{ window" } + }, + { + setup: "{ window.docum<TAB>", + check: { input: "{ window.document" } + } + ]); +}; + +exports.testJsdom = function (options) { + return helpers.audit(options, [ + { + skipIf: options.isRemote || + options.requisition.system.commands.get("{") == null, + setup: "{ window.document.titl<TAB>", + check: { input: "{ window.document.title " } + } + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_keyboard2.js b/devtools/client/commandline/test/browser_gcli_keyboard2.js new file mode 100644 index 000000000..80bb42867 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard2.js @@ -0,0 +1,121 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard2.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_keyboard3.js b/devtools/client/commandline/test/browser_gcli_keyboard3.js new file mode 100644 index 000000000..f47eab2a8 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard3.js @@ -0,0 +1,119 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard3.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_keyboard4.js b/devtools/client/commandline/test/browser_gcli_keyboard4.js new file mode 100644 index 000000000..0ee785a87 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard4.js @@ -0,0 +1,189 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard4.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_keyboard5.js b/devtools/client/commandline/test/browser_gcli_keyboard5.js new file mode 100644 index 000000000..0c2356519 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard5.js @@ -0,0 +1,57 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard5.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_keyboard6.js b/devtools/client/commandline/test/browser_gcli_keyboard6.js new file mode 100644 index 000000000..f3217f8e0 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_keyboard6.js @@ -0,0 +1,65 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_keyboard6.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_menu.js b/devtools/client/commandline/test/browser_gcli_menu.js new file mode 100644 index 000000000..59a4ec0ec --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_menu.js @@ -0,0 +1,51 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_menu.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_node.js b/devtools/client/commandline/test/browser_gcli_node.js new file mode 100644 index 000000000..3fdf1ef6d --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_node.js @@ -0,0 +1,317 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_node.js"); +} + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testNode = function (options) { + return helpers.audit(options, [ + { + 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) { + return helpers.audit(options, [ + { + 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" } + } + }, + exec: { + }, + post: function (output) { + if (!options.isRemote) { + assert.is(output.args.node.tagName, "HTML", ":root tagName"); + } + } + }, + { + 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) { + return helpers.audit(options, [ + { + 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" } + } + }, + exec: { + }, + post: function (output) { + if (!options.isRemote) { + assert.is(output.args.node.tagName, "HTML", ":root tagName"); + assert.ok(output.args.nodes.length > 3, "nodes length"); + assert.is(output.args.nodes2.length, 0, "nodes2 length"); + } + + assert.is(output.data.args.node, ":root", "node data"); + assert.is(output.data.args.nodes, "*", "nodes data"); + assert.is(output.data.args.nodes2, "Error", "nodes2 data"); + } + }, + { + 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" } + } + }, + exec: { + }, + post: function (output) { + if (!options.isRemote) { + assert.is(output.args.node.tagName, "HTML", ":root tagName"); + assert.is(output.args.nodes.length, 0, "nodes length"); + assert.is(output.args.nodes2.item(0).tagName, "DIV", "div tagName"); + } + + assert.is(output.data.args.node, ":root", "node data"); + assert.is(output.data.args.nodes, "Error", "nodes data"); + assert.is(output.data.args.nodes2, "div", "nodes2 data"); + } + }, + { + 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: "" } + } + } + }, + { + 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: "" } + } + } + }, + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_pref1.js b/devtools/client/commandline/test/browser_gcli_pref1.js new file mode 100644 index 000000000..d4788c610 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_pref1.js @@ -0,0 +1,166 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_pref1.js"); +} + +// 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: "eagerHelper", + 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: "eagerHelper <value>", + markup: "VVVVVVVVV", + status: "ERROR" + } + }, + { + setup: "pref set tempTBo", + check: { + typed: "pref set tempTBo", + hints: "ol <value>", + markup: "VVVVVVVVVIIIIIII", + status: "ERROR" + } + }, + { + skipIf: options.isRemote, + 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/devtools/client/commandline/test/browser_gcli_pref2.js b/devtools/client/commandline/test/browser_gcli_pref2.js new file mode 100644 index 000000000..3bbfc5e79 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_pref2.js @@ -0,0 +1,119 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_pref2.js"); +} + +// 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; + } + + 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 } } + } + }, + { + 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: "" + }, + 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"); + } + }, + { + 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/devtools/client/commandline/test/browser_gcli_remotews.js b/devtools/client/commandline/test/browser_gcli_remotews.js new file mode 100644 index 000000000..a4c77b858 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_remotews.js @@ -0,0 +1,485 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_remotews.js"); +} + +// 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 (front) { + assert.is(front.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 (front) { + assert.is(front.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 (front) { + assert.is(front.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/devtools/client/commandline/test/browser_gcli_remotexhr.js b/devtools/client/commandline/test/browser_gcli_remotexhr.js new file mode 100644 index 000000000..69054d2e2 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_remotexhr.js @@ -0,0 +1,485 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_remotexhr.js"); +} + +// 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 (front) { + assert.is(front.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 (front) { + assert.is(front.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 (front) { + assert.is(front.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/devtools/client/commandline/test/browser_gcli_resource.js b/devtools/client/commandline/test/browser_gcli_resource.js new file mode 100644 index 000000000..8ce846bd3 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_resource.js @@ -0,0 +1,154 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_resource.js"); +} + +// var helpers = require('./helpers'); +// var assert = require('../testharness/assert'); + +var util = require("gcli/util/util"); +var resource = require("gcli/types/resource"); +var Status = require("gcli/types/types").Status; + +exports.testCommand = function (options) { + return helpers.audit(options, [ + { + setup: "tsres ", + check: { + predictionsContains: [ "inline-css" ], + } + } + ]); +}; + +exports.testAllPredictions1 = function (options) { + if (options.isRemote) { + assert.log("Can't directly test remote types locally."); + return; + } + + var context = options.requisition.conversionContext; + var resource = options.requisition.system.types.createType("resource"); + return resource.getLookup(context).then(function (opts) { + assert.ok(opts.length > 1, "have all resources"); + + return util.promiseEach(opts, function (prediction) { + return checkPrediction(resource, prediction, context); + }); + }); +}; + +exports.testScriptPredictions = function (options) { + if (options.isRemote || options.isNode) { + assert.log("Can't directly test remote types locally."); + return; + } + + var context = options.requisition.conversionContext; + var types = options.requisition.system.types; + var resource = types.createType({ name: "resource", include: "text/javascript" }); + return resource.getLookup(context).then(function (opts) { + assert.ok(opts.length > 1, "have js resources"); + + return util.promiseEach(opts, function (prediction) { + return checkPrediction(resource, prediction, context); + }); + }); +}; + +exports.testStylePredictions = function (options) { + if (options.isRemote) { + assert.log("Can't directly test remote types locally."); + return; + } + + var context = options.requisition.conversionContext; + var types = options.requisition.system.types; + var resource = types.createType({ name: "resource", include: "text/css" }); + return resource.getLookup(context).then(function (opts) { + assert.ok(opts.length >= 1, "have css resources"); + + return util.promiseEach(opts, function (prediction) { + return checkPrediction(resource, prediction, context); + }); + }); +}; + +exports.testAllPredictions2 = function (options) { + if (options.isRemote) { + assert.log("Can't directly test remote types locally."); + return; + } + + var context = options.requisition.conversionContext; + var types = options.requisition.system.types; + + var scriptRes = types.createType({ name: "resource", include: "text/javascript" }); + return scriptRes.getLookup(context).then(function (scriptOptions) { + var styleRes = types.createType({ name: "resource", include: "text/css" }); + return styleRes.getLookup(context).then(function (styleOptions) { + var allRes = types.createType({ name: "resource" }); + return allRes.getLookup(context).then(function (allOptions) { + assert.is(scriptOptions.length + styleOptions.length, + allOptions.length, + "split"); + }); + }); + }); +}; + +exports.testAllPredictions3 = function (options) { + if (options.isRemote) { + assert.log("Can't directly test remote types locally."); + return; + } + + var context = options.requisition.conversionContext; + var types = options.requisition.system.types; + var res1 = types.createType({ name: "resource" }); + return res1.getLookup(context).then(function (options1) { + var res2 = types.createType("resource"); + return res2.getLookup(context).then(function (options2) { + assert.is(options1.length, options2.length, "type spec"); + }); + }); +}; + +function checkPrediction(res, prediction, context) { + var name = prediction.name; + var value = prediction.value; + + 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/devtools/client/commandline/test/browser_gcli_short.js b/devtools/client/commandline/test/browser_gcli_short.js new file mode 100644 index 000000000..3322ec0af --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_short.js @@ -0,0 +1,248 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_short.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_spell.js b/devtools/client/commandline/test/browser_gcli_spell.js new file mode 100644 index 000000000..0448ed39b --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_spell.js @@ -0,0 +1,72 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_spell.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_split.js b/devtools/client/commandline/test/browser_gcli_split.js new file mode 100644 index 000000000..5939f9952 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_split.js @@ -0,0 +1,67 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_split.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_string.js b/devtools/client/commandline/test/browser_gcli_string.js new file mode 100644 index 000000000..ec964b570 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_string.js @@ -0,0 +1,270 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_string.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_tokenize.js b/devtools/client/commandline/test/browser_gcli_tokenize.js new file mode 100644 index 000000000..d66b66e05 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_tokenize.js @@ -0,0 +1,290 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_tokenize.js"); +} + +// 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/devtools/client/commandline/test/browser_gcli_tooltip.js b/devtools/client/commandline/test/browser_gcli_tooltip.js new file mode 100644 index 000000000..3582490b0 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_tooltip.js @@ -0,0 +1,132 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_tooltip.js"); +} + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testActivate = function (options) { + 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/devtools/client/commandline/test/browser_gcli_types.js b/devtools/client/commandline/test/browser_gcli_types.js new file mode 100644 index 000000000..bbdd73c30 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_types.js @@ -0,0 +1,118 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_types.js"); +} + +// var assert = require('../testharness/assert'); +var util = require("gcli/util/util"); + +function forEachType(options, templateTypeSpec, callback) { + var types = options.requisition.system.types; + return util.promiseEach(types.getTypeNames(), function (name) { + var typeSpec = {}; + util.copyProperties(templateTypeSpec, typeSpec); + 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" }]; + } + else if (options.isRemote) { + if (name === "node" || name === "nodelist") { + return; + } + } + + var type = types.createType(typeSpec); + var reply = callback(type); + return Promise.resolve(reply); + }); +} + +exports.testDefault = function (options) { + 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/devtools/client/commandline/test/browser_gcli_union.js b/devtools/client/commandline/test/browser_gcli_union.js new file mode 100644 index 000000000..cff9395b4 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_union.js @@ -0,0 +1,173 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_union.js"); +} + +// 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, // PhantomJS gets predictions wrong + 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"); + } + }, + { + skipIf: options.isPhantomjs, // PhantomJS URL type is broken + 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\u2019t use \u2018on\u2019." + }, + } + } + } + ]); +}; diff --git a/devtools/client/commandline/test/browser_gcli_url.js b/devtools/client/commandline/test/browser_gcli_url.js new file mode 100644 index 000000000..dadda81f8 --- /dev/null +++ b/devtools/client/commandline/test/browser_gcli_url.js @@ -0,0 +1,107 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +const exports = {}; + +function test() { + helpers.runTestModule(exports, "browser_gcli_url.js"); +} + +// var assert = require('../testharness/assert'); +// var helpers = require('./helpers'); + +exports.testDefault = function (options) { + return helpers.audit(options, [ + { + skipRemainingIf: options.isPhantomjs, // PhantomJS URL type is broken + 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/devtools/client/commandline/test/head.js b/devtools/client/commandline/test/head.js new file mode 100644 index 000000000..b6b2e8cab --- /dev/null +++ b/devtools/client/commandline/test/head.js @@ -0,0 +1,40 @@ +/* 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/devtools/client/commandline/test/"; +const TEST_BASE_HTTPS = "https://example.com/browser/devtools/client/commandline/test/"; + +var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); +var { console } = require("resource://gre/modules/Console.jsm"); +var flags = require("devtools/shared/flags"); + +// Import the GCLI test helper +var testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/")); +Services.scriptloader.loadSubScript(testDir + "/helpers.js", this); +Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this); + +flags.testing = true; +SimpleTest.registerCleanupFunction(() => { + flags.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/devtools/client/commandline/test/helpers.js b/devtools/client/commandline/test/helpers.js new file mode 100644 index 000000000..d365765a2 --- /dev/null +++ b/devtools/client/commandline/test/helpers.js @@ -0,0 +1,1341 @@ +/* + * 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, assert } = (function () { + + var helpers = {}; + + var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + var { TargetFactory } = require("devtools/client/framework/target"); + var Services = require("Services"); + + var assert = { ok: ok, is: is, log: info }; + var util = require("gcli/util/util"); + var cli = require("gcli/cli"); + var KeyEvent = require("gcli/util/util").KeyEvent; + + const { GcliFront } = require("devtools/shared/fronts/gcli"); + +/** + * See notes in helpers.checkOptions() + */ + var createDeveloperToolbarAutomator = function (toolbar) { + var automator = { + setInput: function (typed) { + return toolbar.inputter.setInput(typed); + }, + + setCursor: function (cursor) { + return toolbar.inputter.setCursor(cursor); + }, + + focus: function () { + return toolbar.inputter.focus(); + }, + + fakeKey: function (keyCode) { + var fakeEvent = { + keyCode: keyCode, + preventDefault: function () { }, + timeStamp: new Date().getTime() + }; + + toolbar.inputter.onKeyDown(fakeEvent); + + if (keyCode === KeyEvent.DOM_VK_BACK_SPACE) { + var input = toolbar.inputter.element; + input.value = input.value.slice(0, -1); + } + + return toolbar.inputter.handleKeyUp(fakeEvent); + }, + + getInputState: function () { + return toolbar.inputter.getInputState(); + }, + + getCompleterTemplateData: function () { + return toolbar.completer._getCompleterTemplateData(); + }, + + getErrorMessage: function () { + return toolbar.tooltip.errorEle.textContent; + } + }; + + Object.defineProperty(automator, "focusManager", { + get: function () { return toolbar.focusManager; }, + enumerable: true + }); + + Object.defineProperty(automator, "field", { + get: function () { return toolbar.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 + * - 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) { + 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.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 + * @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.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 toolbar = options.chromeWindow.DeveloperToolbar; + options.automator = createDeveloperToolbarAutomator(toolbar); + options.requisition = toolbar.requisition; + return options; + }); + }; + +/** + * Navigate the current tab to a URL + */ + helpers.navigate = Task.async(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); + + let onLoaded = BrowserTestUtils.browserLoaded(options.browser); + options.browser.loadURI(url); + yield onLoaded; + + return options; + }); + +/** + * 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 which uses 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 toolbar = win.DeveloperToolbar; + innerOptions.automator = createDeveloperToolbarAutomator(toolbar); + innerOptions.requisition = toolbar.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, error.stack); + }; + + 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); + }; + + const MOCK_COMMANDS_URI = "chrome://mochitests/content/browser/devtools/client/commandline/test/mockCommands.js"; + + const defer = function () { + const deferred = { }; + deferred.promise = new Promise(function (resolve, reject) { + deferred.resolve = resolve; + deferred.reject = reject; + }); + return deferred; + }; + +/** + * This does several actions associated with running a GCLI test in mochitest + * 1. Create a new tab containing basic markup for GCLI tests + * 2. Open the developer toolbar + * 3. Register the mock commands with the server process + * 4. Wait for the proxy commands to be auto-regitstered with the client + * 5. Register the mock converters with the client process + * 6. Run all the tests + * 7. Tear down all the setup + */ + helpers.runTestModule = function (exports, name) { + return Task.spawn(function* () { + const uri = "data:text/html;charset=utf-8," + + "<style>div{color:red;}</style>" + + "<div id='gcli-root'>" + name + "</div>"; + + const options = yield helpers.openTab(uri); + options.isRemote = true; + + yield helpers.openToolbar(options); + + const system = options.requisition.system; + + // Register a one time listener with the local set of commands + const addedDeferred = defer(); + const removedDeferred = defer(); + let state = "preAdd"; // Then 'postAdd' then 'postRemove' + + system.commands.onCommandsChange.add(function (ev) { + if (system.commands.get("tsslow") != null) { + if (state === "preAdd") { + addedDeferred.resolve(); + state = "postAdd"; + } + } + else { + if (state === "postAdd") { + removedDeferred.resolve(); + state = "postRemove"; + } + } + }); + + // Send a message to add the commands to the content process + const front = yield GcliFront.create(options.target); + yield front._testOnlyAddItemsByModule(MOCK_COMMANDS_URI); + + // This will cause the local set of commands to be updated with the + // command proxies, wait for that to complete. + yield addedDeferred.promise; + + // Now we need to add the converters to the local GCLI + const converters = mockCommands.items.filter(item => item.item === "converter"); + system.addItems(converters); + + // Next run the tests + yield helpers.runTests(options, exports); + + // Finally undo the mock commands and converters + system.removeItems(converters); + const removePromise = system.commands.onCommandsChange.once(); + yield front._testOnlyRemoveItemsByModule(MOCK_COMMANDS_URI); + yield removedDeferred.promise; + + // And close everything down + yield helpers.closeToolbar(options); + yield helpers.closeTab(options); + }).then(finish, helpers.handleError); + }; + +/** + * 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.isNode && "input" in checks) { + assert.is(helpers._actual.input(options), checks.input, "input" + suffix); + } + + if (!options.isNode && "cursor" in checks) { + assert.is(helpers._actual.cursor(options), checks.cursor, "cursor" + suffix); + } + + if (!options.isNode && "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.isNode && "markup" in checks) { + assert.is(helpers._actual.markup(options), checks.markup, "markup" + suffix); + } + + if (!options.isNode && "hints" in checks) { + var hintCheck = function (actualHints) { + assert.is(actualHints, checks.hints, "hints" + suffix); + }; + outstanding.push(helpers._actual.hints(options).then(hintCheck)); + } + + if (!options.isNode && "predictions" in checks) { + var predictionsCheck = function (actualPredictions) { + helpers.arrayIs(actualPredictions, + checks.predictions, + "predictions" + suffix); + }; + outstanding.push(helpers._actual.predictions(options).then(predictionsCheck)); + } + + if (!options.isNode && "predictionsContains" in checks) { + var containsCheck = function (actualPredictions) { + checks.predictionsContains.forEach(function (prediction) { + var index = actualPredictions.indexOf(prediction); + assert.ok(index !== -1, + "predictionsContains:" + prediction + suffix); + if (index === -1) { + log("Actual predictions (" + actualPredictions.length + "): " + + actualPredictions.join(", ")); + } + }); + }; + 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.isNode && 'tooltipState' in checks) { + assert.is(helpers._actual.tooltipState(options), + checks.tooltipState, + 'tooltipState' + suffix); + } + */ + + if (!options.isNode && "outputState" in checks) { + assert.is(helpers._actual.outputState(options), + checks.outputState, + "outputState" + suffix); + } + + if (!options.isNode && "options" in checks) { + helpers.arrayIs(helpers._actual.options(options), + checks.options, + "options" + suffix); + } + + if (!options.isNode && "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.isNode && "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.isNode) { + convertPromise = output.convert("string", context); + } + else { + convertPromise = output.convert("dom", context).then(function (node) { + return (node == null) ? "" : 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. Create a dummy pass + assert.ok(true, "Each test requires at least one pass, fail or todo"); + + 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, assert: assert }; +})(); diff --git a/devtools/client/commandline/test/mockCommands.js b/devtools/client/commandline/test/mockCommands.js new file mode 100644 index 000000000..82cc7e384 --- /dev/null +++ b/devtools/client/commandline/test/mockCommands.js @@ -0,0 +1,794 @@ +/* + * 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"; + +// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT +// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT + +var mockCommands; +if (typeof exports !== "undefined") { + // If we're being loaded via require(); + mockCommands = exports; +} +else { + // If we're being loaded via loadScript in mochitest + 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, context) { + var promises = []; + + Object.keys(args).map(function (argName) { + var value = args[argName]; + var type = this.getParameterByName(argName).type; + var promise = Promise.resolve(type.stringify(value, context)); + promises.push(promise.then(function (str) { + return { name: argName, value: str }; + }.bind(this))); + }.bind(this)); + + return Promise.all(promises).then(function (data) { + var argValues = {}; + data.forEach(function (entry) { argValues[entry.name] = entry.value; }); + + return context.typedData("testCommandOutput", { + name: name, + args: argValues + }); + }.bind(this)); + }; +} + +mockCommands.items = [ + { + item: "converter", + from: "testCommandOutput", + to: "dom", + exec: function (testCommandOutput, context) { + var view = context.createView({ + data: testCommandOutput, + html: "" + + "<table>" + + "<thead>" + + "<tr>" + + '<th colspan="3">Exec: ${name}</th>' + + "</tr>" + + "</thead>" + + "<tbody>" + + '<tr foreach="key in ${args}">' + + "<td> ${key}</td>" + + "<td>=</td>" + + "<td>${args[key]}</td>" + + "</tr>" + + "</tbody>" + + "</table>", + options: { + allowEval: true + } + }); + + return view.toDom(context.document); + } + }, + { + item: "converter", + from: "testCommandOutput", + to: "string", + exec: function (testCommandOutput, context) { + var argsOut = Object.keys(testCommandOutput.args).map(function (key) { + return key + "=" + testCommandOutput.args[key]; + }).join(" "); + return "Exec: " + testCommandOutput.name + " " + argsOut; + } + }, + { + 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) { + context.environment.window.setTimeout(function () { + reject("rejected promise"); + }, 10); + }); + } + + if (args.method === "rejecttyped") { + return new Promise(function (resolve, reject) { + context.environment.window.setTimeout(function () { + reject(context.typedData("number", 54)); + }, 10); + }); + } + + if (args.method === "throwinpromise") { + return new Promise(function (resolve, reject) { + context.environment.window.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) { + context.environment.window.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; + } + }, + { + item: "command", + name: "tsres", + params: [ + { + name: "resource", + type: "resource" + } + ], + exec: createExec("tsres"), + } +]; |