]> git.donarmstrong.com Git - dactyl.git/blob - common/tests/functional/testCommands.js
Import 1.0b7.1 supporting Firefox up to 8.*
[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: ["dactyl.sf.net", "dactyl.sf.net list"],
161         error: ["!", ""],
162         completions: [
163             "",
164             ["dactyl.sf.net ", 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     mksyntax: {
478         noOutput: [
479             "some-nonexistent-pentadactyl-dir/",
480             "! some-nonexistent-pentadactyl-dir/",
481             "some-nonexistent-pentadactyl-dir/foo.vim",
482             "! some-nonexistent-pentadactyl-dir/foo.vim",
483         ],
484         error: [
485             "some-nonexistent-pentadactyl-dir/",
486             "some-nonexistent-pentadactyl-dir/foo.vim"
487         ],
488         completions: [
489             ["", hasItems]
490         ],
491         cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
492     },
493     get mlistkeys() this.listcommands,
494     mmap: {},
495     mnoremap: {},
496     munmap: {},
497     get nlistkeys() this.listcommands,
498     nmap: {},
499     nnoremap: {},
500     nohlfind: {
501         error: ["!", "foo"]
502     },
503     noremap: {},
504     normal: {
505         error: [""],
506         noOutput: ["<Nop>"],
507         singleOutput: ["<C-g>"],
508         multiOutput: ["g<C-g>"]
509     },
510     nunmap: {},
511     open: {
512         error: ["!"],
513         noOutput: ["about:blank | about:home"],
514         completions: [
515             ["", hasItems],
516             ["./", hasItems],
517             ["./ | ", hasItems], // FIXME: broken feature
518             ["chrome://", hasItems],
519             ["chrome://browser/", hasItems],
520             ["chrome://browser/content/", hasItems],
521             ["about:", hasItems],
522             ["resource://", hasItems],
523             ["resource://dactyl/", hasItems]
524         ]
525     },
526     pageinfo: {
527         multiOutput: ["", "fgm"],
528         completions: [["", hasItems]],
529         error: ["!", "abcdefghijklmnopqrstuvwxyz", "f g m"]
530     },
531     pagestyle: {
532         error: ["!"],
533         completions: [""]
534     },
535     pintab: {},
536     preferences: {
537         error: ["foo"]
538     },
539     pwd: {
540         error: ["!", "foo"],
541         singleOutput: [""]
542     },
543     qmark: {
544         singleOutput: [
545             "m",
546             "m foo bar"
547         ],
548         error: ["!", "", "#"],
549         completions: [
550             ["", hasItems],
551             ["m ", hasItems]
552         ]
553     },
554     qmarks: [
555         {
556             error: ["!"]
557         },
558         {
559             init: ["delqmarks a-zA-Z0-9"],
560             error: ["", "x"],
561         },
562         {
563             init: ["qmark x"],
564             multiOutput: ["", "m", "x"],
565             completions: [["", hasItems]]
566         }
567     ],
568     quit: {
569         error: ["foo"]
570     },
571     quitall: {
572         error: ["!", "foo"]
573     },
574     redraw: {
575         error: ["!", "foo"],
576         noOutput: [""]
577     },
578     rehash: {
579         error: ["!"]
580     },
581     reload: {
582         error: ["foo"],
583         noOutput: [""]
584     },
585     reloadall: {
586         error: ["foo"],
587         noOutput: [""]
588     },
589     restart: {
590         error: ["!", "foo"]
591     },
592     runtime: {
593         init: [
594             "js File('~/.pentadactyl/some-nonexistent/good.css').write('')",
595             "js File('~/.pentadactyl/some-nonexistent/good.js').write('')",
596             "js File('~/.pentadactyl/some-nonexistent/bad.js').write('dactyl.echoerr(\"error\")')",
597             "js File('~/.pentadactyl/some-nonexistent/good.penta').write('')",
598             "js File('~/.pentadactyl/some-nonexistent/bad.penta').write('echoerr \"error\"')",
599         ],
600         cleanup: ["js File('~/.pentadactyl/some-nonexistent').remove(true)"],
601         noOutput: [
602             "some-nonexistent/good.css",
603             "some-nonexistent/good.js",
604             "some-nonexistent/good.penta"
605         ],
606         error: [
607             "",
608             "some-nonexistent/bad.js",
609             "some-nonexistent/bad.penta"
610         ],
611         singleOutput: ["some-nonexistent-file.js"],
612         completions: [
613             ["", hasItems],
614             ["some-nonexistent/", hasItems],
615             ["info/", hasItems]
616         ]
617     },
618     sanitize: {
619         // Skip details for now.
620         completions: [
621             ["", function (context) ["all",
622                                      "cache",
623                                      "downloads",
624                                      "formdata",
625                                      "offlineapps",
626                                      "passwords",
627                                      "sessions",
628                                      "cookies",
629                                      "history",
630                                      "host",
631                                      "sitesettings",
632                                      "commandline",
633                                      "messages",
634                                      "macros",
635                                      "marks",
636                                      "options"
637                 ].every(function (item) context.allItems.items.some(function ({ text }) item == text))
638             ],
639             "-",
640             "-host=",
641             "-timespan="
642         ]
643     },
644     saveas: {},
645     sbclose: {
646         error: ["!", "foo"],
647         noOutput: [""]
648     },
649     scriptnames: {
650         error: ["!", "foo"]
651     },
652     set: {
653         multiOutput: [
654             "vb?", "cpt?", "messages?", "titlestring?", "au?", "eht?",
655             "cpt", "messages", "titlestring", "au", "eht", "! "
656         ],
657         noOutput: ["vb", "novb"],
658         completions: [
659             ["", hasItems],
660             ["c", hasItems],
661             ["cpt=", hasItems],
662             ["cpt=l", hasItems],
663             ["cpt+=", hasItems],
664             ["cpt+=f", hasItems],
665             ["activate=", hasItems],
666             ["activate=links,", hasItems],
667             ["activate+=", hasItems],
668             ["activate+=links,", hasItems],
669             ["activate^=", hasItems],
670             ["activate^=links,", hasItems],
671             ["activate-=", hasItems],
672             ["activate-=links,", hasItems],
673             ["activate!=", hasItems],
674             ["activate!=links,", hasItems]
675         ]
676     },
677     get setglobal() this.set,
678     get setlocal() this.set,
679     sidebar: {
680         error: ["!", ""],
681         test: function (name) [
682             ["! " + name, sidebarState(name)],
683             [name, sidebarState(name)],
684             ["! " + name, sidebarState(false)]
685         ],
686         get noOutput()
687             Array.concat.apply([],
688                 ["Add-ons", // Final "! Add-ons" currently failing
689                  "Bookmarks",
690                  "Downloads",
691                  "Console",
692                  "History",
693                  "Preferences"]
694             .map(this.test))
695             .concat([
696                 ["Preferences", sidebarState("Preferences")],
697                 ["!", sidebarState(false)]
698             ]),
699         completions: [
700             ["", hasntNullItems],
701             "! "
702         ]
703     },
704     silent: {
705         error: ["!"],
706         noOutput: [
707             "echo 'foo'",
708             "echo " + "foo\nbar".quote(),
709             "echoerr 'foo'",
710             "echoerr " + "foo\nbar".quote()
711         ],
712         completions: [["", hasItems]]
713     },
714     get source() ({
715         init: this.runtime.init,
716         cleanup: this.runtime.cleanup,
717         noOutput: [
718             "! .pentadactyl/some-nonexistent/really-nonexistent.js",
719             ".pentadactyl/some-nonexistent/good.css",
720             ".pentadactyl/some-nonexistent/good.js",
721             ".pentadactyl/some-nonexistent/good.penta"
722         ],
723         error: [
724             "",
725             ".pentadactyl/some-nonexistent/really-nonexistent.js",
726             "~/.pentadactyl/some-nonexistent/bad.js",
727             "~/.pentadactyl/some-nonexistent/bad.penta",
728             "./.pentadactyl/some-nonexistent/bad.js",
729             "./.pentadactyl/some-nonexistent/bad.penta",
730             ".pentadactyl/some-nonexistent/bad.js",
731             ".pentadactyl/some-nonexistent/bad.penta",
732             ".pentadactyl/some-nonexistent-file.js"
733         ],
734         completions: [
735             ["", hasItems],
736             [".pentadactyl/some-nonexistent/", hasItems],
737             ["chrome://browser/content/", hasItems],
738             ["resource://dactyl/", hasItems]
739         ]
740     }),
741     stop: {
742         error: ["!", "foo"],
743         noOutput: [""]
744     },
745     stopall: {
746         error: ["!", "foo"],
747         noOutput: [""]
748     },
749     style: {
750         error: ["!"],
751         cleanup: ["delstyle -n foo"],
752         noOutput: [
753             "-name=foo http://does.not.exist/* div { display: inline; }",
754             "-name=foo -append http://does.not.exist/* span { display: block; }"
755         ],
756         multiOutput: [
757             "",
758             "-name=foo"
759         ],
760         completions: [
761             ["", hasItems],
762             ["-name=", hasItems],
763             ["http:* div { -moz", hasItems],
764             ["http:* div { foo: bar; -moz", hasItems],
765             ["http:* div { foo: bar; } span { -moz", hasItems],
766             ["http:* div { foo: bar; } span { foo: bar; -moz", hasItems]
767         ]
768     },
769     styledisable: {
770         init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
771         cleanup: ["delstyle -n foo", "delstyle -n bar"],
772         completions: [
773             ["", hasItems],
774             ["-name=", hasNItems(1)],
775             ["-index=", hasNItems(1)]
776         ],
777         noOutput: ["-name=foo", "-name=bar"]
778     },
779     get styleenable() this.styledisable,
780     styletoggle: {
781         init: ["style -n foo http:* div {}", "style -n bar ftp:* div", "styledisable -n bar"],
782         cleanup: ["delstyle -n foo", "delstyle -n bar"],
783         noOutput: ["-name=foo"],
784         completions: [
785             ["", hasItems],
786             ["-name=", hasNItems(2)],
787             ["-index=", hasNItems(2)]
788         ]
789     },
790     tab: {
791         error: ["!", "", "some-nonexistent-command"],
792         noOutput: ["js ''"],
793         anyOutput: ["echo 'foo'"],
794         completions: [["", hasItems]]
795     },
796     tabattach: {
797         error: ["!", ""]
798     },
799     tabdetach: {
800         error: ["!", "foo"]
801     },
802     tabdo: {
803         error: ["!", "", "some-nonexistent-command"],
804         noOutput: ["js ''"],
805         anyOutput: ["echo 'foo'"],
806         completions: [["", hasItems]]
807     },
808     tabduplicate: {
809         error: ["foo"]
810     },
811     tablast: {
812         error: ["!", "foo"]
813     },
814     tabmove: {
815         error: [""],
816         noOutput: ["1", "$", "999", "-1", "+1", "! +1", "! -1", "-999", "+999", "! +999", "! -999"],
817         completions: [
818             ["", hasItems],
819             ["1", hasItems]
820         ]
821     },
822     tabnext: {
823         error: ["!", "foo"]
824     },
825     tabonly: {
826         error: ["!", "foo"]
827     },
828     tabopen: {},
829     tabprevious: {
830         error: ["!", "foo"]
831     },
832     tabrewind: {
833         error: ["!", "foo"]
834     },
835     time: {
836         error: ["", ":some-nonexistent-command"/*, "some_nonexistent_reference"*/], // FIXME
837         singleOutput: [":js null", "null"]
838
839     },
840     get tlistkeys() this.listcommands,
841     tmap: {},
842     tnoremap: {},
843     toolbarhide: {
844         init: [
845             ["tbs Navigation Toolbar", toolbarState("#nav-bar", true)],
846             ["tbs Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
847         ],
848         completions: [["", hasItems]],
849         noOutput: [
850             ["Navigation Toolbar", toolbarState("#nav-bar", false)],
851             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
852         ],
853         error: ["!", "", "foo"]
854     },
855     toolbarshow: {
856         completions: [["", hasItems]],
857         noOutput: [
858             ["Navigation Toolbar", toolbarState("#nav-bar", true)],
859             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)]
860         ],
861         error: ["!", "", "foo"]
862     },
863     toolbartoggle: {
864         completions: [["", hasItems]],
865         noOutput: [
866             ["Navigation Toolbar", toolbarState("#nav-bar", false)],
867             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)],
868             ["Navigation Toolbar", toolbarState("#nav-bar", true)],
869             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", true)],
870             ["Navigation Toolbar", toolbarState("#nav-bar", false)],
871             ["Bookmarks Toolbar", toolbarState("#PersonalToolbar", false)]
872         ],
873         error: ["!", "", "foo"]
874     },
875     tunmap: {},
876     unabbreviate: {
877         noOutput: ["abc", "! "],
878         error: [""]
879     },
880     undo: {
881         error: ["!"]
882     },
883     undoall: {
884         error: ["!", "foo"]
885     },
886     unpintab: {
887         error: ["!"]
888     },
889     unlet: {
890         error: [""],
891     },
892     unmap: {
893         noOutput: [
894             "i",
895             "! "
896         ],
897         error: [
898             "i",
899             "-group=builtin k",
900             "! -group=builtin"
901         ],
902         completions: [
903             "",
904             "-group="
905         ]
906     },
907     verbose: {
908         error: ["!", ""]
909     },
910     version: {
911         error: ["foo"],
912         multiOutput: [
913             ["", function (msg) {
914                 var res = /(\w+dactyl) (\S+) \(([\^)]+)\) running on:\nMozilla/;
915                 return res && res[2] != "null" && res[3] != "null";
916             }]
917         ]
918     },
919     viewsource: {},
920     get vlistkeys() this.listcommands,
921     vmap: {},
922     vnoremap: {},
923     vunmap: {},
924     winclose: {
925         error: ["!", "foo"]
926     },
927     window: {
928         error: ["!", ""]
929     },
930     winonly: {
931         error: ["!", "foo"]
932     },
933     winopen: {
934         error: ["!"]
935     },
936     wqall: {
937         error: ["!", "foo"]
938     },
939     yank: {
940         multiOutput: [
941             ["foo".quote(), /foo/],
942             [":echo " + "bar".quote(), /bar/],
943             [":addons", /Pentadactyl/]
944         ],
945         error: [
946             "!", "",
947             ":echoerr " + "foo".quote()
948         ],
949         completions: [
950             ["", hasItems],
951             [":", hasItems]
952         ]
953     },
954     zoom: {}
955 };
956
957 var global = this;
958 function addTest(cmdName, testName, func) {
959     global["testCommand_" + cmdName + "_" + testName] = func;
960 }
961
962 function runCommands(cmdName, testName, commands, test, forbidErrors) {
963     addTest(cmdName, testName, function () {
964         commands.forEach(function (val) {
965             var [cmd, testVal] = Array.concat(val);
966
967             dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
968             dactyl.clearMessage();
969             dactyl.closeMessageWindow();
970
971             cmd = cmdName + cmd.replace(/^(!?) ?/, "$1 ");
972             if (forbidErrors)
973                 dactyl.assertNoErrorMessages(function () { dactyl.runExCommand(cmd) },
974                                              null, [], cmd);
975             else
976                 dactyl.runExCommand(cmd);
977             controller.waitForPageLoad(controller.tabs.activeTab);
978
979             test(cmd, testVal);
980         });
981     });
982 }
983 function _runCommands(cmdName, testName, commands) {
984     addTest(cmdName, testName, function () {
985         commands.forEach(function (value) {
986             var [cmd, test] = Array.concat(value);
987
988             dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
989             var res = dactyl.runExCommand(cmd);
990             controller.waitForPageLoad(controller.tabs.activeTab);
991             runTest("Initializing for " + cmdName + " tests failed: " + cmd.quote() + " " + test,
992                     test);
993         });
994     });
995 }
996
997 function runTest(message, test) {
998     if (test)
999         var res = test.apply(null, Array.slice(arguments, runTest.length));
1000     if (res !== undefined)
1001         jumlib.assert(res, message);
1002 }
1003
1004 for (var val in Iterator(tests)) (function ([command, paramsList]) {
1005     Array.concat(paramsList).forEach(function (params, i) {
1006         if (params.init)
1007             _runCommands(command, "init" + (i || ""), params.init);
1008
1009         // Goddamn stupid fucking MozMill and its stupid fucking sandboxes with their ancient fucking JS versions.
1010         for (var val in Iterator(params)) (function ([test, commands]) {
1011             var testName = test + (i || "");
1012
1013             switch (test) {
1014             case "noOutput":
1015                 runCommands(command, testName, commands, function (cmd, test) {
1016                     var res = dactyl.assertMessage(function (msg) !msg, "Unexpected command output: " + cmd);
1017                     if (res && test)
1018                         dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1019                 });
1020                 break;
1021             case "anyOutput":
1022                 runCommands(command, testName, commands, function (cmd, test) {
1023                     if (test)
1024                         dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1025                 });
1026                 break;
1027             case "someOutput":
1028                 runCommands(command, testName, commands, function (cmd, test) {
1029                     var res = dactyl.assertMessage(/./, "Expected command output: " + cmd);
1030                     if (res && test != null)
1031                         dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1032                 });
1033                 break;
1034             case "singleOutput":
1035                 runCommands(command, testName, commands, function (cmd, test) {
1036                     var res = dactyl.assertMessageLine(/./, "Expected command output: " + cmd);
1037                     if (res && test != null)
1038                         dactyl.assertMessageLine(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1039                 }, !params.errorsOk);
1040                 break;
1041             case "multiOutput":
1042                 runCommands(command, testName, commands, function (cmd, test) {
1043                     var res = dactyl.assertMessageWindowOpen(true, "Expected command output: " + cmd);
1044                     if (res && test != null)
1045                         dactyl.assertMessageWindow(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1046                 }, !params.errorsOk);
1047                 break;
1048             case "error":
1049                 addTest(command, testName, function () {
1050                     commands.forEach(function (val) {
1051                         var [cmd, test] = Array.concat(val);
1052                         cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1053
1054                         var res = dactyl.assertMessageError(function () {
1055                             dactyl.runExCommand(cmd);
1056                             controller.waitForPageLoad(controller.tabs.activeTab);
1057                         }, null, [], cmd);
1058
1059                         if (res && test != null)
1060                             dactyl.assertMessage(test, "Running " + testName + " tests failed: " + cmd.quote() + " " + test.toSource());
1061                     });
1062                 });
1063                 break;
1064             case "completions":
1065                 addTest(command, testName, function () {
1066                     commands.forEach(function (val) {
1067                         var [cmd, test] = Array.concat(val);
1068                         cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
1069
1070                         dactyl.assertNoErrorMessages(function () {
1071                             dump("COMPL: " + cmd + "\n");
1072                             var context = dactyl.runExCompletion(cmd);
1073                             if (context)
1074                                 runTest("Completion tests failed: " + cmd.quote() + " " + test,
1075                                         test, context);
1076                         });
1077                     });
1078                 });
1079                 break;
1080             }
1081         })(val);
1082
1083         if (params.cleanup)
1084             _runCommands(command, "cleanup" + (i || ""), params.cleanup);
1085     });
1086 })(val);
1087
1088 // vim: sw=4 ts=8 et: