1 // Runs a slew of generic command tests
3 var utils = require("utils");
4 const { module } = utils;
5 var dactyllib = module("dactyl");
6 var jumlib = module("resource://mozmill/modules/jum.js");
8 var setupModule = function (module) {
9 controller = mozmill.getBrowserController();
10 dactyl = new dactyllib.Controller(controller);
12 dactyl.modules.options["autocomplete"] = [];
13 dactyl.modules.options["wildmode"] = ["list"];
15 dactyl.modules.prefs.set("browser.tabs.closeWindowWithLastTab", false);
16 dactyl.elements.multilineContainer.setAttribute("moz-collapsed", "true");
18 var teardownModule = function (module) {
19 dactyl.elements.multilineContainer.removeAttribute("moz-collapsed");
23 function $(selector) controller.window.document.querySelector(selector);
25 function hasNItems(nItems)
26 function hasNItems(context) {
27 utils.assertEqual("testCommand.hasNItems", nItems, context.allItems.items.length);
30 function hasItems(context) context.allItems.items.length;
32 function hasntNullItems(context) hasItems(context) &&
33 !context.allItems.items.some(function ({ text, description }) [text, description].some(function (text) /^\[object/.test(text)));
35 function sidebarState(state)
36 function sidebarState() {
37 utils.assertEqual("testCommand.sidebarState", state,
38 typeof state == "string" ? $("#sidebar-title").value
39 : !$("#sidebar-box").hidden);
41 function toolbarState(selector, state)
42 function toolbarState() {
43 utils.assertEqual("testCommand.toolbarState", state, !$(selector).collapsed)
48 multiOutput: ["echo foo"]
51 someOutput: ["", "abc"],
52 noOutput: ["abc def", "-js abc def"],
53 completions: ["", "abc ", "-js abc "]
56 multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"],
63 multiOutput: ["", "DOMLoad", "DOMLoad foo"],
64 noOutput: ["DOMLoad foo bar", "-js DOMLoad foo bar"],
71 back: { noOutput: [""] },
73 init: ["tabopen about:pentadactyl", "tabopen about:pentadactyl"],
75 anyOutput: ["about:pentadactyl"],
76 completions: [["", hasItems]]
79 singleOutput: ["", "-tags=foo -title=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
80 error: ["-tags=foo -title=bar -keyword=baz -charset=nonExistentCharset -post=quux about:pentadactyl"],
83 "-max=1 -keyword=foo -tags=",
84 "-max=1 -keyword=foo -tags=bar -title=",
85 ["-max=1 -keyword=foo -tags=bar -title=baz -charset=", hasItems],
86 "-max=1 -keyword=foo -tags=bar -title=baz -charset= about:"
90 multiOutput: ["-max=1", "-max=1 -keyword=foo -tags=bar -title=baz about:pentadactyl"],
93 "-max=1 -keyword=foo -tags=",
94 "-max=1 -keyword=foo -tags=bar -title=",
95 "-max=1 -keyword=foo -tags=bar -title=baz about:"
100 noOutput: ["!", "! 1"],
107 multiOutput: ["", "1"],
108 completions: ["", "1"]
111 singleOutput: ["", "~/"],
112 completions: ["", "~/"]
115 error: ["", "some-nonexistent-scheme"]
119 singleOutput: ["", "foobar"],
120 noOutput: ["foo bar", "-js bar baz"],
125 "-group=builtin baz quux",
126 "! -group=builtin baz quux",
130 ["-group=", hasItems],
131 ["-group=user ", hasItems]
134 contexts: {}, // Not testable in this manner
136 anyOutput: ["dactyl.sf.net", "dactyl.sf.net list"],
140 ["dactyl.sf.net ", hasItems]
143 delbmarks: { anyOutput: ["", "about:pentadactyl"] },
146 init: ["delcommand!", "command foo bar"],
150 ["-group=", hasItems],
151 ["-group=user ", hasItems]
153 noOutput: ["foo", "! "]
156 init: ["delcommand!"],
163 completions: ["", "x"]
165 get delmarks() this.delmacros,
166 get delqmarks() this.delmacros,
168 completions: ["", "-name=", "-name=foo ", "-index=", "-index="]
171 // Skip implementation for now
176 doautoall: {}, // Skip for now
177 doautocmd: {}, // Skip for now
179 multiOutput: ["", "dactyl", "dactyl"]
187 ["window", /\[object\sChromeWindow\]/]
199 __proto__: this.echo,
201 get echomsg() this.echo,
202 else: {}, // Skip for now
203 elseif: {}, // Skip for now
205 noOutput: ["View.Zoom.Zoom In", "View.Zoom.Zoom Out"],
212 endif: {}, // Skip for now
214 noOutput: ["", "'js " + "".quote() + "'"],
215 someOutput: ["'ls'"],
216 completions: [["", hasItems]]
219 completions: [["", hasItems]],
223 completions: [["", hasItems]],
226 get extdisable() this.extdelete,
235 get extrehash() this.extdelete,
236 get exttoggle() this.extdelete,
237 get extupdate() this.extdelete,
242 finish: { noOutput: [""] },
243 forward: { noOutput: [""] },
244 frameonly: { noOutput: [""] },
252 "foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
253 "! foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
262 cleanup: ["delmapgroup foo"]
264 hardcopy: {}, // Skip for now
266 noOutput: ["", "intro"],
267 cleanup: ["tabdelete", "tabdelete"],
273 get helpall() this.help,
275 multiOutput: ["", "Help"],
278 "Help -group=FontCode",
279 "Help -group=FontCode foo: bar;"
285 ["Help -group=", hasItems],
286 ["Help -group=FontCode ", hasItems],
287 ["Help foo: bar; -moz", hasItems]
291 init: ["open about:pentadactyl"],
292 anyOutput: ["-max=1", "-max=1 -sort=+date", "-max=1 dactyl"],
296 ["-sort=+", hasItems],
297 ["-sort=-", hasItems],
298 ["-sort=+date ", hasItems],
302 if: {}, // Skip for now
304 noOutput: ["''", "'\\n'", "<pre>foo bar</pre>", "window"],
307 ["window", hasItems],
308 ["window.", hasItems],
309 ["window['", hasItems],
310 ["File('", hasItems],
311 ["File.expandPath('", hasItems],
312 "autocommands.user.get('",
313 ["commands.get('", hasItems],
314 ["commands.builtin.get('", hasItems],
315 ["highlight.get('", hasItems],
316 ["highlight.highlightNode(null, '", hasItems],
317 ["mappings.get(modes.NORMAL, '", hasItems],
318 // ["mappings.builtin.get(modes.NORMAL, '", hasItems],
319 ["options.get('", hasItems],
320 ["prefs.get('", hasItems],
321 ["prefs.defaults.get('", hasItems],
322 ["localPrefs.get('", hasItems],
323 ["localPrefs.defaults.get('", hasItems],
324 ["styles.system.get('", hasItems],
333 anyOutput: ["echo 'foo'"]
335 let: {}, // Deprecated. Fuck it.
337 anyOutput: ["", "in"],
343 get listkeys() this.listcommands,
344 get listoptions() this.listcommands,
357 "-group=user -b i j",
361 "-mode=ex -b <C-a> <C-a>"
363 multiOutput: ["", "i"],
365 "-mode=some-nonexistent-mode <C-a> <C-a>",
366 "-group=some-nonexistent-group <C-a> <C-a>",
367 "-group=builtin <C-a> <C-a>"
372 ["-mode=ex ", hasItems],
373 ["-mode=", hasItems],
374 ["-group=", hasItems],
375 ["-builtin i ", hasItems],
376 ["-ex i ", hasItems],
377 ["-javascript i ", hasItems]
381 error: ["", "#", "xy"],
386 init: ["delmarks q"],
387 multiOutput: ["", "y"],
392 anyOutput: ["messages"]
400 "some-nonexistent-rc.penta",
401 "! some-nonexistent-rc.penta"
403 error: ["some-nonexistent-rc.penta"],
405 cleanup: ["silent !rm some-nonexistent-rc.penta"]
409 "some-nonexistent-pentadactyl-dir/",
410 "! some-nonexistent-pentadactyl-dir/",
411 "some-nonexistent-pentadactyl-dir/foo.vim",
412 "! some-nonexistent-pentadactyl-dir/foo.vim",
415 "some-nonexistent-pentadactyl-dir/",
416 "some-nonexistent-pentadactyl-dir/foo.vim"
421 cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
425 singleOutput: ["<C-g>"],
426 multiOutput: ["g<C-g>"]
429 noOutput: ["about:blank | about:home"],
433 ["./ | ", hasItems], // FIXME: broken feature
434 ["chrome://", hasItems],
435 ["chrome://browser/", hasItems],
436 ["chrome://browser/content/", hasItems],
437 ["about:", hasItems],
438 ["resource://", hasItems],
439 ["resource://dactyl/", hasItems]
443 multiOutput: ["", "fgm"],
444 completions: [["", hasItems]],
445 error: ["abcdefghijklmnopqrstuvwxyz", "f g m"]
450 preferences: {}, // Skip for now
467 init: ["delqmarks a-zA-Z0-9"],
472 multiOutput: ["", "m", "x"],
473 completions: [["", hasItems]]
476 quit: {}, // Skip for now
477 quitall: {}, // Skip for now
481 rehash: {}, // Skip for now
491 "js File('~/.pentadactyl/some-nonexistent/good.css').write('')",
492 "js File('~/.pentadactyl/some-nonexistent/good.js').write('')",
493 "js File('~/.pentadactyl/some-nonexistent/bad.js').write('dactyl.echoerr(\"error\")')",
494 "js File('~/.pentadactyl/some-nonexistent/good.penta').write('')",
495 "js File('~/.pentadactyl/some-nonexistent/bad.penta').write('echoerr \"error\"')",
497 cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
499 "some-nonexistent/good.css",
500 "some-nonexistent/good.js",
501 "some-nonexistent/good.penta"
504 "some-nonexistent/bad.js",
505 "some-nonexistent/bad.penta"
507 singleOutput: ["some-nonexistent-file.js"],
510 ["some-nonexistent/", hasItems],
515 // Skip details for now.
517 ["", function (context) ["all",
533 ].every(function (item) context.allItems.items.some(function ({ text }) item == text))
547 "vb?", "cpt?", "messages?", "titlestring?", "au?", "eht?",
548 "cpt", "messages", "titlestring", "au", "eht"
550 noOutput: ["vb", "novb"],
557 ["cpt+=f", hasItems],
558 ["activate=", hasItems],
559 ["activate=links,", hasItems],
560 ["activate+=", hasItems],
561 ["activate+=links,", hasItems],
562 ["activate^=", hasItems],
563 ["activate^=links,", hasItems],
564 ["activate-=", hasItems],
565 ["activate-=links,", hasItems],
566 ["activate!=", hasItems],
567 ["activate!=links,", hasItems]
570 get setglobal() this.set,
571 get setlocal() this.set,
574 test: function (name) [
575 ["! " + name, sidebarState(name)],
576 [name, sidebarState(name)],
577 ["! " + name, sidebarState(false)]
580 Array.concat.apply([],
581 ["Add-ons", // Final "! Add-ons" currently failing
589 ["Preferences", sidebarState("Preferences")],
590 ["!", sidebarState(false)]
593 ["", hasntNullItems],
600 "echo " + "foo\nbar".quote(),
602 "echoerr " + "foo\nbar".quote()
604 completions: [["", hasItems]]
607 init: this.runtime.init,
608 cleanup: this.runtime.cleanup,
610 "! .pentadactyl/some-nonexistent/really-nonexistent.js",
611 ".pentadactyl/some-nonexistent/good.css",
612 ".pentadactyl/some-nonexistent/good.js",
613 ".pentadactyl/some-nonexistent/good.penta"
616 ".pentadactyl/some-nonexistent/really-nonexistent.js",
617 "~/.pentadactyl/some-nonexistent/bad.js",
618 "~/.pentadactyl/some-nonexistent/bad.penta",
619 "./.pentadactyl/some-nonexistent/bad.js",
620 "./.pentadactyl/some-nonexistent/bad.penta",
621 ".pentadactyl/some-nonexistent/bad.js",
622 ".pentadactyl/some-nonexistent/bad.penta",
623 ".pentadactyl/some-nonexistent-file.js"
627 [".pentadactyl/some-nonexistent/", hasItems],
628 ["chrome://browser/content/", hasItems],
629 ["resource://dactyl/", hasItems]
632 stop: { noOutput: [""] },
633 stopall: { noOutput: [""] },
635 cleanup: ["delstyle -n foo"],
637 "-name=foo http://does.not.exist/* div { display: inline; }",
638 "-name=foo -append http://does.not.exist/* span { display: block; }"
646 ["-name=", hasItems],
647 ["http:* div { -moz", hasItems],
648 ["http:* div { foo: bar; -moz", hasItems],
649 ["http:* div { foo: bar; } span { -moz", hasItems],
650 ["http:* div { foo: bar; } span { foo: bar; -moz", hasItems]
654 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
655 cleanup: ["delstyle -n foo", "delstyle -n bar"],
658 ["-name=", hasNItems(1)],
659 ["-index=", hasNItems(1)]
661 noOutput: ["-name=foo", "-name=bar"]
663 get styleenable() this.styledisable,
665 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
666 cleanup: ["delstyle -n foo", "delstyle -n bar"],
667 noOutput: ["-name=foo"],
670 ["-name=", hasNItems(2)],
671 ["-index=", hasNItems(2)]
689 ["tbs Navigation Toolbar", toolbarState("#nav-bar", true)],
690 ["tbs Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
692 completions: [["", hasItems]],
694 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
695 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
700 completions: [["", hasItems]],
702 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
703 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
708 completions: [["", hasItems]],
710 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
711 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)],
712 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
713 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)],
714 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
715 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
720 noOutput: ["abc", "! "],
744 ["", function (msg) {
745 var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/;
746 return res && res[2] != "null" && res[3] != "null";
758 ["foo".quote(), /foo/],
759 [":echo " + "bar".quote(), /bar/],
760 [":addons", /Pentadactyl/]
763 ":echoerr " + "foo".quote()
774 function addTest(cmdName, testName, func) {
775 global["testCommand_" + cmdName + "_" + testName] = func;
778 function runCommands(cmdName, testName, commands, test, forbidErrors) {
779 addTest(cmdName, testName, function () {
780 commands.forEach(function (val) {
781 var [cmd, testVal] = Array.concat(val);
783 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
784 dactyl.clearMessage();
785 dactyl.closeMessageWindow();
787 cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
789 dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
792 dactyl.runExCommand(cmd);
793 controller.waitForPageLoad(controller.tabs.activeTab);
799 function _runCommands(cmdName, testName, commands) {
800 addTest(cmdName, testName, function () {
801 commands.forEach(function (value) {
802 var [cmd, test] = Array.concat(value);
804 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
805 var res = dactyl.runExCommand(cmd);
806 controller.waitForPageLoad(controller.tabs.activeTab);
807 runTest("Initializing for " + cmdName + " tests failed: " + cmd.quote() + " " + test,
813 function runTest(message, test) {
815 var res = test.apply(null, Array.slice(arguments, runTest.length));
816 if (res !== undefined)
817 jumlib.assert(res, message);
820 for (var val in Iterator(tests)) (function ([command, paramsList]) {
821 Array.concat(paramsList).forEach(function (params, i) {
823 _runCommands(command, "init" + (i || ""), params.init);
825 // Goddamn stupid fucking MozMill and its stupid fucking sandboxes with their ancient fucking JS versions.
826 for (var val in Iterator(params)) (function ([test, commands]) {
827 var testName = test + (i || "");
831 runCommands(command, testName, commands, function (cmd, test) {
832 var res = dactyl.assertMessage(function (msg) !msg, "Unexpected command output: " + cmd);
834 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
838 runCommands(command, testName, commands, function (cmd, test) {
840 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
844 runCommands(command, testName, commands, function (cmd, test) {
845 var res = dactyl.assertMessage(/./, "Expected command output: " + cmd);
846 if (res && test != null)
847 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
851 runCommands(command, testName, commands, function (cmd, test) {
852 var res = dactyl.assertMessageLine(/./, "Expected command output: " + cmd);
853 if (res && test != null)
854 dactyl.assertMessageLine(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
855 }, !params.errorsOk);
858 runCommands(command, testName, commands, function (cmd, test) {
859 var res = dactyl.assertMessageWindowOpen(true, "Expected command output: " + cmd);
860 if (res && test != null)
861 dactyl.assertMessageWindow(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
862 }, !params.errorsOk);
865 addTest(command, testName, function () {
866 commands.forEach(function (val) {
867 var [cmd, test] = Array.concat(val);
868 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
870 var res = dactyl.assertMessageError(function () {
871 dactyl.runExCommand(cmd);
872 controller.waitForPageLoad(controller.tabs.activeTab);
875 if (res && test != null)
876 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
881 addTest(command, testName, function () {
882 commands.forEach(function (val) {
883 var [cmd, test] = Array.concat(val);
884 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
886 dactyl.assertNoErrorMessages(function () {
887 dump("COMPL: " + cmd + "\n");
888 var context = dactyl.runExCompletion(cmd);
890 runTest("Completion tests failed: " + cmd.quote() + " " + test,
900 _runCommands(command, "cleanup" + (i || ""), params.cleanup);
904 // vim: sw=4 ts=8 et: