]> git.donarmstrong.com Git - dactyl.git/blob - common/tests/functional/testCommands.js
finalize changelog for 7904
[dactyl.git] / common / tests / functional / testCommands.js
1 // Runs a slew of generic command tests
2
3 var utils = require("utils");
4 const { module } = utils;
5 var dactyllib = module("dactyl");
6 var jumlib = module("resource://mozmill/modules/jum.js");
7
8 var setupModule = function (module) {
9     controller = mozmill.getBrowserController();
10     dactyl = new dactyllib.Controller(controller);
11
12     dactyl.modules.options["autocomplete"] = [];
13     dactyl.modules.options["wildmode"] = ["list"];
14
15     dactyl.modules.prefs.set("browser.tabs.closeWindowWithLastTab", false);
16     dactyl.elements.multilineContainer.setAttribute("moz-collapsed", "true");
17 };
18 var teardownModule = function (module) {
19     dactyl.elements.multilineContainer.removeAttribute("moz-collapsed");
20     dactyl.teardown();
21 }
22
23 function $(selector) controller.window.document.querySelector(selector);
24
25 function hasNItems(nItems)
26     function hasNItems(context) {
27         utils.assertEqual("testCommand.hasNItems", nItems, context.allItems.items.length);
28     };
29
30 function hasItems(context) context.allItems.items.length;
31
32 function hasntNullItems(context) hasItems(context) &&
33     !context.allItems.items.some(function ({ text, description }) [text, description].some(function (text) /^\[object/.test(text)));
34
35 function sidebarState(state)
36     function sidebarState() {
37         utils.assertEqual("testCommand.sidebarState", state,
38                           typeof state == "string" ? $("#sidebar-title").value
39                                                    : !$("#sidebar-box").hidden);
40     };
41 function toolbarState(selector, state)
42     function toolbarState() {
43         utils.assertEqual("testCommand.toolbarState", state, !$(selector).collapsed)
44     };
45
46 var tests = {
47     "!": {
48         multiOutput: ["echo foo"]
49     },
50     get Clistkeys() this.listcommands,
51     Cmap: {},
52     Cnoremap: {},
53     Cunmap: {},
54     get Ilistkeys() this.listcommands,
55     Imap: {},
56     Inoremap: {},
57     Iunmap: {},
58     abbreviate: {
59         error: ["!"],
60         someOutput: ["", "abc"],
61         noOutput: ["abc def", "-js abc def"],
62         completions: ["", "abc ", "-js abc "]
63     },
64     addons: {
65         error: ["!"],
66         multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"],
67         completions: [
68             "",
69             ["-types=", hasItems]
70         ]
71     },
72     autocmd: {
73         multiOutput: ["", "DOMLoad", "DOMLoad foo"],
74         noOutput: ["DOMLoad foo bar", "-js DOMLoad foo bar"],
75         completions: [
76             ["", hasntNullItems],
77             "DOMLoad foo ",
78             "-js DOMLoad foo "
79         ]
80     },
81     back: { noOutput: [""] },
82     bdelete: {
83         init: ["tabopen about:pentadactyl", "tabopen about:pentadactyl"],
84         noOutput: [""],
85         anyOutput: ["about:pentadactyl"],
86         completions: [["", hasItems]]
87     },
88     get blistkeys() this.listcommands,
89     bmap: {},
90     bmark: {
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"],
93         completions: [
94             "-max=1 -keyword=",
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:"
99         ]
100     },
101     bmarks: {
102         multiOutput: ["-max=1", "-max=1 -keyword=foo -tags=bar -title=baz about:pentadactyl"],
103         completions: [
104             "-max=1 -keyword=",
105             "-max=1 -keyword=foo -tags=",
106             "-max=1 -keyword=foo -tags=bar -title=",
107             "-max=1 -keyword=foo -tags=bar -title=baz about:"
108         ]
109     },
110     bnoremap: {},
111     buffer: {
112         anyOutput: ["", "1"],
113         noOutput: ["!", "! 1"],
114         completions: [
115             ["", hasItems],
116             ["1", hasItems]
117         ]
118     },
119     buffers: {
120         error: ["!"],
121         multiOutput: ["", "1"],
122         completions: ["", "1"]
123     },
124     bunmap: {},
125     cd: {
126         error: ["!"],
127         singleOutput: ["", "~/"],
128         completions: ["", "~/"]
129     },
130     get clistkeys() this.listcommands,
131     cmap: {},
132     cnoremap: {},
133     colorscheme: {
134         error: ["!", "", "some-nonexistent-scheme"]
135     },
136     command: {
137         init: ["delc!"],
138         singleOutput: ["", "foobar"],
139         noOutput: ["foo bar", "-js bar baz"],
140         multiOutput: [""],
141         error: [
142             "foo bar",
143             "-js bar baz",
144             "-group=builtin baz quux",
145             "! -group=builtin baz quux",
146         ],
147         completions: [
148             ["", hasItems],
149             ["-group=", hasItems],
150             ["-group=user ", hasItems]
151         ]
152     },
153     completions: {
154         error: ["!", ""]
155     },
156     contexts: { // Not testable in this manner
157         error: ["!"]
158     },
159     cookies: {
160         anyOutput: ["5digits.org", "5digits.org list"],
161         error: ["!", ""],
162         completions: [
163             "",
164             ["5digits.org ", hasItems]
165         ]
166     },
167     cunabbreviate: {},
168     cunmap: {},
169     delbmarks: { anyOutput: ["", "about:pentadactyl"] },
170     delcommand: [
171         {
172             init: ["delcommand!", "command foo bar"],
173             error: [""],
174             completions: [
175                 ["", hasItems],
176                 ["-group=", hasItems],
177                 ["-group=user ", hasItems]
178             ],
179             noOutput: ["foo", "! "]
180         },
181         {
182             init: ["delcommand!"],
183             error: ["foo"]
184         }
185     ],
186     delgroup: {
187         error: ["", "! foo", "builtin"],
188         completions: [""]
189     },
190     delmacros: {
191         error: ["", "! foo"],
192         noOutput: ["x"],
193         completions: ["", "x"]
194     },
195     get delmarks() this.delmacros,
196     get delqmarks() this.delmacros,
197     delstyle: {
198         completions: ["", "-name=", "-name=foo ", "-index=", "-index="]
199     },
200     dialog: {
201         error: ["!", ""],
202         // Skip implementation for now
203         completions: [
204             ["", hasntNullItems]
205         ]
206     },
207     dlclear: {
208         error: ["!"]
209     },
210     doautoall: {
211         error: ["!"]
212     },
213     doautocmd: {
214         error: ["!"]
215     },
216     downloads: {
217         error: ["!"],
218         multiOutput: ["", "dactyl", "dactyl"]
219     },
220     echo: {
221         error: ["!"],
222         singleOutput: [
223             ["' - '", " - "]
224         ],
225         multiOutput: [
226             ["'\\n'", /\n/],
227             ["window", /\[object\sChromeWindow\]/]
228         ],
229         completions: [
230             "",
231             "window",
232             "window.",
233             "window['",
234             "commands.get('"
235         ]
236     },
237     get echoerr() ({
238         errorsOk: true,
239         __proto__: this.echo,
240     }),
241     get echomsg() this.echo,
242     else: {
243         error: ["!", "foo"]
244     },
245     elseif: {
246         error: ["!", ""]
247     },
248     emenu: {
249         noOutput: ["View.Zoom.Zoom In", "View.Zoom.Zoom Out"],
250         error: ["!", ""],
251         completions: [
252             ["", hasItems],
253             ["View.", hasItems]
254         ]
255     },
256     endif: {
257         error: ["!", "foo"]
258     },
259     execute: {
260         error: ["!"],
261         noOutput: ["", "'js " + "".quote() + "'"],
262         someOutput: ["'ls'"],
263         completions: [["", hasItems]]
264     },
265     exit: {
266         error: ["foo"]
267     },
268     extadd: {
269         completions: [["", hasItems]],
270         error: ["!", ""]
271     },
272     extdelete: {
273         completions: [["", hasItems]],
274         error: [""]
275     },
276     get extdisable() this.extdelete,
277     extenable: {
278         completions: [""],
279         error: [""]
280     },
281     extoptions: {
282         completions: [""],
283         error: [""]
284     },
285     get extrehash() this.extdelete,
286     get exttoggle() this.extdelete,
287     get extupdate() this.extdelete,
288     feedkeys: {
289         noOutput: ["<Esc>"],
290         error: [""]
291     },
292     finish: {
293         error: ["!", "foo"],
294         noOutput: [""]
295     },
296     forward: { noOutput: [""] },
297     frameonly: {
298         error: ["!", "foo"],
299         noOutput: [""]
300     },
301     group: {
302         multiOutput: [""],
303         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:'",
306             "foo",
307             "user"
308         ],
309         error: ["builtin"],
310         completions: [
311             "",
312             "foo "
313         ],
314         cleanup: ["delmapgroup foo"]
315     },
316     hardcopy: {}, // Skip for now
317     help: {
318         error: ["!"],
319         noOutput: ["", "intro"],
320         cleanup: ["tabdelete", "tabdelete"],
321         completions: [
322             ["", hasItems],
323             ["'wild", hasItems]
324         ]
325     },
326     get helpall() this.help,
327     highlight: {
328         error: ["!"],
329         multiOutput: ["", "Help"],
330         noOutput: [
331             "Help foo: bar;",
332             "Help -group=FontCode",
333             "Help -group=FontCode foo: bar;"
334         ],
335         completions: [
336             ["", hasItems],
337             ["Help", hasItems],
338             ["Help ", hasItems],
339             ["Help -group=", hasItems],
340             ["Help -group=FontCode ", hasItems],
341             ["Help foo: bar; -moz", hasItems]
342         ]
343     },
344     history: {
345         init: ["open about:pentadactyl"],
346         anyOutput: ["-max=1", "-max=1 -sort=+date", "-max=1 dactyl"],
347         completions: [
348             ["", hasItems],
349             "about:",
350             ["-sort=+", hasItems],
351             ["-sort=-", hasItems],
352             ["-sort=+date ", hasItems],
353             "-sort=+date about:"
354         ]
355     },
356     if: {
357         error: ["!", ""],
358     },
359     iabbreviate: {},
360     get ilistkeys() this.listcommands,
361     imap: {},
362     inoremap: {},
363     iunabbreviate: {},
364     iunmap: {},
365     javascript: {
366         noOutput: ["''", "'\\n'", "<pre>foo bar</pre>", "window", "<<EOF\n''\nEOF"],
367         completions: [
368             ["", hasItems],
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],
387         ]
388     },
389     jumps: {
390         error: ["!", "foo"],
391         multiOutput: [""]
392     },
393     keepalt: {
394         error: ["!", "", "some-nonexistent-command"],
395         noOutput: ["js ''"],
396         anyOutput: ["echo 'foo'"],
397         completions: [["", hasItems]]
398     },
399     let: {
400         error: ["!"]
401     },
402     listcommands: {
403         error: ["!"],
404         anyOutput: ["", "in"],
405         completions: [
406             ["", hasItems],
407             "in "
408         ]
409     },
410     get listkeys() this.listcommands,
411     get listoptions() this.listcommands,
412     loadplugins: {},
413     macros: {
414         error: ["!"],
415         multiOutput: [""],
416         completions: [""]
417     },
418     map: {
419         error: ["!"],
420         init: ["unmap!"],
421         anyOutput: [""],
422         singleOutput: ["i"],
423         noOutput: [
424             "i j",
425             "-builtin i j",
426             "-group=user -b i j",
427             "-js i j()",
428             "-ex i :j",
429             "-silent i :j",
430             "-mode=ex -b <C-a> <C-a>"
431         ],
432         multiOutput: ["", "i"],
433         error: [
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>"
437         ],
438         completions: [
439             ["", hasItems],
440             ["-", hasItems],
441             ["-mode=ex ", hasItems],
442             ["-mode=", hasItems],
443             ["-group=", hasItems],
444             ["-builtin i ", hasItems],
445             ["-ex i ", hasItems],
446             ["-javascript i ", hasItems]
447         ]
448     },
449     mark: {
450         error: ["!", "", "#", "xy"],
451         noOutput: ["y"],
452         completions: [""]
453     },
454     marks: {
455         init: ["delmarks q"],
456         multiOutput: ["", "y"],
457         error: ["!", "q", "#"],
458         completions: [""]
459     },
460     messages: {
461         error: ["!", "foo"],
462         anyOutput: ["messages"]
463     },
464     messclear: {
465         error: ["!", "foo"],
466         noOutput: [""]
467     },
468     mkpentadactylrc: {
469         noOutput: [
470             "some-nonexistent-rc.penta",
471             "! some-nonexistent-rc.penta"
472         ],
473         error: ["some-nonexistent-rc.penta"],
474         completions: [""],
475         cleanup: ["silent !rm some-nonexistent-rc.penta"]
476     },
477     mkvimruntime: {
478         error: [
479             "some-nonexistent-pentadactyl-dir/"
480         ],
481         completions: [
482             ["", hasItems]
483         ]
484     },
485     get mlistkeys() this.listcommands,
486     mmap: {},
487     mnoremap: {},
488     munmap: {},
489     get nlistkeys() this.listcommands,
490     nmap: {},
491     nnoremap: {},
492     nohlfind: {
493         error: ["!", "foo"]
494     },
495     noremap: {},
496     normal: {
497         error: [""],
498         noOutput: ["<Nop>"],
499         singleOutput: ["<C-g>"],
500         multiOutput: ["g<C-g>"]
501     },
502     nunmap: {},
503     open: {
504         error: ["!"],
505         noOutput: ["about:blank | about:home"],
506         completions: [
507             ["", hasItems],
508             ["./", hasItems],
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]
516         ]
517     },
518     pageinfo: {
519         multiOutput: ["", "fgm"],
520         completions: [["", hasItems]],
521         error: ["!", "abcdefghijklmnopqrstuvwxyz", "f g m"]
522     },
523     pagestyle: {
524         error: ["!"],
525         completions: [""]
526     },
527     pintab: {},
528     preferences: {
529         error: ["foo"]
530     },
531     pwd: {
532         error: ["!", "foo"],
533         singleOutput: [""]
534     },
535     qmark: {
536         singleOutput: [
537             "m",
538             "m foo bar"
539         ],
540         error: ["!", "", "#"],
541         completions: [
542             ["", hasItems],
543             ["m ", hasItems]
544         ]
545     },
546     qmarks: [
547         {
548             error: ["!"]
549         },
550         {
551             init: ["delqmarks a-zA-Z0-9"],
552             error: ["", "x"],
553         },
554         {
555             init: ["qmark x"],
556             multiOutput: ["", "m", "x"],
557             completions: [["", hasItems]]
558         }
559     ],
560     quit: {
561         error: ["foo"]
562     },
563     quitall: {
564         error: ["!", "foo"]
565     },
566     redraw: {
567         error: ["!", "foo"],
568         noOutput: [""]
569     },
570     rehash: {
571         error: ["!"]
572     },
573     reload: {
574         error: ["foo"],
575         noOutput: [""]
576     },
577     reloadall: {
578         error: ["foo"],
579         noOutput: [""]
580     },
581     restart: {
582         error: ["!", "foo"]
583     },
584     runtime: {
585         init: [
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\"')",
591         ],
592         cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
593         noOutput: [
594             "some-nonexistent/good.css",
595             "some-nonexistent/good.js",
596             "some-nonexistent/good.penta"
597         ],
598         error: [
599             "",
600             "some-nonexistent/bad.js",
601             "some-nonexistent/bad.penta"
602         ],
603         singleOutput: ["some-nonexistent-file.js"],
604         completions: [
605             ["", hasItems],
606             ["some-nonexistent/", hasItems],
607             ["info/", hasItems]
608         ]
609     },
610     sanitize: {
611         // Skip details for now.
612         completions: [
613             ["", function (context) ["all",
614                                      "cache",
615                                      "downloads",
616                                      "formdata",
617                                      "offlineapps",
618                                      "passwords",
619                                      "sessions",
620                                      "cookies",
621                                      "history",
622                                      "host",
623                                      "sitesettings",
624                                      "commandline",
625                                      "messages",
626                                      "macros",
627                                      "marks",
628                                      "options"
629                 ].every(function (item) context.allItems.items.some(function ({ text }) item == text))
630             ],
631             "-",
632             "-host=",
633             "-timespan="
634         ]
635     },
636     saveas: {},
637     sbclose: {
638         error: ["!", "foo"],
639         noOutput: [""]
640     },
641     scriptnames: {
642         error: ["!", "foo"]
643     },
644     set: {
645         multiOutput: [
646             "vb?", "cpt?", "messages?", "titlestring?", "au?", "eht?",
647             "cpt", "messages", "titlestring", "au", "eht", "! "
648         ],
649         noOutput: ["vb", "novb"],
650         completions: [
651             ["", hasItems],
652             ["c", hasItems],
653             ["cpt=", hasItems],
654             ["cpt=l", hasItems],
655             ["cpt+=", hasItems],
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]
667         ]
668     },
669     get setglobal() this.set,
670     get setlocal() this.set,
671     sidebar: {
672         error: ["!", ""],
673         test: function (name) [
674             ["! " + name, sidebarState(name)],
675             [name, sidebarState(name)],
676             ["! " + name, sidebarState(false)]
677         ],
678         get noOutput()
679             Array.concat.apply([],
680                 ["Add-ons", // Final "! Add-ons" currently failing
681                  "Bookmarks",
682                  "Downloads",
683                  "Console",
684                  "History",
685                  "Preferences"]
686             .map(this.test))
687             .concat([
688                 ["Preferences", sidebarState("Preferences")],
689                 ["!", sidebarState(false)]
690             ]),
691         completions: [
692             ["", hasntNullItems],
693             "! "
694         ]
695     },
696     silent: {
697         error: ["!"],
698         noOutput: [
699             "echo 'foo'",
700             "echo " + "foo\nbar".quote(),
701             "echoerr 'foo'",
702             "echoerr " + "foo\nbar".quote()
703         ],
704         completions: [["", hasItems]]
705     },
706     get source() ({
707         init: this.runtime.init,
708         cleanup: this.runtime.cleanup,
709         noOutput: [
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"
714         ],
715         error: [
716             "",
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"
725         ],
726         completions: [
727             ["", hasItems],
728             [".pentadactyl/some-nonexistent/", hasItems],
729             ["chrome://browser/content/", hasItems],
730             ["resource://dactyl/", hasItems]
731         ]
732     }),
733     stop: {
734         error: ["!", "foo"],
735         noOutput: [""]
736     },
737     stopall: {
738         error: ["!", "foo"],
739         noOutput: [""]
740     },
741     style: {
742         error: ["!"],
743         cleanup: ["delstyle -n foo"],
744         noOutput: [
745             "-name=foo http://does.not.exist/* div { display: inline; }",
746             "-name=foo -append http://does.not.exist/* span { display: block; }"
747         ],
748         multiOutput: [
749             "",
750             "-name=foo"
751         ],
752         completions: [
753             ["", hasItems],
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]
759         ]
760     },
761     styledisable: {
762         init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
763         cleanup: ["delstyle -n foo", "delstyle -n bar"],
764         completions: [
765             ["", hasItems],
766             ["-name=", hasNItems(1)],
767             ["-index=", hasNItems(1)]
768         ],
769         noOutput: ["-name=foo", "-name=bar"]
770     },
771     get styleenable() this.styledisable,
772     styletoggle: {
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"],
776         completions: [
777             ["", hasItems],
778             ["-name=", hasNItems(2)],
779             ["-index=", hasNItems(2)]
780         ]
781     },
782     tab: {
783         error: ["!", "", "some-nonexistent-command"],
784         noOutput: ["js ''"],
785         anyOutput: ["echo 'foo'"],
786         completions: [["", hasItems]]
787     },
788     tabattach: {
789         error: ["!", ""]
790     },
791     tabdetach: {
792         error: ["!", "foo"]
793     },
794     tabdo: {
795         error: ["!", "", "some-nonexistent-command"],
796         noOutput: ["js ''"],
797         anyOutput: ["echo 'foo'"],
798         completions: [["", hasItems]]
799     },
800     tabduplicate: {
801         error: ["foo"]
802     },
803     tablast: {
804         error: ["!", "foo"]
805     },
806     tabmove: {
807         error: [""],
808         noOutput: ["1", "$", "999", "-1", "+1", "! +1", "! -1", "-999", "+999", "! +999", "! -999"],
809         completions: [
810             ["", hasItems],
811             ["1", hasItems]
812         ]
813     },
814     tabnext: {
815         error: ["!", "foo"]
816     },
817     tabonly: {
818         error: ["!", "foo"]
819     },
820     tabopen: {},
821     tabprevious: {
822         error: ["!", "foo"]
823     },
824     tabrewind: {
825         error: ["!", "foo"]
826     },
827     time: {
828         error: ["", ":some-nonexistent-command"/*, "some_nonexistent_reference"*/], // FIXME
829         singleOutput: [":js null", "null"]
830     },
831     get tlistkeys() this.listcommands,
832     tmap: {},
833     tnoremap: {},
834     toolbarhide: {
835         init: [
836             ["tbs Navigation Toolbar", toolbarState("#nav-bar", true)],
837             ["tbs Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
838         ],
839         completions: [["", hasItems]],
840         noOutput: [
841             ["Navigation Toolbar", toolbarState("#nav-bar", false)],
842             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
843         ],
844         error: ["!", "", "foo"]
845     },
846     toolbarshow: {
847         completions: [["", hasItems]],
848         noOutput: [
849             ["Navigation Toolbar", toolbarState("#nav-bar", true)],
850             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
851         ],
852         error: ["!", "", "foo"]
853     },
854     toolbartoggle: {
855         completions: [["", hasItems]],
856         noOutput: [
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)]
863         ],
864         error: ["!", "", "foo"]
865     },
866     tunmap: {},
867     unabbreviate: {
868         noOutput: ["abc", "! "],
869         error: [""]
870     },
871     undo: {
872         error: ["!"]
873     },
874     undoall: {
875         error: ["!", "foo"]
876     },
877     unpintab: {
878         error: ["!"]
879     },
880     unlet: {
881         error: [""],
882     },
883     unmap: {
884         noOutput: [
885             "i",
886             "! "
887         ],
888         error: [
889             "i",
890             "-group=builtin k",
891             "! -group=builtin"
892         ],
893         completions: [
894             "",
895             "-group="
896         ]
897     },
898     verbose: {
899         error: ["!", ""]
900     },
901     version: {
902         error: ["foo"],
903         multiOutput: [
904             ["", function (msg) {
905                 var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/.exec(msg);
906                 return res && res[2] != "null" && res[3] != "null";
907             }]
908         ]
909     },
910     viewsource: {},
911     get vlistkeys() this.listcommands,
912     vmap: {},
913     vnoremap: {},
914     vunmap: {},
915     winclose: {
916         error: ["!", "foo"]
917     },
918     window: {
919         error: ["!", ""]
920     },
921     winonly: {
922         error: ["!", "foo"]
923     },
924     winopen: {
925         error: ["!"]
926     },
927     wqall: {
928         error: ["!", "foo"]
929     },
930     yank: {
931         multiOutput: [
932             ["foo".quote(), /foo/],
933             [":echo " + "bar".quote(), /bar/],
934             [":addons", /Pentadactyl/]
935         ],
936         error: [
937             "!", "",
938             ":echoerr " + "foo".quote()
939         ],
940         completions: [
941             ["", hasItems],
942             [":", hasItems]
943         ]
944     },
945     zoom: {}
946 };
947
948 var global = this;
949 function addTest(cmdName, testName, func) {
950     global["testCommand_" + cmdName + "_" + testName] = func;
951 }
952
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);
957
958             dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
959             dactyl.clearMessage();
960             dactyl.closeMessageWindow();
961
962             cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
963             if (forbidErrors)
964                 dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
965                                              null, [], cmd);
966             else
967                 dactyl.runExCommand(cmd);
968             controller.waitForPageLoad(controller.tabs.activeTab);
969
970             test(cmd, testVal);
971         });
972     });
973 }
974 function _runCommands(cmdName, testName, commands) {
975     addTest(cmdName, testName, function () {
976         commands.forEach(function (value) {
977             var [cmd, test] = Array.concat(value);
978
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,
983                     test);
984         });
985     });
986 }
987
988 function runTest(message, test, ...args) {
989     if (test)
990         var res = test.apply(null, args);
991     if (res !== undefined)
992         jumlib.assert(res, message);
993 }
994
995 for (var val in Iterator(tests)) (function ([command, paramsList]) {
996     Array.concat(paramsList).forEach(function (params, i) {
997         if (params.init)
998             _runCommands(command, "init" + (i || ""), params.init);
999
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 || "");
1003
1004             switch (test) {
1005             case "noOutput":
1006                 runCommands(command, testName, commands, function (cmd, test) {
1007                     var res = dactyl.assertMessage(function (msg) !msg, "Unexpected command output: " + cmd);
1008                     if (res && test)
1009                         dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1010                 });
1011                 break;
1012             case "anyOutput":
1013                 runCommands(command, testName, commands, function (cmd, test) {
1014                     if (test)
1015                         dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1016                 });
1017                 break;
1018             case "someOutput":
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());
1023                 });
1024                 break;
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);
1031                 break;
1032             case "multiOutput":
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);
1038                 break;
1039             case "error":
1040                 addTest(command, testName, function () {
1041                     commands.forEach(function (val) {
1042                         var [cmd, test] = Array.concat(val);
1043                         cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1044
1045                         var res = dactyl.assertMessageError(function () {
1046                             dactyl.runExCommand(cmd);
1047                             controller.waitForPageLoad(controller.tabs.activeTab);
1048                         }, null, [], cmd);
1049
1050                         if (res && test != null)
1051                             dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1052                     });
1053                 });
1054                 break;
1055             case "completions":
1056                 addTest(command, testName, function () {
1057                     commands.forEach(function (val) {
1058                         var [cmd, test] = Array.concat(val);
1059                         cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1060
1061                         dactyl.assertNoErrorMessages(function () {
1062                             dump("COMPL: " + cmd + "\n");
1063                             var context = dactyl.runExCompletion(cmd);
1064                             if (context)
1065                                 runTest("Completion tests failed: " + cmd.quote() + " " + test,
1066                                         test, context);
1067                         });
1068                     });
1069                 });
1070                 break;
1071             }
1072         })(val);
1073
1074         if (params.cleanup)
1075             _runCommands(command, "cleanup" + (i || ""), params.cleanup);
1076     });
1077 })(val);
1078
1079 // vim: sw=4 ts=8 et: