2 # Copyright Simon Lydell 2015, 2016.
4 # This file is part of VimFx.
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
20 assert = require('./assert')
21 testUtils = require('./utils')
22 createConfigAPI = require('../lib/api')
23 defaults = require('../lib/defaults')
24 prefs = require('../lib/prefs')
25 utils = require('../lib/utils')
27 exports['test exports'] = ($vimfx) ->
28 vimfx = createConfigAPI($vimfx)
30 assert.equal(typeof vimfx.get, 'function', 'get')
31 assert.equal(typeof vimfx.getDefault, 'function', 'getDefault')
32 assert.equal(typeof vimfx.set, 'function', 'set')
33 assert.equal(typeof vimfx.addCommand, 'function', 'addCommand')
34 assert.equal(typeof vimfx.addOptionOverrides, 'function',
36 assert.equal(typeof vimfx.addKeyOverrides, 'function', 'addKeyOverrides')
37 assert.equal(typeof vimfx.send, 'function', 'send')
38 assert.equal(typeof vimfx.on, 'function', 'on')
39 assert.equal(typeof vimfx.off, 'function', 'off')
40 assert.equal(vimfx.modes, $vimfx.modes, 'modes')
42 exports['test vimfx.get and vimfx.set'] = ($vimfx, teardown) ->
43 vimfx = createConfigAPI($vimfx)
45 resetHintChars = prefs.tmp('hints.chars', 'ab cd')
46 resetBlacklist = prefs.tmp('blacklist', null)
47 originalOptions = Object.assign({}, $vimfx.options)
51 $vimfx.options = originalOptions
54 assert.equal(vimfx.get('hints.chars'), 'ab cd')
55 assert.ok(not prefs.has('blacklist'))
57 vimfx.set('hints.chars', 'xy z')
58 assert.equal(vimfx.get('hints.chars'), 'xy z')
60 vimfx.set('blacklist', 'test')
61 assert.equal(vimfx.get('blacklist'), 'test')
63 vimfx.set('translations', {KeyQ: ['ö', 'Ö']})
64 assert.arrayEqual(Object.keys(vimfx.get('translations')), ['KeyQ'])
65 assert.arrayEqual(vimfx.get('translations').KeyQ, ['ö', 'Ö'])
67 $vimfx.emit('shutdown')
68 assert.equal(vimfx.get('hints.chars'), 'ab cd')
69 assert.ok(not prefs.has('blacklist'))
70 assert.arrayEqual(Object.keys(vimfx.get('translations')), [])
72 exports['test vimfx.getDefault'] = ($vimfx, teardown) ->
73 vimfx = createConfigAPI($vimfx)
75 reset = prefs.tmp('hints.chars', 'ab cd')
80 assert.equal(vimfx.getDefault('hints.chars'), defaults.options['hints.chars'])
82 exports['test customization'] = ($vimfx, teardown) ->
83 vimfx = createConfigAPI($vimfx)
85 originalOptions = Object.assign({}, $vimfx.options)
86 originalCategories = Object.assign({}, $vimfx.options.categories)
87 $vimfx.options.keyValidator = null
88 $vimfx.options.ignore_keyboard_layout = true
89 vimfx.set('translations', {KeyQ: ['ö', 'Ö']})
91 $vimfx.options = originalOptions
92 $vimfx.options.categories = originalCategories
93 delete $vimfx.modes.normal.commands.test_command
94 delete $vimfx.modes.ignore.commands.test_command
98 event = {code: 'KeyQ', key: 'q'}
100 # Add a simple test command.
103 description: 'Test command'
105 vimfx.set('custom.mode.normal.test_command', 'ö')
107 # Add a slightly more complex command.
108 vimfx.get('categories')['new_category'] = {
114 description: 'Test ignore mode command'
116 category: 'new_category'
118 vimfx.set('custom.mode.ignore.test_command', 'ö <ö> <c-c-invalid>')
120 $vimfx.createKeyTrees()
122 # Test that the new simple command can be run.
123 $vimfx.reset('normal')
124 match = $vimfx.consumeKeyEvent(event, {mode: 'normal', focusType: 'none'})
125 assert.equal(match.type, 'full')
126 assert.equal(match.command.run(), nonce)
128 # Test that the new complex command can be run.
129 $vimfx.reset('ignore')
130 match = $vimfx.consumeKeyEvent(event, {mode: 'ignore', focusType: 'none'})
131 assert.equal(match.type, 'full')
132 assert.equal(match.command.run(), nonce)
134 modes = $vimfx.getGroupedCommands({enabledOnly: true})
136 # Test that the new simple command can show up in the help dialog.
137 mode_normal = modes.find((mode) -> mode._name == 'normal')
138 category_misc = mode_normal.categories.find(
139 (category) -> category._name == 'misc'
141 [..., {command: test_command}] = category_misc.commands
142 assert.equal(test_command.description, 'Test command')
144 # Test that the new complex command can show up in the help dialog.
145 mode_ignore = modes.find((mode) -> mode._name == 'ignore')
146 [category_new] = mode_ignore.categories
147 assert.equal(category_new.name, 'New category')
148 [test_command] = category_new.commands
149 assert.equal(test_command.command.description, 'Test ignore mode command')
150 assert.arrayEqual(test_command.enabledSequences, ['ö'])
152 # Remove the added commands.
153 delete vimfx.modes.normal.commands.test_command
154 delete vimfx.modes.ignore.commands.test_command
155 $vimfx.createKeyTrees()
157 # Test that the new simple command cannot be run.
158 $vimfx.reset('normal')
159 match = $vimfx.consumeKeyEvent(event, {mode: 'normal', focusType: 'none'})
160 if match.type == 'full'
161 value = try match.command.run() catch then null
162 assert.notEqual(value, nonce)
164 # Test that the new complex command cannot be run.
165 $vimfx.reset('ignore')
166 match = $vimfx.consumeKeyEvent(event, {mode: 'ignore', focusType: 'none'})
167 if match.type == 'full'
168 value = try match.command.run() catch then null
169 assert.notEqual(value, nonce)
171 modes = $vimfx.getGroupedCommands({enabledOnly: true})
173 # Test that the new simple command cannot show up in the help dialog.
174 mode_normal = modes.find((mode) -> mode._name == 'normal')
175 category_misc = mode_normal.categories.find(
176 (category) -> category._name == 'misc'
178 [..., {command: last_command}] = category_misc.commands
179 assert.notEqual(last_command.description, 'Test command')
181 # Test that the new complex command cannot show up in the help dialog.
182 mode_ignore = modes.find((mode) -> mode._name == 'ignore')
183 [first_category] = mode_ignore.categories
184 assert.notEqual(first_category.name, 'New category')
186 exports['test vimfx.addCommand order'] = ($vimfx, teardown) ->
187 vimfx = createConfigAPI($vimfx)
190 delete vimfx.modes.normal.commands.test_command
195 description: 'Test command'
197 }, Function.prototype)
198 vimfx.set('custom.mode.normal.test_command', 'ö')
200 modes = $vimfx.getGroupedCommands()
201 mode_normal = modes.find((mode) -> mode._name == 'normal')
202 category_misc = mode_normal.categories.find(
203 (category) -> category._name == 'misc'
205 [{command: first_command}] = category_misc.commands
206 assert.equal(first_command.description, 'Test command')
208 assert.ok('test_command' of vimfx.modes.normal.commands)
209 $vimfx.emit('shutdown')
210 assert.ok('test_command' not of vimfx.modes.normal.commands)
212 exports['test vimfx.addOptionOverrides'] = ($vimfx, teardown) ->
213 vimfx = createConfigAPI($vimfx)
215 originalOptions = Object.assign({}, $vimfx.options)
216 originalOptionOverrides = $vimfx.optionOverrides?[..]
217 $vimfx.optionOverrides = null
218 $vimfx.options.prevent_autofocus = true
220 reset?() # Defined below.
221 $vimfx.options = originalOptions
222 $vimfx.optionOverrides = originalOptionOverrides
225 vimfx.addOptionOverrides(
227 (location) -> location.hostname == 'example.com'
228 {prevent_autofocus: false}
232 assert.equal($vimfx.options.prevent_autofocus, true)
234 reset = testUtils.stub(utils, 'getCurrentLocation', -> {
235 hostname: 'example.com'
238 assert.equal($vimfx.options.prevent_autofocus, false)
240 $vimfx.emit('shutdown')
241 assert.equal($vimfx.options.prevent_autofocus, true)
243 exports['test vimfx.addKeyOverrides'] = ($vimfx, teardown) ->
244 vimfx = createConfigAPI($vimfx)
246 originalOptions = Object.assign({}, $vimfx.options)
247 originalKeyOverrides = $vimfx.keyOverrides?[..]
248 $vimfx.options.keyValidator = null
249 $vimfx.options.ignore_keyboard_layout = false
250 $vimfx.options.translations = {}
252 resetScrollToBottom?() # Defined below.
253 resetExitIgnoreMode?() # Defined below.
254 resetGetCurrentLocation?() # Defined below.
255 $vimfx.options = originalOptions
256 $vimfx.keyOverrides = originalKeyOverrides
259 vimfx.addKeyOverrides(
261 (location) -> location.hostname == 'example.co'
265 (location) -> location.href == 'about:blank'
270 resetScrollToBottom = prefs.tmp('mode.normal.scroll_to_bottom', '<foobar>j')
271 resetExitIgnoreMode = prefs.tmp('mode.ignore.exit', '<escape>')
272 $vimfx.createKeyTrees()
273 $vimfx.reset('normal')
275 match = $vimfx.consumeKeyEvent(
276 {key: 'j'}, {mode: 'ignore', focusType: 'none'}
280 resetGetCurrentLocation = testUtils.stub(utils, 'getCurrentLocation', -> {
281 hostname: 'example.co'
285 match = $vimfx.consumeKeyEvent(
286 {key: '1'}, {mode: 'normal', focusType: 'none'}
288 assert.equal(match.type, 'count')
289 assert.equal(match.count, 1)
291 match = $vimfx.consumeKeyEvent(
292 {key: 'j'}, {mode: 'normal', focusType: 'none'}
296 match = $vimfx.consumeKeyEvent(
297 {key: 'foobar', ctrlKey: true},
298 {mode: 'normal', focusType: 'none'}
302 match = $vimfx.consumeKeyEvent(
304 {mode: 'normal', focusType: 'none'}
306 assert.equal(match.type, 'partial')
307 match = $vimfx.consumeKeyEvent(
309 {mode: 'normal', focusType: 'none'}
311 assert.equal(match.type, 'full')
312 assert.equal(match.count, undefined)
314 $vimfx.reset('ignore')
316 match = $vimfx.consumeKeyEvent(
318 {mode: 'ignore', focusType: 'none'}
322 match = $vimfx.consumeKeyEvent(
324 {mode: 'ignore', focusType: 'none'}
326 assert.equal(match.type, 'full')
329 $vimfx.emit('shutdown')
331 $vimfx.reset('normal')
332 match = $vimfx.consumeKeyEvent(
334 {mode: 'normal', focusType: 'none'}
338 $vimfx.reset('ignore')
339 match = $vimfx.consumeKeyEvent(
341 {mode: 'ignore', focusType: 'none'}
345 exports['test vimfx.send'] = ($vimfx) ->
346 vimfx = createConfigAPI($vimfx)
348 messageManager = new testUtils.MockMessageManager()
349 vim = new testUtils.MockVim(messageManager)
351 vimfx.send(vim, 'message', {example: 5})
352 assert.equal(messageManager.sendAsyncMessageCalls, 1)
353 assert.equal(messageManager.addMessageListenerCalls, 0)
354 assert.equal(messageManager.removeMessageListenerCalls, 0)
356 vimfx.send(vim, 'message2', null, ->)
357 assert.equal(messageManager.sendAsyncMessageCalls, 2)
358 assert.equal(messageManager.addMessageListenerCalls, 1)
359 assert.equal(messageManager.removeMessageListenerCalls, 0)
361 $vimfx.emit('shutdown')
362 assert.equal(messageManager.sendAsyncMessageCalls, 2)
363 assert.equal(messageManager.addMessageListenerCalls, 1)
364 assert.equal(messageManager.removeMessageListenerCalls, 0)
366 exports['test vimfx.on and vimfx.off'] = ($vimfx) ->
367 vimfx = createConfigAPI($vimfx)
370 count = -> callCount += 1
371 vimfx.on('foo', count)
372 vimfx.on('bar', count)
375 assert.equal(callCount, 1)
378 assert.equal(callCount, 2)
380 vimfx.off('bar', count)
382 assert.equal(callCount, 2)
384 $vimfx.emit('shutdown')
387 assert.equal(callCount, 2)
389 exports['test vimfx.[gs]et(Default)? errors'] = ($vimfx) ->
390 vimfx = createConfigAPI($vimfx)
392 assert.throws(/unknown option/i, 'undefined', ->
396 assert.throws(/unknown option/i, 'undefined', ->
400 assert.throws(/unknown option/i, 'undefined', ->
404 assert.throws(/unknown option/i, 'unknown_pref', ->
405 vimfx.get('unknown_pref')
408 assert.throws(/unknown option/i, 'unknown_pref', ->
409 vimfx.getDefault('unknown_pref')
412 assert.throws(/no default/i, 'custom.mode.normal.foo', ->
413 vimfx.getDefault('custom.mode.normal.foo')
416 assert.throws(/no default/i, 'translations', ->
417 vimfx.getDefault('translations')
420 assert.throws(/unknown option/i, 'unknown_pref', ->
421 vimfx.set('unknown_pref', 'foo')
424 assert.throws(/boolean, number, string or null/i, 'undefined', ->
425 vimfx.set('hints.chars')
428 assert.throws(/boolean, number, string or null/i, 'object', ->
429 vimfx.set('hints.chars', ['a', 'b', 'c'])
432 exports['test vimfx.addCommand errors'] = ($vimfx) ->
433 vimfx = createConfigAPI($vimfx)
435 assert.throws(/name.+string.+required/i, 'undefined', ->
439 assert.throws(/name.+a-z.+underscore/i, 'Command', ->
440 vimfx.addCommand({name: 'Command'})
443 assert.throws(/name.+a-z.+underscore/i, 'command-name', ->
444 vimfx.addCommand({name: 'command-name'})
447 assert.throws(/name.+a-z.+underscore/i, 'ö', ->
448 vimfx.addCommand({name: 'ö'})
451 assert.throws(/non-empty description/i, 'undefined', ->
452 vimfx.addCommand({name: 'test'})
455 assert.throws(/non-empty description/i, '', ->
456 vimfx.addCommand({name: 'test', description: ''})
459 assert.throws(/unknown mode.+available.+normal/i, 'toString', ->
460 vimfx.addCommand({name: 'test', description: 'Test', mode: 'toString'})
463 assert.throws(/unknown category.+available.+location/i, 'toString', ->
464 vimfx.addCommand({name: 'test', description: 'Test', category: 'toString'})
467 assert.throws(/order.+number/i, 'false', ->
468 vimfx.addCommand({name: 'test', description: 'Test', order: false})
471 assert.throws(/function/i, 'undefined', ->
472 vimfx.addCommand({name: 'test', description: 'Test'})
475 assert.throws(/function/i, 'false', ->
476 vimfx.addCommand({name: 'test_command', description: 'Test command'}, false)
479 exports['test vimfx.add{Option,Key}Overrides errors'] = ($vimfx) ->
480 vimfx = createConfigAPI($vimfx)
482 # Passing nothing is OK, and just shouldn’t throw.
483 vimfx.addOptionOverrides()
484 vimfx.addKeyOverrides()
486 assert.throws(/array/i, '1', ->
487 vimfx.addOptionOverrides(1)
490 assert.throws(/array/i, '1', ->
491 vimfx.addKeyOverrides(1)
494 assert.throws(/length 2/i, '0', ->
495 vimfx.addOptionOverrides([])
498 assert.throws(/length 2/i, '0', ->
499 vimfx.addKeyOverrides([])
502 assert.throws(/length 2/i, '1', ->
503 vimfx.addOptionOverrides([1])
506 assert.throws(/length 2/i, '1', ->
507 vimfx.addKeyOverrides([1])
510 assert.throws(/length 2/i, '3', ->
511 vimfx.addOptionOverrides([1, 2, 3])
514 assert.throws(/length 2/i, '3', ->
515 vimfx.addKeyOverrides([1, 2, 3])
518 assert.throws(/function/i, 'null', ->
519 vimfx.addOptionOverrides([null, 2])
522 assert.throws(/function/i, 'null', ->
523 vimfx.addKeyOverrides([null, 2])
526 assert.throws(/object/i, 'null', ->
527 vimfx.addOptionOverrides([(-> true), null])
530 assert.throws(/array of strings/i, '[object Object]', ->
531 vimfx.addKeyOverrides([(-> true), {j: false}])
534 assert.throws(/array of strings/i, '1,2', ->
535 vimfx.addKeyOverrides([(-> true), [1, 2]])
538 exports['test vimfx.{on,off} errors'] = ($vimfx) ->
539 vimfx = createConfigAPI($vimfx)
541 assert.throws(/string/i, 'undefined', ->
545 assert.throws(/string/i, 'undefined', ->
549 assert.throws(/string/i, '1', ->
553 assert.throws(/string/i, '1', ->
557 assert.throws(/function/i, 'undefined', ->
561 assert.throws(/function/i, 'undefined', ->
565 assert.throws(/function/i, 'null', ->
566 vimfx.on('event', null)
569 assert.throws(/function/i, 'null', ->
570 vimfx.off('event', null)
573 exports['test vimfx.send errors'] = ($vimfx) ->
574 vimfx = createConfigAPI($vimfx)
576 vim = new testUtils.MockVim()
578 assert.throws(/vim object/i, 'undefined', ->
582 assert.throws(/vim object/i, '[object Object]', ->
583 vimfx.send({mode: 'normal'})
586 assert.throws(/message string/i, 'undefined', ->
590 assert.throws(/message string/i, 'false', ->
591 vimfx.send(vim, false)
594 assert.throws(/not.+function/i, 'function() {}', ->
595 vimfx.send(vim, 'message', ->)
598 assert.throws(/if provided.+function/i, '5', ->
599 vimfx.send(vim, 'message', null, 5)