summaryrefslogtreecommitdiffstats
path: root/devtools/client/commandline/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/commandline/test')
-rw-r--r--devtools/client/commandline/test/.eslintrc.js10
-rw-r--r--devtools/client/commandline/test/browser.ini124
-rw-r--r--devtools/client/commandline/test/browser_cmd_addon.js195
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid.js134
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache55
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^2
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_index.html14
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_page1.html14
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_page2.html14
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html14
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^2
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid.js173
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache5
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^2
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_index.html13
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_page1.html13
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_page2.html13
-rw-r--r--devtools/client/commandline/test/browser_cmd_appcache_valid_page3.html13
-rw-r--r--devtools/client/commandline/test/browser_cmd_calllog.js119
-rw-r--r--devtools/client/commandline/test/browser_cmd_calllog_chrome.js116
-rw-r--r--devtools/client/commandline/test/browser_cmd_commands.js63
-rw-r--r--devtools/client/commandline/test/browser_cmd_cookie.html19
-rw-r--r--devtools/client/commandline/test/browser_cmd_cookie.js170
-rw-r--r--devtools/client/commandline/test/browser_cmd_cookie_host.js41
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_oneshot.js318
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_page1.html85
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_page2.html59
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_page3.html52
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_sheetA.css22
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_sheetB.css20
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_sheetC.css20
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_sheetD.css20
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_startstop.js465
-rw-r--r--devtools/client/commandline/test/browser_cmd_csscoverage_util.js24
-rw-r--r--devtools/client/commandline/test/browser_cmd_folder.js58
-rw-r--r--devtools/client/commandline/test/browser_cmd_highlight_01.js90
-rw-r--r--devtools/client/commandline/test/browser_cmd_highlight_02.js45
-rw-r--r--devtools/client/commandline/test/browser_cmd_highlight_03.js131
-rw-r--r--devtools/client/commandline/test/browser_cmd_highlight_04.js94
-rw-r--r--devtools/client/commandline/test/browser_cmd_inject.html8
-rw-r--r--devtools/client/commandline/test/browser_cmd_inject.js69
-rw-r--r--devtools/client/commandline/test/browser_cmd_jsb.js103
-rw-r--r--devtools/client/commandline/test/browser_cmd_jsb_script.jsi2
-rw-r--r--devtools/client/commandline/test/browser_cmd_listen.js80
-rw-r--r--devtools/client/commandline/test/browser_cmd_measure.js53
-rw-r--r--devtools/client/commandline/test/browser_cmd_media.html28
-rw-r--r--devtools/client/commandline/test/browser_cmd_media.js88
-rw-r--r--devtools/client/commandline/test/browser_cmd_pagemod_export.html25
-rw-r--r--devtools/client/commandline/test/browser_cmd_pagemod_export.js417
-rw-r--r--devtools/client/commandline/test/browser_cmd_paintflashing.js60
-rw-r--r--devtools/client/commandline/test/browser_cmd_pref1.js154
-rw-r--r--devtools/client/commandline/test/browser_cmd_pref2.js105
-rw-r--r--devtools/client/commandline/test/browser_cmd_pref3.js113
-rw-r--r--devtools/client/commandline/test/browser_cmd_qsa.js33
-rw-r--r--devtools/client/commandline/test/browser_cmd_restart.js61
-rw-r--r--devtools/client/commandline/test/browser_cmd_rulers.js53
-rw-r--r--devtools/client/commandline/test/browser_cmd_screenshot.html18
-rw-r--r--devtools/client/commandline/test/browser_cmd_screenshot.js374
-rw-r--r--devtools/client/commandline/test/browser_cmd_settings.js124
-rw-r--r--devtools/client/commandline/test/browser_gcli_async.js110
-rw-r--r--devtools/client/commandline/test/browser_gcli_canon.js286
-rw-r--r--devtools/client/commandline/test/browser_gcli_cli1.js528
-rw-r--r--devtools/client/commandline/test/browser_gcli_cli2.js788
-rw-r--r--devtools/client/commandline/test/browser_gcli_completion1.js277
-rw-r--r--devtools/client/commandline/test/browser_gcli_completion2.js263
-rw-r--r--devtools/client/commandline/test/browser_gcli_context.js239
-rw-r--r--devtools/client/commandline/test/browser_gcli_date.js358
-rw-r--r--devtools/client/commandline/test/browser_gcli_exec.js656
-rw-r--r--devtools/client/commandline/test/browser_gcli_fail.js73
-rw-r--r--devtools/client/commandline/test/browser_gcli_file.js821
-rw-r--r--devtools/client/commandline/test/browser_gcli_fileparser.js46
-rw-r--r--devtools/client/commandline/test/browser_gcli_filesystem.js66
-rw-r--r--devtools/client/commandline/test/browser_gcli_focus.js67
-rw-r--r--devtools/client/commandline/test/browser_gcli_history.js72
-rw-r--r--devtools/client/commandline/test/browser_gcli_incomplete.js439
-rw-r--r--devtools/client/commandline/test/browser_gcli_inputter.js97
-rw-r--r--devtools/client/commandline/test/browser_gcli_intro.js71
-rw-r--r--devtools/client/commandline/test/browser_gcli_js.js570
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard1.js72
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard2.js121
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard3.js119
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard4.js189
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard5.js57
-rw-r--r--devtools/client/commandline/test/browser_gcli_keyboard6.js65
-rw-r--r--devtools/client/commandline/test/browser_gcli_menu.js51
-rw-r--r--devtools/client/commandline/test/browser_gcli_node.js317
-rw-r--r--devtools/client/commandline/test/browser_gcli_pref1.js166
-rw-r--r--devtools/client/commandline/test/browser_gcli_pref2.js119
-rw-r--r--devtools/client/commandline/test/browser_gcli_remotews.js485
-rw-r--r--devtools/client/commandline/test/browser_gcli_remotexhr.js485
-rw-r--r--devtools/client/commandline/test/browser_gcli_resource.js154
-rw-r--r--devtools/client/commandline/test/browser_gcli_short.js248
-rw-r--r--devtools/client/commandline/test/browser_gcli_spell.js72
-rw-r--r--devtools/client/commandline/test/browser_gcli_split.js67
-rw-r--r--devtools/client/commandline/test/browser_gcli_string.js270
-rw-r--r--devtools/client/commandline/test/browser_gcli_tokenize.js290
-rw-r--r--devtools/client/commandline/test/browser_gcli_tooltip.js132
-rw-r--r--devtools/client/commandline/test/browser_gcli_types.js118
-rw-r--r--devtools/client/commandline/test/browser_gcli_union.js173
-rw-r--r--devtools/client/commandline/test/browser_gcli_url.js107
-rw-r--r--devtools/client/commandline/test/head.js40
-rw-r--r--devtools/client/commandline/test/helpers.js1341
-rw-r--r--devtools/client/commandline/test/mockCommands.js794
103 files changed, 16688 insertions, 0 deletions
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&gt;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"),
+ }
+];