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"]
50 get Clistkeys() this.listcommands,
54 get Ilistkeys() this.listcommands,
60 someOutput: ["", "abc"],
61 noOutput: ["abc def", "-js abc def"],
62 completions: ["", "abc ", "-js abc "]
66 multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"],
73 multiOutput: ["", "DOMLoad", "DOMLoad foo"],
74 noOutput: ["DOMLoad foo bar", "-js DOMLoad foo bar"],
81 back: { noOutput: [""] },
83 init: ["tabopen about:pentadactyl", "tabopen about:pentadactyl"],
85 anyOutput: ["about:pentadactyl"],
86 completions: [["", hasItems]]
88 get blistkeys() this.listcommands,
91 singleOutput: ["", "-tags=foo -title=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
92 error: ["-tags=foo -title=bar -keyword=baz -charset=nonExistentCharset -post=quux about:pentadactyl"],
95 "-max=1 -keyword=foo -tags=",
96 "-max=1 -keyword=foo -tags=bar -title=",
97 ["-max=1 -keyword=foo -tags=bar -title=baz -charset=", hasItems],
98 "-max=1 -keyword=foo -tags=bar -title=baz -charset= about:"
102 multiOutput: ["-max=1", "-max=1 -keyword=foo -tags=bar -title=baz about:pentadactyl"],
105 "-max=1 -keyword=foo -tags=",
106 "-max=1 -keyword=foo -tags=bar -title=",
107 "-max=1 -keyword=foo -tags=bar -title=baz about:"
112 anyOutput: ["", "1"],
113 noOutput: ["!", "! 1"],
121 multiOutput: ["", "1"],
122 completions: ["", "1"]
127 singleOutput: ["", "~/"],
128 completions: ["", "~/"]
130 get clistkeys() this.listcommands,
134 error: ["!", "", "some-nonexistent-scheme"]
138 singleOutput: ["", "foobar"],
139 noOutput: ["foo bar", "-js bar baz"],
144 "-group=builtin baz quux",
145 "! -group=builtin baz quux",
149 ["-group=", hasItems],
150 ["-group=user ", hasItems]
156 contexts: { // Not testable in this manner
160 anyOutput: ["5digits.org", "5digits.org list"],
164 ["5digits.org ", hasItems]
169 delbmarks: { anyOutput: ["", "about:pentadactyl"] },
172 init: ["delcommand!", "command foo bar"],
176 ["-group=", hasItems],
177 ["-group=user ", hasItems]
179 noOutput: ["foo", "! "]
182 init: ["delcommand!"],
187 error: ["", "! foo", "builtin"],
191 error: ["", "! foo"],
193 completions: ["", "x"]
195 get delmarks() this.delmacros,
196 get delqmarks() this.delmacros,
198 completions: ["", "-name=", "-name=foo ", "-index=", "-index="]
202 // Skip implementation for now
218 multiOutput: ["", "dactyl", "dactyl"]
227 ["window", /\[object\sChromeWindow\]/]
239 __proto__: this.echo,
241 get echomsg() this.echo,
249 noOutput: ["View.Zoom.Zoom In", "View.Zoom.Zoom Out"],
261 noOutput: ["", "'js " + "".quote() + "'"],
262 someOutput: ["'ls'"],
263 completions: [["", hasItems]]
269 completions: [["", hasItems]],
273 completions: [["", hasItems]],
276 get extdisable() this.extdelete,
285 get extrehash() this.extdelete,
286 get exttoggle() this.extdelete,
287 get extupdate() this.extdelete,
296 forward: { noOutput: [""] },
304 "foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
305 "! foo -d='foo group' -nopersist -l 'bar.com','http://bar/*','http://bar','^http:'",
314 cleanup: ["delmapgroup foo"]
316 hardcopy: {}, // Skip for now
319 noOutput: ["", "intro"],
320 cleanup: ["tabdelete", "tabdelete"],
326 get helpall() this.help,
329 multiOutput: ["", "Help"],
332 "Help -group=FontCode",
333 "Help -group=FontCode foo: bar;"
339 ["Help -group=", hasItems],
340 ["Help -group=FontCode ", hasItems],
341 ["Help foo: bar; -moz", hasItems]
345 init: ["open about:pentadactyl"],
346 anyOutput: ["-max=1", "-max=1 -sort=+date", "-max=1 dactyl"],
350 ["-sort=+", hasItems],
351 ["-sort=-", hasItems],
352 ["-sort=+date ", hasItems],
360 get ilistkeys() this.listcommands,
366 noOutput: ["''", "'\\n'", "<pre>foo bar</pre>", "window", "<<EOF\n''\nEOF"],
369 ["window", hasItems],
370 ["window.", hasItems],
371 ["window['", hasItems],
372 ["File('", hasItems],
373 ["File.expandPath('", hasItems],
374 "autocommands.user.get('",
375 ["commands.get('", hasItems],
376 ["commands.builtin.get('", hasItems],
377 ["highlight.get('", hasItems],
378 ["highlight.highlightNode(null, '", hasItems],
379 ["mappings.get(modes.NORMAL, '", hasItems],
380 // ["mappings.builtin.get(modes.NORMAL, '", hasItems],
381 ["options.get('", hasItems],
382 ["prefs.get('", hasItems],
383 ["prefs.defaults.get('", hasItems],
384 ["localPrefs.get('", hasItems],
385 ["localPrefs.defaults.get('", hasItems],
386 ["styles.system.get('", hasItems],
394 error: ["!", "", "some-nonexistent-command"],
396 anyOutput: ["echo 'foo'"],
397 completions: [["", hasItems]]
404 anyOutput: ["", "in"],
410 get listkeys() this.listcommands,
411 get listoptions() this.listcommands,
426 "-group=user -b i j",
430 "-mode=ex -b <C-a> <C-a>"
432 multiOutput: ["", "i"],
434 "-mode=some-nonexistent-mode <C-a> <C-a>",
435 "-group=some-nonexistent-group <C-a> <C-a>",
436 "-group=builtin <C-a> <C-a>"
441 ["-mode=ex ", hasItems],
442 ["-mode=", hasItems],
443 ["-group=", hasItems],
444 ["-builtin i ", hasItems],
445 ["-ex i ", hasItems],
446 ["-javascript i ", hasItems]
450 error: ["!", "", "#", "xy"],
455 init: ["delmarks q"],
456 multiOutput: ["", "y"],
457 error: ["!", "q", "#"],
462 anyOutput: ["messages"]
470 "some-nonexistent-rc.penta",
471 "! some-nonexistent-rc.penta"
473 error: ["some-nonexistent-rc.penta"],
475 cleanup: ["silent !rm some-nonexistent-rc.penta"]
479 "some-nonexistent-pentadactyl-dir/"
485 get mlistkeys() this.listcommands,
489 get nlistkeys() this.listcommands,
499 singleOutput: ["<C-g>"],
500 multiOutput: ["g<C-g>"]
505 noOutput: ["about:blank | about:home"],
509 ["./ | ", hasItems], // FIXME: broken feature
510 ["chrome://", hasItems],
511 ["chrome://browser/", hasItems],
512 ["chrome://browser/content/", hasItems],
513 ["about:", hasItems],
514 ["resource://", hasItems],
515 ["resource://dactyl/", hasItems]
519 multiOutput: ["", "fgm"],
520 completions: [["", hasItems]],
521 error: ["!", "abcdefghijklmnopqrstuvwxyz", "f g m"]
540 error: ["!", "", "#"],
551 init: ["delqmarks a-zA-Z0-9"],
556 multiOutput: ["", "m", "x"],
557 completions: [["", hasItems]]
586 "js File('~/.pentadactyl/some-nonexistent/good.css').write('')",
587 "js File('~/.pentadactyl/some-nonexistent/good.js').write('')",
588 "js File('~/.pentadactyl/some-nonexistent/bad.js').write('dactyl.echoerr(\"error\")')",
589 "js File('~/.pentadactyl/some-nonexistent/good.penta').write('')",
590 "js File('~/.pentadactyl/some-nonexistent/bad.penta').write('echoerr \"error\"')",
592 cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
594 "some-nonexistent/good.css",
595 "some-nonexistent/good.js",
596 "some-nonexistent/good.penta"
600 "some-nonexistent/bad.js",
601 "some-nonexistent/bad.penta"
603 singleOutput: ["some-nonexistent-file.js"],
606 ["some-nonexistent/", hasItems],
611 // Skip details for now.
613 ["", function (context) ["all",
629 ].every(function (item) context.allItems.items.some(function ({ text }) item == text))
646 "vb?", "cpt?", "messages?", "titlestring?", "au?", "eht?",
647 "cpt", "messages", "titlestring", "au", "eht", "! "
649 noOutput: ["vb", "novb"],
656 ["cpt+=f", hasItems],
657 ["activate=", hasItems],
658 ["activate=links,", hasItems],
659 ["activate+=", hasItems],
660 ["activate+=links,", hasItems],
661 ["activate^=", hasItems],
662 ["activate^=links,", hasItems],
663 ["activate-=", hasItems],
664 ["activate-=links,", hasItems],
665 ["activate!=", hasItems],
666 ["activate!=links,", hasItems]
669 get setglobal() this.set,
670 get setlocal() this.set,
673 test: function (name) [
674 ["! " + name, sidebarState(name)],
675 [name, sidebarState(name)],
676 ["! " + name, sidebarState(false)]
679 Array.concat.apply([],
680 ["Add-ons", // Final "! Add-ons" currently failing
688 ["Preferences", sidebarState("Preferences")],
689 ["!", sidebarState(false)]
692 ["", hasntNullItems],
700 "echo " + "foo\nbar".quote(),
702 "echoerr " + "foo\nbar".quote()
704 completions: [["", hasItems]]
707 init: this.runtime.init,
708 cleanup: this.runtime.cleanup,
710 "! .pentadactyl/some-nonexistent/really-nonexistent.js",
711 ".pentadactyl/some-nonexistent/good.css",
712 ".pentadactyl/some-nonexistent/good.js",
713 ".pentadactyl/some-nonexistent/good.penta"
717 ".pentadactyl/some-nonexistent/really-nonexistent.js",
718 "~/.pentadactyl/some-nonexistent/bad.js",
719 "~/.pentadactyl/some-nonexistent/bad.penta",
720 "./.pentadactyl/some-nonexistent/bad.js",
721 "./.pentadactyl/some-nonexistent/bad.penta",
722 ".pentadactyl/some-nonexistent/bad.js",
723 ".pentadactyl/some-nonexistent/bad.penta",
724 ".pentadactyl/some-nonexistent-file.js"
728 [".pentadactyl/some-nonexistent/", hasItems],
729 ["chrome://browser/content/", hasItems],
730 ["resource://dactyl/", hasItems]
743 cleanup: ["delstyle -n foo"],
745 "-name=foo http://does.not.exist/* div { display: inline; }",
746 "-name=foo -append http://does.not.exist/* span { display: block; }"
754 ["-name=", hasItems],
755 ["http:* div { -moz", hasItems],
756 ["http:* div { foo: bar; -moz", hasItems],
757 ["http:* div { foo: bar; } span { -moz", hasItems],
758 ["http:* div { foo: bar; } span { foo: bar; -moz", hasItems]
762 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
763 cleanup: ["delstyle -n foo", "delstyle -n bar"],
766 ["-name=", hasNItems(1)],
767 ["-index=", hasNItems(1)]
769 noOutput: ["-name=foo", "-name=bar"]
771 get styleenable() this.styledisable,
773 init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
774 cleanup: ["delstyle -n foo", "delstyle -n bar"],
775 noOutput: ["-name=foo"],
778 ["-name=", hasNItems(2)],
779 ["-index=", hasNItems(2)]
783 error: ["!", "", "some-nonexistent-command"],
785 anyOutput: ["echo 'foo'"],
786 completions: [["", hasItems]]
795 error: ["!", "", "some-nonexistent-command"],
797 anyOutput: ["echo 'foo'"],
798 completions: [["", hasItems]]
808 noOutput: ["1", "$", "999", "-1", "+1", "! +1", "! -1", "-999", "+999", "! +999", "! -999"],
828 error: ["", ":some-nonexistent-command"/*, "some_nonexistent_reference"*/], // FIXME
829 singleOutput: [":js null", "null"]
831 get tlistkeys() this.listcommands,
836 ["tbs Navigation Toolbar", toolbarState("#nav-bar", true)],
837 ["tbs Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
839 completions: [["", hasItems]],
841 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
842 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
844 error: ["!", "", "foo"]
847 completions: [["", hasItems]],
849 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
850 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
852 error: ["!", "", "foo"]
855 completions: [["", hasItems]],
857 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
858 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)],
859 ["Navigation Toolbar", toolbarState("#nav-bar", true)],
860 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)],
861 ["Navigation Toolbar", toolbarState("#nav-bar", false)],
862 ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
864 error: ["!", "", "foo"]
868 noOutput: ["abc", "! "],
904 ["", function (msg) {
905 var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/.exec(msg);
906 return res && res[2] != "null" && res[3] != "null";
911 get vlistkeys() this.listcommands,
932 ["foo".quote(), /foo/],
933 [":echo " + "bar".quote(), /bar/],
934 [":addons", /Pentadactyl/]
938 ":echoerr " + "foo".quote()
949 function addTest(cmdName, testName, func) {
950 global["testCommand_" + cmdName + "_" + testName] = func;
953 function runCommands(cmdName, testName, commands, test, forbidErrors) {
954 addTest(cmdName, testName, function () {
955 commands.forEach(function (val) {
956 var [cmd, testVal] = Array.concat(val);
958 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
959 dactyl.clearMessage();
960 dactyl.closeMessageWindow();
962 cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
964 dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
967 dactyl.runExCommand(cmd);
968 controller.waitForPageLoad(controller.tabs.activeTab);
974 function _runCommands(cmdName, testName, commands) {
975 addTest(cmdName, testName, function () {
976 commands.forEach(function (value) {
977 var [cmd, test] = Array.concat(value);
979 dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
980 var res = dactyl.runExCommand(cmd);
981 controller.waitForPageLoad(controller.tabs.activeTab);
982 runTest("Initializing for " + cmdName + " tests failed: " + cmd.quote() + " " + test,
988 function runTest(message, test) {
990 var res = test.apply(null, Array.slice(arguments, runTest.length));
991 if (res !== undefined)
992 jumlib.assert(res, message);
995 for (var val in Iterator(tests)) (function ([command, paramsList]) {
996 Array.concat(paramsList).forEach(function (params, i) {
998 _runCommands(command, "init" + (i || ""), params.init);
1000 // Goddamn stupid fucking MozMill and its stupid fucking sandboxes with their ancient fucking JS versions.
1001 for (var val in Iterator(params)) (function ([test, commands]) {
1002 var testName = test + (i || "");
1006 runCommands(command, testName, commands, function (cmd, test) {
1007 var res = dactyl.assertMessage(function (msg) !msg, "Unexpected command output: " + cmd);
1009 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1013 runCommands(command, testName, commands, function (cmd, test) {
1015 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1019 runCommands(command, testName, commands, function (cmd, test) {
1020 var res = dactyl.assertMessage(/./, "Expected command output: " + cmd);
1021 if (res && test != null)
1022 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1025 case "singleOutput":
1026 runCommands(command, testName, commands, function (cmd, test) {
1027 var res = dactyl.assertMessageLine(/./, "Expected command output: " + cmd);
1028 if (res && test != null)
1029 dactyl.assertMessageLine(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1030 }, !params.errorsOk);
1033 runCommands(command, testName, commands, function (cmd, test) {
1034 var res = dactyl.assertMessageWindowOpen(true, "Expected command output: " + cmd);
1035 if (res && test != null)
1036 dactyl.assertMessageWindow(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1037 }, !params.errorsOk);
1040 addTest(command, testName, function () {
1041 commands.forEach(function (val) {
1042 var [cmd, test] = Array.concat(val);
1043 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1045 var res = dactyl.assertMessageError(function () {
1046 dactyl.runExCommand(cmd);
1047 controller.waitForPageLoad(controller.tabs.activeTab);
1050 if (res && test != null)
1051 dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1056 addTest(command, testName, function () {
1057 commands.forEach(function (val) {
1058 var [cmd, test] = Array.concat(val);
1059 cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1061 dactyl.assertNoErrorMessages(function () {
1062 dump("COMPL: " + cmd + "\n");
1063 var context = dactyl.runExCompletion(cmd);
1065 runTest("Completion tests failed: " + cmd.quote() + " " + test,
1075 _runCommands(command, "cleanup" + (i || ""), params.cleanup);
1079 // vim: sw=4 ts=8 et: