summaryrefslogtreecommitdiff
path: root/toolkit/devtools/commandline/test
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/devtools/commandline/test')
-rw-r--r--toolkit/devtools/commandline/test/browser.ini111
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_addon.js134
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js134
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache55
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^2
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html14
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html14
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html14
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html14
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^2
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js173
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache5
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^2
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html13
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html13
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html13
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html13
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_calllog.js119
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js116
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_commands.js60
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_cookie.html18
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_cookie.js170
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js318
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html85
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html59
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html52
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css22
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css20
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css20
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css20
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js457
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js24
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_folder.js58
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_highlight_01.js257
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_highlight_02.js44
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_inject.html8
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_inject.js69
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_jsb.js100
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi2
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_media.html28
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_media.js86
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html25
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js390
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_pref1.js154
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_pref2.js105
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_pref3.js113
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_restart.js61
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_screenshot.html6
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_screenshot.js181
-rw-r--r--toolkit/devtools/commandline/test/browser_cmd_settings.js120
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_async.js128
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_canon.js280
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_cli1.js544
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_cli2.js825
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_completion1.js292
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_completion2.js279
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_context.js254
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_date.js373
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_exec.js659
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_fail.js88
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_file.js839
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_fileparser.js61
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_filesystem.js81
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_focus.js82
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_history.js87
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_incomplete.js454
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_inputter.js112
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_intro.js87
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_js.js592
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard1.js104
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard2.js136
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard3.js134
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard4.js204
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard5.js72
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_keyboard6.js80
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_menu.js66
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_node.js349
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_pref1.js180
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_pref2.js151
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_remotews.js500
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_remotexhr.js500
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_resource.js169
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_short.js263
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_spell.js87
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_split.js82
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_string.js285
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_tokenize.js305
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_tooltip.js152
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_types.js153
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_union.js188
-rw-r--r--toolkit/devtools/commandline/test/browser_gcli_url.js122
-rw-r--r--toolkit/devtools/commandline/test/head.js39
-rw-r--r--toolkit/devtools/commandline/test/helpers.js1274
-rw-r--r--toolkit/devtools/commandline/test/mockCommands.js742
94 files changed, 16547 insertions, 0 deletions
diff --git a/toolkit/devtools/commandline/test/browser.ini b/toolkit/devtools/commandline/test/browser.ini
new file mode 100644
index 000000000..4a2d3ea1a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser.ini
@@ -0,0 +1,111 @@
+[DEFAULT]
+skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
+subsuite = devtools
+support-files =
+ head.js
+ helpers.js
+ mockCommands.js
+
+[browser_cmd_addon.js]
+skip-if = buildapp == 'mulet'
+[browser_cmd_calllog.js]
+skip-if = true || e10s # Bug 845831
+[browser_cmd_calllog_chrome.js]
+skip-if = true || e10s # Bug 845831
+[browser_cmd_appcache_invalid.js]
+support-files =
+ browser_cmd_appcache_invalid_appcache.appcache
+ browser_cmd_appcache_invalid_appcache.appcache^headers^
+ browser_cmd_appcache_invalid_index.html
+ browser_cmd_appcache_invalid_page1.html
+ browser_cmd_appcache_invalid_page2.html
+ browser_cmd_appcache_invalid_page3.html
+ browser_cmd_appcache_invalid_page3.html^headers^
+[browser_cmd_appcache_valid.js]
+support-files =
+ browser_cmd_appcache_valid_appcache.appcache
+ browser_cmd_appcache_valid_appcache.appcache^headers^
+ browser_cmd_appcache_valid_index.html
+ browser_cmd_appcache_valid_page1.html
+ browser_cmd_appcache_valid_page2.html
+ browser_cmd_appcache_valid_page3.html
+[browser_cmd_commands.js]
+[browser_cmd_cookie.js]
+support-files =
+ browser_cmd_cookie.html
+[browser_cmd_csscoverage_oneshot.js]
+support-files =
+ browser_cmd_csscoverage_page1.html
+ browser_cmd_csscoverage_page2.html
+ browser_cmd_csscoverage_page3.html
+ browser_cmd_csscoverage_sheetA.css
+ browser_cmd_csscoverage_sheetB.css
+ browser_cmd_csscoverage_sheetC.css
+ browser_cmd_csscoverage_sheetD.css
+[browser_cmd_csscoverage_startstop.js]
+support-files =
+ browser_cmd_csscoverage_page1.html
+ browser_cmd_csscoverage_page2.html
+ browser_cmd_csscoverage_page3.html
+ browser_cmd_csscoverage_sheetA.css
+ browser_cmd_csscoverage_sheetB.css
+ browser_cmd_csscoverage_sheetC.css
+ browser_cmd_csscoverage_sheetD.css
+[browser_cmd_folder.js]
+[browser_cmd_highlight_01.js]
+[browser_cmd_highlight_02.js]
+[browser_cmd_inject.js]
+support-files =
+ browser_cmd_inject.html
+[browser_cmd_csscoverage_util.js]
+[browser_cmd_jsb.js]
+support-files =
+ browser_cmd_jsb_script.jsi
+[browser_cmd_media.js]
+support-files =
+ browser_cmd_media.html
+[browser_cmd_pagemod_export.js]
+support-files =
+ browser_cmd_pagemod_export.html
+[browser_cmd_pref1.js]
+[browser_cmd_pref2.js]
+[browser_cmd_pref3.js]
+[browser_cmd_restart.js]
+[browser_cmd_screenshot.js]
+support-files =
+ browser_cmd_screenshot.html
+[browser_cmd_settings.js]
+[browser_gcli_async.js]
+[browser_gcli_canon.js]
+[browser_gcli_cli1.js]
+[browser_gcli_cli2.js]
+[browser_gcli_completion1.js]
+[browser_gcli_completion2.js]
+[browser_gcli_date.js]
+skip-if = true || e10s # Disabled until TZ bug is fixed
+[browser_gcli_exec.js]
+[browser_gcli_fail.js]
+[browser_gcli_file.js]
+[browser_gcli_focus.js]
+[browser_gcli_history.js]
+[browser_gcli_incomplete.js]
+[browser_gcli_inputter.js]
+skip-if = true # Bug 1093205 - Test does not run in Firefox due to missing terminal bug
+[browser_gcli_intro.js]
+[browser_gcli_js.js]
+[browser_gcli_keyboard1.js]
+[browser_gcli_keyboard2.js]
+[browser_gcli_keyboard3.js]
+[browser_gcli_keyboard4.js]
+[browser_gcli_keyboard5.js]
+[browser_gcli_menu.js]
+[browser_gcli_node.js]
+[browser_gcli_resource.js]
+[browser_gcli_short.js]
+[browser_gcli_spell.js]
+[browser_gcli_split.js]
+[browser_gcli_tokenize.js]
+[browser_gcli_tooltip.js]
+skip-if = true # Bug 1093205 - Test does not run in Firefox due to missing terminal
+[browser_gcli_types.js]
+[browser_gcli_union.js]
diff --git a/toolkit/devtools/commandline/test/browser_cmd_addon.js b/toolkit/devtools/commandline/test/browser_cmd_addon.js
new file mode 100644
index 000000000..14fb93e44
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_addon.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the addon commands works as they should
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab("about:blank");
+ yield helpers.openToolbar(options);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'addon list dictionary',
+ check: {
+ input: 'addon list dictionary',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: 'There are no add-ons of that type installed.'
+ }
+ },
+ {
+ setup: 'addon list extension',
+ check: {
+ input: 'addon list extension',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: [/The following/, /Mochitest/, /Special Powers/]
+ }
+ },
+ {
+ setup: 'addon list locale',
+ check: {
+ input: 'addon list locale',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: 'There are no add-ons of that type installed.'
+ }
+ },
+ {
+ setup: 'addon list plugin',
+ check: {
+ input: 'addon list plugin',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: [/Test Plug-in/, /Second Test Plug-in/]
+ }
+ },
+ {
+ setup: 'addon list theme',
+ check: {
+ input: 'addon list theme',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: [/following themes/, /Default/]
+ }
+ },
+ {
+ setup: 'addon list all',
+ check: {
+ input: 'addon list all',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: [/The following/, /Default/, /Mochitest/, /Test Plug-in/,
+ /Second Test Plug-in/, /Special Powers/]
+ }
+ },
+ {
+ setup: 'addon disable Test_Plug-in_1.0.0.0',
+ check: {
+ input: 'addon disable Test_Plug-in_1.0.0.0',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: 'Test Plug-in 1.0.0.0 disabled.'
+ }
+ },
+ {
+ setup: 'addon disable WRONG',
+ check: {
+ input: 'addon disable WRONG',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVEEEEE',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'addon enable Test_Plug-in_1.0.0.0',
+ check: {
+ input: 'addon enable Test_Plug-in_1.0.0.0',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ command: { name: 'addon enable' },
+ addon: {
+ value: function(addon) {
+ is(addon.name, 'Test Plug-in', 'test plugin name');
+ },
+ status: 'VALID'
+ }
+ }
+ },
+ exec: {
+ output: 'Test Plug-in 1.0.0.0 enabled.'
+ }
+ }
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js
new file mode 100644
index 000000000..15cade68a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the appcache validate works as they should with an invalid
+// manifest.
+
+const TEST_URI = "http://sub1.test1.example.com/browser/browser/devtools/commandline/" +
+ "test/browser_cmd_appcache_invalid_index.html";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let lines = [
+ 'Manifest has a character encoding of ISO-8859-1. Manifests must have the ' +
+ 'utf-8 character encoding.',
+ 'The first line of the manifest must be "CACHE MANIFEST" at line 1.',
+ '"CACHE MANIFEST" is only valid on the first line but was found at line 3.',
+ 'images/sound-icon.png points to a resource that is not available at line 9.',
+ 'images/background.png points to a resource that is not available at line 10.',
+ '/checking.cgi points to a resource that is not available at line 13.',
+ 'Asterisk (*) incorrectly used in the NETWORK section at line 14. If a line ' +
+ 'in the NETWORK section contains only a single asterisk character, then any ' +
+ 'URI not listed in the manifest will be treated as if the URI was listed in ' +
+ 'the NETWORK section. Otherwise such URIs will be treated as unavailable. ' +
+ 'Other uses of the * character are prohibited',
+ '../rel.html points to a resource that is not available at line 17.',
+ '../../rel.html points to a resource that is not available at line 18.',
+ '../../../rel.html points to a resource that is not available at line 19.',
+ '../../../../rel.html points to a resource that is not available at line 20.',
+ '../../../../../rel.html points to a resource that is not available at line 21.',
+ '/../ is not a valid URI prefix at line 22.',
+ '/test.css points to a resource that is not available at line 23.',
+ '/test.js points to a resource that is not available at line 24.',
+ 'test.png points to a resource that is not available at line 25.',
+ '/main/features.js points to a resource that is not available at line 27.',
+ '/main/settings/index.css points to a resource that is not available at line 28.',
+ 'http://example.com/scene.jpg points to a resource that is not available at line 29.',
+ '/section1/blockedbyfallback.html points to a resource that is not available at line 30.',
+ 'http://example.com/images/world.jpg points to a resource that is not available at line 31.',
+ '/section2/blockedbyfallback.html points to a resource that is not available at line 32.',
+ '/main/home points to a resource that is not available at line 34.',
+ 'main/app.js points to a resource that is not available at line 35.',
+ '/settings/home points to a resource that is not available at line 37.',
+ '/settings/app.js points to a resource that is not available at line 38.',
+ 'The file http://sub1.test1.example.com/browser/browser/devtools/' +
+ 'commandline/test/browser_cmd_appcache_invalid_page3.html was modified ' +
+ 'after http://sub1.test1.example.com/browser/browser/devtools/' +
+ 'commandline/test/browser_cmd_appcache_invalid_appcache.appcache. Unless ' +
+ 'the text in the manifest file is changed the cached version will be used ' +
+ 'instead at line 39.',
+ 'browser_cmd_appcache_invalid_page3.html has cache-control set to no-store. ' +
+ 'This will prevent the application cache from storing the file at line 39.',
+ 'http://example.com/logo.png points to a resource that is not available at line 40.',
+ 'http://example.com/check.png points to a resource that is not available at line 41.',
+ 'Spaces in URIs need to be replaced with % at line 42.',
+ 'http://example.com/cr oss.png points to a resource that is not available at line 42.',
+ 'Asterisk (*) incorrectly used in the CACHE section at line 43. If a line ' +
+ 'in the NETWORK section contains only a single asterisk character, then ' +
+ 'any URI not listed in the manifest will be treated as if the URI was ' +
+ 'listed in the NETWORK section. Otherwise such URIs will be treated as ' +
+ 'unavailable. Other uses of the * character are prohibited',
+ 'The SETTINGS section may only contain a single value, "prefer-online" or "fast" at line 47.',
+ 'FALLBACK section line 50 (/section1/ /offline1.html) prevents caching of ' +
+ 'line 30 (/section1/blockedbyfallback.html) in the CACHE section.',
+ '/offline1.html points to a resource that is not available at line 50.',
+ 'FALLBACK section line 51 (/section2/ offline2.html) prevents caching of ' +
+ 'line 32 (/section2/blockedbyfallback.html) in the CACHE section.',
+ 'offline2.html points to a resource that is not available at line 51.',
+ 'Only two URIs separated by spaces are allowed in the FALLBACK section at line 52.',
+ 'Asterisk (*) incorrectly used in the FALLBACK section at line 53. URIs ' +
+ 'in the FALLBACK section simply need to match a prefix of the request URI.',
+ 'offline3.html points to a resource that is not available at line 53.',
+ 'Invalid section name (BLAH) at line 55.',
+ 'Only two URIs separated by spaces are allowed in the FALLBACK section at line 55.'
+ ];
+
+ let options = yield helpers.openTab(TEST_URI);
+ info("window open");
+
+ // Wait for site to be cached.
+ yield helpers.listenOnce(gBrowser.contentWindow.applicationCache, 'error');
+ info("applicationCache error happened");
+
+ yield helpers.openToolbar(options);
+ info("toolbar open");
+
+ // Pages containing an appcache the notification bar gives options to allow
+ // or deny permission for the app to save data offline. Let's click Allow.
+ let notificationID = "offline-app-requested-sub1.test1.example.com";
+ let notification =
+ PopupNotifications.getNotification(notificationID, gBrowser.selectedBrowser);
+
+ if (notification) {
+ info("Authorizing offline storage.");
+ notification.mainAction.callback();
+ } else {
+ info("No notification box is available.");
+ }
+
+ info("Site now cached, running tests.");
+ yield helpers.audit(options, [
+ {
+ setup: 'appcache validate',
+ check: {
+ input: 'appcache validate',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {}
+ },
+ exec: {
+ output: lines.map(getRegexForString)
+ },
+ },
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
+
+/**
+ * Creates a regular expression that matches a string. This greatly simplifies
+ * matching and debugging long strings.
+ *
+ * @param {String} text
+ * Text to convert
+ * @return {RegExp}
+ * Regular expression matching text
+ */
+function getRegexForString(str) {
+ str = str.replace(/(\.|\\|\/|\(|\)|\[|\]|\*|\+|\?|\$|\^|\|)/g, "\\$1");
+ return new RegExp(str);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache
new file mode 100644
index 000000000..75b5d7bad
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache
@@ -0,0 +1,55 @@
+# some comment
+
+CACHE MANIFEST
+# the above is a required line
+# this is a comment
+# spaces are ignored
+# blank lines are ignored
+
+images/sound-icon.png
+images/background.png
+
+NETWORK:
+/checking.cgi
+/checking.*
+
+CACHE:
+../rel.html
+../../rel.html
+../../../rel.html
+../../../../rel.html
+../../../../../rel.html
+/../invalid.html
+/test.css
+/test.js
+test.png
+browser_cmd_appcache_invalid_index.html
+/main/features.js
+/main/settings/index.css
+http://example.com/scene.jpg
+/section1/blockedbyfallback.html
+http://example.com/images/world.jpg
+/section2/blockedbyfallback.html
+browser_cmd_appcache_invalid_page1.html
+/main/home
+main/app.js
+browser_cmd_appcache_invalid_page2.html
+/settings/home
+/settings/app.js
+browser_cmd_appcache_invalid_page3.html
+http://example.com/logo.png
+http://example.com/check.png
+http://example.com/cr oss.png
+/checking*.png
+
+SETTINGS:
+prefer-online
+fast
+
+FALLBACK:
+/section1/ /offline1.html
+/section2/ offline2.html
+dadsdsd
+* offline3.html
+
+BLAH:
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^
new file mode 100644
index 000000000..af95ed1f5
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_appcache.appcache^headers^
@@ -0,0 +1,2 @@
+Content-Type: text/cache-manifest; charset=ISO-8859-1
+Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html
new file mode 100644
index 000000000..67f9aa675
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_index.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_invalid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example index.html</h1>
+ <br />
+ <a href="browser_cmd_appcache_invalid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html
new file mode 100644
index 000000000..5ff36f102
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_invalid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page1.html</h1>
+ <br />
+ <a href="browser_cmd_appcache_invalid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html
new file mode 100644
index 000000000..7d4a0c44d
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_invalid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page2.html</h1>
+ <br />
+ <a href="browser_cmd_appcache_invalid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html
new file mode 100644
index 000000000..6777e59f8
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_invalid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page3.html</h1>
+ <br />
+ <a href="browser_cmd_appcache_invalid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_invalid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_invalid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_invalid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^
new file mode 100644
index 000000000..177130b43
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_invalid_page3.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-store, no-cache
+Last-Modified: Tue, 23 Apr 9999 11:41:13 GMT
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js
new file mode 100644
index 000000000..e9a11ead3
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the appcache commands works as they should
+
+const TEST_URI = "http://sub1.test2.example.com/browser/browser/devtools/" +
+ "commandline/test/browser_cmd_appcache_valid_index.html";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ info("adding cache listener.");
+
+ // Wait for site to be cached.
+ yield helpers.listenOnce(gBrowser.contentWindow.applicationCache, 'cached');
+
+ // Pages containing an appcache the notification bar gives options to allow
+ // or deny permission for the app to save data offline. Let's click Allow.
+ let notificationID = "offline-app-requested-sub1.test2.example.com";
+ let notification = PopupNotifications.getNotification(notificationID, gBrowser.selectedBrowser);
+
+ if (notification) {
+ info("Authorizing offline storage.");
+ notification.mainAction.callback();
+ } else {
+ info("No notification box is available.");
+ }
+
+ info("Site now cached, running tests.");
+ yield helpers.audit(options, [
+ {
+ setup: 'appcache',
+ check: {
+ input: 'appcache',
+ markup: 'IIIIIIII',
+ status: 'ERROR',
+ args: {}
+ },
+ },
+
+ {
+ setup: function() {
+ Services.prefs.setBoolPref("browser.cache.disk.enable", false);
+ return helpers.setInput(options, 'appcache list', 13);
+ },
+ check: {
+ input: 'appcache list',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {},
+ },
+ exec: {
+ output: [ /cache is disabled/ ]
+ },
+ post: function(output) {
+ Services.prefs.setBoolPref("browser.cache.disk.enable", true);
+ }
+ },
+
+ {
+ setup: 'appcache list',
+ check: {
+ input: 'appcache list',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {},
+ },
+ exec: {
+ output: [ /index/, /page1/, /page2/, /page3/ ]
+ },
+ },
+
+ {
+ setup: 'appcache list page',
+ check: {
+ input: 'appcache list page',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ search: { value: 'page' },
+ }
+ },
+ exec: {
+ output: [ /page1/, /page2/, /page3/ ]
+ },
+ post: function(output, text) {
+ ok(!text.contains("index"), "index is not contained in output");
+ }
+ },
+
+ {
+ setup: 'appcache validate',
+ check: {
+ input: 'appcache validate',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {}
+ },
+ exec: {
+ output: [ /successfully/ ]
+ },
+ },
+
+ {
+ setup: 'appcache validate ' + TEST_URI,
+ check: {
+ input: 'appcache validate ' + TEST_URI,
+ // appcache validate http://sub1.test2.example.com/browser/browser/devtools/commandline/test/browser_cmd_appcache_valid_index.html
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ uri: {
+ value: TEST_URI
+ },
+ }
+ },
+ exec: {
+ output: [ /successfully/ ]
+ },
+ },
+
+ {
+ setup: 'appcache clear',
+ check: {
+ input: 'appcache clear',
+ markup: 'VVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {},
+ },
+ exec: {
+ output: [ /successfully/ ]
+ },
+ },
+
+ {
+ setup: 'appcache list',
+ check: {
+ input: 'appcache list',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {},
+ },
+ exec: {
+ output: [ /no results/ ]
+ },
+ post: function(output, text) {
+ ok(!text.contains("index"), "index is not contained in output");
+ ok(!text.contains("page1"), "page1 is not contained in output");
+ ok(!text.contains("page2"), "page1 is not contained in output");
+ ok(!text.contains("page3"), "page1 is not contained in output");
+ }
+ },
+
+ {
+ setup: 'appcache viewentry --key ' + TEST_URI,
+ check: {
+ input: 'appcache viewentry --key ' + TEST_URI,
+ // appcache viewentry --key http://sub1.test2.example.com/browser/browser/devtools/commandline/test/browser_cmd_appcache_valid_index.html
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {}
+ },
+ },
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache
new file mode 100644
index 000000000..4f62825e9
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache
@@ -0,0 +1,5 @@
+CACHE MANIFEST
+browser_cmd_appcache_valid_index.html
+browser_cmd_appcache_valid_page1.html
+browser_cmd_appcache_valid_page2.html
+browser_cmd_appcache_valid_page3.html
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^
new file mode 100644
index 000000000..d1a0abd3f
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_appcache.appcache^headers^
@@ -0,0 +1,2 @@
+Content-Type: text/cache-manifest
+Last-Modified: Tue, 23 Apr 9998 11:41:13 GMT
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html
new file mode 100644
index 000000000..1ab3f3e31
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_valid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example index.html</h1>
+ <a href="browser_cmd_appcache_valid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_valid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html
new file mode 100644
index 000000000..e0bb429e7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_valid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page1.html</h1>
+ <a href="browser_cmd_appcache_valid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_valid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html
new file mode 100644
index 000000000..1ce36b319
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_valid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page2.html</h1>
+ <a href="browser_cmd_appcache_valid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_valid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html
new file mode 100644
index 000000000..074ff7d41
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_appcache_valid_page3.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html manifest="browser_cmd_appcache_valid_appcache.appcache">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ <h1>Example page3.html</h1>
+ <a href="browser_cmd_appcache_valid_index.html">Home</a> |
+ <a href="browser_cmd_appcache_valid_page1.html">Page 1</a> |
+ <a href="browser_cmd_appcache_valid_page2.html">Page 2</a> |
+ <a href="browser_cmd_appcache_valid_page3.html">Page 3</a>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_calllog.js b/toolkit/devtools/commandline/test/browser_cmd_calllog.js
new file mode 100644
index 000000000..2ca225e3d
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_calllog.js
@@ -0,0 +1,119 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the calllog commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog";
+
+let tests = {};
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ yield helpers.runTests(options, tests);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+tests.testCallLogStatus = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: "calllog",
+ check: {
+ input: 'calllog',
+ hints: '',
+ markup: 'IIIIIII',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: "calllog start",
+ check: {
+ input: 'calllog start',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: "calllog stop",
+ check: {
+ input: 'calllog stop',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ ]);
+};
+
+tests.testCallLogExec = function(options) {
+ var deferred = promise.defer();
+
+ var onWebConsoleOpen = function(subject) {
+ Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
+
+ subject.QueryInterface(Ci.nsISupportsString);
+ let hud = HUDService.getHudReferenceById(subject.data);
+ ok(hud, "console open");
+
+ helpers.audit(options, [
+ {
+ setup: "calllog stop",
+ exec: {
+ output: /Stopped call logging/,
+ }
+ },
+ {
+ setup: "console clear",
+ exec: {
+ output: "",
+ },
+ post: function() {
+ let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
+ is(labels.length, 0, "no output in console");
+ }
+ },
+ {
+ setup: "console close",
+ exec: {
+ output: "",
+ }
+ },
+ ]).then(function() {
+ deferred.resolve();
+ });
+ };
+ Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
+
+ helpers.audit(options, [
+ {
+ setup: "calllog stop",
+ exec: {
+ output: /No call logging/,
+ }
+ },
+ {
+ name: "calllog start",
+ setup: function() {
+ // This test wants to be in a different event
+ var deferred = promise.defer();
+ executeSoon(function() {
+ helpers.setInput(options, "calllog start").then(() => {
+ deferred.resolve();
+ });
+ });
+ return deferred.promise;
+ },
+ exec: {
+ output: /Call logging started/,
+ },
+ },
+ ]);
+
+ return deferred.promise;
+};
diff --git a/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js b/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js
new file mode 100644
index 000000000..1bc9d6106
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_calllog_chrome.js
@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the calllog commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,cmd-calllog-chrome";
+
+let tests = {};
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ yield helpers.runTests(options, tests);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+tests.testCallLogStatus = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: "calllog",
+ check: {
+ status: "ERROR",
+ emptyParameters: [ " " ]
+ }
+ },
+ {
+ setup: "calllog chromestop",
+ check: {
+ status: "VALID",
+ emptyParameters: [ " " ]
+ }
+ },
+ {
+ setup: "calllog chromestart content-variable window",
+ check: {
+ status: "VALID",
+ emptyParameters: [ " " ]
+ }
+ },
+ {
+ setup: "calllog chromestart javascript \"({a1: function() {this.a2()},a2: function() {}});\"",
+ check: {
+ status: "VALID",
+ emptyParameters: [ " " ]
+ }
+ },
+ ]);
+};
+
+tests.testCallLogExec = function(options) {
+ let deferred = promise.defer();
+
+ function onWebConsoleOpen(subject) {
+ Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
+
+ subject.QueryInterface(Ci.nsISupportsString);
+ let hud = HUDService.getHudReferenceById(subject.data);
+ ok(hud, "console open");
+
+ helpers.audit(options, [
+ {
+ setup: "calllog chromestop",
+ exec: {
+ output: /Stopped call logging/,
+ }
+ },
+ {
+ setup: "calllog chromestart javascript XXX",
+ exec: {
+ output: /following exception/,
+ }
+ },
+ {
+ setup: "console clear",
+ exec: {
+ output: '',
+ },
+ post: function() {
+ let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+ is(labels.length, 0, "no output in console");
+ }
+ },
+ {
+ setup: "console close",
+ exec: {
+ output: '',
+ },
+ },
+ ]).then(function() {
+ deferred.resolve();
+ });
+ }
+ Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
+
+ helpers.audit(options, [
+ {
+ setup: "calllog chromestop",
+ exec: {
+ output: /No call logging/
+ }
+ },
+ {
+ setup: "calllog chromestart javascript \"({a1: function() {this.a2()},a2: function() {}});\"",
+ exec: {
+ output: /Call logging started/,
+ }
+ },
+ ]);
+
+ return deferred.promise;
+};
diff --git a/toolkit/devtools/commandline/test/browser_cmd_commands.js b/toolkit/devtools/commandline/test/browser_cmd_commands.js
new file mode 100644
index 000000000..78dc0a488
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_commands.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test various GCLI commands
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ let subjectPromise = helpers.observeOnce("web-console-created");
+
+ helpers.audit(options, [
+ {
+ setup: "console open",
+ exec: { }
+ }
+ ]);
+
+ let subject = yield subjectPromise;
+
+ subject.QueryInterface(Ci.nsISupportsString);
+ let hud = HUDService.getHudReferenceById(subject.data);
+ ok(hud, "console open");
+
+ let msg = yield hud.jsterm.execute("pprint(window)");
+
+ ok(msg, "output for pprint(window)");
+
+ let oncePromise = hud.jsterm.once("messages-cleared");
+
+ helpers.audit(options, [
+ {
+ setup: "console clear",
+ exec: { output: "" }
+ }
+ ]);
+
+ yield oncePromise;
+
+ let labels = hud.outputNode.querySelectorAll(".message");
+ is(labels.length, 0, "no output in console");
+
+ yield helpers.audit(options, [
+ {
+ setup: "console close",
+ exec: { output: true }
+ }
+ ]);
+
+ ok(!HUDService.getHudReferenceById(hud.hudId), "console closed");
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_cookie.html b/toolkit/devtools/commandline/test/browser_cmd_cookie.html
new file mode 100644
index 000000000..e9b385a35
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_cookie.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>GCLI cookie command test</title>
+</head>
+<body>
+
+ <p>Cookie test</p>
+ <p id=result></p>
+ <script type="text/javascript">
+ document.cookie = "zap=zep";
+ document.cookie = "zip=zop";
+ document.getElementById("result").innerHTML = document.cookie;
+ </script>
+
+</body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_cookie.js b/toolkit/devtools/commandline/test/browser_cmd_cookie.js
new file mode 100644
index 000000000..a07b4f350
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_cookie.js
@@ -0,0 +1,170 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the cookie commands works as they should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
+ "test/browser_cmd_cookie.html";
+
+function test() {
+ helpers.addTabWithToolbar(TEST_URI, function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'cookie',
+ check: {
+ input: 'cookie',
+ hints: ' list',
+ markup: 'IIIIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'cookie lis',
+ check: {
+ input: 'cookie lis',
+ hints: 't',
+ markup: 'IIIIIIVIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'cookie list',
+ check: {
+ input: 'cookie list',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ status: 'VALID'
+ },
+ },
+ {
+ setup: 'cookie remove',
+ check: {
+ input: 'cookie remove',
+ hints: ' <name>',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'cookie set',
+ check: {
+ input: 'cookie set',
+ hints: ' <name> <value> [options]',
+ markup: 'VVVVVVVVVV',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'cookie set fruit',
+ check: {
+ input: 'cookie set fruit',
+ hints: ' <value> [options]',
+ markup: 'VVVVVVVVVVVVVVVV',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'cookie set fruit ban',
+ check: {
+ input: 'cookie set fruit ban',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ name: { value: 'fruit' },
+ value: { value: 'ban' },
+ secure: { value: false },
+ }
+ },
+ },
+ {
+ setup: 'cookie set fruit ban --path ""',
+ check: {
+ input: 'cookie set fruit ban --path ""',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ name: { value: 'fruit' },
+ value: { value: 'ban' },
+ path: { value: '' },
+ secure: { value: false },
+ }
+ },
+ },
+ {
+ setup: "cookie list",
+ exec: {
+ output: [ /zap=zep/, /zip=zop/, /Edit/ ]
+ }
+ },
+ {
+ setup: "cookie set zup banana",
+ check: {
+ args: {
+ name: { value: 'zup' },
+ value: { value: 'banana' },
+ }
+ },
+ exec: {
+ output: ""
+ }
+ },
+ {
+ setup: "cookie list",
+ exec: {
+ output: [ /zap=zep/, /zip=zop/, /zup=banana/, /Edit/ ]
+ }
+ },
+ {
+ setup: "cookie remove zip",
+ exec: { },
+ },
+ {
+ setup: "cookie list",
+ exec: {
+ output: [ /zap=zep/, /zup=banana/, /Edit/ ]
+ },
+ post: function(output, text) {
+ ok(!text.contains("zip"), "");
+ ok(!text.contains("zop"), "");
+ }
+ },
+ {
+ setup: "cookie remove zap",
+ exec: { },
+ },
+ {
+ setup: "cookie list",
+ exec: {
+ output: [ /zup=banana/, /Edit/ ]
+ },
+ post: function(output, text) {
+ ok(!text.contains("zap"), "");
+ ok(!text.contains("zep"), "");
+ ok(!text.contains("zip"), "");
+ ok(!text.contains("zop"), "");
+ }
+ },
+ {
+ setup: "cookie remove zup",
+ exec: { }
+ },
+ {
+ setup: "cookie list",
+ exec: {
+ output: 'No cookies found for host example.com'
+ },
+ post: function(output, text) {
+ ok(!text.contains("zap"), "");
+ ok(!text.contains("zep"), "");
+ ok(!text.contains("zip"), "");
+ ok(!text.contains("zop"), "");
+ ok(!text.contains("zup"), "");
+ ok(!text.contains("banana"), "");
+ ok(!text.contains("Edit"), "");
+ }
+ },
+ ]);
+ }).then(finish, helpers.handleError);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js
new file mode 100644
index 000000000..bbff0dd16
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_oneshot.js
@@ -0,0 +1,318 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the addon commands works as they should
+
+const csscoverage = require("devtools/server/actors/csscoverage");
+
+const PAGE_1 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page1.html";
+const PAGE_2 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page2.html";
+const PAGE_3 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page3.html";
+
+const SHEET_A = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetA.css";
+const SHEET_B = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetB.css";
+const SHEET_C = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetC.css";
+const SHEET_D = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetD.css";
+
+add_task(function*() {
+ let options = yield helpers.openTab(PAGE_3);
+ yield helpers.openToolbar(options);
+
+ let usage = yield csscoverage.getUsage(options.target);
+
+ yield navigate(usage, options);
+ yield checkPages(usage);
+ yield checkEditorReport(usage);
+ // usage.createPageReport is not supported for usage.oneshot data as of
+ // bug 1035300 because the page report assumed we have preload data which
+ // oneshot can't gather. The ideal solution is to have a special no-preload
+ // mode for the page report, but since oneshot isn't needed for the UI to
+ // function, we're currently not supporting page report for oneshot data
+ // yield checkPageReport(usage);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+});
+
+/**
+ * Just check current page
+ */
+function* navigate(usage, options) {
+ ok(!usage.isRunning(), "csscoverage is not running");
+
+ yield usage.oneshot();
+
+ ok(!usage.isRunning(), "csscoverage is still not running");
+}
+
+/**
+ * Check the expected pages have been visited
+ */
+function* checkPages(usage) {
+ let expectedVisited = [ PAGE_3 ];
+ let actualVisited = yield usage._testOnly_visitedPages();
+ isEqualJson(actualVisited, expectedVisited, 'Visited');
+}
+
+/**
+ * Check that createEditorReport returns the expected JSON
+ */
+function* checkEditorReport(usage) {
+ // Page1
+ let expectedPage1 = { reports: [] };
+ let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0");
+ isEqualJson(actualPage1, expectedPage1, 'Page1');
+
+ // Page2
+ let expectedPage2 = { reports: [] };
+ let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0");
+ isEqualJson(actualPage2, expectedPage2, 'Page2');
+
+ // Page3a
+ let expectedPage3a = {
+ reports: [
+ {
+ selectorText: ".page3-test2",
+ start: { line: 9, column: 5 },
+ }
+ ]
+ };
+ let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0");
+ isEqualJson(actualPage3a, expectedPage3a, 'Page3a');
+
+ // Page3b
+ let expectedPage3b = {
+ reports: [
+ {
+ selectorText: ".page3-test3",
+ start: { line: 3, column: 5 },
+ }
+ ]
+ };
+ let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1");
+ isEqualJson(actualPage3b, expectedPage3b, 'Page3b');
+
+ // SheetA
+ let expectedSheetA = {
+ reports: [
+ {
+ selectorText: ".sheetA-test2",
+ start: { line: 8, column: 1 },
+ },
+ {
+ selectorText: ".sheetA-test3",
+ start: { line: 12, column: 1 },
+ },
+ {
+ selectorText: ".sheetA-test4",
+ start: { line: 16, column: 1 },
+ }
+ ]
+ };
+ let actualSheetA = yield usage.createEditorReport(SHEET_A);
+ isEqualJson(actualSheetA, expectedSheetA, 'SheetA');
+
+ // SheetB
+ let expectedSheetB = {
+ reports: [
+ {
+ selectorText: ".sheetB-test2",
+ start: { line: 6, column: 1 },
+ },
+ {
+ selectorText: ".sheetB-test3",
+ start: { line: 10, column: 1 },
+ },
+ {
+ selectorText: ".sheetB-test4",
+ start: { line: 14, column: 1 },
+ }
+ ]
+ };
+ let actualSheetB = yield usage.createEditorReport(SHEET_B);
+ isEqualJson(actualSheetB, expectedSheetB, 'SheetB');
+
+ // SheetC
+ let expectedSheetC = {
+ reports: [
+ {
+ selectorText: ".sheetC-test2",
+ start: { line: 6, column: 1 },
+ },
+ {
+ selectorText: ".sheetC-test3",
+ start: { line: 10, column: 1 },
+ },
+ {
+ selectorText: ".sheetC-test4",
+ start: { line: 14, column: 1 },
+ }
+ ]
+ };
+ let actualSheetC = yield usage.createEditorReport(SHEET_C);
+ isEqualJson(actualSheetC, expectedSheetC, 'SheetC');
+
+ // SheetD
+ let expectedSheetD = {
+ reports: [
+ {
+ selectorText: ".sheetD-test2",
+ start: { line: 6, column: 1 },
+ },
+ {
+ selectorText: ".sheetD-test3",
+ start: { line: 10, column: 1 },
+ },
+ {
+ selectorText: ".sheetD-test4",
+ start: { line: 14, column: 1 },
+ }
+ ]
+ };
+ let actualSheetD = yield usage.createEditorReport(SHEET_D);
+ isEqualJson(actualSheetD, expectedSheetD, 'SheetD');
+}
+
+/**
+ * Check that checkPageReport returns the expected JSON
+ */
+function* checkPageReport(usage) {
+ let actualReport = yield usage.createPageReport();
+
+ // Quick check on trivial things. See doc comment for checkRuleProperties
+ actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties));
+ actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties));
+
+ // Check the summary
+ let expectedSummary = { "used": 23, "unused": 9, "preload": 0 };
+ isEqualJson(actualReport.summary, expectedSummary, 'summary');
+
+ // Check the preload header
+ isEqualJson(actualReport.preload.length, 0, 'preload length');
+
+ // Check the unused header
+ isEqualJson(actualReport.unused.length, 6, 'unused length');
+
+ // Check the unused rules
+ isEqualJson(actualReport.unused[0].url, PAGE_3 + " \u2192 <style> index 0", "unused url 0");
+ let expectedUnusedRules0 = [
+ {
+ "url": PAGE_3 + " \u2192 <style> index 0",
+ "start": { "line": 9, "column": 5 },
+ "selectorText": ".page3-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0');
+
+ isEqualJson(actualReport.unused[1].url, PAGE_3 + " \u2192 <style> index 1", "unused url 1");
+ let expectedUnusedRules1 = [
+ {
+ "url": PAGE_3 + " \u2192 <style> index 1",
+ "start": { "line": 3, "column": 5 },
+ "selectorText": ".page3-test3"
+ }
+ ];
+ isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1');
+
+ isEqualJson(actualReport.unused[2].url, SHEET_A, "unused url 2");
+ let expectedUnusedRules2 = [
+ {
+ "url": SHEET_A,
+ "start": { "line": 8, "column": 1 },
+ "selectorText": ".sheetA-test2"
+ },
+ {
+ "url": SHEET_A,
+ "start": { "line": 12, "column": 1 },
+ "selectorText": ".sheetA-test3"
+ },
+ {
+ "url": SHEET_A,
+ "start": { "line": 16, "column": 1 },
+ "selectorText": ".sheetA-test4"
+ }
+ ];
+ isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2');
+
+ isEqualJson(actualReport.unused[3].url, SHEET_B, "unused url 3");
+ let expectedUnusedRules3 = [
+ {
+ "url": SHEET_B,
+ "start": { "line": 6, "column": 1 },
+ "selectorText": ".sheetB-test2"
+ },
+ {
+ "url": SHEET_B,
+ "start": { "line": 10, "column": 1 },
+ "selectorText": ".sheetB-test3"
+ },
+ {
+ "url": SHEET_B,
+ "start": { "line": 14, "column": 1 },
+ "selectorText": ".sheetB-test4"
+ }
+ ];
+ isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3');
+
+ isEqualJson(actualReport.unused[4].url, SHEET_D, "unused url 4");
+ let expectedUnusedRules4 = [
+ {
+ "url": SHEET_D,
+ "start": { "line": 6, "column": 1 },
+ "selectorText": ".sheetD-test2"
+ },
+ {
+ "url": SHEET_D,
+ "start": { "line": 10, "column": 1 },
+ "selectorText": ".sheetD-test3"
+ },
+ {
+ "url": SHEET_D,
+ "start": { "line": 14, "column": 1 },
+ "selectorText": ".sheetD-test4"
+ }
+ ];
+ isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4');
+
+ isEqualJson(actualReport.unused[5].url, SHEET_C, "unused url 5");
+ let expectedUnusedRules5 = [
+ {
+ "url": SHEET_C,
+ "start": { "line": 6, "column": 1 },
+ "selectorText": ".sheetC-test2"
+ },
+ {
+ "url": SHEET_C,
+ "start": { "line": 10, "column": 1 },
+ "selectorText": ".sheetC-test3"
+ },
+ {
+ "url": SHEET_C,
+ "start": { "line": 14, "column": 1 },
+ "selectorText": ".sheetC-test4"
+ }
+ ];
+ isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5');
+}
+
+/**
+ * We do basic tests on the shortUrl and formattedCssText because they are
+ * very derivative, and so make for fragile tests, and having done those quick
+ * existence checks we remove them so the JSON check later can ignore them
+ */
+function checkRuleProperties(rule, index) {
+ is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index);
+ is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index);
+ delete rule.shortUrl;
+
+ is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index);
+ ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index);
+ delete rule.formattedCssText;
+}
+
+/**
+ * Utility to compare JSON structures
+ */
+function isEqualJson(o1, o2, msg) {
+ is(JSON.stringify(o1), JSON.stringify(o2), msg);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html
new file mode 100644
index 000000000..b137ac1e7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page1.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <!--
+ First page of the css coverage test.
+ * Contains page2 in an iframe
+ * Forwards to page2 on a timeout
+ -->
+ <title>Page 1</title>
+ <style>
+ @import url(browser_cmd_csscoverage_sheetD.css);
+ /* This should match below */
+ .page1-test1 {
+ color: #011;
+ }
+ /* This should not match below */
+ .page1-test2 {
+ color: #012;
+ }
+ /* This would match if the mouse was in the right place */
+ .page1-test3:hover {
+ color: #013;
+ }
+ /* This can't match because it's illegal */
+ .page1-test4:broken {
+ color: #014;
+ }
+ /* This doesn't match until the event fires */
+ .page1-test5 {
+ color: #015;
+ }
+ /* TODO: include examples of all CSS rules in
+ https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
+ and include tests for rules nested in media rules, etc */
+
+ /* We're not testing unparable CSS right now */
+ </style>
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css">
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css">
+ <script type="application/javascript;version=1.8">
+ /* How quickly do we rush through this? */
+ let delay = 500;
+ window.addEventListener("load", () => {
+ dump('TEST-INFO | load from browser_cmd_csscoverage_page1.html\n');
+ setTimeout(() => {
+ dump('TEST-INFO | timeout from browser_cmd_csscoverage_page1.html\n');
+ /* This adds <div class=page1-test5></div> */
+ let parent = document.querySelector("#page1-test5-holder");
+ let child = document.createElement("div");
+ child.classList.add("page1-test5");
+ parent.appendChild(child);
+
+ /* Then navigate to the next step */
+ window.location.href = "browser_cmd_csscoverage_page3.html"
+ }, delay);
+ });
+ </script>
+</head>
+<body>
+
+<h2>Page 1</h2>
+
+<div class=page1-test1>.page1-test1</div>
+<div class=page1-test3>.page1-test3</div>
+
+<div id=page1-test5-holder></div>
+
+<div class=sheetA-test1>.sheetA-test1</div>
+<div class=sheetA-test3>.sheetA-test3</div>
+<div class=sheetB-test1>.sheetB-test1</div>
+<div class=sheetB-test3>.sheetB-test3</div>
+<div class=sheetC-test1>.sheetC-test1</div>
+<div class=sheetC-test3>.sheetC-test3</div>
+<div class=sheetD-test1>.sheetD-test1</div>
+<div class=sheetD-test3>.sheetD-test3</div>
+
+<iframe src=browser_cmd_csscoverage_page2.html></iframe>
+
+<p>
+ <a href="browser_cmd_csscoverage_page3.html">Page 3</a>
+</p>
+
+</body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html
new file mode 100644
index 000000000..13fa8697c
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page2.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Page 2</title>
+ <style>
+ @import url(browser_cmd_csscoverage_sheetD.css);
+
+ /* This should match below */
+ .page2-test1 {
+ color: #021;
+ }
+ /* This should not match below */
+ .page2-test2 {
+ color: #022;
+ }
+ /* This doesn't match until the event fires */
+ .page2-test3 {
+ color: #023;
+ }
+ </style>
+
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css">
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css">
+ <script type="application/javascript;version=1.8">
+ /* How quickly do we rush through this? */
+ let delay = 500;
+ window.addEventListener("load", () => {
+ dump('TEST-INFO | load from browser_cmd_csscoverage_page2.html\n');
+ setTimeout(() => {
+ dump('TEST-INFO | timeout from browser_cmd_csscoverage_page2.html\n');
+ /* This adds <div class=page2-test3></div> */
+ let parent = document.querySelector("#page2-test3-holder");
+ let child = document.createElement("div");
+ child.classList.add("page2-test3");
+ parent.appendChild(child);
+ }, delay);
+ });
+ </script>
+</head>
+<body>
+
+<h2>Page 2</h2>
+
+<div class=page2-test1>.page2-test1</div>
+
+<div id=page2-test3-holder></div>
+
+<div class=sheetA-test1>.sheetA-test1</div>
+<div class=sheetA-test4>.sheetA-test4</div>
+<div class=sheetB-test1>.sheetB-test1</div>
+<div class=sheetB-test4>.sheetB-test4</div>
+<div class=sheetC-test1>.sheetC-test1</div>
+<div class=sheetC-test4>.sheetC-test4</div>
+<div class=sheetD-test1>.sheetD-test1</div>
+<div class=sheetD-test4>.sheetD-test4</div>
+
+</body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html
new file mode 100644
index 000000000..4dc91d5b2
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_page3.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Page 3</title>
+ <style>
+ @import url(browser_cmd_csscoverage_sheetD.css);
+
+ /* This should match below */
+ .page3-test1 {
+ color: #031;
+ }
+ /* This should not match below */
+ .page3-test2 {
+ color: #032;
+ }
+ </style>
+ <style>
+ /* This also should not match below, but in a second inline sheet */
+ .page3-test3 {
+ color: #033;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetA.css">
+ <link rel="stylesheet" type="text/css" href="browser_cmd_csscoverage_sheetB.css">
+ <script type="application/javascript;version=1.8">
+ window.addEventListener("load", () => {
+ dump('TEST-INFO | load from browser_cmd_csscoverage_page3.html\n');
+ });
+ </script>
+</head>
+<body>
+
+<h2>Page 3</h2>
+
+<div class=page3-test1>.page3-test1</div>
+
+<div class=sheetA-test1>.sheetA-test1</div>
+<div class=sheetA-test5>.sheetA-test5</div>
+<div class=sheetB-test1>.sheetB-test1</div>
+<div class=sheetB-test5>.sheetB-test5</div>
+<div class=sheetC-test1>.sheetC-test1</div>
+<div class=sheetC-test5>.sheetC-test5</div>
+<div class=sheetD-test1>.sheetD-test1</div>
+<div class=sheetD-test5>.sheetD-test5</div>
+
+<p>
+ <a href="browser_cmd_csscoverage_page1.html">Page 1</a>
+</p>
+
+</body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css
new file mode 100644
index 000000000..1a3bac926
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetA.css
@@ -0,0 +1,22 @@
+@import url(browser_cmd_csscoverage_sheetC.css);
+
+/* This should match in page 1, 2 and 3 */
+.sheetA-test1 {
+ color: #0A1;
+}
+/* This should not match anywhere */
+.sheetA-test2 {
+ color: #0A2;
+}
+/* This should match in page 1 only */
+.sheetA-test3 {
+ color: #0A3;
+}
+/* This should match in page 2 only */
+.sheetA-test4 {
+ color: #0A4;
+}
+/* This should match in page 3 only */
+.sheetA-test5 {
+ color: #0A5;
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css
new file mode 100644
index 000000000..9335bd60d
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetB.css
@@ -0,0 +1,20 @@
+/* This should match in page 1, 2 and 3 */
+.sheetB-test1 {
+ color: #0B1;
+}
+/* This should not match anywhere */
+.sheetB-test2 {
+ color: #0B2;
+}
+/* This should match in page 1 only */
+.sheetB-test3 {
+ color: #0B3;
+}
+/* This should match in page 2 only */
+.sheetB-test4 {
+ color: #0B4;
+}
+/* This should match in page 3 only */
+.sheetB-test5 {
+ color: #0B5;
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css
new file mode 100644
index 000000000..8c899ead9
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetC.css
@@ -0,0 +1,20 @@
+/* This should match in page 1, 2 and 3 */
+.sheetC-test1 {
+ color: #0C1;
+}
+/* This should not match anywhere */
+.sheetC-test2 {
+ color: #0C2;
+}
+/* This should match in page 1 only */
+.sheetC-test3 {
+ color: #0C3;
+}
+/* This should match in page 2 only */
+.sheetC-test4 {
+ color: #0C4;
+}
+/* This should match in page 3 only */
+.sheetC-test5 {
+ color: #0C5;
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css
new file mode 100644
index 000000000..60ebb314a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_sheetD.css
@@ -0,0 +1,20 @@
+/* This should match in page 1, 2 and 3 */
+.sheetD-test1 {
+ color: #0D1;
+}
+/* This should not match anywhere */
+.sheetD-test2 {
+ color: #0D2;
+}
+/* This should match in page 1 only */
+.sheetD-test3 {
+ color: #0D3;
+}
+/* This should match in page 2 only */
+.sheetD-test4 {
+ color: #0D4;
+}
+/* This should match in page 3 only */
+.sheetD-test5 {
+ color: #0D5;
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js
new file mode 100644
index 000000000..f1527c78b
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_startstop.js
@@ -0,0 +1,457 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the addon commands works as they should
+
+const csscoverage = require("devtools/server/actors/csscoverage");
+
+const PAGE_1 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page1.html";
+const PAGE_2 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page2.html";
+const PAGE_3 = TEST_BASE_HTTPS + "browser_cmd_csscoverage_page3.html";
+
+const SHEET_A = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetA.css";
+const SHEET_B = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetB.css";
+const SHEET_C = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetC.css";
+const SHEET_D = TEST_BASE_HTTPS + "browser_cmd_csscoverage_sheetD.css";
+
+add_task(function*() {
+ let options = yield helpers.openTab("about:blank");
+ yield helpers.openToolbar(options);
+
+ let usage = yield csscoverage.getUsage(options.target);
+
+ yield navigate(usage, options);
+ yield checkPages(usage);
+ yield checkEditorReport(usage);
+ yield checkPageReport(usage);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+});
+
+/**
+ * Visit all the pages in the test
+ */
+function* navigate(usage, options) {
+ yield usage.start();
+
+ ok(usage.isRunning(), "csscoverage is running");
+
+ yield helpers.navigate(PAGE_1, options);
+
+ // Wait for the test pages to auto-cycle
+ let ev = yield helpers.listenOnce(options.browser, "load", true);
+ is(ev.target.location.href, PAGE_1, "page 1 loaded");
+
+ ev = yield helpers.listenOnce(options.browser, "load", true);
+ is(ev.target.location.href, PAGE_3, "page 3 loaded");
+
+ yield usage.stop();
+
+ ok(!usage.isRunning(), "csscoverage not is running");
+}
+
+/**
+ * Check the expected pages have been visited
+ */
+function* checkPages(usage) {
+ // 'load' event order. 'null' is for the initial location
+ let expectedVisited = [ 'null', PAGE_2, PAGE_1, PAGE_3 ];
+ let actualVisited = yield usage._testOnly_visitedPages();
+ isEqualJson(actualVisited, expectedVisited, 'Visited');
+}
+
+/**
+ * Check that createEditorReport returns the expected JSON
+ */
+function* checkEditorReport(usage) {
+ // Page1
+ let expectedPage1 = {
+ reports: [
+ {
+ selectorText: ".page1-test2",
+ start: { line: 8, column: 5 },
+ }
+ ]
+ };
+ let actualPage1 = yield usage.createEditorReport(PAGE_1 + " \u2192 <style> index 0");
+ isEqualJson(actualPage1, expectedPage1, 'Page1');
+
+ // Page2
+ let expectedPage2 = {
+ reports: [
+ {
+ selectorText: ".page2-test2",
+ start: { line: 9, column: 5 },
+ },
+ ]
+ };
+ let actualPage2 = yield usage.createEditorReport(PAGE_2 + " \u2192 <style> index 0");
+ isEqualJson(actualPage2, expectedPage2, 'Page2');
+
+ // Page3a
+ let expectedPage3a = {
+ reports: [
+ {
+ selectorText: ".page3-test2",
+ start: { line: 9, column: 5 },
+ }
+ ]
+ };
+ let actualPage3a = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 0");
+ isEqualJson(actualPage3a, expectedPage3a, 'Page3a');
+
+ // Page3b
+ let expectedPage3b = {
+ reports: [
+ {
+ selectorText: ".page3-test3",
+ start: { line: 3, column: 5 },
+ }
+ ]
+ };
+ let actualPage3b = yield usage.createEditorReport(PAGE_3 + " \u2192 <style> index 1");
+ isEqualJson(actualPage3b, expectedPage3b, 'Page3b');
+
+ // SheetA
+ let expectedSheetA = {
+ reports: [
+ {
+ selectorText: ".sheetA-test2",
+ start: { line: 8, column: 1 },
+ }
+ ]
+ };
+ let actualSheetA = yield usage.createEditorReport(SHEET_A);
+ isEqualJson(actualSheetA, expectedSheetA, 'SheetA');
+
+ // SheetB
+ let expectedSheetB = {
+ reports: [
+ {
+ selectorText: ".sheetB-test2",
+ start: { line: 6, column: 1 },
+ }
+ ]
+ };
+ let actualSheetB = yield usage.createEditorReport(SHEET_B);
+ isEqualJson(actualSheetB, expectedSheetB, 'SheetB');
+
+ // SheetC
+ let expectedSheetC = {
+ reports: [
+ {
+ selectorText: ".sheetC-test2",
+ start: { line: 6, column: 1 },
+ }
+ ]
+ };
+ let actualSheetC = yield usage.createEditorReport(SHEET_C);
+ isEqualJson(actualSheetC, expectedSheetC, 'SheetC');
+
+ // SheetD
+ let expectedSheetD = {
+ reports: [
+ {
+ selectorText: ".sheetD-test2",
+ start: { line: 6, column: 1 },
+ }
+ ]
+ };
+ let actualSheetD = yield usage.createEditorReport(SHEET_D);
+ isEqualJson(actualSheetD, expectedSheetD, 'SheetD');
+}
+
+/**
+ * Check that checkPageReport returns the expected JSON
+ */
+function* checkPageReport(usage) {
+ let actualReport = yield usage.createPageReport();
+
+ // Quick check on trivial things. See doc comment for checkRuleProperties
+ actualReport.preload.forEach(page => page.rules.forEach(checkRuleProperties));
+ actualReport.unused.forEach(page => page.rules.forEach(checkRuleProperties));
+
+ // Check the summary
+ let expectedSummary = { "used": 92, "unused": 22, "preload": 28 };
+ isEqualJson(actualReport.summary, expectedSummary, 'summary');
+
+ checkPageReportPreload(actualReport);
+ checkPageReportUnused(actualReport);
+}
+
+/**
+ * Check that checkPageReport returns the expected preload JSON
+ */
+function checkPageReportPreload(actualReport) {
+ // Check the preload header
+ isEqualJson(actualReport.preload.length, 3, 'preload length');
+
+ // Check the preload rules
+ isEqualJson(actualReport.preload[0].url, PAGE_2, 'preload url 0');
+ let expectedPreloadRules0 = [
+ // TODO: This is already pre-loaded, we should note this
+ {
+ url: PAGE_2 + " \u2192 <style> index 0",
+ start: { line: 5, column: 5 },
+ selectorText: ".page2-test1"
+ },
+ {
+ url: SHEET_A,
+ start: { line: 4, column: 1 },
+ selectorText: ".sheetA-test1"
+ },
+ {
+ url: SHEET_A,
+ start: { line: 16, column: 1 },
+ selectorText: ".sheetA-test4"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetB-test1"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 14, column: 1 },
+ selectorText: ".sheetB-test4"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetD-test1"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 14, column: 1 },
+ selectorText: ".sheetD-test4"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetC-test1"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 14, column: 1 },
+ selectorText: ".sheetC-test4"
+ }
+ ];
+ isEqualJson(actualReport.preload[0].rules, expectedPreloadRules0, 'preload rules 0');
+
+ isEqualJson(actualReport.preload[1].url, PAGE_1, 'preload url 1');
+ let expectedPreloadRules1 = [
+ {
+ url: SHEET_A,
+ start: { line: 4, column: 1 },
+ selectorText: ".sheetA-test1"
+ },
+ {
+ url: SHEET_A,
+ start: { line: 12, column: 1 },
+ selectorText: ".sheetA-test3"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetB-test1"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 10, column: 1 },
+ selectorText: ".sheetB-test3"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetD-test1"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 10, column: 1 },
+ selectorText: ".sheetD-test3"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetC-test1"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 10, column: 1 },
+ selectorText: ".sheetC-test3"
+ },
+ {
+ url: PAGE_1 + " \u2192 <style> index 0",
+ start: { line: 4, column: 5 },
+ selectorText: ".page1-test1"
+ },
+ {
+ url: PAGE_1 + " \u2192 <style> index 0",
+ start: { line: 12, column: 5 },
+ selectorText: ".page1-test3:hover"
+ }
+ ];
+ isEqualJson(actualReport.preload[1].rules, expectedPreloadRules1, 'preload rules 1');
+
+ isEqualJson(actualReport.preload[2].url, PAGE_3, 'preload url 2');
+ let expectedPreloadRules2 = [
+ {
+ url: SHEET_A,
+ start: { line: 4, column: 1 },
+ selectorText: ".sheetA-test1"
+ },
+ {
+ url: SHEET_A,
+ start: { line: 20, column: 1 },
+ selectorText: ".sheetA-test5"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetB-test1"
+ },
+ {
+ url: SHEET_B,
+ start: { line: 18, column: 1 },
+ selectorText: ".sheetB-test5"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetD-test1"
+ },
+ {
+ url: SHEET_D,
+ start: { line: 18, column: 1 },
+ selectorText: ".sheetD-test5"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 2, column: 1 },
+ selectorText: ".sheetC-test1"
+ },
+ {
+ url: SHEET_C,
+ start: { line: 18, column: 1 },
+ selectorText: ".sheetC-test5"
+ },
+ {
+ url: PAGE_3 + " \u2192 <style> index 0",
+ start: { line: 5, column: 5 },
+ selectorText: ".page3-test1"
+ },
+ ];
+ isEqualJson(actualReport.preload[2].rules, expectedPreloadRules2, 'preload rules 2');
+}
+
+/**
+ * Check that checkPageReport returns the expected unused JSON
+ */
+function checkPageReportUnused(actualReport) {
+ // Check the unused header
+ isEqualJson(actualReport.unused.length, 8, 'unused length');
+
+ // Check the unused rules
+ isEqualJson(actualReport.unused[0].url, PAGE_2 + " \u2192 <style> index 0", "unused url 0");
+ let expectedUnusedRules0 = [
+ {
+ url: PAGE_2 + " \u2192 <style> index 0",
+ start: { line: 9, column: 5 },
+ selectorText: ".page2-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[0].rules, expectedUnusedRules0, 'unused rules 0');
+
+ isEqualJson(actualReport.unused[1].url, SHEET_A, "unused url 1");
+ let expectedUnusedRules1 = [
+ {
+ url: SHEET_A,
+ start: { line: 8, column: 1 },
+ selectorText: ".sheetA-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[1].rules, expectedUnusedRules1, 'unused rules 1');
+
+ isEqualJson(actualReport.unused[2].url, SHEET_B, "unused url 2");
+ let expectedUnusedRules2 = [
+ {
+ url: SHEET_B,
+ start: { line: 6, column: 1 },
+ selectorText: ".sheetB-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[2].rules, expectedUnusedRules2, 'unused rules 2');
+
+ isEqualJson(actualReport.unused[3].url, SHEET_D, "unused url 3");
+ let expectedUnusedRules3 = [
+ {
+ url: SHEET_D,
+ start: { line: 6, column: 1 },
+ selectorText: ".sheetD-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[3].rules, expectedUnusedRules3, 'unused rules 3');
+
+ isEqualJson(actualReport.unused[4].url, SHEET_C, "unused url 4");
+ let expectedUnusedRules4 = [
+ {
+ url: SHEET_C,
+ start: { line: 6, column: 1 },
+ selectorText: ".sheetC-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[4].rules, expectedUnusedRules4, 'unused rules 4');
+
+ isEqualJson(actualReport.unused[5].url, PAGE_1 + " \u2192 <style> index 0", "unused url 5");
+ let expectedUnusedRules5 = [
+ {
+ url: PAGE_1 + " \u2192 <style> index 0",
+ start: { line: 8, column: 5 },
+ selectorText: ".page1-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[5].rules, expectedUnusedRules5, 'unused rules 5');
+
+ isEqualJson(actualReport.unused[6].url, PAGE_3 + " \u2192 <style> index 0", "unused url 6");
+ let expectedUnusedRules6 = [
+ {
+ url: PAGE_3 + " \u2192 <style> index 0",
+ start: { line: 9, column: 5 },
+ selectorText: ".page3-test2"
+ }
+ ];
+ isEqualJson(actualReport.unused[6].rules, expectedUnusedRules6, 'unused rules 6');
+
+ isEqualJson(actualReport.unused[7].url, PAGE_3 + " \u2192 <style> index 1", "unused url 7");
+ let expectedUnusedRules7 = [
+ {
+ url: PAGE_3 + " \u2192 <style> index 1",
+ start: { line: 3, column: 5 },
+ selectorText: ".page3-test3"
+ }
+ ];
+ isEqualJson(actualReport.unused[7].rules, expectedUnusedRules7, 'unused rules 7');
+}
+
+/**
+ * We do basic tests on the shortUrl and formattedCssText because they are
+ * very derivative, and so make for fragile tests, and having done those quick
+ * existence checks we remove them so the JSON check later can ignore them
+ */
+function checkRuleProperties(rule, index) {
+ is(typeof rule.shortUrl, "string", "typeof rule.shortUrl for " + index);
+ is(rule.shortUrl.indexOf("http://"), -1, "http not in rule.shortUrl for" + index);
+ delete rule.shortUrl;
+
+ is(typeof rule.formattedCssText, "string", "typeof rule.formattedCssText for " + index);
+ ok(rule.formattedCssText.indexOf("{") > 0, "{ in rule.formattedCssText for " + index);
+ delete rule.formattedCssText;
+}
+
+/**
+ * Utility to compare JSON structures
+ */
+function isEqualJson(o1, o2, msg) {
+ is(JSON.stringify(o1), JSON.stringify(o2), msg);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js
new file mode 100644
index 000000000..6890af7c1
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_csscoverage_util.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the addon commands works as they should
+
+const csscoverage = require("devtools/server/actors/csscoverage");
+
+add_task(function*() {
+ testDeconstructRuleId();
+});
+
+function testDeconstructRuleId() {
+ // This is the easy case
+ let rule = csscoverage.deconstructRuleId("http://thing/blah|10|20");
+ is(rule.url, "http://thing/blah", "1 url");
+ is(rule.line, 10, "1 line");
+ is(rule.column, 20, "1 column");
+
+ // This is the harder case with a URL containing a '|'
+ rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22");
+ is(rule.url, "http://thing/blah?q=a|b", "2 url");
+ is(rule.line, 11, "2 line");
+ is(rule.column, 22, "2 column");
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_folder.js b/toolkit/devtools/commandline/test/browser_cmd_folder.js
new file mode 100644
index 000000000..9ceb38135
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_folder.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the folder commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,cmd-folder";
+
+function test() {
+ helpers.addTabWithToolbar(TEST_URI, function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'folder',
+ check: {
+ input: 'folder',
+ hints: ' open',
+ markup: 'IIIIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'folder open',
+ check: {
+ input: 'folder open',
+ hints: ' [path]',
+ markup: 'VVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'folder open ~',
+ check: {
+ input: 'folder open ~',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'folder openprofile',
+ check: {
+ input: 'folder openprofile',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'folder openprofile WRONG',
+ check: {
+ input: 'folder openprofile WRONG',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVEEEEE',
+ status: 'ERROR'
+ }
+ }
+ ]);
+ }).then(finish, helpers.handleError);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js b/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js
new file mode 100644
index 000000000..a29fd8181
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_highlight_01.js
@@ -0,0 +1,257 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests the various highlight command parameters and options
+
+// Creating a test page with many elements to test the --showall option
+let TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>";
+for (let i = 0; i < 200; i ++) {
+ TEST_PAGE += "<li class='item'>" + i + "</li>";
+}
+TEST_PAGE += "</ul></body>";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function* spawnTest() {
+ let options = yield helpers.openTab(TEST_PAGE);
+ yield helpers.openToolbar(options);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'highlight',
+ check: {
+ input: 'highlight',
+ hints: ' [selector] [options]',
+ markup: 'VVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '0 nodes highlighted'
+ }
+ },
+ {
+ setup: 'highlight bo',
+ check: {
+ input: 'highlight bo',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: No matches'
+ }
+ },
+ {
+ setup: 'highlight body',
+ check: {
+ input: 'highlight body',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight body --hide',
+ check: {
+ input: 'highlight body --hide',
+ hints: 'guides [options]',
+ markup: 'VVVVVVVVVVVVVVVIIIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --hideguides',
+ check: {
+ input: 'highlight body --hideguides',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight body --show',
+ check: {
+ input: 'highlight body --show',
+ hints: 'infobar [options]',
+ markup: 'VVVVVVVVVVVVVVVIIIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --showinfobar',
+ check: {
+ input: 'highlight body --showinfobar',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight body --showa',
+ check: {
+ input: 'highlight body --showa',
+ hints: 'll [options]',
+ markup: 'VVVVVVVVVVVVVVVIIIIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --showall',
+ check: {
+ input: 'highlight body --showall',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight body --r',
+ check: {
+ input: 'highlight body --r',
+ hints: 'egion [options]',
+ markup: 'VVVVVVVVVVVVVVVIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --region',
+ check: {
+ input: 'highlight body --region',
+ hints: ' <selection> [options]',
+ markup: 'VVVVVVVVVVVVVVVIIIIIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Value required for \'region\'.'
+ }
+ },
+ {
+ setup: 'highlight body --fi',
+ check: {
+ input: 'highlight body --fi',
+ hints: 'll [options]',
+ markup: 'VVVVVVVVVVVVVVVIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --fill',
+ check: {
+ input: 'highlight body --fill',
+ hints: ' <string> [options]',
+ markup: 'VVVVVVVVVVVVVVVIIIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Value required for \'fill\'.'
+ }
+ },
+ {
+ setup: 'highlight body --ke',
+ check: {
+ input: 'highlight body --ke',
+ hints: 'ep [options]',
+ markup: 'VVVVVVVVVVVVVVVIIII',
+ status: 'ERROR'
+ },
+ exec: {
+ output: 'Error: Too many arguments'
+ }
+ },
+ {
+ setup: 'highlight body --keep',
+ check: {
+ input: 'highlight body --keep',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight body --hideguides --showinfobar --showall --region ' +
+ 'content --fill red --keep',
+ check: {
+ input: 'highlight body --hideguides --showinfobar --showall --region ' +
+ 'content --fill red --keep',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV' +
+ 'VVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '1 node highlighted'
+ }
+ },
+ {
+ setup: 'highlight .item',
+ check: {
+ input: 'highlight .item',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '200 nodes matched, but only 100 nodes highlighted. Use ' +
+ '\'--showall\' to show all'
+ }
+ },
+ {
+ setup: 'highlight .item --showall',
+ check: {
+ input: 'highlight .item --showall',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ exec: {
+ output: '200 nodes highlighted'
+ }
+ },
+ {
+ setup: 'unhighlight',
+ check: {
+ input: 'unhighlight',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ status: 'VALID'
+ }
+ }
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js b/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js
new file mode 100644
index 000000000..8670c1282
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_highlight_02.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the highlight command actually creates a highlighter
+
+const TEST_PAGE = "data:text/html;charset=utf-8,<div></div>";
+
+function test() {
+ return Task.spawn(function*() {
+ let options = yield helpers.openTab(TEST_PAGE);
+ yield helpers.openToolbar(options);
+
+ info("highlighting the body node");
+ yield runCommand("highlight body", options);
+ is(getHighlighterNumber(), 1, "The highlighter element exists for body");
+
+ info("highlighting the div node");
+ yield runCommand("highlight div", options);
+ is(getHighlighterNumber(), 1, "The highlighter element exists for div");
+
+ info("highlighting the body node again, asking to keep the div");
+ yield runCommand("highlight body --keep", options);
+ is(getHighlighterNumber(), 2, "2 highlighter elements have been created");
+
+ info("unhighlighting all nodes");
+ yield runCommand("unhighlight", options);
+ is(getHighlighterNumber(), 0, "All highlighters have been removed");
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+function getHighlighterNumber() {
+ // Note that this only works as long as gcli tests aren't run with e10s on.
+ // To make this e10s ready, execute this in a content frame script instead.
+ return require("gcli/commands/highlight").highlighters.length;
+}
+
+function* runCommand(cmd, options) {
+ yield helpers.audit(options, [{ setup: cmd, exec: {} }]);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_inject.html b/toolkit/devtools/commandline/test/browser_cmd_inject.html
new file mode 100644
index 000000000..ea84be393
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_inject.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <head>
+ <body>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_inject.js b/toolkit/devtools/commandline/test/browser_cmd_inject.js
new file mode 100644
index 000000000..588487b2e
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_inject.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the inject commands works as they should
+
+const TEST_URI = 'http://example.com/browser/browser/devtools/commandline/'+
+ 'test/browser_cmd_inject.html';
+
+function test() {
+ helpers.addTabWithToolbar(TEST_URI, function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'inject',
+ check: {
+ input: 'inject',
+ markup: 'VVVVVV',
+ hints: ' <library>',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'inject j',
+ check: {
+ input: 'inject j',
+ markup: 'VVVVVVVI',
+ hints: 'Query',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'inject notauri',
+ check: {
+ input: 'inject notauri',
+ hints: ' -> http://notauri/',
+ markup: 'VVVVVVVIIIIIII',
+ status: 'ERROR',
+ args: {
+ library: {
+ value: undefined,
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
+ check: {
+ input: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ hints: '',
+ status: 'VALID',
+ args: {
+ library: {
+ value: function(library) {
+ is(library.type, 'url', 'inject type name');
+ is(library.url.origin, 'http://example.com', 'inject url hostname');
+ ok(library.url.path.indexOf('_inject.js') != -1, 'inject url path');
+ },
+ status: 'VALID'
+ }
+ }
+ },
+ exec: {
+ output: [ /http:\/\/example.com\/browser\/browser\/devtools\/commandline\/test\/browser_cmd_inject.js loaded/ ]
+ }
+ }
+ ]);
+ }).then(finish, helpers.handleError);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_jsb.js b/toolkit/devtools/commandline/test/browser_cmd_jsb.js
new file mode 100644
index 000000000..cf2a9da13
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_jsb.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the jsb command works as it should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+ "test/browser_cmd_jsb_script.jsi";
+
+function test() {
+ return Task.spawn(testTask).then(finish, helpers.handleError);
+}
+
+function testTask() {
+ let options = yield helpers.openTab("about:blank");
+ yield helpers.openToolbar(options);
+
+ let notifyPromise = wwNotifyOnce();
+
+ helpers.audit(options, [
+ {
+ setup: 'jsb',
+ check: {
+ input: 'jsb',
+ hints: ' <url> [options]',
+ markup: 'VVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'jsb ' + TEST_URI,
+ // Should result in a new scratchpad window
+ exec: { }
+ }
+ ]);
+
+ let { subject } = yield notifyPromise;
+ let scratchpadWin = subject.QueryInterface(Ci.nsIDOMWindow);
+ yield helpers.listenOnce(scratchpadWin, "load");
+
+ let scratchpad = scratchpadWin.Scratchpad;
+
+ yield observeOnce(scratchpad);
+
+ let result = scratchpad.getText();
+ result = result.replace(/[\r\n]]*/g, "\n");
+ let correct = "function somefunc() {\n" +
+ " if (true) // Some comment\n" +
+ " doSomething();\n" +
+ " for (let n = 0; n < 500; n++) {\n" +
+ " if (n % 2 == 1) {\n" +
+ " console.log(n);\n" +
+ " console.log(n + 1);\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ is(result, correct, "JS has been correctly prettified");
+
+ if (scratchpadWin) {
+ scratchpadWin.close();
+ scratchpadWin = null;
+ }
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
+
+/**
+ * A wrapper for calling Services.ww.[un]registerNotification using promises.
+ * @return a promise that resolves when the notification service first notifies
+ * with topic == "domwindowopened".
+ * The value of the promise is { subject: subject, topic: topic, data: data }
+ */
+function wwNotifyOnce() {
+ return new Promise(resolve => {
+ let onNotify = (subject, topic, data) => {
+ if (topic == "domwindowopened") {
+ Services.ww.unregisterNotification(onNotify);
+ resolve({ subject: subject, topic: topic, data: data });
+ }
+ };
+
+ Services.ww.registerNotification(onNotify);
+ });
+}
+
+/**
+ * YET ANOTHER WRAPPER for a place where we are using events as poor-man's
+ * promises. Perhaps this should be promoted to scratchpad?
+ */
+function observeOnce(scratchpad) {
+ return new Promise(resolve => {
+ let observer = {
+ onReady: function() {
+ scratchpad.removeObserver(observer);
+ resolve();
+ },
+ };
+ scratchpad.addObserver(observer);
+ });
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi b/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi
new file mode 100644
index 000000000..dcaac807c
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_jsb_script.jsi
@@ -0,0 +1,2 @@
+function somefunc(){if (true) // Some comment
+doSomething();for(let n=0;n<500;n++){if(n%2==1){console.log(n);console.log(n+1);}}}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_media.html b/toolkit/devtools/commandline/test/browser_cmd_media.html
new file mode 100644
index 000000000..9bc1e7aeb
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_media.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>GCLI Test for Bug 819930</title>
+ <style>
+ @media braille {
+ body {
+ background-color: yellow;
+ }
+ }
+
+ @media embossed {
+ body {
+ background-color: indigo;
+ }
+ }
+
+ @media screen {
+ body {
+ background-color: white;
+ }
+ }
+ </style>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_media.js b/toolkit/devtools/commandline/test/browser_cmd_media.js
new file mode 100644
index 000000000..41973c3f8
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_media.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that screenshot command works properly
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+ "test/browser_cmd_media.html";
+let tests = {
+ testInput: function(options) {
+ return helpers.audit(options, [
+ {
+ setup: "media emulate braille",
+ check: {
+ input: "media emulate braille",
+ markup: "VVVVVVVVVVVVVVVVVVVVV",
+ status: "VALID",
+ args: {
+ type: { value: "braille"},
+ }
+ },
+ },
+ {
+ setup: "media reset",
+ check: {
+ input: "media reset",
+ markup: "VVVVVVVVVVV",
+ status: "VALID",
+ args: {
+ }
+ },
+ },
+ ]);
+ },
+
+ testEmulateMedia: function(options) {
+ return helpers.audit(options, [
+ {
+ setup: "media emulate braille",
+ check: {
+ args: {
+ type: { value: "braille"}
+ }
+ },
+ exec: {
+ output: ""
+ },
+ post: function() {
+ let body = options.window.document.body;
+ let style = options.window.getComputedStyle(body);
+ is(style.backgroundColor, "rgb(255, 255, 0)", "media correctly emulated");
+ }
+ }
+ ]);
+ },
+
+ testEndMediaEmulation: function(options) {
+ return helpers.audit(options, [
+ {
+ setup: function() {
+ let mDV = options.browser.markupDocumentViewer;
+ mDV.emulateMedium("embossed");
+ return helpers.setInput(options, "media reset");
+ },
+ exec: {
+ output: ""
+ },
+ post: function() {
+ let body = options.window.document.body;
+ let style = options.window.getComputedStyle(body);
+ is(style.backgroundColor, "rgb(255, 255, 255)", "media reset");
+ }
+ }
+ ]);
+ }
+};
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ yield helpers.runTests(options, tests);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html
new file mode 100644
index 000000000..a7d28828c
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>GCLI inspect command test</title>
+</head>
+<body>
+
+ <!-- This is a list of 0 h1 elements -->
+
+ <!-- This is a list of 1 div elements -->
+ <div>Hello, I'm a div</div>
+
+ <!-- This is a list of 2 span elements -->
+ <span>Hello, I'm a span</span>
+ <span>And me</span>
+
+ <!-- This is a collection of various things that match only once -->
+ <p class="someclass">.someclass</p>
+ <p id="someid">#someid</p>
+ <button disabled>button[disabled]</button>
+ <p><strong>p&gt;strong</strong></p>
+
+</body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js
new file mode 100644
index 000000000..c405a29c7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_pagemod_export.js
@@ -0,0 +1,390 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the inspect command works as it should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
+ "test/browser_cmd_pagemod_export.html";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ const documentElement = options.document.documentElement;
+ const initialHtml = documentElement.innerHTML;
+ function resetContent() {
+ options.document.documentElement.innerHTML = initialHtml;
+ }
+
+ // Test exporting HTML
+ let oldOpen = options.window.open;
+ let openURL = "";
+ options.window.open = function(url) {
+ // The URL is a data: URL that contains the document source
+ openURL = decodeURIComponent(url);
+ };
+
+ yield helpers.audit(options, [
+ {
+ setup: 'export html',
+ skipIf: true,
+ check: {
+ input: 'export html',
+ hints: ' [destination]',
+ markup: 'VVVVVVVVVVV',
+ status: 'VALID',
+ },
+ exec: {
+ output: ''
+ },
+ post: function() {
+ isnot(openURL.indexOf('<html lang="en">'), -1, "export html works: <html>");
+ isnot(openURL.indexOf("<title>GCLI"), -1, "export html works: <title>");
+ isnot(openURL.indexOf('<p id="someid">#'), -1, "export html works: <p>");
+ }
+ },
+ {
+ setup: 'export html stdout',
+ check: {
+ input: 'export html stdout',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ destination: { value: "stdout" }
+ },
+ },
+ exec: {
+ output: [
+ /<html lang="en">/,
+ /<title>GCLI/,
+ /<p id="someid">#/
+ ]
+ }
+ }
+ ]);
+
+ options.window.open = oldOpen;
+ oldOpen = undefined;
+
+ // Test 'pagemod replace'
+ yield helpers.audit(options, [
+ {
+ setup: 'pagemod replace',
+ check: {
+ input: 'pagemod replace',
+ hints: ' <search> <replace> [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
+ markup: 'VVVVVVVVVVVVVVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pagemod replace some foo',
+ check: {
+ input: 'pagemod replace some foo',
+ hints: ' [ignoreCase] [selector] [root] [attrOnly] [contentOnly] [attributes]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'pagemod replace some foo true',
+ check: {
+ input: 'pagemod replace some foo true',
+ hints: ' [selector] [root] [attrOnly] [contentOnly] [attributes]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'pagemod replace some foo true --attrOnly',
+ check: {
+ input: 'pagemod replace some foo true --attrOnly',
+ hints: ' [selector] [root] [contentOnly] [attributes]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'pagemod replace sOme foOBar',
+ exec: {
+ output: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "no change in the page");
+ }
+ },
+ {
+ setup: 'pagemod replace sOme foOBar true',
+ exec: {
+ output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ isnot(html.indexOf('<p class="foOBarclass">.foOBarclass'), -1,
+ ".someclass changed to .foOBarclass");
+ isnot(html.indexOf('<p id="foOBarid">#foOBarid'), -1,
+ "#someid changed to #foOBarid");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod replace some foobar --contentOnly',
+ exec: {
+ output: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ isnot(html.indexOf('<p class="someclass">.foobarclass'), -1,
+ ".someclass changed to .foobarclass (content only)");
+ isnot(html.indexOf('<p id="someid">#foobarid'), -1,
+ "#someid changed to #foobarid (content only)");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod replace some foobar --attrOnly',
+ exec: {
+ output: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ isnot(html.indexOf('<p class="foobarclass">.someclass'), -1,
+ ".someclass changed to .foobarclass (attr only)");
+ isnot(html.indexOf('<p id="foobarid">#someid'), -1,
+ "#someid changed to #foobarid (attr only)");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod replace some foobar --root head',
+ exec: {
+ output: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed");
+ }
+ },
+ {
+ setup: 'pagemod replace some foobar --selector .someclass,div,span',
+ exec: {
+ output: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ isnot(html.indexOf('<p class="foobarclass">.foobarclass'), -1,
+ ".someclass changed to .foobarclass");
+ isnot(html.indexOf('<p id="someid">#someid'), -1,
+ "#someid did not change");
+
+ resetContent();
+ }
+ },
+ ]);
+
+ // Test 'pagemod remove element'
+ yield helpers.audit(options, [
+ {
+ setup: 'pagemod remove',
+ check: {
+ input: 'pagemod remove',
+ hints: ' attribute',
+ markup: 'IIIIIIIVIIIIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pagemod remove element',
+ check: {
+ input: 'pagemod remove element',
+ hints: ' <search> [root] [stripOnly] [ifEmptyOnly]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVV',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pagemod remove element foo',
+ check: {
+ input: 'pagemod remove element foo',
+ hints: ' [root] [stripOnly] [ifEmptyOnly]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ },
+ {
+ setup: 'pagemod remove element p',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ is(html.indexOf('<p class="someclass">'), -1, "p.someclass removed");
+ is(html.indexOf('<p id="someid">'), -1, "p#someid removed");
+ is(html.indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+ isnot(html.indexOf("<span>"), -1, "<span> not removed");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod remove element p head',
+ exec: {
+ output: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed in the page");
+ }
+ },
+ {
+ setup: 'pagemod remove element p --ifEmptyOnly',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed in the page");
+ }
+ },
+ {
+ setup: 'pagemod remove element meta,title --ifEmptyOnly',
+ exec: {
+ output: /^[^:]+: 2\. [^:]+: 1\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ is(html.indexOf("<meta charset="), -1, "<meta> removed");
+ isnot(html.indexOf("<title>"), -1, "<title> not removed");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod remove element p --stripOnly',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+ },
+ post: function() {
+ let html = documentElement.innerHTML;
+
+ is(html.indexOf('<p class="someclass">'), -1, "p.someclass removed");
+ is(html.indexOf('<p id="someid">'), -1, "p#someid removed");
+ is(html.indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+ isnot(html.indexOf(".someclass"), -1, ".someclass still exists");
+ isnot(html.indexOf("#someid"), -1, "#someid still exists");
+ isnot(html.indexOf("<strong>p"), -1, "<strong> still exists");
+
+ resetContent();
+ }
+ },
+ ]);
+
+ // Test 'pagemod remove attribute'
+ yield helpers.audit(options, [
+ {
+ setup: 'pagemod remove attribute',
+ check: {
+ input: 'pagemod remove attribute',
+ hints: ' <searchAttributes> <searchElements> [root] [ignoreCase]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'ERROR',
+ args: {
+ searchAttributes: { value: undefined, status: 'INCOMPLETE' },
+ searchElements: { value: undefined, status: 'INCOMPLETE' },
+ root: { value: undefined },
+ ignoreCase: { value: false },
+ }
+ },
+ },
+ {
+ setup: 'pagemod remove attribute foo bar',
+ check: {
+ input: 'pagemod remove attribute foo bar',
+ hints: ' [root] [ignoreCase]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ searchAttributes: { value: 'foo' },
+ searchElements: { value: 'bar' },
+ root: { value: undefined },
+ ignoreCase: { value: false },
+ }
+ },
+ post: function() {
+ return new Promise(resolve => {
+ executeSoon(resolve);
+ });
+ }
+ },
+ {
+ setup: 'pagemod remove attribute foo bar',
+ exec: {
+ output: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed in the page");
+ }
+ },
+ {
+ setup: 'pagemod remove attribute foo p',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed in the page");
+ }
+ },
+ {
+ setup: 'pagemod remove attribute id p,span',
+ exec: {
+ output: /^[^:]+: 5\. [^:]+: 1\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML.indexOf('<p id="someid">#someid'), -1,
+ "p#someid attribute removed");
+ isnot(documentElement.innerHTML.indexOf("<p>#someid"), -1,
+ "p with someid content still exists");
+
+ resetContent();
+ }
+ },
+ {
+ setup: 'pagemod remove attribute Class p',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML, initialHtml, "nothing changed in the page");
+ }
+ },
+ {
+ setup: 'pagemod remove attribute Class p --ignoreCase',
+ exec: {
+ output: /^[^:]+: 3\. [^:]+: 1\.\s*$/
+ },
+ post: function() {
+ is(documentElement.innerHTML.indexOf('<p class="someclass">.someclass'), -1,
+ "p.someclass attribute removed");
+ isnot(documentElement.innerHTML.indexOf("<p>.someclass"), -1,
+ "p with someclass content still exists");
+
+ resetContent();
+ }
+ },
+ ]);
+
+ // Shutdown
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref1.js b/toolkit/devtools/commandline/test/browser_cmd_pref1.js
new file mode 100644
index 000000000..4e2aa41e5
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_pref1.js
@@ -0,0 +1,154 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the pref commands work
+
+let prefBranch = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService).getBranch(null)
+ .QueryInterface(Ci.nsIPrefBranch2);
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-pref1";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ let tiltEnabledOrig = prefBranch.getBoolPref("devtools.tilt.enabled");
+ info("originally: devtools.tilt.enabled = " + tiltEnabledOrig);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'pref',
+ check: {
+ input: 'pref',
+ hints: ' reset',
+ markup: 'IIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref s',
+ check: {
+ input: 'pref s',
+ hints: 'et',
+ markup: 'IIIIVI',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref sh',
+ check: {
+ input: 'pref sh',
+ hints: 'ow',
+ markup: 'IIIIVII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref show ',
+ check: {
+ input: 'pref show ',
+ markup: 'VVVVVVVVVV',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref show usetexttospeech',
+ check: {
+ input: 'pref show usetexttospeech',
+ hints: ' -> accessibility.usetexttospeech',
+ markup: 'VVVVVVVVVVIIIIIIIIIIIIIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref show devtools.til',
+ check: {
+ input: 'pref show devtools.til',
+ hints: 't.enabled',
+ markup: 'VVVVVVVVVVIIIIIIIIIIII',
+ status: 'ERROR',
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ setting: { value: undefined, status: 'INCOMPLETE' },
+ }
+ },
+ },
+ {
+ setup: 'pref reset devtools.tilt.enabled',
+ check: {
+ input: 'pref reset devtools.tilt.enabled',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID'
+ },
+ },
+ {
+ setup: 'pref show devtools.tilt.enabled 4',
+ check: {
+ input: 'pref show devtools.tilt.enabled 4',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref set devtools.tilt.enabled 4',
+ check: {
+ input: 'pref set devtools.tilt.enabled 4',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
+ status: 'ERROR',
+ args: {
+ setting: { arg: ' devtools.tilt.enabled' },
+ value: { status: 'ERROR', message: 'Can\'t use \'4\'.' },
+ }
+ },
+ },
+ {
+ setup: 'pref set devtools.editor.tabsize 4',
+ check: {
+ input: 'pref set devtools.editor.tabsize 4',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ setting: { arg: ' devtools.editor.tabsize' },
+ value: { value: 4 },
+ }
+ },
+ },
+ {
+ setup: 'pref list',
+ check: {
+ input: 'pref list',
+ hints: ' -> pref set',
+ markup: 'IIIIVIIII',
+ status: 'ERROR'
+ },
+ },
+ {
+ setup: 'pref show devtools.tilt.enabled',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.tilt.enabled")
+ }
+ },
+ },
+ exec: {
+ output: "devtools.tilt.enabled: " + tiltEnabledOrig,
+ },
+ post: function() {
+ prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig);
+ }
+ },
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref2.js b/toolkit/devtools/commandline/test/browser_cmd_pref2.js
new file mode 100644
index 000000000..74ed916a3
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_pref2.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the pref commands work
+
+let prefBranch = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService).getBranch(null)
+ .QueryInterface(Ci.nsIPrefBranch2);
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-pref2";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ let tabSizeOrig = prefBranch.getIntPref("devtools.editor.tabsize");
+ info("originally: devtools.editor.tabsize = " + tabSizeOrig);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'pref show devtools.editor.tabsize',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.editor.tabsize")
+ }
+ },
+ },
+ exec: {
+ output: "devtools.editor.tabsize: " + tabSizeOrig,
+ },
+ },
+ {
+ setup: 'pref set devtools.editor.tabsize 20',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.editor.tabsize")
+ },
+ value: { value: 20 }
+ },
+ },
+ exec: {
+ output: '',
+ },
+ post: function() {
+ is(prefBranch.getIntPref("devtools.editor.tabsize"), 20,
+ "devtools.editor.tabsize is 20");
+ }
+ },
+ {
+ setup: 'pref show devtools.editor.tabsize',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.editor.tabsize")
+ }
+ },
+ },
+ exec: {
+ output: "devtools.editor.tabsize: 20",
+ }
+ },
+ {
+ setup: 'pref set devtools.editor.tabsize 1',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.editor.tabsize")
+ },
+ value: { value: 1 }
+ },
+ },
+ exec: {
+ output: '',
+ },
+ },
+ {
+ setup: 'pref show devtools.editor.tabsize',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.editor.tabsize")
+ }
+ },
+ },
+ exec: {
+ output: "devtools.editor.tabsize: 1",
+ },
+ post: function() {
+ is(prefBranch.getIntPref("devtools.editor.tabsize"), 1,
+ "devtools.editor.tabsize is 1");
+ }
+ },
+ ]);
+
+ prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_pref3.js b/toolkit/devtools/commandline/test/browser_cmd_pref3.js
new file mode 100644
index 000000000..fea31d948
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_pref3.js
@@ -0,0 +1,113 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the pref commands work
+
+let prefBranch = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService).getBranch(null)
+ .QueryInterface(Ci.nsIPrefBranch2);
+
+let supportsString = Cc["@mozilla.org/supports-string;1"]
+ .createInstance(Ci.nsISupportsString);
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-pref3";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+
+ let remoteHostOrig = prefBranch.getComplexValue("devtools.debugger.remote-host",
+ Ci.nsISupportsString).data;
+ info("originally: devtools.debugger.remote-host = " + remoteHostOrig);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'pref show devtools.debugger.remote-host',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.debugger.remote-host")
+ }
+ },
+ },
+ exec: {
+ output: new RegExp("^devtools\.debugger\.remote-host: " + remoteHostOrig + "$"),
+ },
+ },
+ {
+ setup: 'pref set devtools.debugger.remote-host e.com',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.debugger.remote-host")
+ },
+ value: { value: "e.com" }
+ },
+ },
+ exec: {
+ output: '',
+ },
+ },
+ {
+ setup: 'pref show devtools.debugger.remote-host',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.debugger.remote-host")
+ }
+ },
+ },
+ exec: {
+ output: new RegExp("^devtools\.debugger\.remote-host: e.com$"),
+ },
+ post: function() {
+ var ecom = prefBranch.getComplexValue("devtools.debugger.remote-host",
+ Ci.nsISupportsString).data;
+ is(ecom, "e.com", "devtools.debugger.remote-host is e.com");
+ }
+ },
+ {
+ setup: 'pref set devtools.debugger.remote-host moz.foo',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.debugger.remote-host")
+ },
+ value: { value: "moz.foo" }
+ },
+ },
+ exec: {
+ output: '',
+ },
+ },
+ {
+ setup: 'pref show devtools.debugger.remote-host',
+ check: {
+ args: {
+ setting: {
+ value: options.requisition.system.settings.get("devtools.debugger.remote-host")
+ }
+ },
+ },
+ exec: {
+ output: new RegExp("^devtools\.debugger\.remote-host: moz.foo$"),
+ },
+ post: function() {
+ var mozfoo = prefBranch.getComplexValue("devtools.debugger.remote-host",
+ Ci.nsISupportsString).data;
+ is(mozfoo, "moz.foo", "devtools.debugger.remote-host is moz.foo");
+ }
+ },
+ ]);
+
+ supportsString.data = remoteHostOrig;
+ prefBranch.setComplexValue("devtools.debugger.remote-host",
+ Ci.nsISupportsString, supportsString);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_restart.js b/toolkit/devtools/commandline/test/browser_cmd_restart.js
new file mode 100644
index 000000000..ad93326cb
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_restart.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that restart command works properly (input wise)
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
+
+function test() {
+ helpers.addTabWithToolbar(TEST_URI, function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'restart',
+ check: {
+ input: 'restart',
+ markup: 'VVVVVVV',
+ status: 'VALID',
+ args: {
+ nocache: { value: false },
+ safemode: { value: false },
+ }
+ },
+ },
+ {
+ setup: 'restart --nocache',
+ check: {
+ input: 'restart --nocache',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ nocache: { value: true },
+ safemode: { value: false },
+ }
+ },
+ },
+ {
+ setup: 'restart --safemode',
+ check: {
+ input: 'restart --safemode',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ nocache: { value: false },
+ safemode: { value: true },
+ }
+ },
+ },
+ {
+ setup: 'restart --safemode --nocache',
+ check: {
+ input: 'restart --safemode --nocache',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ nocache: { value: true },
+ safemode: { value: true },
+ }
+ },
+ },
+ ]);
+ }).then(finish, helpers.handleError);
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_screenshot.html b/toolkit/devtools/commandline/test/browser_cmd_screenshot.html
new file mode 100644
index 000000000..8e30016f1
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_screenshot.html
@@ -0,0 +1,6 @@
+<html>
+ <head></head>
+ <body>
+ <img id="testImage" ></img>
+ </body>
+</html>
diff --git a/toolkit/devtools/commandline/test/browser_cmd_screenshot.js b/toolkit/devtools/commandline/test/browser_cmd_screenshot.js
new file mode 100644
index 000000000..437daa99f
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_screenshot.js
@@ -0,0 +1,181 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that screenshot command works properly
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+ "test/browser_cmd_screenshot.html";
+
+let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ waitForExplicitFinish();
+
+ info("RUN TEST: non-private window");
+ let normWin = yield addWindow({ private: false });
+ yield addTabWithToolbarRunTests(normWin);
+ normWin.close();
+
+ info("RUN TEST: private window");
+ let pbWin = yield addWindow({ private: true });
+ yield addTabWithToolbarRunTests(pbWin);
+ pbWin.close();
+}
+
+function addTabWithToolbarRunTests(win) {
+ let options = yield helpers.openTab(TEST_URI, { chromeWindow: win });
+ yield helpers.openToolbar(options);
+
+ // Test input status
+ yield helpers.audit(options, [
+ {
+ setup: 'screenshot',
+ check: {
+ input: 'screenshot',
+ markup: 'VVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ }
+ },
+ },
+ {
+ setup: 'screenshot abc.png',
+ check: {
+ input: 'screenshot abc.png',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ filename: { value: "abc.png"},
+ }
+ },
+ },
+ {
+ setup: 'screenshot --fullpage',
+ check: {
+ input: 'screenshot --fullpage',
+ markup: 'VVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ fullpage: { value: true},
+ }
+ },
+ },
+ {
+ setup: 'screenshot abc --delay 5',
+ check: {
+ input: 'screenshot abc --delay 5',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ filename: { value: "abc"},
+ delay: { value: 5 },
+ }
+ },
+ },
+ {
+ setup: 'screenshot --selector img#testImage',
+ check: {
+ input: 'screenshot --selector img#testImage',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ selector: {
+ value: options.window.document.getElementById("testImage")
+ },
+ }
+ },
+ },
+ ]);
+
+ // Test capture to file
+ let file = FileUtils.getFile("TmpD", [ "TestScreenshotFile.png" ]);
+
+ yield helpers.audit(options, [
+ {
+ setup: 'screenshot ' + file.path,
+ check: {
+ args: {
+ filename: { value: "" + file.path },
+ fullpage: { value: false },
+ clipboard: { value: false },
+ chrome: { value: false },
+ },
+ },
+ exec: {
+ output: new RegExp("^Saved to "),
+ },
+ post: function() {
+ // Bug 849168: screenshot command tests fail in try but not locally
+ // ok(file.exists(), "Screenshot file exists");
+
+ if (file.exists()) {
+ file.remove(false);
+ }
+ }
+ },
+ ]);
+
+ // Test capture to clipboard
+ let clipid = Ci.nsIClipboard;
+ let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+ let trans = Cc["@mozilla.org/widget/transferable;1"]
+ .createInstance(Ci.nsITransferable);
+ trans.init(null);
+ trans.addDataFlavor("image/png");
+
+ yield helpers.audit(options, [
+ {
+ setup: 'screenshot --fullpage --clipboard',
+ check: {
+ args: {
+ fullpage: { value: true },
+ clipboard: { value: true },
+ chrome: { value: false },
+ },
+ },
+ exec: {
+ output: new RegExp("^Copied to clipboard.$"),
+ },
+ post: function() {
+ try {
+ clip.getData(trans, clipid.kGlobalClipboard);
+ let str = new Object();
+ let strLength = new Object();
+ trans.getTransferData("image/png", str, strLength);
+
+ ok(str.value, "screenshot exists");
+ ok(strLength.value > 0, "screenshot has length");
+ }
+ finally {
+ Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+
+ // Recent PB changes to the test I'm modifying removed the 'pb'
+ // variable, but left this line in tact. This seems so obviously
+ // wrong that I'm leaving this in in case the analysis is wrong
+ // pb.privateBrowsingEnabled = true;
+ }
+ }
+ },
+ ]);
+
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+}
+
+function addWindow(windowOptions) {
+ return new Promise(resolve => {
+ let win = OpenBrowserWindow(windowOptions);
+
+ // This feels hacky, we should refactor it
+ whenDelayedStartupFinished(win, () => {
+ // Would like to get rid of this executeSoon, but without it the url
+ // (TEST_URI) provided in addTabWithToolbarRunTests hasn't loaded
+ executeSoon(() => {
+ resolve(win);
+ });
+ });
+ });
+}
diff --git a/toolkit/devtools/commandline/test/browser_cmd_settings.js b/toolkit/devtools/commandline/test/browser_cmd_settings.js
new file mode 100644
index 000000000..8b4e27225
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_cmd_settings.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the pref commands work
+
+let prefBranch = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService).getBranch(null)
+ .QueryInterface(Ci.nsIPrefBranch2);
+
+let supportsString = Cc["@mozilla.org/supports-string;1"]
+ .createInstance(Ci.nsISupportsString);
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-settings";
+
+function test() {
+ return Task.spawn(spawnTest).then(finish, helpers.handleError);
+}
+
+function spawnTest() {
+ // Setup
+ let options = yield helpers.openTab(TEST_URI);
+
+ require("devtools/commandline/commands-index");
+ let gcli = require("gcli/index");
+ yield gcli.load();
+ let settings = gcli.settings;
+
+ let hideIntroEnabled = settings.get("devtools.gcli.hideIntro");
+ let tabSize = settings.get("devtools.editor.tabsize");
+ let remoteHost = settings.get("devtools.debugger.remote-host");
+
+ let hideIntroOrig = prefBranch.getBoolPref("devtools.gcli.hideIntro");
+ let tabSizeOrig = prefBranch.getIntPref("devtools.editor.tabsize");
+ let remoteHostOrig = prefBranch.getComplexValue(
+ "devtools.debugger.remote-host",
+ Components.interfaces.nsISupportsString).data;
+
+ info("originally: devtools.gcli.hideIntro = " + hideIntroOrig);
+ info("originally: devtools.editor.tabsize = " + tabSizeOrig);
+ info("originally: devtools.debugger.remote-host = " + remoteHostOrig);
+
+ // Actual tests
+ is(hideIntroEnabled.value, hideIntroOrig, "hideIntroEnabled default");
+ is(tabSize.value, tabSizeOrig, "tabSize default");
+ is(remoteHost.value, remoteHostOrig, "remoteHost default");
+
+ hideIntroEnabled.setDefault();
+ tabSize.setDefault();
+ remoteHost.setDefault();
+
+ let hideIntroEnabledDefault = hideIntroEnabled.value;
+ let tabSizeDefault = tabSize.value;
+ let remoteHostDefault = remoteHost.value;
+
+ hideIntroEnabled.value = false;
+ tabSize.value = 42;
+ remoteHost.value = "example.com";
+
+ is(hideIntroEnabled.value, false, "hideIntroEnabled basic");
+ is(tabSize.value, 42, "tabSize basic");
+ is(remoteHost.value, "example.com", "remoteHost basic");
+
+ function hideIntroEnabledCheck(ev) {
+ is(ev.setting, hideIntroEnabled, "hideIntroEnabled event setting");
+ is(ev.value, true, "hideIntroEnabled event value");
+ is(ev.setting.value, true, "hideIntroEnabled event setting value");
+ }
+ hideIntroEnabled.onChange.add(hideIntroEnabledCheck);
+ hideIntroEnabled.value = true;
+ is(hideIntroEnabled.value, true, "hideIntroEnabled change");
+
+ function tabSizeCheck(ev) {
+ is(ev.setting, tabSize, "tabSize event setting");
+ is(ev.value, 1, "tabSize event value");
+ is(ev.setting.value, 1, "tabSize event setting value");
+ }
+ tabSize.onChange.add(tabSizeCheck);
+ tabSize.value = 1;
+ is(tabSize.value, 1, "tabSize change");
+
+ function remoteHostCheck(ev) {
+ is(ev.setting, remoteHost, "remoteHost event setting");
+ is(ev.value, "y.com", "remoteHost event value");
+ is(ev.setting.value, "y.com", "remoteHost event setting value");
+ }
+ remoteHost.onChange.add(remoteHostCheck);
+ remoteHost.value = "y.com";
+ is(remoteHost.value, "y.com", "remoteHost change");
+
+ hideIntroEnabled.onChange.remove(hideIntroEnabledCheck);
+ tabSize.onChange.remove(tabSizeCheck);
+ remoteHost.onChange.remove(remoteHostCheck);
+
+ function remoteHostReCheck(ev) {
+ is(ev.setting, remoteHost, "remoteHost event reset");
+ is(ev.value, null, "remoteHost event revalue");
+ is(ev.setting.value, null, "remoteHost event setting revalue");
+ }
+ remoteHost.onChange.add(remoteHostReCheck);
+
+ hideIntroEnabled.setDefault();
+ tabSize.setDefault();
+ remoteHost.setDefault();
+
+ remoteHost.onChange.remove(remoteHostReCheck);
+
+ is(hideIntroEnabled.value, hideIntroEnabledDefault, "hideIntroEnabled reset");
+ is(tabSize.value, tabSizeDefault, "tabSize reset");
+ is(remoteHost.value, remoteHostDefault, "remoteHost reset");
+
+ // Cleanup
+ prefBranch.setBoolPref("devtools.gcli.hideIntro", hideIntroOrig);
+ prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig);
+ supportsString.data = remoteHostOrig;
+ prefBranch.setComplexValue("devtools.debugger.remote-host",
+ Components.interfaces.nsISupportsString,
+ supportsString);
+
+ yield helpers.closeTab(options);
+}
diff --git a/toolkit/devtools/commandline/test/browser_gcli_async.js b/toolkit/devtools/commandline/test/browser_gcli_async.js
new file mode 100644
index 000000000..590bb2cc8
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_async.js
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testAsync.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsslo',
+ check: {
+ input: 'tsslo',
+ hints: 'w',
+ markup: 'IIIII',
+ cursor: 5,
+ current: '__command',
+ status: 'ERROR',
+ predictions: ['tsslow'],
+ unassigned: [ ]
+ }
+ },
+ {
+ setup: 'tsslo<TAB>',
+ check: {
+ input: 'tsslow ',
+ hints: 'Shalom',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'hello',
+ status: 'ERROR',
+ predictions: [
+ 'Shalom', 'Namasté', 'Hallo', 'Dydd-da', 'Chào', 'Hej',
+ 'Saluton', 'Sawubona'
+ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsslow' },
+ hello: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ },
+ }
+ }
+ },
+ {
+ setup: 'tsslow S',
+ check: {
+ input: 'tsslow S',
+ hints: 'halom',
+ markup: 'VVVVVVVI',
+ cursor: 8,
+ current: 'hello',
+ status: 'ERROR',
+ predictions: [ 'Shalom', 'Saluton', 'Sawubona', 'Namasté' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsslow' },
+ hello: {
+ value: undefined,
+ arg: ' S',
+ status: 'INCOMPLETE'
+ },
+ }
+ }
+ },
+ {
+ setup: 'tsslow S<TAB>',
+ check: {
+ input: 'tsslow Shalom ',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'hello',
+ status: 'VALID',
+ predictions: [ 'Shalom' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsslow' },
+ hello: {
+ value: 'Shalom',
+ arg: ' Shalom ',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_canon.js b/toolkit/devtools/commandline/test/browser_gcli_canon.js
new file mode 100644
index 000000000..613e5b2d4
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_canon.js
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCanon.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var Commands = require('gcli/commands/commands').Commands;
+
+var startCount;
+var events;
+
+var commandsChange = function(ev) {
+ events++;
+};
+
+exports.setup = function(options) {
+ startCount = options.requisition.system.commands.getAll().length;
+ events = 0;
+};
+
+exports.shutdown = function(options) {
+ startCount = undefined;
+ events = undefined;
+};
+
+exports.testAddRemove1 = function(options) {
+ var commands = options.requisition.system.commands;
+
+ return helpers.audit(options, [
+ {
+ name: 'testadd add',
+ setup: function() {
+ commands.onCommandsChange.add(commandsChange);
+
+ commands.add({
+ name: 'testadd',
+ exec: function() {
+ return 1;
+ }
+ });
+
+ assert.is(commands.getAll().length,
+ startCount + 1,
+ 'add command success');
+ assert.is(events, 1, 'add event');
+
+ return helpers.setInput(options, 'testadd');
+ },
+ check: {
+ input: 'testadd',
+ hints: '',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: '__command',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: { }
+ },
+ exec: {
+ output: /^1$/
+ }
+ },
+ {
+ name: 'testadd alter',
+ setup: function() {
+ commands.add({
+ name: 'testadd',
+ exec: function() {
+ return 2;
+ }
+ });
+
+ assert.is(commands.getAll().length,
+ startCount + 1,
+ 'read command success');
+ assert.is(events, 2, 'read event');
+
+ return helpers.setInput(options, 'testadd');
+ },
+ check: {
+ input: 'testadd',
+ hints: '',
+ markup: 'VVVVVVV',
+ },
+ exec: {
+ output: '2'
+ }
+ },
+ {
+ name: 'testadd remove',
+ setup: function() {
+ commands.remove('testadd');
+
+ assert.is(commands.getAll().length,
+ startCount,
+ 'remove command success');
+ assert.is(events, 3, 'remove event');
+
+ return helpers.setInput(options, 'testadd');
+ },
+ check: {
+ typed: 'testadd',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ unassigned: [ ],
+ }
+ }
+ ]);
+};
+
+exports.testAddRemove2 = function(options) {
+ var commands = options.requisition.system.commands;
+
+ commands.add({
+ name: 'testadd',
+ exec: function() {
+ return 3;
+ }
+ });
+
+ assert.is(commands.getAll().length,
+ startCount + 1,
+ 'rereadd command success');
+ assert.is(events, 4, 'rereadd event');
+
+ return helpers.audit(options, [
+ {
+ setup: 'testadd',
+ exec: {
+ output: /^3$/
+ },
+ post: function() {
+ commands.remove({
+ name: 'testadd'
+ });
+
+ assert.is(commands.getAll().length,
+ startCount,
+ 'reremove command success');
+ assert.is(events, 5, 'reremove event');
+ }
+ },
+ {
+ setup: 'testadd',
+ check: {
+ typed: 'testadd',
+ status: 'ERROR'
+ }
+ }
+ ]);
+};
+
+exports.testAddRemove3 = function(options) {
+ var commands = options.requisition.system.commands;
+
+ commands.remove({ name: 'nonexistant' });
+ assert.is(commands.getAll().length,
+ startCount,
+ 'nonexistant1 command success');
+ assert.is(events, 5, 'nonexistant1 event');
+
+ commands.remove('nonexistant');
+ assert.is(commands.getAll().length,
+ startCount,
+ 'nonexistant2 command success');
+ assert.is(events, 5, 'nonexistant2 event');
+
+ commands.onCommandsChange.remove(commandsChange);
+};
+
+exports.testAltCommands = function(options) {
+ var commands = options.requisition.system.commands;
+ var altCommands = new Commands(options.requisition.system.types);
+
+ var tss = {
+ name: 'tss',
+ params: [
+ { name: 'str', type: 'string' },
+ { name: 'num', type: 'number' },
+ { name: 'opt', type: { name: 'selection', data: [ '1', '2', '3' ] } },
+ ],
+ exec: function(args, context) {
+ return context.commandName + ':' +
+ args.str + ':' + args.num + ':' + args.opt;
+ }
+ };
+ altCommands.add(tss);
+
+ var commandSpecs = altCommands.getCommandSpecs();
+ assert.is(JSON.stringify(commandSpecs),
+ '[{"item":"command","name":"tss","params":[' +
+ '{"name":"str","type":"string"},' +
+ '{"name":"num","type":"number"},' +
+ '{"name":"opt","type":{"name":"selection","data":["1","2","3"]}}' +
+ '],"isParent":false}]',
+ 'JSON.stringify(commandSpecs)');
+
+ var remoter = function(args, context) {
+ assert.is(context.commandName, 'tss', 'commandName is tss');
+
+ var cmd = altCommands.get(context.commandName);
+ return cmd.exec(args, context);
+ };
+
+ commands.addProxyCommands(commandSpecs, remoter, 'proxy', 'test');
+
+ var parent = commands.get('proxy');
+ assert.is(parent.name, 'proxy', 'Parent command called proxy');
+
+ var child = commands.get('proxy tss');
+ assert.is(child.name, 'proxy tss', 'child command called proxy tss');
+
+ return helpers.audit(options, [
+ {
+ setup: 'proxy tss foo 6 3',
+ check: {
+ input: 'proxy tss foo 6 3',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ status: 'VALID',
+ args: {
+ str: { value: 'foo', status: 'VALID' },
+ num: { value: 6, status: 'VALID' },
+ opt: { value: '3', status: 'VALID' }
+ }
+ },
+ exec: {
+ output: 'tss:foo:6:3'
+ },
+ post: function() {
+ commands.remove('proxy');
+ commands.remove('proxy tss');
+
+ assert.is(commands.get('proxy'), undefined, 'remove proxy');
+ assert.is(commands.get('proxy tss'), undefined, 'remove proxy tss');
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_cli1.js b/toolkit/devtools/commandline/test/browser_gcli_cli1.js
new file mode 100644
index 000000000..cb4d52e7a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_cli1.js
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCli1.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+exports.testBlank = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: '',
+ check: {
+ input: '',
+ hints: '',
+ markup: '',
+ cursor: 0,
+ current: '__command',
+ status: 'ERROR'
+ },
+ post: function() {
+ assert.is(options.requisition.commandAssignment.value, undefined);
+ }
+ },
+ {
+ setup: ' ',
+ check: {
+ input: ' ',
+ hints: '',
+ markup: 'V',
+ cursor: 1,
+ current: '__command',
+ status: 'ERROR'
+ },
+ post: function() {
+ assert.is(options.requisition.commandAssignment.value, undefined);
+ }
+ },
+ {
+ name: '| ',
+ setup: function() {
+ return helpers.setInput(options, ' ', 0);
+ },
+ check: {
+ input: ' ',
+ hints: '',
+ markup: 'V',
+ cursor: 0,
+ current: '__command',
+ status: 'ERROR'
+ },
+ post: function() {
+ assert.is(options.requisition.commandAssignment.value, undefined);
+ }
+ }
+ ]);
+};
+
+exports.testDelete = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'x<BACKSPACE>',
+ check: {
+ input: '',
+ hints: '',
+ markup: '',
+ cursor: 0,
+ current: '__command',
+ status: 'ERROR'
+ },
+ post: function() {
+ assert.is(options.requisition.commandAssignment.value, undefined);
+ }
+ }
+ ]);
+};
+
+exports.testIncompleteMultiMatch = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn ex',
+ check: {
+ input: 'tsn ex',
+ hints: 't',
+ markup: 'IIIVII',
+ cursor: 6,
+ current: '__command',
+ status: 'ERROR',
+ predictionsContains: [
+ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend'
+ ]
+ }
+ }
+ ]);
+};
+
+exports.testIncompleteSingleMatch = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tselar',
+ check: {
+ input: 'tselar',
+ hints: 'r',
+ markup: 'IIIIII',
+ cursor: 6,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tselarr' ],
+ unassigned: [ ]
+ }
+ }
+ ]);
+};
+
+exports.testTsv = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsv',
+ check: {
+ input: 'tsv',
+ hints: ' <optionType> <optionValue>',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: { arg: '', status: 'INCOMPLETE' },
+ optionValue: { arg: '', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ setup: 'tsv ',
+ check: {
+ input: 'tsv ',
+ hints: 'option1 <optionValue>',
+ markup: 'VVVV',
+ cursor: 4,
+ current: 'optionType',
+ status: 'ERROR',
+ predictions: [ 'option1', 'option2', 'option3' ],
+ unassigned: [ ],
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tsv' },
+ optionType: { arg: '', status: 'INCOMPLETE' },
+ optionValue: { arg: '', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ name: 'ts|v',
+ setup: function() {
+ return helpers.setInput(options, 'tsv ', 2);
+ },
+ check: {
+ input: 'tsv ',
+ hints: '<optionType> <optionValue>',
+ markup: 'VVVV',
+ cursor: 2,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: { arg: '', status: 'INCOMPLETE' },
+ optionValue: { arg: '', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ setup: 'tsv o',
+ check: {
+ input: 'tsv o',
+ hints: 'ption1 <optionValue>',
+ markup: 'VVVVI',
+ cursor: 5,
+ current: 'optionType',
+ status: 'ERROR',
+ predictions: [ 'option1', 'option2', 'option3' ],
+ unassigned: [ ],
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: undefined,
+ arg: ' o',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionType\'.'
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option',
+ check: {
+ input: 'tsv option',
+ hints: '1 <optionValue>',
+ markup: 'VVVVIIIIII',
+ cursor: 10,
+ current: 'optionType',
+ status: 'ERROR',
+ predictions: [ 'option1', 'option2', 'option3' ],
+ unassigned: [ ],
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: undefined,
+ arg: ' option',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionType\'.'
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ skipRemainingIf: options.isNoDom,
+ name: '|tsv option',
+ setup: function() {
+ return helpers.setInput(options, 'tsv option', 0);
+ },
+ check: {
+ input: 'tsv option',
+ hints: ' <optionValue>',
+ markup: 'VVVVEEEEEE',
+ cursor: 0,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: undefined,
+ arg: ' option',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionType\'.'
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option ',
+ check: {
+ input: 'tsv option ',
+ hints: '<optionValue>',
+ markup: 'VVVVEEEEEEV',
+ cursor: 11,
+ current: 'optionValue',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'false:default',
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: undefined,
+ arg: ' option ',
+ status: 'ERROR',
+ message: 'Can\'t use \'option\'.'
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option1',
+ check: {
+ input: 'tsv option1',
+ hints: ' <optionValue>',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'optionType',
+ status: 'ERROR',
+ predictions: [ 'option1' ],
+ unassigned: [ ],
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'string',
+ arg: ' option1',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option1 ',
+ check: {
+ input: 'tsv option1 ',
+ hints: '<optionValue>',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'optionValue',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'string',
+ arg: ' option1 ',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option2',
+ check: {
+ input: 'tsv option2',
+ hints: ' <optionValue>',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'optionType',
+ status: 'ERROR',
+ predictions: [ 'option2' ],
+ unassigned: [ ],
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'number',
+ arg: ' option2',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'optionValue\'.'
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testTsvValues = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsv option1 6',
+ check: {
+ input: 'tsv option1 6',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'optionValue',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'string',
+ arg: ' option1',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ arg: ' 6',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsv option2 6',
+ check: {
+ input: 'tsv option2 6',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'optionValue',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'number',
+ arg: ' option2',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ arg: ' 6',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ // Delegated remote types can't transfer value types so we only test for
+ // the value of 'value' when we're local
+ {
+ skipIf: options.isRemote,
+ setup: 'tsv option1 6',
+ check: {
+ args: {
+ optionValue: { value: '6' }
+ }
+ }
+ },
+ {
+ skipIf: options.isRemote,
+ setup: 'tsv option2 6',
+ check: {
+ args: {
+ optionValue: { value: 6 }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testInvalid = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'zxjq',
+ check: {
+ input: 'zxjq',
+ hints: '',
+ markup: 'EEEE',
+ cursor: 4,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError'
+ }
+ },
+ {
+ setup: 'zxjq ',
+ check: {
+ input: 'zxjq ',
+ hints: '',
+ markup: 'EEEEV',
+ cursor: 5,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError'
+ }
+ },
+ {
+ setup: 'zxjq one',
+ check: {
+ input: 'zxjq one',
+ hints: '',
+ markup: 'EEEEVEEE',
+ cursor: 8,
+ current: '__unassigned',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ' one' ],
+ tooltipState: 'true:isError'
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_cli2.js b/toolkit/devtools/commandline/test/browser_gcli_cli2.js
new file mode 100644
index 000000000..f1a0a9e98
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_cli2.js
@@ -0,0 +1,825 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCli2.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+var nodetype = require('gcli/types/node');
+
+exports.setup = function(options) {
+ if (options.window) {
+ nodetype.setDocument(options.window.document);
+ }
+};
+
+exports.shutdown = function(options) {
+ nodetype.unsetDocument();
+};
+
+exports.testSingleString = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsr',
+ check: {
+ input: 'tsr',
+ hints: ' <text>',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsr ',
+ check: {
+ input: 'tsr ',
+ hints: '<text>',
+ markup: 'VVVV',
+ cursor: 4,
+ current: 'text',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsr h',
+ check: {
+ input: 'tsr h',
+ hints: '',
+ markup: 'VVVVV',
+ cursor: 5,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'h',
+ arg: ' h',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsr "h h"',
+ check: {
+ input: 'tsr "h h"',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'h h',
+ arg: ' "h h"',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsr h h h',
+ check: {
+ input: 'tsr h h h',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'h h h',
+ arg: ' h h h',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testSingleNumber = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsu',
+ check: {
+ input: 'tsu',
+ hints: ' <num>',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'num\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsu ',
+ check: {
+ input: 'tsu ',
+ hints: '<num>',
+ markup: 'VVVV',
+ cursor: 4,
+ current: 'num',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'num\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsu 1',
+ check: {
+ input: 'tsu 1',
+ hints: '',
+ markup: 'VVVVV',
+ cursor: 5,
+ current: 'num',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: { value: 1, arg: ' 1', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ setup: 'tsu x',
+ check: {
+ input: 'tsu x',
+ hints: '',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'num',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError',
+ args: {
+ command: { name: 'tsu' },
+ num: {
+ value: undefined,
+ arg: ' x',
+ status: 'ERROR',
+ message: 'Can\'t convert "x" to a number.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsu 1.5',
+ check: {
+ input: 'tsu 1.5',
+ hints: '',
+ markup: 'VVVVEEE',
+ cursor: 7,
+ current: 'num',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: {
+ value: undefined,
+ arg: ' 1.5',
+ status: 'ERROR',
+ message: 'Can\'t convert "1.5" to an integer.'
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testSingleFloat = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsf',
+ check: {
+ input: 'tsf',
+ hints: ' <num>',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ error: '',
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'num\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsf 1',
+ check: {
+ input: 'tsf 1',
+ hints: '',
+ markup: 'VVVVV',
+ cursor: 5,
+ current: 'num',
+ status: 'VALID',
+ error: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: { value: 1, arg: ' 1', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ setup: 'tsf 1.',
+ check: {
+ input: 'tsf 1.',
+ hints: '',
+ markup: 'VVVVVV',
+ cursor: 6,
+ current: 'num',
+ status: 'VALID',
+ error: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: { value: 1, arg: ' 1.', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ setup: 'tsf 1.5',
+ check: {
+ input: 'tsf 1.5',
+ hints: '',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'num',
+ status: 'VALID',
+ error: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: { value: 1.5, arg: ' 1.5', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ setup: 'tsf 1.5x',
+ check: {
+ input: 'tsf 1.5x',
+ hints: '',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ current: 'num',
+ status: 'VALID',
+ error: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: { value: 1.5, arg: ' 1.5x', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ skipRemainingIf: options.isNoDom,
+ name: 'tsf x (cursor=4)',
+ setup: function() {
+ return helpers.setInput(options, 'tsf x', 4);
+ },
+ check: {
+ input: 'tsf x',
+ hints: '',
+ markup: 'VVVVE',
+ cursor: 4,
+ current: 'num',
+ status: 'ERROR',
+ error: 'Can\'t convert "x" to a number.',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsf' },
+ num: {
+ value: undefined,
+ arg: ' x',
+ status: 'ERROR',
+ message: 'Can\'t convert "x" to a number.'
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testElementWeb = function(options) {
+ var inputElement = options.isNoDom ?
+ null :
+ options.window.document.getElementById('gcli-input');
+
+ return helpers.audit(options, [
+ {
+ skipIf: function gcliInputElementExists() {
+ return inputElement == null;
+ },
+ setup: 'tse #gcli-input',
+ check: {
+ input: 'tse #gcli-input',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVV',
+ cursor: 15,
+ current: 'node',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: inputElement,
+ arg: ' #gcli-input',
+ status: 'VALID',
+ message: ''
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ }
+ ]);
+};
+
+exports.testElement = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isNoDom,
+ setup: 'tse',
+ check: {
+ input: 'tse',
+ hints: ' <node> [options]',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tse', 'tselarr' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tse' },
+ node: { value: undefined, arg: '', status: 'INCOMPLETE' },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tse #gcli-nomatch',
+ check: {
+ input: 'tse #gcli-nomatch',
+ hints: ' [options]',
+ markup: 'VVVVIIIIIIIIIIIII',
+ cursor: 17,
+ current: 'node',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'true:isError',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' #gcli-nomatch',
+ // This is somewhat debatable because this input can't be corrected
+ // simply by typing so it's and error rather than incomplete,
+ // however without digging into the CSS engine we can't tell that
+ // so we default to incomplete
+ status: 'INCOMPLETE',
+ message: 'No matches'
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tse #',
+ check: {
+ input: 'tse #',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' #',
+ status: 'ERROR',
+ message: 'Syntax error in CSS query'
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tse .',
+ check: {
+ input: 'tse .',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' .',
+ status: 'ERROR',
+ message: 'Syntax error in CSS query'
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tse *',
+ check: {
+ input: 'tse *',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' *',
+ status: 'ERROR',
+ message: /^Too many matches \([0-9]*\)/
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: '', status: 'VALID', message: '' },
+ }
+ }
+ }
+ ]);
+};
+
+exports.testNestedCommand = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn',
+ check: {
+ input: 'tsn',
+ hints: ' deep down nested cmd',
+ markup: 'III',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictionsInclude: [
+ 'tsn deep', 'tsn deep down', 'tsn deep down nested',
+ 'tsn deep down nested cmd', 'tsn dif'
+ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn' }
+ }
+ }
+ },
+ {
+ setup: 'tsn ',
+ check: {
+ input: 'tsn ',
+ hints: ' deep down nested cmd',
+ markup: 'IIIV',
+ cursor: 4,
+ current: '__command',
+ status: 'ERROR',
+ unassigned: [ ]
+ }
+ },
+ {
+ skipIf: options.isPhantomjs,
+ setup: 'tsn x',
+ check: {
+ input: 'tsn x',
+ hints: ' -> tsn ext',
+ markup: 'IIIVI',
+ cursor: 5,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tsn ext' ],
+ unassigned: [ ]
+ }
+ },
+ {
+ setup: 'tsn dif',
+ check: {
+ input: 'tsn dif',
+ hints: ' <text>',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn dif' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsn dif ',
+ check: {
+ input: 'tsn dif ',
+ hints: '<text>',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ current: 'text',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn dif' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsn dif x',
+ check: {
+ input: 'tsn dif x',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn dif' },
+ text: { value: 'x', arg: ' x', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ setup: 'tsn ext',
+ check: {
+ input: 'tsn ext',
+ hints: ' <text>',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn ext' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsn exte',
+ check: {
+ input: 'tsn exte',
+ hints: ' <text>',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tsn exte', 'tsn exten', 'tsn extend' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn exte' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsn exten',
+ check: {
+ input: 'tsn exten',
+ hints: ' <text>',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tsn exten', 'tsn extend' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn exten' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsn extend',
+ check: {
+ input: 'tsn extend',
+ hints: ' <text>',
+ markup: 'VVVVVVVVVV',
+ cursor: 10,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn extend' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'text\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'ts ',
+ check: {
+ input: 'ts ',
+ hints: '',
+ markup: 'EEV',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ tooltipState: 'true:isError'
+ }
+ },
+ ]);
+};
+
+// From Bug 664203
+exports.testDeeplyNested = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn deep down nested',
+ check: {
+ input: 'tsn deep down nested',
+ hints: ' cmd',
+ markup: 'IIIVIIIIVIIIIVIIIIII',
+ cursor: 20,
+ current: '__command',
+ status: 'ERROR',
+ predictions: [ 'tsn deep down nested cmd' ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'false:default',
+ args: {
+ command: { name: 'tsn deep down nested' },
+ }
+ }
+ },
+ {
+ setup: 'tsn deep down nested cmd',
+ check: {
+ input: 'tsn deep down nested cmd',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 24,
+ current: '__command',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn deep down nested cmd' },
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_completion1.js b/toolkit/devtools/commandline/test/browser_gcli_completion1.js
new file mode 100644
index 000000000..0df796265
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_completion1.js
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCompletion1.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testActivate = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: '',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ setup: ' ',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ setup: 'tsr',
+ check: {
+ hints: ' <text>'
+ }
+ },
+ {
+ setup: 'tsr ',
+ check: {
+ hints: '<text>'
+ }
+ },
+ {
+ setup: 'tsr b',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ setup: 'tsb',
+ check: {
+ hints: ' [toggle]'
+ }
+ },
+ {
+ setup: 'tsm',
+ check: {
+ hints: ' <abc> <txt> <num>'
+ }
+ },
+ {
+ setup: 'tsm ',
+ check: {
+ hints: 'a <txt> <num>'
+ }
+ },
+ {
+ setup: 'tsm a',
+ check: {
+ hints: ' <txt> <num>'
+ }
+ },
+ {
+ setup: 'tsm a ',
+ check: {
+ hints: '<txt> <num>'
+ }
+ },
+ {
+ setup: 'tsm a ',
+ check: {
+ hints: '<txt> <num>'
+ }
+ },
+ {
+ setup: 'tsm a d',
+ check: {
+ hints: ' <num>'
+ }
+ },
+ {
+ setup: 'tsm a "d d"',
+ check: {
+ hints: ' <num>'
+ }
+ },
+ {
+ setup: 'tsm a "d ',
+ check: {
+ hints: ' <num>'
+ }
+ },
+ {
+ setup: 'tsm a "d d" ',
+ check: {
+ hints: '<num>'
+ }
+ },
+ {
+ setup: 'tsm a "d d ',
+ check: {
+ hints: ' <num>'
+ }
+ },
+ {
+ setup: 'tsm d r',
+ check: {
+ hints: ' <num>'
+ }
+ },
+ {
+ setup: 'tsm a d ',
+ check: {
+ hints: '<num>'
+ }
+ },
+ {
+ setup: 'tsm a d 4',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ setup: 'tsg',
+ check: {
+ hints: ' <solo> [options]'
+ }
+ },
+ {
+ setup: 'tsg ',
+ check: {
+ hints: 'aaa [options]'
+ }
+ },
+ {
+ setup: 'tsg a',
+ check: {
+ hints: 'aa [options]'
+ }
+ },
+ {
+ setup: 'tsg b',
+ check: {
+ hints: 'bb [options]'
+ }
+ },
+ {
+ skipIf: options.isPhantomjs,
+ setup: 'tsg d',
+ check: {
+ hints: ' [options] -> ccc'
+ }
+ },
+ {
+ setup: 'tsg aa',
+ check: {
+ hints: 'a [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa ',
+ check: {
+ hints: '[options]'
+ }
+ },
+ {
+ setup: 'tsg aaa d',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa dddddd',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa dddddd ',
+ check: {
+ hints: '[options]'
+ }
+ },
+ {
+ setup: 'tsg aaa "d',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa "d d',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsg aaa "d d"',
+ check: {
+ hints: ' [options]'
+ }
+ },
+ {
+ setup: 'tsn ex ',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ setup: 'selarr',
+ check: {
+ hints: ' -> tselarr'
+ }
+ },
+ {
+ setup: 'tselar 1',
+ check: {
+ hints: ''
+ }
+ },
+ {
+ name: 'tselar |1',
+ setup: function() {
+ return helpers.setInput(options, 'tselar 1', 7);
+ },
+ check: {
+ hints: ''
+ }
+ },
+ {
+ name: 'tselar| 1',
+ setup: function() {
+ return helpers.setInput(options, 'tselar 1', 6);
+ },
+ check: {
+ hints: ' -> tselarr'
+ }
+ },
+ {
+ name: 'tsela|r 1',
+ setup: function() {
+ return helpers.setInput(options, 'tselar 1', 5);
+ },
+ check: {
+ hints: ' -> tselarr'
+ }
+ },
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_completion2.js b/toolkit/devtools/commandline/test/browser_gcli_completion2.js
new file mode 100644
index 000000000..b27b8e747
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_completion2.js
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testCompletion2.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testLong = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tslong --sel',
+ check: {
+ input: 'tslong --sel',
+ hints: ' <selection> <msg> [options]',
+ markup: 'VVVVVVVIIIII'
+ }
+ },
+ {
+ setup: 'tslong --sel<TAB>',
+ check: {
+ input: 'tslong --sel ',
+ hints: 'space <msg> [options]',
+ markup: 'VVVVVVVIIIIIV'
+ }
+ },
+ {
+ setup: 'tslong --sel ',
+ check: {
+ input: 'tslong --sel ',
+ hints: 'space <msg> [options]',
+ markup: 'VVVVVVVIIIIIV'
+ }
+ },
+ {
+ setup: 'tslong --sel s',
+ check: {
+ input: 'tslong --sel s',
+ hints: 'pace <msg> [options]',
+ markup: 'VVVVVVVIIIIIVI'
+ }
+ },
+ {
+ setup: 'tslong --num ',
+ check: {
+ input: 'tslong --num ',
+ hints: '<number> <msg> [options]',
+ markup: 'VVVVVVVIIIIIV'
+ }
+ },
+ {
+ setup: 'tslong --num 42',
+ check: {
+ input: 'tslong --num 42',
+ hints: ' <msg> [options]',
+ markup: 'VVVVVVVVVVVVVVV'
+ }
+ },
+ {
+ setup: 'tslong --num 42 ',
+ check: {
+ input: 'tslong --num 42 ',
+ hints: '<msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVV'
+ }
+ },
+ {
+ setup: 'tslong --num 42 --se',
+ check: {
+ input: 'tslong --num 42 --se',
+ hints: 'l <msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVIIII'
+ }
+ },
+ {
+ setup: 'tslong --num 42 --se<TAB>',
+ check: {
+ input: 'tslong --num 42 --sel ',
+ hints: 'space <msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVIIIIIV'
+ }
+ },
+ {
+ setup: 'tslong --num 42 --se<TAB><TAB>',
+ check: {
+ input: 'tslong --num 42 --sel space ',
+ hints: '<msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV'
+ }
+ },
+ {
+ setup: 'tslong --num 42 --sel ',
+ check: {
+ input: 'tslong --num 42 --sel ',
+ hints: 'space <msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVIIIIIV'
+ }
+ },
+ {
+ setup: 'tslong --num 42 --sel space ',
+ check: {
+ input: 'tslong --num 42 --sel space ',
+ hints: '<msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV'
+ }
+ }
+ ]);
+};
+
+exports.testNoTab = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tss<TAB>',
+ check: {
+ input: 'tss ',
+ markup: 'VVVV',
+ hints: ''
+ }
+ },
+ {
+ setup: 'tss<TAB><TAB>',
+ check: {
+ input: 'tss ',
+ markup: 'VVVV',
+ hints: ''
+ }
+ },
+ {
+ setup: 'xxxx',
+ check: {
+ input: 'xxxx',
+ markup: 'EEEE',
+ hints: ''
+ }
+ },
+ {
+ skipIf: options.isNoDom,
+ name: '<TAB>',
+ setup: function() {
+ // Doing it this way avoids clearing the input buffer
+ return helpers.pressTab(options);
+ },
+ check: {
+ input: 'xxxx',
+ markup: 'EEEE',
+ hints: ''
+ }
+ }
+ ]);
+};
+
+exports.testOutstanding = function(options) {
+ // See bug 779800
+ /*
+ return helpers.audit(options, [
+ {
+ setup: 'tsg --txt1 ddd ',
+ check: {
+ input: 'tsg --txt1 ddd ',
+ hints: 'aaa [options]',
+ markup: 'VVVVVVVVVVVVVVV'
+ }
+ },
+ ]);
+ */
+};
+
+exports.testCompleteIntoOptional = function(options) {
+ // From bug 779816
+ return helpers.audit(options, [
+ {
+ setup: 'tso ',
+ check: {
+ typed: 'tso ',
+ hints: '[text]',
+ markup: 'VVVV',
+ status: 'VALID'
+ }
+ },
+ {
+ setup: 'tso<TAB>',
+ check: {
+ typed: 'tso ',
+ hints: '[text]',
+ markup: 'VVVV',
+ status: 'VALID'
+ }
+ }
+ ]);
+};
+
+exports.testSpaceComplete = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tslong --sel2 wit',
+ check: {
+ input: 'tslong --sel2 wit',
+ hints: 'h space <msg> [options]',
+ markup: 'VVVVVVVIIIIIIVIII',
+ cursor: 17,
+ current: 'sel2',
+ status: 'ERROR',
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tslong' },
+ msg: { status: 'INCOMPLETE' },
+ num: { status: 'VALID' },
+ sel: { status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ num2: { status: 'VALID' },
+ bool2: { value: false, status: 'VALID' },
+ sel2: { arg: ' --sel2 wit', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ setup: 'tslong --sel2 wit<TAB>',
+ check: {
+ input: 'tslong --sel2 \'with space\' ',
+ hints: '<msg> [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 27,
+ current: 'sel2',
+ status: 'ERROR',
+ tooltipState: 'true:importantFieldFlag',
+ args: {
+ command: { name: 'tslong' },
+ msg: { status: 'INCOMPLETE' },
+ num: { status: 'VALID' },
+ sel: { status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ num2: { status: 'VALID' },
+ bool2: { value: false, status: 'VALID' },
+ sel2: {
+ value: 'with space',
+ arg: ' --sel2 \'with space\' ',
+ status: 'VALID'
+ }
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_context.js b/toolkit/devtools/commandline/test/browser_gcli_context.js
new file mode 100644
index 000000000..1aed2851e
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_context.js
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testContext.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testBaseline = function(options) {
+ return helpers.audit(options, [
+ // These 3 establish a baseline for comparison when we have used the
+ // context command
+ {
+ setup: 'ext',
+ check: {
+ input: 'ext',
+ hints: ' -> context',
+ markup: 'III',
+ message: '',
+ predictions: [ 'context', 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
+ unassigned: [ ],
+ }
+ },
+ {
+ setup: 'ext test',
+ check: {
+ input: 'ext test',
+ hints: '',
+ markup: 'IIIVEEEE',
+ status: 'ERROR',
+ message: 'Too many arguments',
+ unassigned: [ ' test' ],
+ }
+ },
+ {
+ setup: 'tsn',
+ check: {
+ input: 'tsn',
+ hints: ' deep down nested cmd',
+ markup: 'III',
+ cursor: 3,
+ current: '__command',
+ status: 'ERROR',
+ predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ],
+ args: {
+ command: { name: 'tsn' },
+ }
+ }
+ }
+ ]);
+};
+
+exports.testContext = function(options) {
+ return helpers.audit(options, [
+ // Use the 'tsn' context
+ {
+ setup: 'context tsn',
+ check: {
+ input: 'context tsn',
+ hints: ' deep down nested cmd',
+ markup: 'VVVVVVVVVVV',
+ message: '',
+ predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ],
+ args: {
+ command: { name: 'context' },
+ prefix: {
+ value: options.requisition.system.commands.get('tsn'),
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Using tsn as a command prefix'
+ }
+ },
+ // For comparison with earlier
+ {
+ setup: 'ext',
+ check: {
+ input: 'ext',
+ hints: ' <text>',
+ markup: 'VVV',
+ predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
+ args: {
+ command: { name: 'tsn ext' },
+ text: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: 'ext test',
+ check: {
+ input: 'ext test',
+ hints: '',
+ markup: 'VVVVVVVV',
+ args: {
+ command: { name: 'tsn ext' },
+ text: {
+ value: 'test',
+ arg: ' test',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsnExt text=test'
+ }
+ },
+ {
+ setup: 'tsn',
+ check: {
+ input: 'tsn',
+ hints: ' deep down nested cmd',
+ markup: 'III',
+ message: '',
+ predictionsContains: [ 'tsn deep down nested cmd', 'tsn ext', 'tsn exte' ],
+ args: {
+ command: { name: 'tsn' },
+ }
+ }
+ },
+ // Does it actually work?
+ {
+ setup: 'tsb true',
+ check: {
+ input: 'tsb true',
+ hints: '',
+ markup: 'VVVVVVVV',
+ options: [ 'true' ],
+ message: '',
+ predictions: [ 'true' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsb' },
+ toggle: { value: true, arg: ' true', status: 'VALID', message: '' }
+ }
+ }
+ },
+ {
+ // Bug 866710 - GCLI should allow argument merging for non-string parameters
+ setup: 'context tsn ext',
+ skip: true
+ },
+ {
+ setup: 'context "tsn ext"',
+ check: {
+ input: 'context "tsn ext"',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ message: '',
+ predictions: [ 'tsn ext', 'tsn exte', 'tsn exten', 'tsn extend' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: {
+ value: options.requisition.system.commands.get('tsn ext'),
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Can\'t use \'tsn ext\' as a prefix because it is not a parent command.',
+ error: true
+ }
+ },
+ /*
+ {
+ setup: 'context "tsn deep"',
+ check: {
+ input: 'context "tsn deep"',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ status: 'ERROR',
+ message: '',
+ predictions: [ 'tsn deep' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: {
+ value: options.requisition.system.commands.get('tsn deep'),
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: ''
+ }
+ },
+ */
+ {
+ setup: 'context',
+ check: {
+ input: 'context',
+ hints: ' [prefix]',
+ markup: 'VVVVVVV',
+ status: 'VALID',
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: { value: undefined, arg: '', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Command prefix is unset',
+ type: 'string',
+ error: false
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_date.js b/toolkit/devtools/commandline/test/browser_gcli_date.js
new file mode 100644
index 000000000..352679cc1
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_date.js
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testDate.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+var Status = require('gcli/types/types').Status;
+
+exports.testParse = function(options) {
+ var date = options.requisition.system.types.createType('date');
+ return date.parseString('now').then(function(conversion) {
+ // Date comparison - these 2 dates may not be the same, but how close is
+ // close enough? If this test takes more than 30secs to run the it will
+ // probably time out, so we'll assume that these 2 values must be within
+ // 1 min of each other
+ var gap = new Date().getTime() - conversion.value.getTime();
+ assert.ok(gap < 60000, 'now is less than a minute away');
+
+ assert.is(conversion.getStatus(), Status.VALID, 'now parse');
+ });
+};
+
+exports.testMaxMin = function(options) {
+ var max = new Date();
+ var min = new Date();
+ var types = options.requisition.system.types;
+ var date = types.createType({ name: 'date', max: max, min: min });
+ assert.is(date.getMax(), max, 'max setup');
+
+ var incremented = date.increment(min);
+ assert.is(incremented, max, 'incremented');
+};
+
+exports.testIncrement = function(options) {
+ var date = options.requisition.system.types.createType('date');
+ return date.parseString('now').then(function(conversion) {
+ var plusOne = date.increment(conversion.value);
+ var minusOne = date.decrement(plusOne);
+
+ // See comments in testParse
+ var gap = new Date().getTime() - minusOne.getTime();
+ assert.ok(gap < 60000, 'now is less than a minute away');
+ });
+};
+
+exports.testInput = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsdate 2001-01-01 1980-01-03',
+ check: {
+ input: 'tsdate 2001-01-01 1980-01-03',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ assert.is(d1.getFullYear(), 2001, 'd1 year');
+ assert.is(d1.getMonth(), 0, 'd1 month');
+ assert.is(d1.getDate(), 1, 'd1 date');
+ assert.is(d1.getHours(), 0, 'd1 hours');
+ assert.is(d1.getMinutes(), 0, 'd1 minutes');
+ assert.is(d1.getSeconds(), 0, 'd1 seconds');
+ assert.is(d1.getMilliseconds(), 0, 'd1 millis');
+ },
+ arg: ' 2001-01-01',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: function(d2) {
+ assert.is(d2.getFullYear(), 1980, 'd2 year');
+ assert.is(d2.getMonth(), 0, 'd2 month');
+ assert.is(d2.getDate(), 3, 'd2 date');
+ assert.is(d2.getHours(), 0, 'd2 hours');
+ assert.is(d2.getMinutes(), 0, 'd2 minutes');
+ assert.is(d2.getSeconds(), 0, 'd2 seconds');
+ assert.is(d2.getMilliseconds(), 0, 'd2 millis');
+ },
+ arg: ' 1980-01-03',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ },
+ exec: {
+ output: [ /^Exec: tsdate/, /2001/, /1980/ ],
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'tsdate 2001/01/01 1980/01/03',
+ check: {
+ input: 'tsdate 2001/01/01 1980/01/03',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ assert.is(d1.getFullYear(), 2001, 'd1 year');
+ assert.is(d1.getMonth(), 0, 'd1 month');
+ assert.is(d1.getDate(), 1, 'd1 date');
+ assert.is(d1.getHours(), 0, 'd1 hours');
+ assert.is(d1.getMinutes(), 0, 'd1 minutes');
+ assert.is(d1.getSeconds(), 0, 'd1 seconds');
+ assert.is(d1.getMilliseconds(), 0, 'd1 millis');
+ },
+ arg: ' 2001/01/01',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: function(d2) {
+ assert.is(d2.getFullYear(), 1980, 'd2 year');
+ assert.is(d2.getMonth(), 0, 'd2 month');
+ assert.is(d2.getDate(), 3, 'd2 date');
+ assert.is(d2.getHours(), 0, 'd2 hours');
+ assert.is(d2.getMinutes(), 0, 'd2 minutes');
+ assert.is(d2.getSeconds(), 0, 'd2 seconds');
+ assert.is(d2.getMilliseconds(), 0, 'd2 millis');
+ },
+ arg: ' 1980/01/03',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ },
+ exec: {
+ output: [ /^Exec: tsdate/, /2001/, /1980/ ],
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'tsdate now today',
+ check: {
+ input: 'tsdate now today',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ // How long should we allow between d1 and now? Mochitest will
+ // time out after 30 secs, so that seems like a decent upper
+ // limit, although 30 ms should probably do it. I don't think
+ // reducing the limit from 30 secs will find any extra bugs
+ assert.ok(d1.getTime() - new Date().getTime() < 30 * 1000,
+ 'd1 time');
+ },
+ arg: ' now',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: function(d2) {
+ // See comment for d1 above
+ assert.ok(d2.getTime() - new Date().getTime() < 30 * 1000,
+ 'd2 time');
+ },
+ arg: ' today',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ },
+ exec: {
+ output: [ /^Exec: tsdate/, new Date().getFullYear() ],
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'tsdate yesterday tomorrow',
+ check: {
+ input: 'tsdate yesterday tomorrow',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ var compare = new Date().getTime() - (24 * 60 * 60 * 1000);
+ // See comment for d1 in the test for 'tsdate now today'
+ assert.ok(d1.getTime() - compare < 30 * 1000,
+ 'd1 time');
+ },
+ arg: ' yesterday',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: function(d2) {
+ var compare = new Date().getTime() + (24 * 60 * 60 * 1000);
+ // See comment for d1 in the test for 'tsdate now today'
+ assert.ok(d2.getTime() - compare < 30 * 1000,
+ 'd2 time');
+ },
+ arg: ' tomorrow',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ },
+ exec: {
+ output: [ /^Exec: tsdate/, new Date().getFullYear() ],
+ type: 'string',
+ error: false
+ }
+ }
+ ]);
+};
+
+exports.testIncrDecr = function(options) {
+ return helpers.audit(options, [
+ {
+ // createRequisitionAutomator doesn't fake UP/DOWN well enough
+ skipRemainingIf: options.isNoDom,
+ setup: 'tsdate 2001-01-01<UP>',
+ check: {
+ input: 'tsdate 2001-01-02',
+ hints: ' <d2>',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ assert.is(d1.getFullYear(), 2001, 'd1 year');
+ assert.is(d1.getMonth(), 0, 'd1 month');
+ assert.is(d1.getDate(), 2, 'd1 date');
+ assert.is(d1.getHours(), 0, 'd1 hours');
+ assert.is(d1.getMinutes(), 0, 'd1 minutes');
+ assert.is(d1.getSeconds(), 0, 'd1 seconds');
+ assert.is(d1.getMilliseconds(), 0, 'd1 millis');
+ },
+ arg: ' 2001-01-02',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: undefined,
+ status: 'INCOMPLETE'
+ },
+ }
+ }
+ },
+ {
+ // Check wrapping on decrement
+ setup: 'tsdate 2001-02-01<DOWN>',
+ check: {
+ input: 'tsdate 2001-01-31',
+ hints: ' <d2>',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ assert.is(d1.getFullYear(), 2001, 'd1 year');
+ assert.is(d1.getMonth(), 0, 'd1 month');
+ assert.is(d1.getDate(), 31, 'd1 date');
+ assert.is(d1.getHours(), 0, 'd1 hours');
+ assert.is(d1.getMinutes(), 0, 'd1 minutes');
+ assert.is(d1.getSeconds(), 0, 'd1 seconds');
+ assert.is(d1.getMilliseconds(), 0, 'd1 millis');
+ },
+ arg: ' 2001-01-31',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: undefined,
+ status: 'INCOMPLETE'
+ },
+ }
+ }
+ },
+ {
+ // Check 'max' value capping on increment
+ setup: 'tsdate 2001-02-01 "27 feb 2000"<UP>',
+ check: {
+ input: 'tsdate 2001-02-01 "2000-02-28"',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsdate' },
+ d1: {
+ value: function(d1) {
+ assert.is(d1.getFullYear(), 2001, 'd1 year');
+ assert.is(d1.getMonth(), 1, 'd1 month');
+ assert.is(d1.getDate(), 1, 'd1 date');
+ assert.is(d1.getHours(), 0, 'd1 hours');
+ assert.is(d1.getMinutes(), 0, 'd1 minutes');
+ assert.is(d1.getSeconds(), 0, 'd1 seconds');
+ assert.is(d1.getMilliseconds(), 0, 'd1 millis');
+ },
+ arg: ' 2001-02-01',
+ status: 'VALID',
+ message: ''
+ },
+ d2: {
+ value: function(d2) {
+ assert.is(d2.getFullYear(), 2000, 'd2 year');
+ assert.is(d2.getMonth(), 1, 'd2 month');
+ assert.is(d2.getDate(), 28, 'd2 date');
+ assert.is(d2.getHours(), 0, 'd2 hours');
+ assert.is(d2.getMinutes(), 0, 'd2 minutes');
+ assert.is(d2.getSeconds(), 0, 'd2 seconds');
+ assert.is(d2.getMilliseconds(), 0, 'd2 millis');
+ },
+ arg: ' "2000-02-28"',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_exec.js b/toolkit/devtools/commandline/test/browser_gcli_exec.js
new file mode 100644
index 000000000..0b1f47ddc
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_exec.js
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testExec.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var nodetype = require('gcli/types/node');
+
+var mockBody = {
+ style: {}
+};
+
+var mockEmptyNodeList = {
+ length: 0,
+ item: function() { return null; }
+};
+
+var mockRootNodeList = {
+ length: 1,
+ item: function(i) { return mockBody; }
+};
+
+var mockDoc = {
+ querySelectorAll: function(css) {
+ return (css === ':root') ? mockRootNodeList : mockEmptyNodeList;
+ }
+};
+
+exports.testParamGroup = function(options) {
+ var tsg = options.requisition.system.commands.get('tsg');
+
+ assert.is(tsg.params[0].groupName, null, 'tsg param 0 group null');
+ assert.is(tsg.params[1].groupName, 'First', 'tsg param 1 group First');
+ assert.is(tsg.params[2].groupName, 'First', 'tsg param 2 group First');
+ assert.is(tsg.params[3].groupName, 'Second', 'tsg param 3 group Second');
+ assert.is(tsg.params[4].groupName, 'Second', 'tsg param 4 group Second');
+};
+
+exports.testWithHelpers = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tss',
+ check: {
+ input: 'tss',
+ hints: '',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'VALID',
+ unassigned: [ ],
+ args: {
+ command: { name: 'tss' },
+ }
+ },
+ exec: {
+ output: /^Exec: tss/,
+ }
+ },
+ {
+ setup: 'tsv option1 10',
+ check: {
+ input: 'tsv option1 10',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'optionValue',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'string',
+ arg: ' option1',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ arg: ' 10',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsv optionType=string, optionValue=10'
+ }
+ },
+ {
+ setup: 'tsv option2 10',
+ check: {
+ input: 'tsv option2 10',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'optionValue',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsv' },
+ optionType: {
+ value: 'number',
+ arg: ' option2',
+ status: 'VALID',
+ message: ''
+ },
+ optionValue: {
+ arg: ' 10',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsv optionType=number, optionValue=10'
+ }
+ },
+ // Delegated remote types can't transfer value types so we only test for
+ // the value of optionValue when we're local
+ {
+ skipIf: options.isRemote,
+ setup: 'tsv option1 10',
+ check: {
+ args: { optionValue: { value: '10' } }
+ },
+ exec: {
+ output: 'Exec: tsv optionType=string, optionValue=10'
+ }
+ },
+ {
+ skipIf: options.isRemote,
+ setup: 'tsv option2 10',
+ check: {
+ args: { optionValue: { value: 10 } }
+ },
+ exec: {
+ output: 'Exec: tsv optionType=number, optionValue=10'
+ }
+ }
+ ]);
+};
+
+exports.testExecText = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsr fred',
+ check: {
+ input: 'tsr fred',
+ hints: '',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'fred',
+ arg: ' fred',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsr text=fred'
+ }
+ },
+ {
+ setup: 'tsr fred bloggs',
+ check: {
+ input: 'tsr fred bloggs',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVV',
+ cursor: 15,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'fred bloggs',
+ arg: ' fred bloggs',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsr text=fred bloggs'
+ }
+ },
+ {
+ setup: 'tsr "fred bloggs"',
+ check: {
+ input: 'tsr "fred bloggs"',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'fred bloggs',
+ arg: ' "fred bloggs"',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsr text=fred bloggs'
+ }
+ },
+ {
+ setup: 'tsr "fred bloggs',
+ check: {
+ input: 'tsr "fred bloggs',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ cursor: 16,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsr' },
+ text: {
+ value: 'fred bloggs',
+ arg: ' "fred bloggs',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsr text=fred bloggs'
+ }
+ }
+ ]);
+};
+
+exports.testExecBoolean = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsb',
+ check: {
+ input: 'tsb',
+ hints: ' [toggle]',
+ markup: 'VVV',
+ cursor: 3,
+ current: '__command',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsb' },
+ toggle: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsb toggle=false'
+ }
+ },
+ {
+ setup: 'tsb --toggle',
+ check: {
+ input: 'tsb --toggle',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'toggle',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ args: {
+ command: { name: 'tsb' },
+ toggle: {
+ value: true,
+ arg: ' --toggle',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsb toggle=true'
+ }
+ }
+ ]);
+};
+
+exports.testExecNumber = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsu 10',
+ check: {
+ input: 'tsu 10',
+ hints: '',
+ markup: 'VVVVVV',
+ cursor: 6,
+ current: 'num',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: { value: 10, arg: ' 10', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Exec: tsu num=10'
+ }
+ },
+ {
+ setup: 'tsu --num 10',
+ check: {
+ input: 'tsu --num 10',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'num',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsu' },
+ num: { value: 10, arg: ' --num 10', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Exec: tsu num=10'
+ }
+ }
+ ]);
+};
+
+exports.testExecScript = function(options) {
+ return helpers.audit(options, [
+ {
+ // Bug 704829 - Enable GCLI Javascript parameters
+ // The answer to this should be 2
+ setup: 'tsj { 1 + 1 }',
+ check: {
+ input: 'tsj { 1 + 1 }',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsj' },
+ javascript: {
+ value: '1 + 1',
+ arg: ' { 1 + 1 }',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Exec: tsj javascript=1 + 1'
+ }
+ }
+ ]);
+};
+
+exports.testExecNode = function(options) {
+ var origDoc = nodetype.getDocument();
+ nodetype.setDocument(mockDoc);
+
+ return helpers.audit(options, [
+ {
+ skipIf: options.isNoDom,
+ setup: 'tse :root',
+ check: {
+ input: 'tse :root',
+ hints: ' [options]',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'node',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: mockBody,
+ arg: ' :root',
+ status: 'VALID',
+ message: ''
+ },
+ nodes: {
+ value: mockEmptyNodeList,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ nodes2: {
+ value: mockEmptyNodeList,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: /^Exec: tse/
+ },
+ post: function() {
+ nodetype.setDocument(origDoc);
+ }
+ }
+ ]);
+};
+
+exports.testExecSubCommand = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn dif fred',
+ check: {
+ input: 'tsn dif fred',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn dif' },
+ text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Exec: tsnDif text=fred'
+ }
+ },
+ {
+ setup: 'tsn exten fred',
+ check: {
+ input: 'tsn exten fred',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn exten' },
+ text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tsnExten text=fred'
+ }
+ },
+ {
+ setup: 'tsn extend fred',
+ check: {
+ input: 'tsn extend fred',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVV',
+ cursor: 15,
+ current: 'text',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsn extend' },
+ text: { value: 'fred', arg: ' fred', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tsnExtend text=fred'
+ }
+ }
+ ]);
+};
+
+exports.testExecArray = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tselarr 1',
+ check: {
+ input: 'tselarr 1',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'num',
+ status: 'VALID',
+ predictions: ['1'],
+ unassigned: [ ],
+ outputState: 'false:default',
+ args: {
+ command: { name: 'tselarr' },
+ num: { value: '1', arg: ' 1', status: 'VALID', message: '' },
+ arr: { /*value:,*/ arg: '{}', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tselarr num=1, arr='
+ }
+ },
+ {
+ setup: 'tselarr 1 a',
+ check: {
+ input: 'tselarr 1 a',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'arr',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tselarr' },
+ num: { value: '1', arg: ' 1', status: 'VALID', message: '' },
+ arr: { /*value:a,*/ arg: '{ a}', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tselarr num=1, arr=a'
+ }
+ },
+ {
+ setup: 'tselarr 1 a b',
+ check: {
+ input: 'tselarr 1 a b',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'arr',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tselarr' },
+ num: { value: '1', arg: ' 1', status: 'VALID', message: '' },
+ arr: { /*value:a,b,*/ arg: '{ a, b}', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tselarr num=1, arr=a,b'
+ }
+ }
+ ]);
+};
+
+exports.testExecMultiple = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsm a 10 10',
+ check: {
+ input: 'tsm a 10 10',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'num',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsm' },
+ abc: { value: 'a', arg: ' a', status: 'VALID', message: '' },
+ txt: { value: '10', arg: ' 10', status: 'VALID', message: '' },
+ num: { value: 10, arg: ' 10', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tsm abc=a, txt=10, num=10'
+ }
+ }
+ ]);
+};
+
+exports.testExecDefaults = function(options) {
+ return helpers.audit(options, [
+ {
+ // Bug 707009 - GCLI doesn't always fill in default parameters properly
+ setup: 'tsg aaa',
+ check: {
+ input: 'tsg aaa',
+ hints: ' [options]',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'solo',
+ status: 'VALID',
+ predictions: ['aaa'],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tsg' },
+ solo: { value: 'aaa', arg: ' aaa', status: 'VALID', message: '' },
+ txt1: { value: undefined, arg: '', status: 'VALID', message: '' },
+ bool: { value: false, arg: '', status: 'VALID', message: '' },
+ txt2: { value: undefined, arg: '', status: 'VALID', message: '' },
+ num: { value: undefined, arg: '', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ output: 'Exec: tsg solo=aaa, txt1=null, bool=false, txt2=d, num=42'
+ }
+ }
+ ]);
+
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_fail.js b/toolkit/devtools/commandline/test/browser_gcli_fail.js
new file mode 100644
index 000000000..c0b94f492
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_fail.js
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFail.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsfail reject',
+ exec: {
+ output: 'rejected promise',
+ type: 'error',
+ error: true
+ }
+ },
+ {
+ setup: 'tsfail rejecttyped',
+ exec: {
+ output: '54',
+ type: 'number',
+ error: true
+ }
+ },
+ {
+ setup: 'tsfail throwerror',
+ exec: {
+ output: /thrown error$/,
+ type: 'error',
+ error: true
+ }
+ },
+ {
+ setup: 'tsfail throwstring',
+ exec: {
+ output: 'thrown string',
+ type: 'error',
+ error: true
+ }
+ },
+ {
+ setup: 'tsfail noerror',
+ exec: {
+ output: 'no error',
+ type: 'string',
+ error: false
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_file.js b/toolkit/devtools/commandline/test/browser_gcli_file.js
new file mode 100644
index 000000000..1317d9c7d
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_file.js
@@ -0,0 +1,839 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFile.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+var local = false;
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ // These tests require us to be using node directly or to be in
+ // PhantomJS connected to an execute enabled node server or to be in
+ // firefox.
+ skipRemainingIf: options.isPhantomjs || options.isFirefox,
+ setup: 'tsfile open /',
+ check: {
+ input: 'tsfile open /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVI',
+ cursor: 13,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' is not a file',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' is not a file'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile open /zxcv',
+ check: {
+ input: 'tsfile open /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVIIIII',
+ cursor: 17,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile open /mach_kernel',
+ check: {
+ input: 'tsfile open /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 24,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile saveas /',
+ check: {
+ input: 'tsfile saveas /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVI',
+ cursor: 15,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' already exists',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' already exists'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile saveas /zxcv',
+ check: {
+ input: 'tsfile saveas /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVVVVVVVV',
+ cursor: 19,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile saveas /mach_kernel',
+ check: {
+ input: 'tsfile saveas /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
+ cursor: 26,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/mach_kernel\' already exists',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: undefined,
+ arg: ' /mach_kernel',
+ status: 'INCOMPLETE',
+ message: '\'/mach_kernel\' already exists'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile save /',
+ check: {
+ input: 'tsfile save /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVI',
+ cursor: 13,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' is not a file',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' is not a file'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile save /zxcv',
+ check: {
+ input: 'tsfile save /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile save /mach_kernel',
+ check: {
+ input: 'tsfile save /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 24,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile cd /',
+ check: {
+ input: 'tsfile cd /',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: '/',
+ arg: ' /',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile cd /zxcv',
+ check: {
+ input: 'tsfile cd /zxcv',
+ // hints: ' -> /dev/',
+ markup: 'VVVVVVVVVVIIIII',
+ cursor: 15,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true || !local,
+ setup: 'tsfile cd /etc/passwd',
+ check: {
+ input: 'tsfile cd /etc/passwd',
+ hints: ' -> /etc/pam.d/',
+ markup: 'VVVVVVVVVVIIIIIIIIIII',
+ cursor: 21,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/etc/passwd\' is not a directory',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: undefined,
+ arg: ' /etc/passwd',
+ status: 'INCOMPLETE',
+ message: '\'/etc/passwd\' is not a directory'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile mkdir /',
+ check: {
+ input: 'tsfile mkdir /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVI',
+ cursor: 14,
+ current: 'p1',
+ status: 'ERROR',
+ message: ''/' already exists',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' already exists'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile mkdir /zxcv',
+ check: {
+ input: 'tsfile mkdir /zxcv',
+ // hints: ' -> /dev/',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ cursor: 18,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile mkdir /mach_kernel',
+ check: {
+ input: 'tsfile mkdir /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
+ cursor: 25,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/mach_kernel\' already exists',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: undefined,
+ arg: ' /mach_kernel',
+ status: 'INCOMPLETE',
+ message: '\'/mach_kernel\' already exists'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile rm /',
+ check: {
+ input: 'tsfile rm /',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: '/',
+ arg: ' /',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile rm /zxcv',
+ check: {
+ input: 'tsfile rm /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVIIIII',
+ cursor: 15,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile rm /mach_kernel',
+ check: {
+ input: 'tsfile rm /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 22,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testFirefoxBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ // These tests are just like the ones above tailored for running in
+ // Firefox
+ skipRemainingIf: true,
+ // skipRemainingIf: !options.isFirefox,
+ skipIf: true,
+ setup: 'tsfile open /',
+ check: {
+ input: 'tsfile open /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVI',
+ cursor: 13,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' is not a file',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' is not a file'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile open /zxcv',
+ check: {
+ input: 'tsfile open /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVIIIII',
+ cursor: 17,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile open /mach_kernel',
+ check: {
+ input: 'tsfile open /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 24,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile open' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile saveas /',
+ check: {
+ input: 'tsfile saveas /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVI',
+ cursor: 15,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' already exists',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' already exists'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile saveas /zxcv',
+ check: {
+ input: 'tsfile saveas /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVVVVVVVV',
+ cursor: 19,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile saveas /mach_kernel',
+ check: {
+ input: 'tsfile saveas /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVIIIIIIIIIIII',
+ cursor: 26,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/mach_kernel\' already exists',
+ args: {
+ command: { name: 'tsfile saveas' },
+ p1: {
+ value: undefined,
+ arg: ' /mach_kernel',
+ status: 'INCOMPLETE',
+ message: '\'/mach_kernel\' already exists'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile save /',
+ check: {
+ input: 'tsfile save /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVI',
+ cursor: 13,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/\' is not a file',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' is not a file'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile save /zxcv',
+ check: {
+ input: 'tsfile save /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile save /mach_kernel',
+ check: {
+ input: 'tsfile save /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 24,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile save' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile cd /',
+ check: {
+ input: 'tsfile cd /',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: '/',
+ arg: ' /',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile cd /zxcv',
+ check: {
+ input: 'tsfile cd /zxcv',
+ // hints: ' -> /dev/',
+ // markup: 'VVVVVVVVVVIIIII',
+ cursor: 15,
+ current: 'p1',
+ // status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ // status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true || !local,
+ setup: 'tsfile cd /etc/passwd',
+ check: {
+ input: 'tsfile cd /etc/passwd',
+ hints: ' -> /etc/pam.d/',
+ markup: 'VVVVVVVVVVIIIIIIIIIII',
+ cursor: 21,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/etc/passwd\' is not a directory',
+ args: {
+ command: { name: 'tsfile cd' },
+ p1: {
+ value: undefined,
+ arg: ' /etc/passwd',
+ status: 'INCOMPLETE',
+ message: '\'/etc/passwd\' is not a directory'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile mkdir /',
+ check: {
+ input: 'tsfile mkdir /',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVI',
+ cursor: 14,
+ current: 'p1',
+ status: 'ERROR',
+ message: ''/' already exists',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: undefined,
+ arg: ' /',
+ status: 'INCOMPLETE',
+ message: '\'/\' already exists'
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsfile mkdir /zxcv',
+ check: {
+ input: 'tsfile mkdir /zxcv',
+ // hints: ' -> /dev/',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ cursor: 18,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: '/zxcv',
+ arg: ' /zxcv',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile mkdir /mach_kernel',
+ check: {
+ input: 'tsfile mkdir /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVIIIIIIIIIIII',
+ cursor: 25,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/mach_kernel\' already exists',
+ args: {
+ command: { name: 'tsfile mkdir' },
+ p1: {
+ value: undefined,
+ arg: ' /mach_kernel',
+ status: 'INCOMPLETE',
+ message: '\'/mach_kernel\' already exists'
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile rm /',
+ check: {
+ input: 'tsfile rm /',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: '/',
+ arg: ' /',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ skipIf: true,
+ setup: 'tsfile rm /zxcv',
+ check: {
+ input: 'tsfile rm /zxcv',
+ // hints: ' -> /etc/',
+ markup: 'VVVVVVVVVVIIIII',
+ cursor: 15,
+ current: 'p1',
+ status: 'ERROR',
+ message: '\'/zxcv\' doesn\'t exist',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: undefined,
+ arg: ' /zxcv',
+ status: 'INCOMPLETE',
+ message: '\'/zxcv\' doesn\'t exist'
+ }
+ }
+ }
+ },
+ {
+ skipIf: !local,
+ setup: 'tsfile rm /mach_kernel',
+ check: {
+ input: 'tsfile rm /mach_kernel',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 22,
+ current: 'p1',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsfile rm' },
+ p1: {
+ value: '/mach_kernel',
+ arg: ' /mach_kernel',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_fileparser.js b/toolkit/devtools/commandline/test/browser_gcli_fileparser.js
new file mode 100644
index 000000000..219b793a9
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_fileparser.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFileparser.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var fileparser = require('gcli/util/fileparser');
+
+var local = false;
+
+exports.testGetPredictor = function(options) {
+ if (!options.isNode || !local) {
+ assert.log('Skipping tests due to install differences.');
+ return;
+ }
+
+ var opts = { filetype: 'file', existing: 'yes' };
+ var predictor = fileparser.getPredictor('/usr/locl/bin/nmp', opts);
+ return predictor().then(function(replies) {
+ assert.is(replies[0].name,
+ '/usr/local/bin/npm',
+ 'predict npm');
+ });
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_filesystem.js b/toolkit/devtools/commandline/test/browser_gcli_filesystem.js
new file mode 100644
index 000000000..23c8dda28
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_filesystem.js
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFilesystem.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var filesystem = require('gcli/util/filesystem');
+
+exports.testSplit = function(options) {
+ if (!options.isNode) {
+ return;
+ }
+
+ helpers.arrayIs(filesystem.split('', '/'),
+ [ '.' ],
+ 'split <blank>');
+
+ helpers.arrayIs(filesystem.split('a', '/'),
+ [ 'a' ],
+ 'split a');
+
+ helpers.arrayIs(filesystem.split('a/b/c', '/'),
+ [ 'a', 'b', 'c' ],
+ 'split a/b/c');
+
+ helpers.arrayIs(filesystem.split('/a/b/c/', '/'),
+ [ 'a', 'b', 'c' ],
+ 'split a/b/c');
+
+ helpers.arrayIs(filesystem.split('/a/b///c/', '/'),
+ [ 'a', 'b', 'c' ],
+ 'split a/b/c');
+};
+
+exports.testJoin = function(options) {
+ if (!options.isNode) {
+ return;
+ }
+
+ assert.is(filesystem.join('usr', 'local', 'bin'),
+ 'usr/local/bin',
+ 'join to usr/local/bin');
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_focus.js b/toolkit/devtools/commandline/test/browser_gcli_focus.js
new file mode 100644
index 000000000..48def8195
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_focus.js
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testFocus.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ name: 'exec setup',
+ setup: function() {
+ // Just check that we've got focus, and everything is clear
+ helpers.focusInput(options);
+ return helpers.setInput(options, 'echo hi');
+ },
+ check: { },
+ exec: { }
+ },
+ {
+ setup: 'tsn deep',
+ check: {
+ input: 'tsn deep',
+ hints: ' down nested cmd',
+ markup: 'IIIVIIII',
+ cursor: 8,
+ status: 'ERROR',
+ outputState: 'false:default',
+ tooltipState: 'false:default'
+ }
+ },
+ {
+ setup: 'tsn deep<TAB>',
+ check: {
+ input: 'tsn deep down nested cmd ',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 25,
+ status: 'VALID',
+ outputState: 'false:default',
+ tooltipState: 'false:default'
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_history.js b/toolkit/devtools/commandline/test/browser_gcli_history.js
new file mode 100644
index 000000000..590353cbe
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_history.js
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testHistory.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var History = require('gcli/ui/history').History;
+
+exports.testSimpleHistory = function (options) {
+ var history = new History({});
+ history.add('foo');
+ history.add('bar');
+ assert.is(history.backward(), 'bar');
+ assert.is(history.backward(), 'foo');
+
+ // Adding to the history again moves us back to the start of the history.
+ history.add('quux');
+ assert.is(history.backward(), 'quux');
+ assert.is(history.backward(), 'bar');
+ assert.is(history.backward(), 'foo');
+};
+
+exports.testBackwardsPastIndex = function (options) {
+ var history = new History({});
+ history.add('foo');
+ history.add('bar');
+ assert.is(history.backward(), 'bar');
+ assert.is(history.backward(), 'foo');
+
+ // Moving backwards past recorded history just keeps giving you the last
+ // item.
+ assert.is(history.backward(), 'foo');
+};
+
+exports.testForwardsPastIndex = function (options) {
+ var history = new History({});
+ history.add('foo');
+ history.add('bar');
+ assert.is(history.backward(), 'bar');
+ assert.is(history.backward(), 'foo');
+
+ // Going forward through the history again.
+ assert.is(history.forward(), 'bar');
+
+ // 'Present' time.
+ assert.is(history.forward(), '');
+
+ // Going to the 'future' just keeps giving us the empty string.
+ assert.is(history.forward(), '');
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_incomplete.js b/toolkit/devtools/commandline/test/browser_gcli_incomplete.js
new file mode 100644
index 000000000..c443bbd49
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_incomplete.js
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testIncomplete.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsu 2 extra',
+ check: {
+ args: {
+ num: { value: 2, type: 'Argument' }
+ }
+ },
+ post: function() {
+ var requisition = options.requisition;
+
+ assert.is(requisition._unassigned.length,
+ 1,
+ 'single unassigned: tsu 2 extra');
+ assert.is(requisition._unassigned[0].param.type.isIncompleteName,
+ false,
+ 'unassigned.isIncompleteName: tsu 2 extra');
+ }
+ },
+ {
+ setup: 'tsu',
+ check: {
+ args: {
+ num: { value: undefined, type: 'BlankArgument' }
+ }
+ }
+ },
+ {
+ setup: 'tsg',
+ check: {
+ args: {
+ solo: { type: 'BlankArgument' },
+ txt1: { type: 'BlankArgument' },
+ bool: { type: 'BlankArgument' },
+ txt2: { type: 'BlankArgument' },
+ num: { type: 'BlankArgument' }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testCompleted = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsela<TAB>',
+ check: {
+ args: {
+ command: { name: 'tselarr', type: 'Argument' },
+ num: { type: 'BlankArgument' },
+ arr: { type: 'ArrayArgument' }
+ }
+ }
+ },
+ {
+ setup: 'tsn dif ',
+ check: {
+ input: 'tsn dif ',
+ hints: '<text>',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ status: 'ERROR',
+ args: {
+ command: { name: 'tsn dif', type: 'MergedArgument' },
+ text: { type: 'BlankArgument', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ setup: 'tsn di<TAB>',
+ check: {
+ input: 'tsn dif ',
+ hints: '<text>',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ status: 'ERROR',
+ args: {
+ command: { name: 'tsn dif', type: 'Argument' },
+ text: { type: 'BlankArgument', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ // The above 2 tests take different routes to 'tsn dif '.
+ // The results should be similar. The difference is in args.command.type.
+ {
+ setup: 'tsg -',
+ check: {
+ input: 'tsg -',
+ hints: '-txt1 <solo> [options]',
+ markup: 'VVVVI',
+ cursor: 5,
+ status: 'ERROR',
+ args: {
+ solo: { value: undefined, status: 'INCOMPLETE' },
+ txt1: { value: undefined, status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ txt2: { value: undefined, status: 'VALID' },
+ num: { value: undefined, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tsg -<TAB>',
+ check: {
+ input: 'tsg --txt1 ',
+ hints: '<string> <solo> [options]',
+ markup: 'VVVVIIIIIIV',
+ cursor: 11,
+ status: 'ERROR',
+ args: {
+ solo: { value: undefined, status: 'INCOMPLETE' },
+ txt1: { value: undefined, status: 'INCOMPLETE' },
+ bool: { value: false, status: 'VALID' },
+ txt2: { value: undefined, status: 'VALID' },
+ num: { value: undefined, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tsg --txt1 fred',
+ check: {
+ input: 'tsg --txt1 fred',
+ hints: ' <solo> [options]',
+ markup: 'VVVVVVVVVVVVVVV',
+ status: 'ERROR',
+ args: {
+ solo: { value: undefined, status: 'INCOMPLETE' },
+ txt1: { value: 'fred', status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ txt2: { value: undefined, status: 'VALID' },
+ num: { value: undefined, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tscook key value --path path --',
+ check: {
+ input: 'tscook key value --path path --',
+ hints: 'domain [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+ status: 'ERROR',
+ args: {
+ key: { value: 'key', status: 'VALID' },
+ value: { value: 'value', status: 'VALID' },
+ path: { value: 'path', status: 'VALID' },
+ domain: { value: undefined, status: 'VALID' },
+ secure: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tscook key value --path path --domain domain --',
+ check: {
+ input: 'tscook key value --path path --domain domain --',
+ hints: 'secure [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+ status: 'ERROR',
+ args: {
+ key: { value: 'key', status: 'VALID' },
+ value: { value: 'value', status: 'VALID' },
+ path: { value: 'path', status: 'VALID' },
+ domain: { value: 'domain', status: 'VALID' },
+ secure: { value: false, status: 'VALID' }
+ }
+ }
+ }
+ ]);
+
+};
+
+exports.testCase = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsg AA',
+ check: {
+ input: 'tsg AA',
+ hints: ' [options] -> aaa',
+ markup: 'VVVVII',
+ status: 'ERROR',
+ args: {
+ solo: { value: undefined, text: 'AA', status: 'INCOMPLETE' },
+ txt1: { value: undefined, status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ txt2: { value: undefined, status: 'VALID' },
+ num: { value: undefined, status: 'VALID' }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testIncomplete = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsm a a -',
+ check: {
+ args: {
+ abc: { value: 'a', type: 'Argument' },
+ txt: { value: 'a', type: 'Argument' },
+ num: { value: undefined, arg: ' -', type: 'Argument', status: 'INCOMPLETE' }
+ }
+ }
+ },
+ {
+ setup: 'tsg -',
+ check: {
+ args: {
+ solo: { type: 'BlankArgument' },
+ txt1: { type: 'BlankArgument' },
+ bool: { type: 'BlankArgument' },
+ txt2: { type: 'BlankArgument' },
+ num: { type: 'BlankArgument' }
+ }
+ },
+ post: function() {
+ var requisition = options.requisition;
+
+ assert.is(requisition._unassigned[0],
+ requisition.getAssignmentAt(5),
+ 'unassigned -');
+ assert.is(requisition._unassigned.length,
+ 1,
+ 'single unassigned - tsg -');
+ assert.is(requisition._unassigned[0].param.type.isIncompleteName,
+ true,
+ 'unassigned.isIncompleteName: tsg -');
+ }
+ }
+ ]);
+};
+
+exports.testRepeated = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tscook key value --path jjj --path kkk',
+ check: {
+ input: 'tscook key value --path jjj --path kkk',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVEEEEEEVEEE',
+ cursor: 38,
+ current: '__unassigned',
+ status: 'ERROR',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ' --path', ' kkk' ],
+ args: {
+ command: { name: 'tscook' },
+ key: {
+ value: 'key',
+ arg: ' key',
+ status: 'VALID',
+ message: ''
+ },
+ value: {
+ value: 'value',
+ arg: ' value',
+ status: 'VALID',
+ message: ''
+ },
+ path: {
+ value: 'jjj',
+ arg: ' --path jjj',
+ status: 'VALID',
+ message: ''
+ },
+ domain: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ secure: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ }
+ }
+ }
+ ]);
+};
+
+exports.testHidden = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tshidde',
+ check: {
+ input: 'tshidde',
+ hints: ' -> tse',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'tshidden',
+ check: {
+ input: 'tshidden',
+ hints: ' [options]',
+ markup: 'VVVVVVVV',
+ status: 'VALID',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --vis',
+ check: {
+ input: 'tshidden --vis',
+ hints: 'ible [options]',
+ markup: 'VVVVVVVVVIIIII',
+ status: 'ERROR',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --invisiblestrin',
+ check: {
+ input: 'tshidden --invisiblestrin',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVEEEEEEEEEEEEEEEE',
+ status: 'ERROR',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --invisiblestring',
+ check: {
+ input: 'tshidden --invisiblestring',
+ hints: ' <string> [options]',
+ markup: 'VVVVVVVVVIIIIIIIIIIIIIIIII',
+ status: 'ERROR',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'INCOMPLETE' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --invisiblestring x',
+ check: {
+ input: 'tshidden --invisiblestring x',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: 'x', status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --invisibleboolea',
+ check: {
+ input: 'tshidden --invisibleboolea',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVEEEEEEEEEEEEEEEEE',
+ status: 'ERROR',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --invisibleboolean',
+ check: {
+ input: 'tshidden --invisibleboolean',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ args: {
+ visible: { value: undefined, status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: true, status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tshidden --visible xxx',
+ check: {
+ input: 'tshidden --visible xxx',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ hints: '',
+ args: {
+ visible: { value: 'xxx', status: 'VALID' },
+ invisiblestring: { value: undefined, status: 'VALID' },
+ invisibleboolean: { value: false, status: 'VALID' }
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_inputter.js b/toolkit/devtools/commandline/test/browser_gcli_inputter.js
new file mode 100644
index 000000000..e8d1c214a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_inputter.js
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testInputter.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var KeyEvent = require('gcli/util/util').KeyEvent;
+
+var latestEvent;
+var latestData;
+
+var outputted = function(ev) {
+ latestEvent = ev;
+
+ ev.output.promise.then(function() {
+ latestData = ev.output.data;
+ });
+};
+
+
+exports.setup = function(options) {
+ options.requisition.commandOutputManager.onOutput.add(outputted);
+};
+
+exports.shutdown = function(options) {
+ options.requisition.commandOutputManager.onOutput.remove(outputted);
+};
+
+exports.testOutput = function(options) {
+ latestEvent = undefined;
+ latestData = undefined;
+
+ var terminal = options.terminal;
+ if (!terminal) {
+ assert.log('Skipping testInputter.testOutput due to lack of terminal.');
+ return;
+ }
+
+ var focusManager = terminal.focusManager;
+
+ terminal.setInput('tss');
+
+ var ev0 = { keyCode: KeyEvent.DOM_VK_RETURN };
+ terminal.onKeyDown(ev0);
+
+ assert.is(terminal.getInputState().typed,
+ 'tss',
+ 'terminal should do nothing on RETURN keyDown');
+ assert.is(latestEvent, undefined, 'no events this test');
+ assert.is(latestData, undefined, 'no data this test');
+
+ var ev1 = { keyCode: KeyEvent.DOM_VK_RETURN };
+ return terminal.handleKeyUp(ev1).then(function() {
+ assert.ok(latestEvent != null, 'events this test');
+ assert.is(latestData, 'Exec: tss ', 'last command is tss');
+
+ assert.is(terminal.getInputState().typed,
+ '',
+ 'terminal should exec on RETURN keyUp');
+
+ assert.ok(focusManager._recentOutput, 'recent output happened');
+
+ var ev2 = { keyCode: KeyEvent.DOM_VK_F1 };
+ return terminal.handleKeyUp(ev2).then(function() {
+ assert.ok(!focusManager._recentOutput, 'no recent output happened post F1');
+ assert.ok(focusManager._helpRequested, 'F1 = help');
+
+ var ev3 = { keyCode: KeyEvent.DOM_VK_ESCAPE };
+ return terminal.handleKeyUp(ev3).then(function() {
+ assert.ok(!focusManager._helpRequested, 'ESCAPE = anti help');
+ });
+ });
+
+ });
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_intro.js b/toolkit/devtools/commandline/test/browser_gcli_intro.js
new file mode 100644
index 000000000..263000e89
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_intro.js
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testIntro.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testIntroStatus = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: function commandIntroMissing() {
+ return options.requisition.system.commands.get('intro') == null;
+ },
+ setup: 'intro',
+ check: {
+ typed: 'intro',
+ markup: 'VVVVV',
+ status: 'VALID',
+ hints: ''
+ }
+ },
+ {
+ setup: 'intro foo',
+ check: {
+ typed: 'intro foo',
+ markup: 'VVVVVVEEE',
+ status: 'ERROR',
+ hints: ''
+ }
+ },
+ {
+ setup: 'intro',
+ skipIf: options.isNoDom,
+ check: {
+ typed: 'intro',
+ markup: 'VVVVV',
+ status: 'VALID',
+ hints: ''
+ },
+ exec: {
+ output: [
+ /command\s*line/,
+ /help/,
+ /F1/,
+ /Escape/
+ ]
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_js.js b/toolkit/devtools/commandline/test/browser_gcli_js.js
new file mode 100644
index 000000000..4128c4642
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_js.js
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testJs.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var javascript = require('gcli/types/javascript');
+
+var tempWindow;
+
+exports.setup = function(options) {
+ if (options.isNoDom) {
+ return;
+ }
+
+ tempWindow = javascript.getGlobalObject();
+ Object.defineProperty(options.window, 'donteval', {
+ get: function() {
+ assert.ok(false, 'donteval should not be used');
+ return { cant: '', touch: '', 'this': '' };
+ },
+ enumerable: true,
+ configurable : true
+ });
+ javascript.setGlobalObject(options.window);
+};
+
+exports.shutdown = function(options) {
+ if (options.isNoDom) {
+ return;
+ }
+
+ javascript.setGlobalObject(tempWindow);
+ tempWindow = undefined;
+ delete options.window.donteval;
+};
+
+function jsTestAllowed(options) {
+ return options.isRemote || options.isNoDom ||
+ options.requisition.system.commands.get('{') == null;
+}
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: jsTestAllowed,
+ setup: '{',
+ check: {
+ input: '{',
+ hints: '',
+ markup: 'V',
+ cursor: 1,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: undefined,
+ arg: '{',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ ',
+ check: {
+ input: '{ ',
+ hints: '',
+ markup: 'VV',
+ cursor: 2,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: undefined,
+ arg: '{ ',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ w',
+ check: {
+ input: '{ w',
+ hints: 'indow',
+ markup: 'VVI',
+ cursor: 3,
+ current: 'javascript',
+ status: 'ERROR',
+ predictionsContains: [ 'window' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'w',
+ arg: '{ w',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ windo',
+ check: {
+ input: '{ windo',
+ hints: 'w',
+ markup: 'VVIIIII',
+ cursor: 7,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ 'window' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'windo',
+ arg: '{ windo',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ window',
+ check: {
+ input: '{ window',
+ hints: '',
+ markup: 'VVVVVVVV',
+ cursor: 8,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'window',
+ arg: '{ window',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: '{ window.do',
+ check: {
+ input: '{ window.do',
+ hints: 'cument',
+ markup: 'VVIIIIIIIII',
+ cursor: 11,
+ current: 'javascript',
+ status: 'ERROR',
+ predictionsContains: [ 'window.document' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'window.do',
+ arg: '{ window.do',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ window.document.title',
+ check: {
+ input: '{ window.document.title',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 23,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'window.document.title',
+ arg: '{ window.document.title',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testDocument = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: jsTestAllowed,
+ setup: '{ docu',
+ check: {
+ input: '{ docu',
+ hints: 'ment',
+ markup: 'VVIIII',
+ cursor: 6,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ 'document' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'docu',
+ arg: '{ docu',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ docu<TAB>',
+ check: {
+ input: '{ document',
+ hints: '',
+ markup: 'VVVVVVVVVV',
+ cursor: 10,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'document',
+ arg: '{ document',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: '{ document.titl',
+ check: {
+ input: '{ document.titl',
+ hints: 'e',
+ markup: 'VVIIIIIIIIIIIII',
+ cursor: 15,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ 'document.title' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'document.titl',
+ arg: '{ document.titl',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ document.titl<TAB>',
+ check: {
+ input: '{ document.title ',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'document.title',
+ arg: '{ document.title ',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: '{ document.title',
+ check: {
+ input: '{ document.title',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ cursor: 16,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'document.title',
+ arg: '{ document.title',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testDonteval = function(options) {
+ if (!options.isNoDom) {
+ // nodom causes an eval here, maybe that's node/v8?
+ assert.ok('donteval' in options.window, 'donteval exists');
+ }
+
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: jsTestAllowed,
+ setup: '{ don',
+ check: {
+ input: '{ don',
+ hints: 'teval',
+ markup: 'VVIII',
+ cursor: 5,
+ current: 'javascript',
+ status: 'ERROR',
+ predictions: [ 'donteval' ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'don',
+ arg: '{ don',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: '{ donteval',
+ check: {
+ input: '{ donteval',
+ hints: '',
+ markup: 'VVVVVVVVVV',
+ cursor: 10,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'donteval',
+ arg: '{ donteval',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ /*
+ // This is a controversial test - technically we can tell that it's an error
+ // because 'donteval.' is a syntax error, however donteval is unsafe so we
+ // are playing safe by bailing out early. It's enough of a corner case that
+ // I don't think it warrants fixing
+ {
+ setup: '{ donteval.',
+ check: {
+ input: '{ donteval.',
+ hints: '',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'donteval.',
+ arg: '{ donteval.',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ */
+ {
+ setup: '{ donteval.cant',
+ check: {
+ input: '{ donteval.cant',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVV',
+ cursor: 15,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'donteval.cant',
+ arg: '{ donteval.cant',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: '{ donteval.xxx',
+ check: {
+ input: '{ donteval.xxx',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'javascript',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: '{' },
+ javascript: {
+ value: 'donteval.xxx',
+ arg: '{ donteval.xxx',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testExec = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: jsTestAllowed,
+ setup: '{ 1+1',
+ check: {
+ input: '{ 1+1',
+ hints: '',
+ markup: 'VVVVV',
+ cursor: 5,
+ current: 'javascript',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ javascript: {
+ value: '1+1',
+ arg: '{ 1+1',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: '2',
+ type: 'number',
+ error: false
+ }
+ },
+ {
+ setup: '{ 1+1 }',
+ check: {
+ input: '{ 1+1 }',
+ hints: '',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'javascript',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ javascript: {
+ value: '1+1',
+ arg: '{ 1+1 }',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: '2',
+ type: 'number',
+ error: false
+ }
+ },
+ {
+ setup: '{ "hello"',
+ check: {
+ input: '{ "hello"',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'javascript',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ javascript: {
+ value: '"hello"',
+ arg: '{ "hello"',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'hello',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: '{ "hello" + 1',
+ check: {
+ input: '{ "hello" + 1',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'javascript',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ javascript: {
+ value: '"hello" + 1',
+ arg: '{ "hello" + 1',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'hello1',
+ type: 'string',
+ error: false
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js
new file mode 100644
index 000000000..0de779491
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard1.js
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard1.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+var javascript = require('gcli/types/javascript');
+// var helpers = require('./helpers');
+
+var tempWindow;
+
+exports.setup = function(options) {
+ tempWindow = javascript.getGlobalObject();
+ javascript.setGlobalObject(options.window);
+};
+
+exports.shutdown = function(options) {
+ javascript.setGlobalObject(tempWindow);
+ tempWindow = undefined;
+};
+
+exports.testSimple = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsela<TAB>',
+ check: { input: 'tselarr ', cursor: 8 }
+ },
+ {
+ setup: 'tsn di<TAB>',
+ check: { input: 'tsn dif ', cursor: 8 }
+ },
+ {
+ setup: 'tsg a<TAB>',
+ check: { input: 'tsg aaa ', cursor: 8 }
+ }
+ ]);
+};
+
+exports.testScript = function(options) {
+ return helpers.audit(options, [
+ {
+ skipIf: function commandJsMissing() {
+ return options.requisition.system.commands.get('{') == null;
+ },
+ setup: '{ wind<TAB>',
+ check: { input: '{ window' }
+ },
+ {
+ skipIf: function commandJsMissing() {
+ return options.requisition.system.commands.get('{') == null;
+ },
+ setup: '{ window.docum<TAB>',
+ check: { input: '{ window.document' }
+ }
+ ]);
+};
+
+exports.testJsdom = function(options) {
+ return helpers.audit(options, [
+ {
+ skipIf: function jsDomOrCommandJsMissing() {
+ return options.requisition.system.commands.get('{') == null;
+ },
+ setup: '{ window.document.titl<TAB>',
+ check: { input: '{ window.document.title ' }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js
new file mode 100644
index 000000000..7f510f08e
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard2.js
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard2.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testIncr = function(options) {
+ return helpers.audit(options, [
+ /*
+ // We currently refuse to increment/decrement things with a non-valid
+ // status which makes sense for many cases, and is a decent default.
+ // However in theory we could do better, these tests are there for then
+ {
+ setup: 'tsu -70<UP>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -7<UP>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -6<UP>',
+ check: { input: 'tsu -5' }
+ },
+ */
+ {
+ setup: 'tsu -5<UP>',
+ check: { input: 'tsu -3' }
+ },
+ {
+ setup: 'tsu -4<UP>',
+ check: { input: 'tsu -3' }
+ },
+ {
+ setup: 'tsu -3<UP>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu -2<UP>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu -1<UP>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu 0<UP>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 1<UP>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 2<UP>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 3<UP>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 4<UP>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 5<UP>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 6<UP>',
+ check: { input: 'tsu 9' }
+ },
+ {
+ setup: 'tsu 7<UP>',
+ check: { input: 'tsu 9' }
+ },
+ {
+ setup: 'tsu 8<UP>',
+ check: { input: 'tsu 9' }
+ },
+ {
+ setup: 'tsu 9<UP>',
+ check: { input: 'tsu 10' }
+ },
+ {
+ setup: 'tsu 10<UP>',
+ check: { input: 'tsu 10' }
+ }
+ /*
+ // See notes above
+ {
+ setup: 'tsu 100<UP>',
+ check: { input: 'tsu 10' }
+ }
+ */
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js
new file mode 100644
index 000000000..c1bfc15fc
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard3.js
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard3.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testDecr = function(options) {
+ return helpers.audit(options, [
+ /*
+ // See notes at top of testIncr in testKeyboard2.js
+ {
+ setup: 'tsu -70<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -7<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -6<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ */
+ {
+ setup: 'tsu -5<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -4<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -3<DOWN>',
+ check: { input: 'tsu -5' }
+ },
+ {
+ setup: 'tsu -2<DOWN>',
+ check: { input: 'tsu -3' }
+ },
+ {
+ setup: 'tsu -1<DOWN>',
+ check: { input: 'tsu -3' }
+ },
+ {
+ setup: 'tsu 0<DOWN>',
+ check: { input: 'tsu -3' }
+ },
+ {
+ setup: 'tsu 1<DOWN>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu 2<DOWN>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu 3<DOWN>',
+ check: { input: 'tsu 0' }
+ },
+ {
+ setup: 'tsu 4<DOWN>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 5<DOWN>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 6<DOWN>',
+ check: { input: 'tsu 3' }
+ },
+ {
+ setup: 'tsu 7<DOWN>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 8<DOWN>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 9<DOWN>',
+ check: { input: 'tsu 6' }
+ },
+ {
+ setup: 'tsu 10<DOWN>',
+ check: { input: 'tsu 9' }
+ }
+ /*
+ // See notes at top of testIncr
+ {
+ setup: 'tsu 100<DOWN>',
+ check: { input: 'tsu 9' }
+ }
+ */
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js
new file mode 100644
index 000000000..5a358f481
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard4.js
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard4.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testIncrFloat = function(options) {
+ return helpers.audit(options, [
+ /*
+ // See notes at top of testIncr
+ {
+ setup: 'tsf -70<UP>',
+ check: { input: 'tsf -6.5' }
+ },
+ */
+ {
+ setup: 'tsf -6.5<UP>',
+ check: { input: 'tsf -6' }
+ },
+ {
+ setup: 'tsf -6<UP>',
+ check: { input: 'tsf -4.5' }
+ },
+ {
+ setup: 'tsf -4.5<UP>',
+ check: { input: 'tsf -3' }
+ },
+ {
+ setup: 'tsf -4<UP>',
+ check: { input: 'tsf -3' }
+ },
+ {
+ setup: 'tsf -3<UP>',
+ check: { input: 'tsf -1.5' }
+ },
+ {
+ setup: 'tsf -1.5<UP>',
+ check: { input: 'tsf 0' }
+ },
+ {
+ setup: 'tsf 0<UP>',
+ check: { input: 'tsf 1.5' }
+ },
+ {
+ setup: 'tsf 1.5<UP>',
+ check: { input: 'tsf 3' }
+ },
+ {
+ setup: 'tsf 2<UP>',
+ check: { input: 'tsf 3' }
+ },
+ {
+ setup: 'tsf 3<UP>',
+ check: { input: 'tsf 4.5' }
+ },
+ {
+ setup: 'tsf 5<UP>',
+ check: { input: 'tsf 6' }
+ }
+ /*
+ // See notes at top of testIncr
+ {
+ setup: 'tsf 100<UP>',
+ check: { input: 'tsf -6.5' }
+ }
+ */
+ ]);
+};
+
+exports.testDecrFloat = function(options) {
+ return helpers.audit(options, [
+ /*
+ // See notes at top of testIncr
+ {
+ setup: 'tsf -70<DOWN>',
+ check: { input: 'tsf 11.5' }
+ },
+ */
+ {
+ setup: 'tsf -6.5<DOWN>',
+ check: { input: 'tsf -6.5' }
+ },
+ {
+ setup: 'tsf -6<DOWN>',
+ check: { input: 'tsf -6.5' }
+ },
+ {
+ setup: 'tsf -4.5<DOWN>',
+ check: { input: 'tsf -6' }
+ },
+ {
+ setup: 'tsf -4<DOWN>',
+ check: { input: 'tsf -4.5' }
+ },
+ {
+ setup: 'tsf -3<DOWN>',
+ check: { input: 'tsf -4.5' }
+ },
+ {
+ setup: 'tsf -1.5<DOWN>',
+ check: { input: 'tsf -3' }
+ },
+ {
+ setup: 'tsf 0<DOWN>',
+ check: { input: 'tsf -1.5' }
+ },
+ {
+ setup: 'tsf 1.5<DOWN>',
+ check: { input: 'tsf 0' }
+ },
+ {
+ setup: 'tsf 2<DOWN>',
+ check: { input: 'tsf 1.5' }
+ },
+ {
+ setup: 'tsf 3<DOWN>',
+ check: { input: 'tsf 1.5' }
+ },
+ {
+ setup: 'tsf 5<DOWN>',
+ check: { input: 'tsf 4.5' }
+ }
+ /*
+ // See notes at top of testIncr
+ {
+ setup: 'tsf 100<DOWN>',
+ check: { input: 'tsf 11.5' }
+ }
+ */
+ ]);
+};
+
+exports.testIncrSelection = function(options) {
+ /*
+ // Bug 829516: GCLI up/down navigation over selection is sometimes bizarre
+ return helpers.audit(options, [
+ {
+ setup: 'tselarr <DOWN>',
+ check: { hints: '2' },
+ exec: {}
+ },
+ {
+ setup: 'tselarr <DOWN><DOWN>',
+ check: { hints: '3' },
+ exec: {}
+ },
+ {
+ setup: 'tselarr <DOWN><DOWN><DOWN>',
+ check: { hints: '1' },
+ exec: {}
+ }
+ ]);
+ */
+};
+
+exports.testDecrSelection = function(options) {
+ /*
+ // Bug 829516: GCLI up/down navigation over selection is sometimes bizarre
+ return helpers.audit(options, [
+ {
+ setup: 'tselarr <UP>',
+ check: { hints: '3' }
+ }
+ ]);
+ */
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js
new file mode 100644
index 000000000..41e36a4b9
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard5.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard5.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testCompleteDown = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn e<DOWN><DOWN><DOWN><DOWN><DOWN><TAB>',
+ check: { input: 'tsn exte ' }
+ },
+ {
+ setup: 'tsn e<DOWN><DOWN><DOWN><DOWN><TAB>',
+ check: { input: 'tsn ext ' }
+ },
+ {
+ setup: 'tsn e<DOWN><DOWN><DOWN><TAB>',
+ check: { input: 'tsn extend ' }
+ },
+ {
+ setup: 'tsn e<DOWN><DOWN><TAB>',
+ check: { input: 'tsn exten ' }
+ },
+ {
+ setup: 'tsn e<DOWN><TAB>',
+ check: { input: 'tsn exte ' }
+ },
+ {
+ setup: 'tsn e<TAB>',
+ check: { input: 'tsn ext ' }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js b/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js
new file mode 100644
index 000000000..d53a855b3
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_keyboard6.js
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testKeyboard6.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testCompleteUp = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsn e<UP><TAB>',
+ check: { input: 'tsn extend ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><TAB>',
+ check: { input: 'tsn exten ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><TAB>',
+ check: { input: 'tsn exte ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><UP><TAB>',
+ check: { input: 'tsn ext ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><UP><UP><TAB>',
+ check: { input: 'tsn extend ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><UP><UP><UP><TAB>',
+ check: { input: 'tsn exten ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><UP><UP><UP><UP><TAB>',
+ check: { input: 'tsn exte ' }
+ },
+ {
+ setup: 'tsn e<UP><UP><UP><UP><UP><UP><UP><UP><TAB>',
+ check: { input: 'tsn ext ' }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_menu.js b/toolkit/devtools/commandline/test/browser_gcli_menu.js
new file mode 100644
index 000000000..8e3eb167f
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_menu.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testMenu.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testOptions = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tslong',
+ check: {
+ input: 'tslong',
+ markup: 'VVVVVV',
+ status: 'ERROR',
+ hints: ' <msg> [options]',
+ args: {
+ msg: { value: undefined, status: 'INCOMPLETE' },
+ num: { value: undefined, status: 'VALID' },
+ sel: { value: undefined, status: 'VALID' },
+ bool: { value: false, status: 'VALID' },
+ bool2: { value: false, status: 'VALID' },
+ sel2: { value: undefined, status: 'VALID' },
+ num2: { value: undefined, status: 'VALID' }
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_node.js b/toolkit/devtools/commandline/test/browser_gcli_node.js
new file mode 100644
index 000000000..7be07ba76
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_node.js
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testNode.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var nodetype = require('gcli/types/node');
+
+exports.setup = function(options) {
+ if (options.window) {
+ nodetype.setDocument(options.window.document);
+ }
+};
+
+exports.shutdown = function(options) {
+ nodetype.unsetDocument();
+};
+
+exports.testNode = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isNoDom,
+ setup: 'tse ',
+ check: {
+ input: 'tse ',
+ hints: '<node> [options]',
+ markup: 'VVVV',
+ cursor: 4,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: { status: 'INCOMPLETE' },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tse :',
+ check: {
+ input: 'tse :',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ arg: ' :',
+ status: 'ERROR',
+ message: 'Syntax error in CSS query'
+ },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tse #',
+ check: {
+ input: 'tse #',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' #',
+ status: 'ERROR',
+ message: 'Syntax error in CSS query'
+ },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tse .',
+ check: {
+ input: 'tse .',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' .',
+ status: 'ERROR',
+ message: 'Syntax error in CSS query'
+ },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tse *',
+ check: {
+ input: 'tse *',
+ hints: ' [options]',
+ markup: 'VVVVE',
+ cursor: 5,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' *',
+ status: 'ERROR'
+ // message: 'Too many matches (128)'
+ },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testNodeDom = function(options) {
+ var requisition = options.requisition;
+
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isNoDom,
+ setup: 'tse :root',
+ check: {
+ input: 'tse :root',
+ hints: ' [options]',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'node',
+ status: 'VALID',
+ args: {
+ command: { name: 'tse' },
+ node: { arg: ' :root', status: 'VALID' },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ },
+ {
+ setup: 'tse :root ',
+ check: {
+ input: 'tse :root ',
+ hints: '[options]',
+ markup: 'VVVVVVVVVV',
+ cursor: 10,
+ current: 'node',
+ status: 'VALID',
+ args: {
+ command: { name: 'tse' },
+ node: { arg: ' :root ', status: 'VALID' },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ },
+ post: function() {
+ assert.is(requisition.getAssignment('node').value.tagName,
+ 'HTML',
+ 'root id');
+ }
+ },
+ {
+ setup: 'tse #gcli-nomatch',
+ check: {
+ input: 'tse #gcli-nomatch',
+ hints: ' [options]',
+ markup: 'VVVVIIIIIIIIIIIII',
+ cursor: 17,
+ current: 'node',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: ' #gcli-nomatch',
+ status: 'INCOMPLETE',
+ message: 'No matches'
+ },
+ nodes: { status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testNodes = function(options) {
+ var requisition = options.requisition;
+
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isNoDom,
+ setup: 'tse :root --nodes *',
+ check: {
+ input: 'tse :root --nodes *',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVV',
+ current: 'nodes',
+ status: 'VALID',
+ args: {
+ command: { name: 'tse' },
+ node: { arg: ' :root', status: 'VALID' },
+ nodes: { arg: ' --nodes *', status: 'VALID' },
+ nodes2: { status: 'VALID' }
+ }
+ },
+ post: function() {
+ assert.is(requisition.getAssignment('node').value.tagName,
+ 'HTML',
+ '#gcli-input id');
+ }
+ },
+ {
+ setup: 'tse :root --nodes2 div',
+ check: {
+ input: 'tse :root --nodes2 div',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 22,
+ current: 'nodes2',
+ status: 'VALID',
+ args: {
+ command: { name: 'tse' },
+ node: { arg: ' :root', status: 'VALID' },
+ nodes: { status: 'VALID' },
+ nodes2: { arg: ' --nodes2 div', status: 'VALID' }
+ }
+ },
+ post: function() {
+ assert.is(requisition.getAssignment('node').value.tagName,
+ 'HTML',
+ 'root id');
+ }
+ },
+ {
+ setup: 'tse --nodes ffff',
+ check: {
+ input: 'tse --nodes ffff',
+ hints: ' <node> [options]',
+ markup: 'VVVVIIIIIIIVIIII',
+ cursor: 16,
+ current: 'nodes',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ },
+ nodes: {
+ value: undefined,
+ arg: ' --nodes ffff',
+ status: 'INCOMPLETE',
+ message: 'No matches'
+ },
+ nodes2: { arg: '', status: 'VALID', message: '' }
+ }
+ },
+ post: function() {
+ /*
+ assert.is(requisition.getAssignment('nodes2').value.constructor.name,
+ 'NodeList',
+ '#gcli-input id');
+ */
+ }
+ },
+ {
+ setup: 'tse --nodes2 ffff',
+ check: {
+ input: 'tse --nodes2 ffff',
+ hints: ' <node> [options]',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'nodes2',
+ status: 'ERROR',
+ args: {
+ command: { name: 'tse' },
+ node: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ },
+ nodes: { arg: '', status: 'VALID', message: '' },
+ nodes2: { arg: ' --nodes2 ffff', status: 'VALID', message: '' }
+ }
+ },
+ post: function() {
+ /*
+ assert.is(requisition.getAssignment('nodes').value.constructor.name,
+ 'NodeList',
+ '#gcli-input id');
+ assert.is(requisition.getAssignment('nodes2').value.constructor.name,
+ 'NodeList',
+ '#gcli-input id');
+ */
+ }
+ },
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_pref1.js b/toolkit/devtools/commandline/test/browser_gcli_pref1.js
new file mode 100644
index 000000000..ee9c51d5e
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_pref1.js
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testPref1.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testPrefShowStatus = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.requisition.system.commands.get('pref') == null,
+ setup: 'pref s',
+ check: {
+ typed: 'pref s',
+ hints: 'et',
+ markup: 'IIIIVI',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref show',
+ check: {
+ typed: 'pref show',
+ hints: ' <setting>',
+ markup: 'VVVVVVVVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref show ',
+ check: {
+ typed: 'pref show ',
+ hints: 'allowSet',
+ markup: 'VVVVVVVVVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref show tempTBo',
+ check: {
+ typed: 'pref show tempTBo',
+ hints: 'ol',
+ markup: 'VVVVVVVVVVIIIIIII',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref show tempTBool',
+ check: {
+ typed: 'pref show tempTBool',
+ markup: 'VVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ hints: ''
+ }
+ },
+ {
+ setup: 'pref show tempTBool 4',
+ check: {
+ typed: 'pref show tempTBool 4',
+ markup: 'VVVVVVVVVVVVVVVVVVVVE',
+ status: 'ERROR',
+ hints: ''
+ }
+ },
+ {
+ setup: 'pref show tempNumber 4',
+ check: {
+ typed: 'pref show tempNumber 4',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVE',
+ status: 'ERROR',
+ hints: ''
+ }
+ }
+ ]);
+};
+
+exports.testPrefSetStatus = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.requisition.system.commands.get('pref') == null,
+ setup: 'pref s',
+ check: {
+ typed: 'pref s',
+ hints: 'et',
+ markup: 'IIIIVI',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref set',
+ check: {
+ typed: 'pref set',
+ hints: ' <setting> <value>',
+ markup: 'VVVVVVVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref xxx',
+ check: {
+ typed: 'pref xxx',
+ markup: 'IIIIVIII',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref set ',
+ check: {
+ typed: 'pref set ',
+ hints: 'allowSet <value>',
+ markup: 'VVVVVVVVV',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref set tempTBo',
+ check: {
+ typed: 'pref set tempTBo',
+ hints: 'ol <value>',
+ markup: 'VVVVVVVVVIIIIIII',
+ status: 'ERROR'
+ }
+ },
+ {
+ setup: 'pref set tempTBool 4',
+ check: {
+ typed: 'pref set tempTBool 4',
+ markup: 'VVVVVVVVVVVVVVVVVVVE',
+ status: 'ERROR',
+ hints: ''
+ }
+ },
+ {
+ setup: 'pref set tempNumber 4',
+ check: {
+ typed: 'pref set tempNumber 4',
+ markup: 'VVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ hints: ''
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_pref2.js b/toolkit/devtools/commandline/test/browser_gcli_pref2.js
new file mode 100644
index 000000000..019283077
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_pref2.js
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testPref2.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+var mockSettings = require('./mockSettings');
+
+exports.testPrefExec = function(options) {
+ if (options.requisition.system.commands.get('pref') == null) {
+ assert.log('Skipping test; missing pref command.');
+ return;
+ }
+
+ if (options.isRemote) {
+ assert.log('Skipping test which assumes local settings.');
+ return;
+ }
+
+ var allowSet = settings.getSetting('allowSet');
+ var initialAllowSet = allowSet.value;
+ allowSet.value = false;
+
+ assert.is(mockSettings.tempNumber.value, 42, 'set to 42');
+
+ return helpers.audit(options, [
+ {
+ // Delegated remote types can't transfer value types so we only test for
+ // the value of 'value' when we're local
+ skipIf: options.isRemote,
+ setup: 'pref set tempNumber 4',
+ check: {
+ setting: { value: mockSettings.tempNumber },
+ args: { value: { value: 4 } }
+ }
+ },
+ {
+ skipRemainingIf: options.isNoDom,
+ setup: 'pref set tempNumber 4',
+ check: {
+ input: 'pref set tempNumber 4',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVV',
+ cursor: 21,
+ current: 'value',
+ status: 'VALID',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'pref set' },
+ setting: {
+ arg: ' tempNumber',
+ status: 'VALID',
+ message: ''
+ },
+ value: {
+ arg: ' 4',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: [ /void your warranty/, /I promise/ ]
+ },
+ post: function() {
+ assert.is(mockSettings.tempNumber.value, 42, 'still set to 42');
+ allowSet.value = true;
+ }
+ },
+ {
+ setup: 'pref set tempNumber 4',
+ exec: {
+ output: ''
+ },
+ post: function() {
+ assert.is(mockSettings.tempNumber.value, 4, 'set to 4');
+ }
+ },
+ {
+ setup: 'pref reset tempNumber',
+ check: {
+ args: {
+ command: { name: 'pref reset' },
+ setting: { value: mockSettings.tempNumber }
+ }
+ },
+ exec: {
+ output: ''
+ },
+ post: function() {
+ assert.is(mockSettings.tempNumber.value, 42, 'reset to 42');
+
+ allowSet.value = initialAllowSet;
+ }
+ },
+ {
+ skipRemainingIf: function commandPrefListMissing() {
+ return options.requisition.system.commands.get('pref list') == null;
+ },
+ setup: 'pref list tempNum',
+ check: {
+ args: {
+ command: { name: 'pref list' },
+ search: { value: 'tempNum' }
+ }
+ },
+ exec: {
+ output: /tempNum/
+ }
+ },
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_remotews.js b/toolkit/devtools/commandline/test/browser_gcli_remotews.js
new file mode 100644
index 000000000..7b9237e19
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_remotews.js
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testRemoteWs.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+// testRemoteWs and testRemoteXhr are virtually identical.
+// Changes made here should be made there too.
+// They are kept separate to save adding complexity to the test system and so
+// to help us select the test that are available in different environments
+
+exports.testRemoteWebsocket = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isRemote || options.isNode || options.isFirefox,
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ hints: '',
+ markup: 'EEEEEEV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'remote\'.',
+ predictions: [ ],
+ unassigned: [ ],
+ }
+ },
+ {
+ setup: 'connect remote',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ }
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'connect remote --method websocket',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ }
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'connect remote --method websocket',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ output: /^Added [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ // PhantomJS fails on this. Unsure why
+ // hints: ' {',
+ markup: 'IIIIIIV',
+ status: 'ERROR',
+ optionsIncludes: [
+ 'remote', 'remote cd', 'remote context', 'remote echo',
+ 'remote exec', 'remote exit', 'remote firefox', 'remote help',
+ 'remote intro', 'remote make'
+ ],
+ message: '',
+ predictionsIncludes: [ 'remote' ],
+ unassigned: [ ],
+ }
+ },
+ {
+ setup: 'remote echo hello world',
+ check: {
+ input: 'remote echo hello world',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 23,
+ current: 'message',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote echo' },
+ message: {
+ value: 'hello world',
+ arg: ' hello world',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'hello world',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote exec ls',
+ check: {
+ input: 'remote exec ls',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: {
+ value: 'ls',
+ arg: ' ls',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ // output: '', We can't rely on the contents of the FS
+ type: 'output',
+ error: false
+ }
+ },
+ {
+ setup: 'remote sleep mistake',
+ check: {
+ input: 'remote sleep mistake',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVEEEEEEE',
+ cursor: 20,
+ current: 'length',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t convert "mistake" to a number.',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote sleep' },
+ length: {
+ value: undefined,
+ arg: ' mistake',
+ status: 'ERROR',
+ message: 'Can\'t convert "mistake" to a number.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'remote sleep 1',
+ check: {
+ input: 'remote sleep 1',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'length',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote sleep' },
+ length: { value: 1, arg: ' 1', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Done',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote help ',
+ skipIf: true, // The help command is not remotable
+ check: {
+ input: 'remote help ',
+ hints: '[search]',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'search',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote help' },
+ search: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: '',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote intro',
+ check: {
+ input: 'remote intro',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: '__command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote intro' }
+ }
+ },
+ exec: {
+ output: [
+ /GCLI is an experiment/,
+ /F1\/Escape/
+ ],
+ type: 'intro',
+ error: false
+ }
+ },
+ {
+ setup: 'context remote',
+ check: {
+ input: 'context remote',
+ // hints: ' {',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'prefix',
+ status: 'VALID',
+ optionsContains: [
+ 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ 'remote firefox', 'remote help', 'remote intro', 'remote make'
+ ],
+ message: '',
+ // predictionsContains: [
+ // 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ // 'remote firefox', 'remote help', 'remote intro', 'remote make',
+ // 'remote pref'
+ // ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: {
+ arg: ' remote',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Using remote as a command prefix',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'exec ls',
+ check: {
+ input: 'exec ls',
+ hints: '',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { value: 'ls', arg: ' ls', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ // output: '', We can't rely on the contents of the filesystem
+ type: 'output',
+ error: false
+ }
+ },
+ {
+ setup: 'echo hello world',
+ check: {
+ input: 'echo hello world',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ cursor: 16,
+ current: 'message',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote echo' },
+ message: {
+ value: 'hello world',
+ arg: ' hello world',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: /^hello world$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'context',
+ check: {
+ input: 'context',
+ hints: ' [prefix]',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: '__command',
+ status: 'VALID',
+ optionsContains: [
+ 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ 'remote firefox', 'remote help', 'remote intro', 'remote make'
+ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: { value: undefined, arg: '', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Command prefix is unset',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect ',
+ check: {
+ input: 'disconnect ',
+ hints: 'remote',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'prefix',
+ status: 'ERROR',
+ options: [ 'remote' ],
+ message: '',
+ predictions: [ 'remote' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'disconnect' },
+ prefix: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'prefix\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ input: 'disconnect remote',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ unassigned: [ ],
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ },
+ arg: ' remote',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ hints: '',
+ markup: 'EEEEEEV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'remote\'.',
+ predictions: [ ],
+ unassigned: [ ],
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js b/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js
new file mode 100644
index 000000000..b89b9d52b
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_remotexhr.js
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testRemoteXhr.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+// testRemoteWs and testRemoteXhr are virtually identical.
+// Changes made here should be made there too.
+// They are kept separate to save adding complexity to the test system and so
+// to help us select the test that are available in different environments
+
+exports.testRemoteXhr = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isRemote || options.isNode || options.isFirefox,
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ hints: '',
+ markup: 'EEEEEEV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'remote\'.',
+ predictions: [ ],
+ unassigned: [ ],
+ }
+ },
+ {
+ setup: 'connect remote',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ }
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'connect remote --method xhr',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ }
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'connect remote --method xhr',
+ check: {
+ args: {
+ prefix: { value: 'remote' },
+ url: { value: undefined }
+ }
+ },
+ exec: {
+ output: /^Added [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ // PhantomJS fails on this. Unsure why
+ // hints: ' {',
+ markup: 'IIIIIIV',
+ status: 'ERROR',
+ optionsIncludes: [
+ 'remote', 'remote cd', 'remote context', 'remote echo',
+ 'remote exec', 'remote exit', 'remote firefox', 'remote help',
+ 'remote intro', 'remote make'
+ ],
+ message: '',
+ predictionsIncludes: [ 'remote' ],
+ unassigned: [ ],
+ }
+ },
+ {
+ setup: 'remote echo hello world',
+ check: {
+ input: 'remote echo hello world',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVV',
+ cursor: 23,
+ current: 'message',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote echo' },
+ message: {
+ value: 'hello world',
+ arg: ' hello world',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'hello world',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote exec ls',
+ check: {
+ input: 'remote exec ls',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: {
+ value: 'ls',
+ arg: ' ls',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ // output: '', We can't rely on the contents of the FS
+ type: 'output',
+ error: false
+ }
+ },
+ {
+ setup: 'remote sleep mistake',
+ check: {
+ input: 'remote sleep mistake',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVEEEEEEE',
+ cursor: 20,
+ current: 'length',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t convert "mistake" to a number.',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote sleep' },
+ length: {
+ value: undefined,
+ arg: ' mistake',
+ status: 'ERROR',
+ message: 'Can\'t convert "mistake" to a number.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'remote sleep 1',
+ check: {
+ input: 'remote sleep 1',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'length',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote sleep' },
+ length: { value: 1, arg: ' 1', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Done',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote help ',
+ skipIf: true, // The help command is not remotable
+ check: {
+ input: 'remote help ',
+ hints: '[search]',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: 'search',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote help' },
+ search: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: '',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote intro',
+ check: {
+ input: 'remote intro',
+ hints: '',
+ markup: 'VVVVVVVVVVVV',
+ cursor: 12,
+ current: '__command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote intro' }
+ }
+ },
+ exec: {
+ output: [
+ /GCLI is an experiment/,
+ /F1\/Escape/
+ ],
+ type: 'intro',
+ error: false
+ }
+ },
+ {
+ setup: 'context remote',
+ check: {
+ input: 'context remote',
+ // hints: ' {',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'prefix',
+ status: 'VALID',
+ optionsContains: [
+ 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ 'remote firefox', 'remote help', 'remote intro', 'remote make'
+ ],
+ message: '',
+ // predictionsContains: [
+ // 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ // 'remote firefox', 'remote help', 'remote intro', 'remote make',
+ // 'remote pref'
+ // ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: {
+ arg: ' remote',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: 'Using remote as a command prefix',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'exec ls',
+ check: {
+ input: 'exec ls',
+ hints: '',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: 'command',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { value: 'ls', arg: ' ls', status: 'VALID', message: '' },
+ }
+ },
+ exec: {
+ // output: '', We can't rely on the contents of the filesystem
+ type: 'output',
+ error: false
+ }
+ },
+ {
+ setup: 'echo hello world',
+ check: {
+ input: 'echo hello world',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVV',
+ cursor: 16,
+ current: 'message',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'remote echo' },
+ message: {
+ value: 'hello world',
+ arg: ' hello world',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: /^hello world$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'context',
+ check: {
+ input: 'context',
+ hints: ' [prefix]',
+ markup: 'VVVVVVV',
+ cursor: 7,
+ current: '__command',
+ status: 'VALID',
+ optionsContains: [
+ 'remote', 'remote cd', 'remote echo', 'remote exec', 'remote exit',
+ 'remote firefox', 'remote help', 'remote intro', 'remote make'
+ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'context' },
+ prefix: { value: undefined, arg: '', status: 'VALID', message: '' }
+ }
+ },
+ exec: {
+ output: 'Command prefix is unset',
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'disconnect ',
+ check: {
+ input: 'disconnect ',
+ hints: 'remote',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'prefix',
+ status: 'ERROR',
+ options: [ 'remote' ],
+ message: '',
+ predictions: [ 'remote' ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'disconnect' },
+ prefix: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE',
+ message: 'Value required for \'prefix\'.'
+ }
+ }
+ }
+ },
+ {
+ setup: 'disconnect remote',
+ check: {
+ input: 'disconnect remote',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ unassigned: [ ],
+ args: {
+ prefix: {
+ value: function(connection) {
+ assert.is(connection.prefix, 'remote', 'disconnecting remote');
+ },
+ arg: ' remote',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ },
+ exec: {
+ output: /^Removed [0-9]* commands.$/,
+ type: 'string',
+ error: false
+ }
+ },
+ {
+ setup: 'remote ',
+ check: {
+ input: 'remote ',
+ hints: '',
+ markup: 'EEEEEEV',
+ cursor: 7,
+ current: '__command',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'remote\'.',
+ predictions: [ ],
+ unassigned: [ ],
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_resource.js b/toolkit/devtools/commandline/test/browser_gcli_resource.js
new file mode 100644
index 000000000..2a23253f7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_resource.js
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testResource.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+
+var Promise = require('gcli/util/promise').Promise;
+var util = require('gcli/util/util');
+var resource = require('gcli/types/resource');
+var Status = require('gcli/types/types').Status;
+
+
+var tempDocument;
+
+exports.setup = function(options) {
+ tempDocument = resource.getDocument();
+ if (options.window) {
+ resource.setDocument(options.window.document);
+ }
+};
+
+exports.shutdown = function(options) {
+ resource.setDocument(tempDocument);
+ tempDocument = undefined;
+};
+
+exports.testAllPredictions1 = function(options) {
+ if (options.isFirefox || options.isNoDom) {
+ assert.log('Skipping checks due to firefox document.stylsheets support.');
+ return;
+ }
+
+ var resource = options.requisition.system.types.createType('resource');
+ return resource.getLookup().then(function(opts) {
+ assert.ok(opts.length > 1, 'have all resources');
+
+ return util.promiseEach(opts, function(prediction) {
+ return checkPrediction(resource, prediction);
+ });
+ });
+};
+
+exports.testScriptPredictions = function(options) {
+ if (options.isFirefox || options.isNoDom) {
+ assert.log('Skipping checks due to firefox document.stylsheets support.');
+ return;
+ }
+
+ var types = options.requisition.system.types;
+ var resource = types.createType({ name: 'resource', include: 'text/javascript' });
+ return resource.getLookup().then(function(opts) {
+ assert.ok(opts.length > 1, 'have js resources');
+
+ return util.promiseEach(opts, function(prediction) {
+ return checkPrediction(resource, prediction);
+ });
+ });
+};
+
+exports.testStylePredictions = function(options) {
+ if (options.isFirefox || options.isNoDom) {
+ assert.log('Skipping checks due to firefox document.stylsheets support.');
+ return;
+ }
+
+ var types = options.requisition.system.types;
+ var resource = types.createType({ name: 'resource', include: 'text/css' });
+ return resource.getLookup().then(function(opts) {
+ assert.ok(opts.length >= 1, 'have css resources');
+
+ return util.promiseEach(opts, function(prediction) {
+ return checkPrediction(resource, prediction);
+ });
+ });
+};
+
+exports.testAllPredictions2 = function(options) {
+ if (options.isNoDom) {
+ assert.log('Skipping checks due to nodom document.stylsheets support.');
+ return;
+ }
+ var types = options.requisition.system.types;
+
+ var scriptRes = types.createType({ name: 'resource', include: 'text/javascript' });
+ return scriptRes.getLookup().then(function(scriptOptions) {
+ var styleRes = types.createType({ name: 'resource', include: 'text/css' });
+ return styleRes.getLookup().then(function(styleOptions) {
+ var allRes = types.createType({ name: 'resource' });
+ return allRes.getLookup().then(function(allOptions) {
+ assert.is(scriptOptions.length + styleOptions.length,
+ allOptions.length,
+ 'split');
+ });
+ });
+ });
+};
+
+exports.testAllPredictions3 = function(options) {
+ if (options.isNoDom) {
+ assert.log('Skipping checks due to nodom document.stylsheets support.');
+ return;
+ }
+
+ var types = options.requisition.system.types;
+ var res1 = types.createType({ name: 'resource' });
+ return res1.getLookup().then(function(options1) {
+ var res2 = types.createType('resource');
+ return res2.getLookup().then(function(options2) {
+ assert.is(options1.length, options2.length, 'type spec');
+ });
+ });
+};
+
+function checkPrediction(res, prediction) {
+ var name = prediction.name;
+ var value = prediction.value;
+
+ // resources don't need context so cheat and pass in null
+ var context = null;
+ return res.parseString(name, context).then(function(conversion) {
+ assert.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name);
+ assert.is(conversion.value, value, 'value for ' + name);
+
+ assert.is(typeof value.loadContents, 'function', 'resource for ' + name);
+ assert.is(typeof value.element, 'object', 'resource for ' + name);
+
+ return Promise.resolve(res.stringify(value, context)).then(function(strung) {
+ assert.is(strung, name, 'stringify for ' + name);
+ });
+ });
+}
diff --git a/toolkit/devtools/commandline/test/browser_gcli_short.js b/toolkit/devtools/commandline/test/browser_gcli_short.js
new file mode 100644
index 000000000..812d6ef5e
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_short.js
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testShort.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testBasic = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tshidden -v',
+ check: {
+ input: 'tshidden -v',
+ hints: ' <string>',
+ markup: 'VVVVVVVVVII',
+ cursor: 11,
+ current: 'visible',
+ status: 'ERROR',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: undefined,
+ arg: ' -v',
+ status: 'INCOMPLETE'
+ },
+ invisiblestring: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tshidden -v v',
+ check: {
+ input: 'tshidden -v v',
+ hints: '',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'visible',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: 'v',
+ arg: ' -v v',
+ status: 'VALID',
+ message: ''
+ },
+ invisiblestring: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tshidden -i i',
+ check: {
+ input: 'tshidden -i i',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVVVV',
+ cursor: 13,
+ current: 'invisiblestring',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisiblestring: {
+ value: 'i',
+ arg: ' -i i',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tshidden -b',
+ check: {
+ input: 'tshidden -b',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVVV',
+ cursor: 11,
+ current: 'invisibleboolean',
+ status: 'VALID',
+ options: [ ],
+ message: '',
+ predictions: [ ],
+ unassigned: [ ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisiblestring: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: true,
+ arg: ' -b',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tshidden -j',
+ check: {
+ input: 'tshidden -j',
+ hints: ' [options]',
+ markup: 'VVVVVVVVVEE',
+ cursor: 11,
+ current: '__unassigned',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'-j\'.',
+ predictions: [ ],
+ unassigned: [ ' -j' ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisiblestring: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: false,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tshidden -v jj -b --',
+ check: {
+ input: 'tshidden -v jj -b --',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVEE',
+ cursor: 20,
+ current: '__unassigned',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'--\'.',
+ predictions: [ ],
+ unassigned: [ ' --' ],
+ args: {
+ command: { name: 'tshidden' },
+ visible: {
+ value: 'jj',
+ arg: ' -v jj',
+ status: 'VALID',
+ message: ''
+ },
+ invisiblestring: {
+ value: undefined,
+ arg: '',
+ status: 'VALID',
+ message: ''
+ },
+ invisibleboolean: {
+ value: true,
+ arg: ' -b',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_spell.js b/toolkit/devtools/commandline/test/browser_gcli_spell.js
new file mode 100644
index 000000000..bcd130fee
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_spell.js
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009 Panagiotis Astithas
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testSpell.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var spell = require('gcli/util/spell');
+
+exports.testSpellerSimple = function(options) {
+ var alternatives = [
+ 'window', 'document', 'InstallTrigger', 'requirejs', 'require','define',
+ 'console', 'location', 'constructor', 'getInterface', 'external', 'sidebar'
+ ];
+
+ assert.is(spell.correct('document', alternatives), 'document');
+ assert.is(spell.correct('documen', alternatives), 'document');
+ assert.is(spell.correct('ocument', alternatives), 'document');
+ assert.is(spell.correct('odcument', alternatives), 'document');
+
+ assert.is(spell.correct('=========', alternatives), undefined);
+};
+
+exports.testRank = function(options) {
+ var distances = spell.rank('fred', [ 'banana', 'fred', 'ed', 'red', 'FRED' ]);
+
+ assert.is(distances.length, 5, 'rank length');
+
+ assert.is(distances[0].name, 'fred', 'fred name #0');
+ assert.is(distances[1].name, 'FRED', 'FRED name #1');
+ assert.is(distances[2].name, 'red', 'red name #2');
+ assert.is(distances[3].name, 'ed', 'ed name #3');
+ assert.is(distances[4].name, 'banana', 'banana name #4');
+
+ assert.is(distances[0].dist, 0, 'fred dist 0');
+ assert.is(distances[1].dist, 4, 'FRED dist 4');
+ assert.is(distances[2].dist, 10, 'red dist 10');
+ assert.is(distances[3].dist, 20, 'ed dist 20');
+ assert.is(distances[4].dist, 100, 'banana dist 100');
+};
+
+exports.testRank2 = function(options) {
+ var distances = spell.rank('caps', [ 'CAPS', 'false' ]);
+ assert.is(JSON.stringify(distances),
+ '[{"name":"CAPS","dist":4},{"name":"false","dist":50}]',
+ 'spell.rank("caps", [ "CAPS", "false" ]');
+};
+
+exports.testDistancePrefix = function(options) {
+ assert.is(spell.distancePrefix('fred', 'freddy'), 0, 'distancePrefix fred');
+ assert.is(spell.distancePrefix('FRED', 'freddy'), 4, 'distancePrefix FRED');
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_split.js b/toolkit/devtools/commandline/test/browser_gcli_split.js
new file mode 100644
index 000000000..5e32cbfb8
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_split.js
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testSplit.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+
+var cli = require('gcli/cli');
+
+exports.testSplitSimple = function(options) {
+ var args = cli.tokenize('s');
+ options.requisition._split(args);
+ assert.is(args.length, 0);
+ assert.is(options.requisition.commandAssignment.arg.text, 's');
+};
+
+exports.testFlatCommand = function(options) {
+ var args = cli.tokenize('tsv');
+ options.requisition._split(args);
+ assert.is(args.length, 0);
+ assert.is(options.requisition.commandAssignment.value.name, 'tsv');
+
+ args = cli.tokenize('tsv a b');
+ options.requisition._split(args);
+ assert.is(options.requisition.commandAssignment.value.name, 'tsv');
+ assert.is(args.length, 2);
+ assert.is(args[0].text, 'a');
+ assert.is(args[1].text, 'b');
+};
+
+exports.testJavascript = function(options) {
+ if (!options.requisition.system.commands.get('{')) {
+ assert.log('Skipping testJavascript because { is not registered');
+ return;
+ }
+
+ var args = cli.tokenize('{');
+ options.requisition._split(args);
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '');
+ assert.is(options.requisition.commandAssignment.arg.text, '');
+ assert.is(options.requisition.commandAssignment.value.name, '{');
+};
+
+// BUG 663081 - add tests for sub commands
diff --git a/toolkit/devtools/commandline/test/browser_gcli_string.js b/toolkit/devtools/commandline/test/browser_gcli_string.js
new file mode 100644
index 000000000..5f992dfdd
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_string.js
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testString.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var helpers = require('./helpers');
+
+exports.testNewLine = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'echo a\\nb',
+ check: {
+ input: 'echo a\\nb',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'message',
+ status: 'VALID',
+ args: {
+ command: { name: 'echo' },
+ message: {
+ value: 'a\nb',
+ arg: ' a\\nb',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testTab = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'echo a\\tb',
+ check: {
+ input: 'echo a\\tb',
+ hints: '',
+ markup: 'VVVVVVVVV',
+ cursor: 9,
+ current: 'message',
+ status: 'VALID',
+ args: {
+ command: { name: 'echo' },
+ message: {
+ value: 'a\tb',
+ arg: ' a\\tb',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testEscape = function(options) {
+ return helpers.audit(options, [
+ {
+ // What's typed is actually:
+ // tsrsrsr a\\ b c
+ setup: 'tsrsrsr a\\\\ b c',
+ check: {
+ input: 'tsrsrsr a\\\\ b c',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: { value: 'a\\', arg: ' a\\\\', status: 'VALID', message: '' },
+ p2: { value: 'b', arg: ' b', status: 'VALID', message: '' },
+ p3: { value: 'c', arg: ' c', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ // What's typed is actually:
+ // tsrsrsr abc\\ndef asd asd
+ setup: 'tsrsrsr abc\\\\ndef asd asd',
+ check: {
+ input: 'tsrsrsr abc\\\\ndef asd asd',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVV',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: {
+ value: 'abc\\ndef',
+ arg: ' abc\\\\ndef',
+ status: 'VALID',
+ message: ''
+ },
+ p2: { value: 'asd', arg: ' asd', status: 'VALID', message: '' },
+ p3: { value: 'asd', arg: ' asd', status: 'VALID', message: '' },
+ }
+ }
+ }
+ ]);
+};
+
+exports.testBlank = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsrsrsr a "" c',
+ check: {
+ input: 'tsrsrsr a "" c',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'p3',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: {
+ value: 'a',
+ arg: ' a',
+ status: 'VALID',
+ message: ''
+ },
+ p2: {
+ value: undefined,
+ arg: ' ""',
+ status: 'INCOMPLETE'
+ },
+ p3: {
+ value: 'c',
+ arg: ' c',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ },
+ {
+ setup: 'tsrsrsr a b ""',
+ check: {
+ input: 'tsrsrsr a b ""',
+ hints: '',
+ markup: 'VVVVVVVVVVVVVV',
+ cursor: 14,
+ current: 'p3',
+ status: 'VALID',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: {
+ value: 'a',
+ arg: ' a',
+ status:'VALID',
+ message: '' },
+ p2: {
+ value: 'b',
+ arg: ' b',
+ status: 'VALID',
+ message: ''
+ },
+ p3: {
+ value: '',
+ arg: ' ""',
+ status: 'VALID',
+ message: ''
+ }
+ }
+ }
+ }
+ ]);
+};
+
+exports.testBlankWithParam = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'tsrsrsr a --p3',
+ check: {
+ input: 'tsrsrsr a --p3',
+ hints: ' <string> <p2>',
+ markup: 'VVVVVVVVVVVVVVV',
+ cursor: 15,
+ current: 'p3',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: { value: 'a', arg: ' a', status: 'VALID', message: '' },
+ p2: { value: undefined, arg: '', status: 'INCOMPLETE' },
+ p3: { value: '', arg: ' --p3', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tsrsrsr a --p3 ',
+ check: {
+ input: 'tsrsrsr a --p3 ',
+ hints: '<string> <p2>',
+ markup: 'VVVVVVVVVVVVVVVV',
+ cursor: 16,
+ current: 'p3',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: { value: 'a', arg: ' a', status: 'VALID', message: '' },
+ p2: { value: undefined, arg: '', status: 'INCOMPLETE' },
+ p3: { value: '', arg: ' --p3 ', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tsrsrsr a --p3 "',
+ check: {
+ input: 'tsrsrsr a --p3 "',
+ hints: ' <p2>',
+ markup: 'VVVVVVVVVVVVVVVVV',
+ cursor: 17,
+ current: 'p3',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: { value: 'a', arg: ' a', status: 'VALID', message: '' },
+ p2: { value: undefined, arg: '', status: 'INCOMPLETE' },
+ p3: { value: '', arg: ' --p3 "', status: 'VALID', message: '' },
+ }
+ }
+ },
+ {
+ setup: 'tsrsrsr a --p3 ""',
+ check: {
+ input: 'tsrsrsr a --p3 ""',
+ hints: ' <p2>',
+ markup: 'VVVVVVVVVVVVVVVVVV',
+ cursor: 18,
+ current: 'p3',
+ status: 'ERROR',
+ message: '',
+ args: {
+ command: { name: 'tsrsrsr' },
+ p1: { value: 'a', arg: ' a', status: 'VALID', message: '' },
+ p2: { value: undefined, arg: '', status: 'INCOMPLETE' },
+ p3: { value: '', arg: ' --p3 ""', status: 'VALID', message: '' },
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_tokenize.js b/toolkit/devtools/commandline/test/browser_gcli_tokenize.js
new file mode 100644
index 000000000..dae64af84
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_tokenize.js
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTokenize.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var cli = require('gcli/cli');
+
+exports.testBlanks = function(options) {
+ var args;
+
+ args = cli.tokenize('');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '');
+ assert.is(args[0].prefix, '');
+ assert.is(args[0].suffix, '');
+
+ args = cli.tokenize(' ');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '');
+ assert.is(args[0].prefix, ' ');
+ assert.is(args[0].suffix, '');
+};
+
+exports.testTokSimple = function(options) {
+ var args;
+
+ args = cli.tokenize('s');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, 's');
+ assert.is(args[0].prefix, '');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'Argument');
+
+ args = cli.tokenize('s s');
+ assert.is(args.length, 2);
+ assert.is(args[0].text, 's');
+ assert.is(args[0].prefix, '');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'Argument');
+ assert.is(args[1].text, 's');
+ assert.is(args[1].prefix, ' ');
+ assert.is(args[1].suffix, '');
+ assert.is(args[1].type, 'Argument');
+};
+
+exports.testJavascript = function(options) {
+ var args;
+
+ args = cli.tokenize('{x}');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, 'x');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{ x }');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, 'x');
+ assert.is(args[0].prefix, '{ ');
+ assert.is(args[0].suffix, ' }');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{x} {y}');
+ assert.is(args.length, 2);
+ assert.is(args[0].text, 'x');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+ assert.is(args[1].text, 'y');
+ assert.is(args[1].prefix, ' {');
+ assert.is(args[1].suffix, '}');
+ assert.is(args[1].type, 'ScriptArgument');
+
+ args = cli.tokenize('{x}{y}');
+ assert.is(args.length, 2);
+ assert.is(args[0].text, 'x');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+ assert.is(args[1].text, 'y');
+ assert.is(args[1].prefix, '{');
+ assert.is(args[1].suffix, '}');
+ assert.is(args[1].type, 'ScriptArgument');
+
+ args = cli.tokenize('{');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{ ');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '');
+ assert.is(args[0].prefix, '{ ');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{x');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, 'x');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'ScriptArgument');
+};
+
+exports.testRegularNesting = function(options) {
+ var args;
+
+ args = cli.tokenize('{"x"}');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '"x"');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{\'x\'}');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '\'x\'');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('"{x}"');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '{x}');
+ assert.is(args[0].prefix, '"');
+ assert.is(args[0].suffix, '"');
+ assert.is(args[0].type, 'Argument');
+
+ args = cli.tokenize('\'{x}\'');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '{x}');
+ assert.is(args[0].prefix, '\'');
+ assert.is(args[0].suffix, '\'');
+ assert.is(args[0].type, 'Argument');
+};
+
+exports.testDeepNesting = function(options) {
+ var args;
+
+ args = cli.tokenize('{{}}');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '{}');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{{x} {y}}');
+ assert.is(args.length, 1);
+ assert.is(args[0].text, '{x} {y}');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ args = cli.tokenize('{{w} {{{x}}}} {y} {{{z}}}');
+
+ assert.is(args.length, 3);
+
+ assert.is(args[0].text, '{w} {{{x}}}');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ assert.is(args[1].text, 'y');
+ assert.is(args[1].prefix, ' {');
+ assert.is(args[1].suffix, '}');
+ assert.is(args[1].type, 'ScriptArgument');
+
+ assert.is(args[2].text, '{{z}}');
+ assert.is(args[2].prefix, ' {');
+ assert.is(args[2].suffix, '}');
+ assert.is(args[2].type, 'ScriptArgument');
+
+ args = cli.tokenize('{{w} {{{x}}} {y} {{{z}}}');
+
+ assert.is(args.length, 1);
+
+ assert.is(args[0].text, '{w} {{{x}}} {y} {{{z}}}');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'ScriptArgument');
+};
+
+exports.testStrangeNesting = function(options) {
+ var args;
+
+ // Note: When we get real JS parsing this should break
+ args = cli.tokenize('{"x}"}');
+
+ assert.is(args.length, 2);
+
+ assert.is(args[0].text, '"x');
+ assert.is(args[0].prefix, '{');
+ assert.is(args[0].suffix, '}');
+ assert.is(args[0].type, 'ScriptArgument');
+
+ assert.is(args[1].text, '}');
+ assert.is(args[1].prefix, '"');
+ assert.is(args[1].suffix, '');
+ assert.is(args[1].type, 'Argument');
+};
+
+exports.testComplex = function(options) {
+ var args;
+
+ args = cli.tokenize(' 1234 \'12 34\'');
+
+ assert.is(args.length, 2);
+
+ assert.is(args[0].text, '1234');
+ assert.is(args[0].prefix, ' ');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'Argument');
+
+ assert.is(args[1].text, '12 34');
+ assert.is(args[1].prefix, ' \'');
+ assert.is(args[1].suffix, '\'');
+ assert.is(args[1].type, 'Argument');
+
+ args = cli.tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \
+
+ assert.is(args.length, 3);
+
+ assert.is(args[0].text, '12\'34');
+ assert.is(args[0].prefix, '');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'Argument');
+
+ assert.is(args[1].text, '12 34');
+ assert.is(args[1].prefix, ' "');
+ assert.is(args[1].suffix, '"');
+ assert.is(args[1].type, 'Argument');
+
+ assert.is(args[2].text, '\\');
+ assert.is(args[2].prefix, ' ');
+ assert.is(args[2].suffix, '');
+ assert.is(args[2].type, 'Argument');
+};
+
+exports.testPathological = function(options) {
+ var args;
+
+ args = cli.tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd
+
+ assert.is(args.length, 4);
+
+ assert.is(args[0].text, 'a\\ b');
+ assert.is(args[0].prefix, '');
+ assert.is(args[0].suffix, '');
+ assert.is(args[0].type, 'Argument');
+
+ assert.is(args[1].text, '\\t\\n\\r');
+ assert.is(args[1].prefix, ' ');
+ assert.is(args[1].suffix, '');
+ assert.is(args[1].type, 'Argument');
+
+ assert.is(args[2].text, '\\\'x\\"');
+ assert.is(args[2].prefix, ' ');
+ assert.is(args[2].suffix, '');
+ assert.is(args[2].type, 'Argument');
+
+ assert.is(args[3].text, 'd');
+ assert.is(args[3].prefix, ' \'');
+ assert.is(args[3].suffix, '');
+ assert.is(args[3].type, 'Argument');
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_tooltip.js b/toolkit/devtools/commandline/test/browser_gcli_tooltip.js
new file mode 100644
index 000000000..10aa558d7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_tooltip.js
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTooltip.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+exports.testActivate = function(options) {
+ if (!options.display) {
+ assert.log('No display. Skipping activate tests');
+ return;
+ }
+
+ return helpers.audit(options, [
+ {
+ setup: ' ',
+ check: {
+ input: ' ',
+ hints: '',
+ markup: 'V',
+ cursor: 1,
+ current: '__command',
+ status: 'ERROR',
+ message: '',
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'false:default'
+ }
+ },
+ {
+ setup: 'tsb ',
+ check: {
+ input: 'tsb ',
+ hints: 'false',
+ markup: 'VVVV',
+ cursor: 4,
+ current: 'toggle',
+ status: 'VALID',
+ options: [ 'false', 'true' ],
+ message: '',
+ predictions: [ 'false', 'true' ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'true:importantFieldFlag'
+ }
+ },
+ {
+ setup: 'tsb t',
+ check: {
+ input: 'tsb t',
+ hints: 'rue',
+ markup: 'VVVVI',
+ cursor: 5,
+ current: 'toggle',
+ status: 'ERROR',
+ options: [ 'true' ],
+ message: '',
+ predictions: [ 'true' ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'true:importantFieldFlag'
+ }
+ },
+ {
+ setup: 'tsb tt',
+ check: {
+ input: 'tsb tt',
+ hints: ' -> true',
+ markup: 'VVVVII',
+ cursor: 6,
+ current: 'toggle',
+ status: 'ERROR',
+ options: [ 'true' ],
+ message: '',
+ predictions: [ 'true' ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'true:importantFieldFlag'
+ }
+ },
+ {
+ setup: 'wxqy',
+ check: {
+ input: 'wxqy',
+ hints: '',
+ markup: 'EEEE',
+ cursor: 4,
+ current: '__command',
+ status: 'ERROR',
+ options: [ ],
+ message: 'Can\'t use \'wxqy\'.',
+ predictions: [ ],
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'true:isError'
+ }
+ },
+ {
+ setup: '',
+ check: {
+ input: '',
+ hints: '',
+ markup: '',
+ cursor: 0,
+ current: '__command',
+ status: 'ERROR',
+ message: '',
+ unassigned: [ ],
+ outputState: 'false:default',
+ tooltipState: 'false:default'
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_types.js b/toolkit/devtools/commandline/test/browser_gcli_types.js
new file mode 100644
index 000000000..01c11c39d
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_types.js
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testTypes.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+var util = require('gcli/util/util');
+var Promise = require('gcli/util/promise').Promise;
+var nodetype = require('gcli/types/node');
+
+exports.setup = function(options) {
+ if (options.window) {
+ nodetype.setDocument(options.window.document);
+ }
+};
+
+exports.shutdown = function(options) {
+ nodetype.unsetDocument();
+};
+
+function forEachType(options, typeSpec, callback) {
+ var types = options.requisition.system.types;
+ return util.promiseEach(types.getTypeNames(), function(name) {
+ typeSpec.name = name;
+ typeSpec.requisition = options.requisition;
+
+ // Provide some basic defaults to help selection/delegate/array work
+ if (name === 'selection') {
+ typeSpec.data = [ 'a', 'b' ];
+ }
+ else if (name === 'delegate') {
+ typeSpec.delegateType = function() {
+ return 'string';
+ };
+ }
+ else if (name === 'array') {
+ typeSpec.subtype = 'string';
+ }
+ else if (name === 'remote') {
+ return;
+ }
+ else if (name === 'union') {
+ typeSpec.alternatives = [{ name: 'string' }];
+ }
+
+ var type = types.createType(typeSpec);
+ var reply = callback(type);
+ return Promise.resolve(reply).then(function(value) {
+ // Clean up
+ delete typeSpec.name;
+ delete typeSpec.requisition;
+ delete typeSpec.data;
+ delete typeSpec.delegateType;
+ delete typeSpec.subtype;
+ delete typeSpec.alternatives;
+
+ return value;
+ });
+ });
+}
+
+exports.testDefault = function(options) {
+ if (options.isNoDom) {
+ assert.log('Skipping tests due to issues with resource type.');
+ return;
+ }
+
+ return forEachType(options, {}, function(type) {
+ var context = options.requisition.executionContext;
+ var blank = type.getBlank(context).value;
+
+ // boolean and array types are exempt from needing undefined blank values
+ if (type.name === 'boolean') {
+ assert.is(blank, false, 'blank boolean is false');
+ }
+ else if (type.name === 'array') {
+ assert.ok(Array.isArray(blank), 'blank array is array');
+ assert.is(blank.length, 0, 'blank array is empty');
+ }
+ else if (type.name === 'nodelist') {
+ assert.ok(typeof blank.item, 'function', 'blank.item is function');
+ assert.is(blank.length, 0, 'blank nodelist is empty');
+ }
+ else {
+ assert.is(blank, undefined, 'default defined for ' + type.name);
+ }
+ });
+};
+
+exports.testNullDefault = function(options) {
+ var context = null; // Is this test still valid with a null context?
+
+ return forEachType(options, { defaultValue: null }, function(type) {
+ var reply = type.stringify(null, context);
+ return Promise.resolve(reply).then(function(str) {
+ assert.is(str, '', 'stringify(null) for ' + type.name);
+ });
+ });
+};
+
+exports.testGetSpec = function(options) {
+ return forEachType(options, {}, function(type) {
+ if (type.name === 'param') {
+ return;
+ }
+
+ var spec = type.getSpec('cmd', 'param');
+ assert.ok(spec != null, 'non null spec for ' + type.name);
+
+ var str = JSON.stringify(spec);
+ assert.ok(str != null, 'serializable spec for ' + type.name);
+
+ var example = options.requisition.system.types.createType(spec);
+ assert.ok(example != null, 'creatable spec for ' + type.name);
+ });
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_union.js b/toolkit/devtools/commandline/test/browser_gcli_union.js
new file mode 100644
index 000000000..9f3dd08c1
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_union.js
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUnion.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+exports.testDefault = function(options) {
+ return helpers.audit(options, [
+ {
+ setup: 'unionc1',
+ check: {
+ input: 'unionc1',
+ markup: 'VVVVVVV',
+ hints: ' <first>',
+ status: 'ERROR',
+ args: {
+ first: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: 'unionc1 three',
+ check: {
+ input: 'unionc1 three',
+ markup: 'VVVVVVVVVVVVV',
+ hints: '',
+ status: 'VALID',
+ args: {
+ first: {
+ value: function(data) {
+ assert.is(Object.keys(data).length, 2, 'union3 Object.keys');
+ assert.is(data.type, 'string', 'union3 val type');
+ assert.is(data.string, 'three', 'union3 val string');
+ },
+ arg: ' three',
+ status: 'VALID'
+ }
+ }
+ },
+ exec: {
+ output: [
+ /"type": ?"string"/,
+ /"string": ?"three"/
+ ]
+ },
+ post: function(output, text) {
+ var data = output.data.first;
+ assert.is(Object.keys(data).length, 2, 'union3 Object.keys');
+ assert.is(data.type, 'string', 'union3 val type');
+ assert.is(data.string, 'three', 'union3 val string');
+ }
+ },
+ {
+ setup: 'unionc1 one',
+ check: {
+ input: 'unionc1 one',
+ markup: 'VVVVVVVVVVV',
+ hints: '',
+ status: 'VALID',
+ args: {
+ first: {
+ value: function(data) {
+ assert.is(Object.keys(data).length, 2, 'union1 Object.keys');
+ assert.is(data.type, 'selection', 'union1 val type');
+ assert.is(data.selection, 1, 'union1 val selection');
+ },
+ arg: ' one',
+ status: 'VALID'
+ }
+ }
+ },
+ exec: {
+ output: [
+ /"type": ?"selection"/,
+ /"selection": ?1/
+ ]
+ },
+ post: function(output, text) {
+ var data = output.data.first;
+ assert.is(Object.keys(data).length, 2, 'union1 Object.keys');
+ assert.is(data.type, 'selection', 'union1 val type');
+ assert.is(data.selection, 1, 'union1 val selection');
+ }
+ },
+ {
+ skipIf: options.isPhantomjs, // Phantom goes weird with predictions
+ setup: 'unionc1 5',
+ check: {
+ input: 'unionc1 5',
+ markup: 'VVVVVVVVV',
+ hints: ' -> two',
+ predictions: [ 'two' ],
+ status: 'VALID',
+ args: {
+ first: {
+ value: function(data) {
+ assert.is(Object.keys(data).length, 2, 'union5 Object.keys');
+ assert.is(data.type, 'number', 'union5 val type');
+ assert.is(data.number, 5, 'union5 val number');
+ },
+ arg: ' 5',
+ status: 'VALID'
+ }
+ }
+ },
+ exec: {
+ output: [
+ /"type": ?"number"/,
+ /"number": ?5/
+ ]
+ },
+ post: function(output, text) {
+ var data = output.data.first;
+ assert.is(Object.keys(data).length, 2, 'union5 Object.keys');
+ assert.is(data.type, 'number', 'union5 val type');
+ assert.is(data.number, 5, 'union5 val number');
+ }
+ },
+ {
+ skipRemainingIf: options.isPhantomjs,
+ setup: 'unionc2 on',
+ check: {
+ input: 'unionc2 on',
+ hints: 'e',
+ markup: 'VVVVVVVVII',
+ current: 'first',
+ status: 'ERROR',
+ predictionsContains: [
+ 'one',
+ 'http://on/',
+ 'https://on/'
+ ],
+ args: {
+ command: { name: 'unionc2' },
+ first: {
+ value: undefined,
+ arg: ' on',
+ status: 'INCOMPLETE',
+ message: 'Can\'t use \'on\'.'
+ },
+ }
+ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/browser_gcli_url.js b/toolkit/devtools/commandline/test/browser_gcli_url.js
new file mode 100644
index 000000000..1fec41eb7
--- /dev/null
+++ b/toolkit/devtools/commandline/test/browser_gcli_url.js
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+var exports = {};
+
+var TEST_URI = "data:text/html;charset=utf-8,<p id='gcli-input'>gcli-testUrl.js</p>";
+
+function test() {
+ return Task.spawn(function() {
+ let options = yield helpers.openTab(TEST_URI);
+ yield helpers.openToolbar(options);
+ gcli.addItems(mockCommands.items);
+
+ yield helpers.runTests(options, exports);
+
+ gcli.removeItems(mockCommands.items);
+ yield helpers.closeToolbar(options);
+ yield helpers.closeTab(options);
+ }).then(finish, helpers.handleError);
+}
+
+// <INJECTED SOURCE:END>
+
+// var assert = require('../testharness/assert');
+// var helpers = require('./helpers');
+
+exports.testDefault = function(options) {
+ return helpers.audit(options, [
+ {
+ skipRemainingIf: options.isPhantomjs,
+ setup: 'urlc',
+ check: {
+ input: 'urlc',
+ markup: 'VVVV',
+ hints: ' <url>',
+ status: 'ERROR',
+ args: {
+ url: {
+ value: undefined,
+ arg: '',
+ status: 'INCOMPLETE'
+ }
+ }
+ }
+ },
+ {
+ setup: 'urlc example',
+ check: {
+ input: 'urlc example',
+ markup: 'VVVVVIIIIIII',
+ hints: ' -> http://example/',
+ predictions: [
+ 'http://example/',
+ 'https://example/',
+ 'http://localhost:9999/example'
+ ],
+ status: 'ERROR',
+ args: {
+ url: {
+ value: undefined,
+ arg: ' example',
+ status: 'INCOMPLETE'
+ }
+ }
+ },
+ },
+ {
+ setup: 'urlc example.com/',
+ check: {
+ input: 'urlc example.com/',
+ markup: 'VVVVVIIIIIIIIIIII',
+ hints: ' -> http://example.com/',
+ status: 'ERROR',
+ args: {
+ url: {
+ value: undefined,
+ arg: ' example.com/',
+ status: 'INCOMPLETE'
+ }
+ }
+ },
+ },
+ {
+ setup: 'urlc http://example.com/index?q=a#hash',
+ check: {
+ input: 'urlc http://example.com/index?q=a#hash',
+ markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+ hints: '',
+ status: 'VALID',
+ args: {
+ url: {
+ value: function(data) {
+ assert.is(data.hash, '#hash', 'url hash');
+ },
+ arg: ' http://example.com/index?q=a#hash',
+ status: 'VALID'
+ }
+ }
+ },
+ exec: { output: /"url": ?/ }
+ }
+ ]);
+};
diff --git a/toolkit/devtools/commandline/test/head.js b/toolkit/devtools/commandline/test/head.js
new file mode 100644
index 000000000..36d6e356a
--- /dev/null
+++ b/toolkit/devtools/commandline/test/head.js
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/commandline/test/";
+const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/";
+
+var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
+var console = require("resource://gre/modules/devtools/Console.jsm").console;
+
+// Import the GCLI test helper
+let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
+Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
+Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this);
+
+gDevTools.testing = true;
+SimpleTest.registerCleanupFunction(() => {
+ gDevTools.testing = false;
+});
+
+function whenDelayedStartupFinished(aWindow, aCallback) {
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ if (aWindow == aSubject) {
+ Services.obs.removeObserver(observer, aTopic);
+ executeSoon(aCallback);
+ }
+ }, "browser-delayed-startup-finished", false);
+}
+
+/**
+ * Force GC on shutdown, because it seems that GCLI can outrun the garbage
+ * collector in some situations, which causes test failures in later tests
+ * Bug 774619 is an example.
+ */
+registerCleanupFunction(function tearDown() {
+ window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils)
+ .garbageCollect();
+});
diff --git a/toolkit/devtools/commandline/test/helpers.js b/toolkit/devtools/commandline/test/helpers.js
new file mode 100644
index 000000000..dc33b183b
--- /dev/null
+++ b/toolkit/devtools/commandline/test/helpers.js
@@ -0,0 +1,1274 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+// A copy of this code exists in firefox mochitests. They should be kept
+// in sync. Hence the exports synonym for non AMD contexts.
+var { helpers, gcli, assert } = (function() {
+
+var helpers = {};
+
+var TargetFactory = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.TargetFactory;
+var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
+
+var assert = { ok: ok, is: is, log: info };
+var util = require('gcli/util/util');
+var Promise = require('gcli/util/promise').Promise;
+var cli = require('gcli/cli');
+var KeyEvent = require('gcli/util/util').KeyEvent;
+var gcli = require('gcli/index');
+
+/**
+ * See notes in helpers.checkOptions()
+ */
+var createFFDisplayAutomator = function(display) {
+ var automator = {
+ setInput: function(typed) {
+ return display.inputter.setInput(typed);
+ },
+
+ setCursor: function(cursor) {
+ return display.inputter.setCursor(cursor);
+ },
+
+ focus: function() {
+ return display.inputter.focus();
+ },
+
+ fakeKey: function(keyCode) {
+ var fakeEvent = {
+ keyCode: keyCode,
+ preventDefault: function() { },
+ timeStamp: new Date().getTime()
+ };
+
+ display.inputter.onKeyDown(fakeEvent);
+
+ if (keyCode === KeyEvent.DOM_VK_BACK_SPACE) {
+ var input = display.inputter.element;
+ input.value = input.value.slice(0, -1);
+ }
+
+ return display.inputter.handleKeyUp(fakeEvent);
+ },
+
+ getInputState: function() {
+ return display.inputter.getInputState();
+ },
+
+ getCompleterTemplateData: function() {
+ return display.completer._getCompleterTemplateData();
+ },
+
+ getErrorMessage: function() {
+ return display.tooltip.errorEle.textContent;
+ }
+ };
+
+ Object.defineProperty(automator, 'focusManager', {
+ get: function() { return display.focusManager; },
+ enumerable: true
+ });
+
+ Object.defineProperty(automator, 'field', {
+ get: function() { return display.tooltip.field; },
+ enumerable: true
+ });
+
+ return automator;
+};
+
+/**
+ * Warning: For use with Firefox Mochitests only.
+ *
+ * Open a new tab at a URL and call a callback on load, and then tidy up when
+ * the callback finishes.
+ * The function will be passed a set of test options, and will usually return a
+ * promise to indicate that the tab can be cleared up. (To be formal, we call
+ * Promise.resolve() on the return value of the callback function)
+ *
+ * The options used by addTab include:
+ * - chromeWindow: XUL window parent of created tab. a.k.a 'window' in mochitest
+ * - tab: The new XUL tab element, as returned by gBrowser.addTab()
+ * - target: The debug target as defined by the devtools framework
+ * - browser: The XUL browser element for the given tab
+ * - window: Content window for the created tab. a.k.a 'content' in mochitest
+ * - isFirefox: Always true. Allows test sharing with GCLI
+ *
+ * Normally addTab will create an options object containing the values as
+ * described above. However these options can be customized by the third
+ * 'options' parameter. This has the ability to customize the value of
+ * chromeWindow or isFirefox, and to add new properties.
+ *
+ * @param url The URL for the new tab
+ * @param callback The function to call on page load
+ * @param options An optional set of options to customize the way the tests run
+ */
+helpers.addTab = function(url, callback, options) {
+ waitForExplicitFinish();
+
+ options = options || {};
+ options.chromeWindow = options.chromeWindow || window;
+ options.isFirefox = true;
+
+ var tabbrowser = options.chromeWindow.gBrowser;
+ options.tab = tabbrowser.addTab();
+ tabbrowser.selectedTab = options.tab;
+ options.browser = tabbrowser.getBrowserForTab(options.tab);
+ options.target = TargetFactory.forTab(options.tab);
+
+ var loaded = helpers.listenOnce(options.browser, "load", true).then(function(ev) {
+ options.document = options.browser.contentDocument;
+ options.window = options.document.defaultView;
+
+ var reply = callback.call(null, options);
+
+ return Promise.resolve(reply).then(null, function(error) {
+ ok(false, error);
+ }).then(function() {
+ tabbrowser.removeTab(options.tab);
+
+ delete options.window;
+ delete options.document;
+
+ delete options.target;
+ delete options.browser;
+ delete options.tab;
+
+ delete options.chromeWindow;
+ delete options.isFirefox;
+ });
+ });
+
+ options.browser.contentWindow.location = url;
+ return loaded;
+};
+
+/**
+ * Open a new tab
+ * @param url Address of the page to open
+ * @param options Object to which we add properties describing the new tab. The
+ * following properties are added:
+ * - chromeWindow
+ * - tab
+ * - browser
+ * - target
+ * - document
+ * - window
+ * @return A promise which resolves to the options object when the 'load' event
+ * happens on the new tab
+ */
+helpers.openTab = function(url, options) {
+ waitForExplicitFinish();
+
+ options = options || {};
+ options.chromeWindow = options.chromeWindow || window;
+ options.isFirefox = true;
+
+ var tabbrowser = options.chromeWindow.gBrowser;
+ options.tab = tabbrowser.addTab();
+ tabbrowser.selectedTab = options.tab;
+ options.browser = tabbrowser.getBrowserForTab(options.tab);
+ options.target = TargetFactory.forTab(options.tab);
+
+ return helpers.navigate(url, options);
+};
+
+/**
+ * Undo the effects of |helpers.openTab|
+ * @param options The options object passed to |helpers.openTab|
+ * @return A promise resolved (with undefined) when the tab is closed
+ */
+helpers.closeTab = function(options) {
+ options.chromeWindow.gBrowser.removeTab(options.tab);
+
+ delete options.window;
+ delete options.document;
+
+ delete options.target;
+ delete options.browser;
+ delete options.tab;
+
+ delete options.chromeWindow;
+ delete options.isFirefox;
+
+ return Promise.resolve(undefined);
+};
+
+/**
+ * Open the developer toolbar in a tab
+ * @param options Object to which we add properties describing the developer
+ * toolbar. The following properties are added:
+ * - automator
+ * - requisition
+ * @return A promise which resolves to the options object when the 'load' event
+ * happens on the new tab
+ */
+helpers.openToolbar = function(options) {
+ options = options || {};
+ options.chromeWindow = options.chromeWindow || window;
+
+ return options.chromeWindow.DeveloperToolbar.show(true).then(function() {
+ var display = options.chromeWindow.DeveloperToolbar.display;
+ options.automator = createFFDisplayAutomator(display);
+ options.requisition = display.requisition;
+ return options;
+ });
+};
+
+/**
+ * Navigate the current tab to a URL
+ */
+helpers.navigate = function(url, options) {
+ options = options || {};
+ options.chromeWindow = options.chromeWindow || window;
+ options.tab = options.tab || options.chromeWindow.gBrowser.selectedTab;
+
+ var tabbrowser = options.chromeWindow.gBrowser;
+ options.browser = tabbrowser.getBrowserForTab(options.tab);
+
+ var promise = helpers.listenOnce(options.browser, "load", true).then(function() {
+ options.document = options.browser.contentDocument;
+ options.window = options.document.defaultView;
+ return options;
+ });
+
+ options.browser.contentWindow.location = url;
+
+ return promise;
+};
+
+/**
+ * Undo the effects of |helpers.openToolbar|
+ * @param options The options object passed to |helpers.openToolbar|
+ * @return A promise resolved (with undefined) when the toolbar is closed
+ */
+helpers.closeToolbar = function(options) {
+ return options.chromeWindow.DeveloperToolbar.hide().then(function() {
+ delete options.automator;
+ delete options.requisition;
+ });
+};
+
+/**
+ * A helper to work with Task.spawn so you can do:
+ * return Task.spawn(realTestFunc).then(finish, helpers.handleError);
+ */
+helpers.handleError = function(ex) {
+ console.error(ex);
+ ok(false, ex);
+ finish();
+};
+
+/**
+ * A helper for calling addEventListener and then removeEventListener as soon
+ * as the event is called, passing the results on as a promise
+ * @param element The DOM element to listen on
+ * @param event The name of the event to listen for
+ * @param useCapture Should we use the capturing phase?
+ * @return A promise resolved with the event object when the event first happens
+ */
+helpers.listenOnce = function(element, event, useCapture) {
+ return new Promise(function(resolve, reject) {
+ var onEvent = function(ev) {
+ element.removeEventListener(event, onEvent, useCapture);
+ resolve(ev);
+ };
+ element.addEventListener(event, onEvent, useCapture);
+ }.bind(this));
+};
+
+/**
+ * A wrapper for calling Services.obs.[add|remove]Observer using promises.
+ * @param topic The topic parameter to Services.obs.addObserver
+ * @param ownsWeak The ownsWeak parameter to Services.obs.addObserver with a
+ * default value of false
+ * @return a promise that resolves when the ObserverService first notifies us
+ * of the topic. The value of the promise is the first parameter to the observer
+ * function other parameters are dropped.
+ */
+helpers.observeOnce = function(topic, ownsWeak=false) {
+ return new Promise(function(resolve, reject) {
+ let resolver = function(subject) {
+ Services.obs.removeObserver(resolver, topic);
+ resolve(subject);
+ };
+ Services.obs.addObserver(resolver, topic, ownsWeak);
+ }.bind(this));
+};
+
+/**
+ * Takes a function that uses a callback as its last parameter, and returns a
+ * new function that returns a promise instead
+ */
+helpers.promiseify = function(functionWithLastParamCallback, scope) {
+ return function() {
+ let args = [].slice.call(arguments);
+ return new Promise(resolve => {
+ args.push((...results) => {
+ resolve(results.length > 1 ? results : results[0]);
+ });
+ functionWithLastParamCallback.apply(scope, args);
+ });
+ };
+};
+
+/**
+ * Warning: For use with Firefox Mochitests only.
+ *
+ * As addTab, but that also opens the developer toolbar. In addition a new
+ * 'automator' property is added to the options object with the display from GCLI
+ * in the developer toolbar
+ */
+helpers.addTabWithToolbar = function(url, callback, options) {
+ return helpers.addTab(url, function(innerOptions) {
+ var win = innerOptions.chromeWindow;
+
+ return win.DeveloperToolbar.show(true).then(function() {
+ var display = win.DeveloperToolbar.display;
+ innerOptions.automator = createFFDisplayAutomator(display);
+ innerOptions.requisition = display.requisition;
+
+ var reply = callback.call(null, innerOptions);
+
+ return Promise.resolve(reply).then(null, function(error) {
+ ok(false, error);
+ console.error(error);
+ }).then(function() {
+ win.DeveloperToolbar.hide().then(function() {
+ delete innerOptions.automator;
+ });
+ });
+ });
+ }, options);
+};
+
+/**
+ * Warning: For use with Firefox Mochitests only.
+ *
+ * Run a set of test functions stored in the values of the 'exports' object
+ * functions stored under setup/shutdown will be run at the start/end of the
+ * sequence of tests.
+ * A test will be considered finished when its return value is resolved.
+ * @param options An object to be passed to the test functions
+ * @param tests An object containing named test functions
+ * @return a promise which will be resolved when all tests have been run and
+ * their return values resolved
+ */
+helpers.runTests = function(options, tests) {
+ var testNames = Object.keys(tests).filter(function(test) {
+ return test != "setup" && test != "shutdown";
+ });
+
+ var recover = function(error) {
+ ok(false, error);
+ console.error(error);
+ };
+
+ info("SETUP");
+ var setupDone = (tests.setup != null) ?
+ Promise.resolve(tests.setup(options)) :
+ Promise.resolve();
+
+ var testDone = setupDone.then(function() {
+ return util.promiseEach(testNames, function(testName) {
+ info(testName);
+ var action = tests[testName];
+
+ if (typeof action === "function") {
+ var reply = action.call(tests, options);
+ return Promise.resolve(reply);
+ }
+ else if (Array.isArray(action)) {
+ return helpers.audit(options, action);
+ }
+
+ return Promise.reject("test action '" + testName +
+ "' is not a function or helpers.audit() object");
+ });
+ }, recover);
+
+ return testDone.then(function() {
+ info("SHUTDOWN");
+ return (tests.shutdown != null) ?
+ Promise.resolve(tests.shutdown(options)) :
+ Promise.resolve();
+ }, recover);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Ensure that the options object is setup correctly
+ * options should contain an automator object that looks like this:
+ * {
+ * getInputState: function() { ... },
+ * setCursor: function(cursor) { ... },
+ * getCompleterTemplateData: function() { ... },
+ * focus: function() { ... },
+ * getErrorMessage: function() { ... },
+ * fakeKey: function(keyCode) { ... },
+ * setInput: function(typed) { ... },
+ * focusManager: ...,
+ * field: ...,
+ * }
+ */
+function checkOptions(options) {
+ if (options == null) {
+ console.trace();
+ throw new Error('Missing options object');
+ }
+ if (options.requisition == null) {
+ console.trace();
+ throw new Error('options.requisition == null');
+ }
+}
+
+/**
+ * Various functions to return the actual state of the command line
+ */
+helpers._actual = {
+ input: function(options) {
+ return options.automator.getInputState().typed;
+ },
+
+ hints: function(options) {
+ return options.automator.getCompleterTemplateData().then(function(data) {
+ var emptyParams = data.emptyParameters.join('');
+ return (data.directTabText + emptyParams + data.arrowTabText)
+ .replace(/\u00a0/g, ' ')
+ .replace(/\u21E5/, '->')
+ .replace(/ $/, '');
+ });
+ },
+
+ markup: function(options) {
+ var cursor = helpers._actual.cursor(options);
+ var statusMarkup = options.requisition.getInputStatusMarkup(cursor);
+ return statusMarkup.map(function(s) {
+ return new Array(s.string.length + 1).join(s.status.toString()[0]);
+ }).join('');
+ },
+
+ cursor: function(options) {
+ return options.automator.getInputState().cursor.start;
+ },
+
+ current: function(options) {
+ var cursor = helpers._actual.cursor(options);
+ return options.requisition.getAssignmentAt(cursor).param.name;
+ },
+
+ status: function(options) {
+ return options.requisition.status.toString();
+ },
+
+ predictions: function(options) {
+ var cursor = helpers._actual.cursor(options);
+ var assignment = options.requisition.getAssignmentAt(cursor);
+ var context = options.requisition.executionContext;
+ return assignment.getPredictions(context).then(function(predictions) {
+ return predictions.map(function(prediction) {
+ return prediction.name;
+ });
+ });
+ },
+
+ unassigned: function(options) {
+ return options.requisition._unassigned.map(function(assignment) {
+ return assignment.arg.toString();
+ }.bind(this));
+ },
+
+ outputState: function(options) {
+ var outputData = options.automator.focusManager._shouldShowOutput();
+ return outputData.visible + ':' + outputData.reason;
+ },
+
+ tooltipState: function(options) {
+ var tooltipData = options.automator.focusManager._shouldShowTooltip();
+ return tooltipData.visible + ':' + tooltipData.reason;
+ },
+
+ options: function(options) {
+ if (options.automator.field.menu == null) {
+ return [];
+ }
+ return options.automator.field.menu.items.map(function(item) {
+ return item.name.textContent ? item.name.textContent : item.name;
+ });
+ },
+
+ message: function(options) {
+ return options.automator.getErrorMessage();
+ }
+};
+
+function shouldOutputUnquoted(value) {
+ var type = typeof value;
+ return value == null || type === 'boolean' || type === 'number';
+}
+
+function outputArray(array) {
+ return (array.length === 0) ?
+ '[ ]' :
+ '[ \'' + array.join('\', \'') + '\' ]';
+}
+
+helpers._createDebugCheck = function(options) {
+ checkOptions(options);
+ var requisition = options.requisition;
+ var command = requisition.commandAssignment.value;
+ var cursor = helpers._actual.cursor(options);
+ var input = helpers._actual.input(options);
+ var padding = new Array(input.length + 1).join(' ');
+
+ var hintsPromise = helpers._actual.hints(options);
+ var predictionsPromise = helpers._actual.predictions(options);
+
+ return Promise.all([ hintsPromise, predictionsPromise ]).then(function(values) {
+ var hints = values[0];
+ var predictions = values[1];
+ var output = '';
+
+ output += 'return helpers.audit(options, [\n';
+ output += ' {\n';
+
+ if (cursor === input.length) {
+ output += ' setup: \'' + input + '\',\n';
+ }
+ else {
+ output += ' name: \'' + input + ' (cursor=' + cursor + ')\',\n';
+ output += ' setup: function() {\n';
+ output += ' return helpers.setInput(options, \'' + input + '\', ' + cursor + ');\n';
+ output += ' },\n';
+ }
+
+ output += ' check: {\n';
+
+ output += ' input: \'' + input + '\',\n';
+ output += ' hints: ' + padding + '\'' + hints + '\',\n';
+ output += ' markup: \'' + helpers._actual.markup(options) + '\',\n';
+ output += ' cursor: ' + cursor + ',\n';
+ output += ' current: \'' + helpers._actual.current(options) + '\',\n';
+ output += ' status: \'' + helpers._actual.status(options) + '\',\n';
+ output += ' options: ' + outputArray(helpers._actual.options(options)) + ',\n';
+ output += ' message: \'' + helpers._actual.message(options) + '\',\n';
+ output += ' predictions: ' + outputArray(predictions) + ',\n';
+ output += ' unassigned: ' + outputArray(requisition._unassigned) + ',\n';
+ output += ' outputState: \'' + helpers._actual.outputState(options) + '\',\n';
+ output += ' tooltipState: \'' + helpers._actual.tooltipState(options) + '\'' +
+ (command ? ',' : '') +'\n';
+
+ if (command) {
+ output += ' args: {\n';
+ output += ' command: { name: \'' + command.name + '\' },\n';
+
+ requisition.getAssignments().forEach(function(assignment) {
+ output += ' ' + assignment.param.name + ': { ';
+
+ if (typeof assignment.value === 'string') {
+ output += 'value: \'' + assignment.value + '\', ';
+ }
+ else if (shouldOutputUnquoted(assignment.value)) {
+ output += 'value: ' + assignment.value + ', ';
+ }
+ else {
+ output += '/*value:' + assignment.value + ',*/ ';
+ }
+
+ output += 'arg: \'' + assignment.arg + '\', ';
+ output += 'status: \'' + assignment.getStatus().toString() + '\', ';
+ output += 'message: \'' + assignment.message + '\'';
+ output += ' },\n';
+ });
+
+ output += ' }\n';
+ }
+
+ output += ' },\n';
+ output += ' exec: {\n';
+ output += ' output: \'\',\n';
+ output += ' type: \'string\',\n';
+ output += ' error: false\n';
+ output += ' }\n';
+ output += ' }\n';
+ output += ']);';
+
+ return output;
+ }.bind(this), util.errorHandler);
+};
+
+/**
+ * Simulate focusing the input field
+ */
+helpers.focusInput = function(options) {
+ checkOptions(options);
+ options.automator.focus();
+};
+
+/**
+ * Simulate pressing TAB in the input field
+ */
+helpers.pressTab = function(options) {
+ checkOptions(options);
+ return helpers.pressKey(options, KeyEvent.DOM_VK_TAB);
+};
+
+/**
+ * Simulate pressing RETURN in the input field
+ */
+helpers.pressReturn = function(options) {
+ checkOptions(options);
+ return helpers.pressKey(options, KeyEvent.DOM_VK_RETURN);
+};
+
+/**
+ * Simulate pressing a key by keyCode in the input field
+ */
+helpers.pressKey = function(options, keyCode) {
+ checkOptions(options);
+ return options.automator.fakeKey(keyCode);
+};
+
+/**
+ * A list of special key presses and how to to them, for the benefit of
+ * helpers.setInput
+ */
+var ACTIONS = {
+ '<TAB>': function(options) {
+ return helpers.pressTab(options);
+ },
+ '<RETURN>': function(options) {
+ return helpers.pressReturn(options);
+ },
+ '<UP>': function(options) {
+ return helpers.pressKey(options, KeyEvent.DOM_VK_UP);
+ },
+ '<DOWN>': function(options) {
+ return helpers.pressKey(options, KeyEvent.DOM_VK_DOWN);
+ },
+ '<BACKSPACE>': function(options) {
+ return helpers.pressKey(options, KeyEvent.DOM_VK_BACK_SPACE);
+ }
+};
+
+/**
+ * Used in helpers.setInput to cut an input string like 'blah<TAB>foo<UP>' into
+ * an array like [ 'blah', '<TAB>', 'foo', '<UP>' ].
+ * When using this RegExp, you also need to filter out the blank strings.
+ */
+var CHUNKER = /([^<]*)(<[A-Z]+>)/;
+
+/**
+ * Alter the input to <code>typed</code> optionally leaving the cursor at
+ * <code>cursor</code>.
+ * @return A promise of the number of key-presses to respond
+ */
+helpers.setInput = function(options, typed, cursor) {
+ checkOptions(options);
+ var inputPromise;
+ var automator = options.automator;
+ // We try to measure average keypress time, but setInput can simulate
+ // several, so we try to keep track of how many
+ var chunkLen = 1;
+
+ // The easy case is a simple string without things like <TAB>
+ if (typed.indexOf('<') === -1) {
+ inputPromise = automator.setInput(typed);
+ }
+ else {
+ // Cut the input up into input strings separated by '<KEY>' tokens. The
+ // CHUNKS RegExp leaves blanks so we filter them out.
+ var chunks = typed.split(CHUNKER).filter(function(s) {
+ return s !== '';
+ });
+ chunkLen = chunks.length + 1;
+
+ // We're working on this in chunks so first clear the input
+ inputPromise = automator.setInput('').then(function() {
+ return util.promiseEach(chunks, function(chunk) {
+ if (chunk.charAt(0) === '<') {
+ var action = ACTIONS[chunk];
+ if (typeof action !== 'function') {
+ console.error('Known actions: ' + Object.keys(ACTIONS).join());
+ throw new Error('Key action not found "' + chunk + '"');
+ }
+ return action(options);
+ }
+ else {
+ return automator.setInput(automator.getInputState().typed + chunk);
+ }
+ });
+ });
+ }
+
+ return inputPromise.then(function() {
+ if (cursor != null) {
+ automator.setCursor({ start: cursor, end: cursor });
+ }
+
+ if (automator.focusManager) {
+ automator.focusManager.onInputChange();
+ }
+
+ // Firefox testing is noisy and distant, so logging helps
+ if (options.isFirefox) {
+ var cursorStr = (cursor == null ? '' : ', ' + cursor);
+ log('setInput("' + typed + '"' + cursorStr + ')');
+ }
+
+ return chunkLen;
+ });
+};
+
+/**
+ * Helper for helpers.audit() to ensure that all the 'check' properties match.
+ * See helpers.audit for more information.
+ * @param name The name to use in error messages
+ * @param checks See helpers.audit for a list of available checks
+ * @return A promise which resolves to undefined when the checks are complete
+ */
+helpers._check = function(options, name, checks) {
+ // A test method to check that all args are assigned in some way
+ var requisition = options.requisition;
+ requisition._args.forEach(function(arg) {
+ if (arg.assignment == null) {
+ assert.ok(false, 'No assignment for ' + arg);
+ }
+ });
+
+ if (checks == null) {
+ return Promise.resolve();
+ }
+
+ var outstanding = [];
+ var suffix = name ? ' (for \'' + name + '\')' : '';
+
+ if (!options.isNoDom && 'input' in checks) {
+ assert.is(helpers._actual.input(options), checks.input, 'input' + suffix);
+ }
+
+ if (!options.isNoDom && 'cursor' in checks) {
+ assert.is(helpers._actual.cursor(options), checks.cursor, 'cursor' + suffix);
+ }
+
+ if (!options.isNoDom && 'current' in checks) {
+ assert.is(helpers._actual.current(options), checks.current, 'current' + suffix);
+ }
+
+ if ('status' in checks) {
+ assert.is(helpers._actual.status(options), checks.status, 'status' + suffix);
+ }
+
+ if (!options.isNoDom && 'markup' in checks) {
+ assert.is(helpers._actual.markup(options), checks.markup, 'markup' + suffix);
+ }
+
+ if (!options.isNoDom && 'hints' in checks) {
+ var hintCheck = function(actualHints) {
+ assert.is(actualHints, checks.hints, 'hints' + suffix);
+ };
+ outstanding.push(helpers._actual.hints(options).then(hintCheck));
+ }
+
+ if (!options.isNoDom && 'predictions' in checks) {
+ var predictionsCheck = function(actualPredictions) {
+ helpers.arrayIs(actualPredictions,
+ checks.predictions,
+ 'predictions' + suffix);
+ };
+ outstanding.push(helpers._actual.predictions(options).then(predictionsCheck));
+ }
+
+ if (!options.isNoDom && 'predictionsContains' in checks) {
+ var containsCheck = function(actualPredictions) {
+ checks.predictionsContains.forEach(function(prediction) {
+ var index = actualPredictions.indexOf(prediction);
+ assert.ok(index !== -1,
+ 'predictionsContains:' + prediction + suffix);
+ });
+ };
+ outstanding.push(helpers._actual.predictions(options).then(containsCheck));
+ }
+
+ if ('unassigned' in checks) {
+ helpers.arrayIs(helpers._actual.unassigned(options),
+ checks.unassigned,
+ 'unassigned' + suffix);
+ }
+
+ /* TODO: Fix this
+ if (!options.isNoDom && 'tooltipState' in checks) {
+ assert.is(helpers._actual.tooltipState(options),
+ checks.tooltipState,
+ 'tooltipState' + suffix);
+ }
+ */
+
+ if (!options.isNoDom && 'outputState' in checks) {
+ assert.is(helpers._actual.outputState(options),
+ checks.outputState,
+ 'outputState' + suffix);
+ }
+
+ if (!options.isNoDom && 'options' in checks) {
+ helpers.arrayIs(helpers._actual.options(options),
+ checks.options,
+ 'options' + suffix);
+ }
+
+ if (!options.isNoDom && 'error' in checks) {
+ assert.is(helpers._actual.message(options), checks.error, 'error' + suffix);
+ }
+
+ if (checks.args != null) {
+ Object.keys(checks.args).forEach(function(paramName) {
+ var check = checks.args[paramName];
+
+ // We allow an 'argument' called 'command' to be the command itself, but
+ // what if the command has a parameter called 'command' (for example, an
+ // 'exec' command)? We default to using the parameter because checking
+ // the command value is less useful
+ var assignment = requisition.getAssignment(paramName);
+ if (assignment == null && paramName === 'command') {
+ assignment = requisition.commandAssignment;
+ }
+
+ if (assignment == null) {
+ assert.ok(false, 'Unknown arg: ' + paramName + suffix);
+ return;
+ }
+
+ if ('value' in check) {
+ if (typeof check.value === 'function') {
+ try {
+ check.value(assignment.value);
+ }
+ catch (ex) {
+ assert.ok(false, '' + ex);
+ }
+ }
+ else {
+ assert.is(assignment.value,
+ check.value,
+ 'arg.' + paramName + '.value' + suffix);
+ }
+ }
+
+ if ('name' in check) {
+ assert.is(assignment.value.name,
+ check.name,
+ 'arg.' + paramName + '.name' + suffix);
+ }
+
+ if ('type' in check) {
+ assert.is(assignment.arg.type,
+ check.type,
+ 'arg.' + paramName + '.type' + suffix);
+ }
+
+ if ('arg' in check) {
+ assert.is(assignment.arg.toString(),
+ check.arg,
+ 'arg.' + paramName + '.arg' + suffix);
+ }
+
+ if ('status' in check) {
+ assert.is(assignment.getStatus().toString(),
+ check.status,
+ 'arg.' + paramName + '.status' + suffix);
+ }
+
+ if (!options.isNoDom && 'message' in check) {
+ if (typeof check.message.test === 'function') {
+ assert.ok(check.message.test(assignment.message),
+ 'arg.' + paramName + '.message' + suffix);
+ }
+ else {
+ assert.is(assignment.message,
+ check.message,
+ 'arg.' + paramName + '.message' + suffix);
+ }
+ }
+ });
+ }
+
+ return Promise.all(outstanding).then(function() {
+ // Ensure the promise resolves to nothing
+ return undefined;
+ });
+};
+
+/**
+ * Helper for helpers.audit() to ensure that all the 'exec' properties work.
+ * See helpers.audit for more information.
+ * @param name The name to use in error messages
+ * @param expected See helpers.audit for a list of available exec checks
+ * @return A promise which resolves to undefined when the checks are complete
+ */
+helpers._exec = function(options, name, expected) {
+ var requisition = options.requisition;
+ if (expected == null) {
+ return Promise.resolve({});
+ }
+
+ var origLogErrors = cli.logErrors;
+ if (expected.error) {
+ cli.logErrors = false;
+ }
+
+ try {
+ return requisition.exec({ hidden: true }).then(function(output) {
+ if ('type' in expected) {
+ assert.is(output.type,
+ expected.type,
+ 'output.type for: ' + name);
+ }
+
+ if ('error' in expected) {
+ assert.is(output.error,
+ expected.error,
+ 'output.error for: ' + name);
+ }
+
+ if (!('output' in expected)) {
+ return { output: output };
+ }
+
+ var context = requisition.conversionContext;
+ var convertPromise;
+ if (options.isNoDom) {
+ convertPromise = output.convert('string', context);
+ }
+ else {
+ convertPromise = output.convert('dom', context).then(function(node) {
+ return node.textContent.trim();
+ });
+ }
+
+ return convertPromise.then(function(textOutput) {
+ var doTest = function(match, against) {
+ // Only log the real textContent if the test fails
+ if (against.match(match) != null) {
+ assert.ok(true, 'html output for \'' + name + '\' ' +
+ 'should match /' + (match.source || match) + '/');
+ } else {
+ assert.ok(false, 'html output for \'' + name + '\' ' +
+ 'should match /' + (match.source || match) + '/. ' +
+ 'Actual textContent: "' + against + '"');
+ }
+ };
+
+ if (typeof expected.output === 'string') {
+ assert.is(textOutput,
+ expected.output,
+ 'html output for ' + name);
+ }
+ else if (Array.isArray(expected.output)) {
+ expected.output.forEach(function(match) {
+ doTest(match, textOutput);
+ });
+ }
+ else {
+ doTest(expected.output, textOutput);
+ }
+
+ if (expected.error) {
+ cli.logErrors = origLogErrors;
+ }
+ return { output: output, text: textOutput };
+ });
+ }.bind(this)).then(function(data) {
+ if (expected.error) {
+ cli.logErrors = origLogErrors;
+ }
+
+ return data;
+ });
+ }
+ catch (ex) {
+ assert.ok(false, 'Failure executing \'' + name + '\': ' + ex);
+ util.errorHandler(ex);
+
+ if (expected.error) {
+ cli.logErrors = origLogErrors;
+ }
+ return Promise.resolve({});
+ }
+};
+
+/**
+ * Helper to setup the test
+ */
+helpers._setup = function(options, name, audit) {
+ if (typeof audit.setup === 'string') {
+ return helpers.setInput(options, audit.setup);
+ }
+
+ if (typeof audit.setup === 'function') {
+ return Promise.resolve(audit.setup.call(audit));
+ }
+
+ return Promise.reject('\'setup\' property must be a string or a function. Is ' + audit.setup);
+};
+
+/**
+ * Helper to shutdown the test
+ */
+helpers._post = function(name, audit, data) {
+ if (typeof audit.post === 'function') {
+ return Promise.resolve(audit.post.call(audit, data.output, data.text));
+ }
+ return Promise.resolve(audit.post);
+};
+
+/*
+ * We do some basic response time stats so we can see if we're getting slow
+ */
+var totalResponseTime = 0;
+var averageOver = 0;
+var maxResponseTime = 0;
+var maxResponseCulprit;
+var start;
+
+/**
+ * Restart the stats collection process
+ */
+helpers.resetResponseTimes = function() {
+ start = new Date().getTime();
+ totalResponseTime = 0;
+ averageOver = 0;
+ maxResponseTime = 0;
+ maxResponseCulprit = undefined;
+};
+
+/**
+ * Expose an average response time in milliseconds
+ */
+Object.defineProperty(helpers, 'averageResponseTime', {
+ get: function() {
+ return averageOver === 0 ?
+ undefined :
+ Math.round(100 * totalResponseTime / averageOver) / 100;
+ },
+ enumerable: true
+});
+
+/**
+ * Expose a maximum response time in milliseconds
+ */
+Object.defineProperty(helpers, 'maxResponseTime', {
+ get: function() { return Math.round(maxResponseTime * 100) / 100; },
+ enumerable: true
+});
+
+/**
+ * Expose the name of the test that provided the maximum response time
+ */
+Object.defineProperty(helpers, 'maxResponseCulprit', {
+ get: function() { return maxResponseCulprit; },
+ enumerable: true
+});
+
+/**
+ * Quick summary of the times
+ */
+Object.defineProperty(helpers, 'timingSummary', {
+ get: function() {
+ var elapsed = (new Date().getTime() - start) / 1000;
+ return 'Total ' + elapsed + 's, ' +
+ 'ave response ' + helpers.averageResponseTime + 'ms, ' +
+ 'max response ' + helpers.maxResponseTime + 'ms ' +
+ 'from \'' + helpers.maxResponseCulprit + '\'';
+ },
+ enumerable: true
+});
+
+/**
+ * A way of turning a set of tests into something more declarative, this helps
+ * to allow tests to be asynchronous.
+ * @param audits An array of objects each of which contains:
+ * - setup: string/function to be called to set the test up.
+ * If audit is a string then it is passed to helpers.setInput().
+ * If audit is a function then it is executed. The tests will wait while
+ * tests that return promises complete.
+ * - name: For debugging purposes. If name is undefined, and 'setup'
+ * is a string then the setup value will be used automatically
+ * - skipIf: A function to define if the test should be skipped. Useful for
+ * excluding tests from certain environments (e.g. nodom, firefox, etc).
+ * The name of the test will be used in log messages noting the skip
+ * See helpers.reason for pre-defined skip functions. The skip function must
+ * be synchronous, and will be passed the test options object.
+ * - skipRemainingIf: A function to skip all the remaining audits in this set.
+ * See skipIf for details of how skip functions work.
+ * - check: Check data. Available checks:
+ * - input: The text displayed in the input field
+ * - cursor: The position of the start of the cursor
+ * - status: One of 'VALID', 'ERROR', 'INCOMPLETE'
+ * - hints: The hint text, i.e. a concatenation of the directTabText, the
+ * emptyParameters and the arrowTabText. The text as inserted into the UI
+ * will include NBSP and Unicode RARR characters, these should be
+ * represented using normal space and '->' for the arrow
+ * - markup: What state should the error markup be in. e.g. 'VVVIIIEEE'
+ * - args: Maps of checks to make against the arguments:
+ * - value: i.e. assignment.value (which ignores defaultValue)
+ * - type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
+ * Care should be taken with this since it's something of an
+ * implementation detail
+ * - arg: The toString value of the argument
+ * - status: i.e. assignment.getStatus
+ * - message: i.e. assignment.message
+ * - name: For commands - checks assignment.value.name
+ * - exec: Object to indicate we should execute the command and check the
+ * results. Available checks:
+ * - output: A string, RegExp or array of RegExps to compare with the output
+ * If typeof output is a string then the output should be exactly equal
+ * to the given string. If the type of output is a RegExp or array of
+ * RegExps then the output should match all RegExps
+ * - error: If true, then it is expected that this command will fail (that
+ * is, return a rejected promise or throw an exception)
+ * - type: A string documenting the expected type of the return value
+ * - post: Function to be called after the checks have been run, which will be
+ * passed 2 parameters: the first being output data (with type, data, and
+ * error properties), and the second being the converted text version of
+ * the output data
+ */
+helpers.audit = function(options, audits) {
+ checkOptions(options);
+ var skipReason = null;
+ return util.promiseEach(audits, function(audit) {
+ var name = audit.name;
+ if (name == null && typeof audit.setup === 'string') {
+ name = audit.setup;
+ }
+
+ if (assert.testLogging) {
+ log('- START \'' + name + '\' in ' + assert.currentTest);
+ }
+
+ if (audit.skipRemainingIf) {
+ var skipRemainingIf = (typeof audit.skipRemainingIf === 'function') ?
+ audit.skipRemainingIf(options) :
+ !!audit.skipRemainingIf;
+ if (skipRemainingIf) {
+ skipReason = audit.skipRemainingIf.name ?
+ 'due to ' + audit.skipRemainingIf.name :
+ '';
+ assert.log('Skipped ' + name + ' ' + skipReason);
+
+ // Tests need at least one pass, fail or todo. Let's create a dummy pass
+ // in case there are none.
+ ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
+
+ return Promise.resolve(undefined);
+ }
+ }
+
+ if (audit.skipIf) {
+ var skip = (typeof audit.skipIf === 'function') ?
+ audit.skipIf(options) :
+ !!audit.skipIf;
+ if (skip) {
+ var reason = audit.skipIf.name ? 'due to ' + audit.skipIf.name : '';
+ assert.log('Skipped ' + name + ' ' + reason);
+ return Promise.resolve(undefined);
+ }
+ }
+
+ if (skipReason != null) {
+ assert.log('Skipped ' + name + ' ' + skipReason);
+ return Promise.resolve(undefined);
+ }
+
+ var start = new Date().getTime();
+
+ var setupDone = helpers._setup(options, name, audit);
+ return setupDone.then(function(chunkLen) {
+ if (typeof chunkLen !== 'number') {
+ chunkLen = 1;
+ }
+
+ // Nasty hack to allow us to auto-skip tests where we're actually testing
+ // a key-sequence (i.e. targeting terminal.js) when there is no terminal
+ if (chunkLen === -1) {
+ assert.log('Skipped ' + name + ' ' + skipReason);
+ return Promise.resolve(undefined);
+ }
+
+ if (assert.currentTest) {
+ var responseTime = (new Date().getTime() - start) / chunkLen;
+ totalResponseTime += responseTime;
+ if (responseTime > maxResponseTime) {
+ maxResponseTime = responseTime;
+ maxResponseCulprit = assert.currentTest + '/' + name;
+ }
+ averageOver++;
+ }
+
+ var checkDone = helpers._check(options, name, audit.check);
+ return checkDone.then(function() {
+ var execDone = helpers._exec(options, name, audit.exec);
+ return execDone.then(function(data) {
+ return helpers._post(name, audit, data).then(function() {
+ if (assert.testLogging) {
+ log('- END \'' + name + '\' in ' + assert.currentTest);
+ }
+ });
+ });
+ });
+ });
+ }).then(function() {
+ return options.automator.setInput('');
+ }, function(ex) {
+ options.automator.setInput('');
+ throw ex;
+ });
+};
+
+/**
+ * Compare 2 arrays.
+ */
+helpers.arrayIs = function(actual, expected, message) {
+ assert.ok(Array.isArray(actual), 'actual is not an array: ' + message);
+ assert.ok(Array.isArray(expected), 'expected is not an array: ' + message);
+
+ if (!Array.isArray(actual) || !Array.isArray(expected)) {
+ return;
+ }
+
+ assert.is(actual.length, expected.length, 'array length: ' + message);
+
+ for (var i = 0; i < actual.length && i < expected.length; i++) {
+ assert.is(actual[i], expected[i], 'member[' + i + ']: ' + message);
+ }
+};
+
+/**
+ * A quick helper to log to the correct place
+ */
+function log(message) {
+ if (typeof info === 'function') {
+ info(message);
+ }
+ else {
+ console.log(message);
+ }
+}
+
+return { helpers: helpers, gcli: gcli, assert: assert };
+})();
diff --git a/toolkit/devtools/commandline/test/mockCommands.js b/toolkit/devtools/commandline/test/mockCommands.js
new file mode 100644
index 000000000..0b9f9343f
--- /dev/null
+++ b/toolkit/devtools/commandline/test/mockCommands.js
@@ -0,0 +1,742 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+// <INJECTED SOURCE:START>
+
+// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
+// DO NOT EDIT IT DIRECTLY
+
+// <INJECTED SOURCE:END>
+
+
+var Promise = require('gcli/util/promise').Promise;
+var mockCommands = {};
+
+// We use an alias for exports here because this module is used in Firefox
+// mochitests where we don't have define/require
+
+/**
+ * Registration and de-registration.
+ */
+mockCommands.setup = function(requisition) {
+ requisition.system.addItems(mockCommands.items);
+};
+
+mockCommands.shutdown = function(requisition) {
+ requisition.system.removeItems(mockCommands.items);
+};
+
+function createExec(name) {
+ return function(args, executionContext) {
+ var argsOut = Object.keys(args).map(function(key) {
+ return key + '=' + args[key];
+ }).join(', ');
+ return 'Exec: ' + name + ' ' + argsOut;
+ };
+}
+
+mockCommands.items = [
+ {
+ item: 'converter',
+ from: 'json',
+ to: 'string',
+ exec: function(json, context) {
+ return JSON.stringify(json, null, ' ');
+ }
+ },
+ {
+ item: 'converter',
+ from: 'json',
+ to: 'view',
+ exec: function(json, context) {
+ var html = JSON.stringify(json, null, '&#160;').replace(/\n/g, '<br/>');
+ return {
+ html: '<pre>' + html + '</pre>'
+ };
+ }
+ },
+ {
+ item: 'type',
+ name: 'optionType',
+ parent: 'selection',
+ lookup: [
+ {
+ name: 'option1',
+ value: 'string'
+ },
+ {
+ name: 'option2',
+ value: 'number'
+ },
+ {
+ name: 'option3',
+ value: {
+ name: 'selection',
+ lookup: [
+ { name: 'one', value: 1 },
+ { name: 'two', value: 2 },
+ { name: 'three', value: 3 }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ item: 'type',
+ name: 'optionValue',
+ parent: 'delegate',
+ delegateType: function(executionContext) {
+ if (executionContext != null) {
+ var option = executionContext.getArgsObject().optionType;
+ if (option != null) {
+ return option;
+ }
+ }
+ return 'blank';
+ }
+ },
+ {
+ item: 'command',
+ name: 'tsv',
+ params: [
+ { name: 'optionType', type: 'optionType' },
+ { name: 'optionValue', type: 'optionValue' }
+ ],
+ exec: createExec('tsv')
+ },
+ {
+ item: 'command',
+ name: 'tsr',
+ params: [ { name: 'text', type: 'string' } ],
+ exec: createExec('tsr')
+ },
+ {
+ item: 'command',
+ name: 'tsrsrsr',
+ params: [
+ { name: 'p1', type: 'string' },
+ { name: 'p2', type: 'string' },
+ { name: 'p3', type: { name: 'string', allowBlank: true} },
+ ],
+ exec: createExec('tsrsrsr')
+ },
+ {
+ item: 'command',
+ name: 'tso',
+ params: [ { name: 'text', type: 'string', defaultValue: null } ],
+ exec: createExec('tso')
+ },
+ {
+ item: 'command',
+ name: 'tse',
+ params: [
+ { name: 'node', type: 'node' },
+ {
+ group: 'options',
+ params: [
+ { name: 'nodes', type: { name: 'nodelist' } },
+ { name: 'nodes2', type: { name: 'nodelist', allowEmpty: true } }
+ ]
+ }
+ ],
+ exec: createExec('tse')
+ },
+ {
+ item: 'command',
+ name: 'tsj',
+ params: [ { name: 'javascript', type: 'javascript' } ],
+ exec: createExec('tsj')
+ },
+ {
+ item: 'command',
+ name: 'tsb',
+ params: [ { name: 'toggle', type: 'boolean' } ],
+ exec: createExec('tsb')
+ },
+ {
+ item: 'command',
+ name: 'tss',
+ exec: createExec('tss')
+ },
+ {
+ item: 'command',
+ name: 'tsu',
+ params: [
+ {
+ name: 'num',
+ type: {
+ name: 'number',
+ max: 10,
+ min: -5,
+ step: 3
+ }
+ }
+ ],
+ exec: createExec('tsu')
+ },
+ {
+ item: 'command',
+ name: 'tsf',
+ params: [
+ {
+ name: 'num',
+ type: {
+ name: 'number',
+ allowFloat: true,
+ max: 11.5,
+ min: -6.5,
+ step: 1.5
+ }
+ }
+ ],
+ exec: createExec('tsf')
+ },
+ {
+ item: 'command',
+ name: 'tsn'
+ },
+ {
+ item: 'command',
+ name: 'tsn dif',
+ params: [ { name: 'text', type: 'string', description: 'tsn dif text' } ],
+ exec: createExec('tsnDif')
+ },
+ {
+ item: 'command',
+ name: 'tsn hidden',
+ hidden: true,
+ exec: createExec('tsnHidden')
+ },
+ {
+ item: 'command',
+ name: 'tsn ext',
+ params: [ { name: 'text', type: 'string' } ],
+ exec: createExec('tsnExt')
+ },
+ {
+ item: 'command',
+ name: 'tsn exte',
+ params: [ { name: 'text', type: 'string' } ],
+ exec: createExec('tsnExte')
+ },
+ {
+ item: 'command',
+ name: 'tsn exten',
+ params: [ { name: 'text', type: 'string' } ],
+ exec: createExec('tsnExten')
+ },
+ {
+ item: 'command',
+ name: 'tsn extend',
+ params: [ { name: 'text', type: 'string' } ],
+ exec: createExec('tsnExtend')
+ },
+ {
+ item: 'command',
+ name: 'tsn deep'
+ },
+ {
+ item: 'command',
+ name: 'tsn deep down'
+ },
+ {
+ item: 'command',
+ name: 'tsn deep down nested'
+ },
+ {
+ item: 'command',
+ name: 'tsn deep down nested cmd',
+ exec: createExec('tsnDeepDownNestedCmd')
+ },
+ {
+ item: 'command',
+ name: 'tshidden',
+ hidden: true,
+ params: [
+ {
+ group: 'Options',
+ params: [
+ {
+ name: 'visible',
+ type: 'string',
+ short: 'v',
+ defaultValue: null,
+ description: 'visible'
+ },
+ {
+ name: 'invisiblestring',
+ type: 'string',
+ short: 'i',
+ description: 'invisiblestring',
+ defaultValue: null,
+ hidden: true
+ },
+ {
+ name: 'invisibleboolean',
+ short: 'b',
+ type: 'boolean',
+ description: 'invisibleboolean',
+ hidden: true
+ }
+ ]
+ }
+ ],
+ exec: createExec('tshidden')
+ },
+ {
+ item: 'command',
+ name: 'tselarr',
+ params: [
+ { name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
+ { name: 'arr', type: { name: 'array', subtype: 'string' } }
+ ],
+ exec: createExec('tselarr')
+ },
+ {
+ item: 'command',
+ name: 'tsm',
+ description: 'a 3-param test selection|string|number',
+ params: [
+ { name: 'abc', type: { name: 'selection', data: [ 'a', 'b', 'c' ] } },
+ { name: 'txt', type: 'string' },
+ { name: 'num', type: { name: 'number', max: 42, min: 0 } }
+ ],
+ exec: createExec('tsm')
+ },
+ {
+ item: 'command',
+ name: 'tsg',
+ description: 'a param group test',
+ params: [
+ {
+ name: 'solo',
+ type: { name: 'selection', data: [ 'aaa', 'bbb', 'ccc' ] },
+ description: 'solo param'
+ },
+ {
+ group: 'First',
+ params: [
+ {
+ name: 'txt1',
+ type: 'string',
+ defaultValue: null,
+ description: 'txt1 param'
+ },
+ {
+ name: 'bool',
+ type: 'boolean',
+ description: 'bool param'
+ }
+ ]
+ },
+ {
+ name: 'txt2',
+ type: 'string',
+ defaultValue: 'd',
+ description: 'txt2 param',
+ option: 'Second'
+ },
+ {
+ name: 'num',
+ type: { name: 'number', min: 40 },
+ defaultValue: 42,
+ description: 'num param',
+ option: 'Second'
+ }
+ ],
+ exec: createExec('tsg')
+ },
+ {
+ item: 'command',
+ name: 'tscook',
+ description: 'param group test to catch problems with cookie command',
+ params: [
+ {
+ name: 'key',
+ type: 'string',
+ description: 'tscookKeyDesc'
+ },
+ {
+ name: 'value',
+ type: 'string',
+ description: 'tscookValueDesc'
+ },
+ {
+ group: 'tscookOptionsDesc',
+ params: [
+ {
+ name: 'path',
+ type: 'string',
+ defaultValue: '/',
+ description: 'tscookPathDesc'
+ },
+ {
+ name: 'domain',
+ type: 'string',
+ defaultValue: null,
+ description: 'tscookDomainDesc'
+ },
+ {
+ name: 'secure',
+ type: 'boolean',
+ description: 'tscookSecureDesc'
+ }
+ ]
+ }
+ ],
+ exec: createExec('tscook')
+ },
+ {
+ item: 'command',
+ name: 'tslong',
+ description: 'long param tests to catch problems with the jsb command',
+ params: [
+ {
+ name: 'msg',
+ type: 'string',
+ description: 'msg Desc'
+ },
+ {
+ group: 'Options Desc',
+ params: [
+ {
+ name: 'num',
+ short: 'n',
+ type: 'number',
+ description: 'num Desc',
+ defaultValue: 2
+ },
+ {
+ name: 'sel',
+ short: 's',
+ type: {
+ name: 'selection',
+ lookup: [
+ { name: 'space', value: ' ' },
+ { name: 'tab', value: '\t' }
+ ]
+ },
+ description: 'sel Desc',
+ defaultValue: ' '
+ },
+ {
+ name: 'bool',
+ short: 'b',
+ type: 'boolean',
+ description: 'bool Desc'
+ },
+ {
+ name: 'num2',
+ short: 'm',
+ type: 'number',
+ description: 'num2 Desc',
+ defaultValue: -1
+ },
+ {
+ name: 'bool2',
+ short: 'c',
+ type: 'boolean',
+ description: 'bool2 Desc'
+ },
+ {
+ name: 'sel2',
+ short: 't',
+ type: {
+ name: 'selection',
+ data: [ 'collapse', 'basic', 'with space', 'with two spaces' ]
+ },
+ description: 'sel2 Desc',
+ defaultValue: 'collapse'
+ }
+ ]
+ }
+ ],
+ exec: createExec('tslong')
+ },
+ {
+ item: 'command',
+ name: 'tsdate',
+ description: 'long param tests to catch problems with the jsb command',
+ params: [
+ {
+ name: 'd1',
+ type: 'date',
+ },
+ {
+ name: 'd2',
+ type: {
+ name: 'date',
+ min: '1 jan 2000',
+ max: '28 feb 2000',
+ step: 2
+ }
+ },
+ ],
+ exec: createExec('tsdate')
+ },
+ {
+ item: 'command',
+ name: 'tsfail',
+ description: 'test errors',
+ params: [
+ {
+ name: 'method',
+ type: {
+ name: 'selection',
+ data: [
+ 'reject', 'rejecttyped',
+ 'throwerror', 'throwstring', 'throwinpromise',
+ 'noerror'
+ ]
+ }
+ }
+ ],
+ exec: function(args, context) {
+ if (args.method === 'reject') {
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ reject('rejected promise');
+ }, 10);
+ });
+ }
+
+ if (args.method === 'rejecttyped') {
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ reject(context.typedData('number', 54));
+ }, 10);
+ });
+ }
+
+ if (args.method === 'throwinpromise') {
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ resolve('should be lost');
+ }, 10);
+ }).then(function() {
+ var t = null;
+ return t.foo;
+ });
+ }
+
+ if (args.method === 'throwerror') {
+ throw new Error('thrown error');
+ }
+
+ if (args.method === 'throwstring') {
+ throw 'thrown string';
+ }
+
+ return 'no error';
+ }
+ },
+ {
+ item: 'command',
+ name: 'tsfile',
+ description: 'test file params',
+ },
+ {
+ item: 'command',
+ name: 'tsfile open',
+ description: 'a file param in open mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'file',
+ existing: 'yes'
+ }
+ }
+ ],
+ exec: createExec('tsfile open')
+ },
+ {
+ item: 'command',
+ name: 'tsfile saveas',
+ description: 'a file param in saveas mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'file',
+ existing: 'no'
+ }
+ }
+ ],
+ exec: createExec('tsfile saveas')
+ },
+ {
+ item: 'command',
+ name: 'tsfile save',
+ description: 'a file param in save mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'file',
+ existing: 'maybe'
+ }
+ }
+ ],
+ exec: createExec('tsfile save')
+ },
+ {
+ item: 'command',
+ name: 'tsfile cd',
+ description: 'a file param in cd mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'directory',
+ existing: 'yes'
+ }
+ }
+ ],
+ exec: createExec('tsfile cd')
+ },
+ {
+ item: 'command',
+ name: 'tsfile mkdir',
+ description: 'a file param in mkdir mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'directory',
+ existing: 'no'
+ }
+ }
+ ],
+ exec: createExec('tsfile mkdir')
+ },
+ {
+ item: 'command',
+ name: 'tsfile rm',
+ description: 'a file param in rm mode',
+ params: [
+ {
+ name: 'p1',
+ type: {
+ name: 'file',
+ filetype: 'any',
+ existing: 'yes'
+ }
+ }
+ ],
+ exec: createExec('tsfile rm')
+ },
+ {
+ item: 'command',
+ name: 'tsslow',
+ params: [
+ {
+ name: 'hello',
+ type: {
+ name: 'selection',
+ data: function(context) {
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ resolve([
+ 'Shalom', 'Namasté', 'Hallo', 'Dydd-da',
+ 'Chào', 'Hej', 'Saluton', 'Sawubona'
+ ]);
+ }, 10);
+ });
+ }
+ }
+ }
+ ],
+ exec: function(args, context) {
+ return 'Test completed';
+ }
+ },
+ {
+ item: 'command',
+ name: 'urlc',
+ params: [
+ {
+ name: 'url',
+ type: 'url'
+ }
+ ],
+ returnType: 'json',
+ exec: function(args, context) {
+ return args;
+ }
+ },
+ {
+ item: 'command',
+ name: 'unionc1',
+ params: [
+ {
+ name: 'first',
+ type: {
+ name: 'union',
+ alternatives: [
+ {
+ name: 'selection',
+ lookup: [
+ { name: 'one', value: 1 },
+ { name: 'two', value: 2 },
+ ]
+ },
+ 'number',
+ { name: 'string' }
+ ]
+ }
+ }
+ ],
+ returnType: 'json',
+ exec: function(args, context) {
+ return args;
+ }
+ },
+ {
+ item: 'command',
+ name: 'unionc2',
+ params: [
+ {
+ name: 'first',
+ type: {
+ name: 'union',
+ alternatives: [
+ {
+ name: 'selection',
+ lookup: [
+ { name: 'one', value: 1 },
+ { name: 'two', value: 2 },
+ ]
+ },
+ {
+ name: 'url'
+ }
+ ]
+ }
+ }
+ ],
+ returnType: 'json',
+ exec: function(args, context) {
+ return args;
+ }
+ }
+];