cover Vim edit-ops and extension edge branches
Lift line coverage back over the 95% floor after the Flutter 3.44.1 merge nudged it to 94.99%. Adds tests for the changeWord/no-op-edit/ empty-paste/word-motion-edge branches in vim_edit_ops, the lone-key flush path in SequenceMatcher, and the keybindings-ui / vim extension identity + deactivate paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -149,6 +149,43 @@ void main() {
|
||||
expect(r.enterInsert, isTrue);
|
||||
expect(r.register?.linewise, isTrue);
|
||||
});
|
||||
|
||||
test('cw deletes to the next word and enters insert', () {
|
||||
final r = applyVim(VimAction.changeWord, _tev('hello world', 0));
|
||||
expect(r.value.text, 'world');
|
||||
expect(r.enterInsert, isTrue);
|
||||
expect(r.register?.text, 'hello ');
|
||||
});
|
||||
|
||||
test('x at the line end is a no-op', () {
|
||||
final r = applyVim(VimAction.deleteChar, _tev('ab\ncd', 2)); // caret on the newline
|
||||
expect(r.value.text, 'ab\ncd');
|
||||
expect(r.register, isNull);
|
||||
});
|
||||
|
||||
test('D at the line end is a no-op', () {
|
||||
final r = applyVim(VimAction.deleteToEnd, _tev('ab', 2));
|
||||
expect(r.value.text, 'ab');
|
||||
});
|
||||
|
||||
test('p with an empty register does nothing', () {
|
||||
final r = applyVim(VimAction.paste, _tev('ab', 0));
|
||||
expect(r.value.text, 'ab');
|
||||
});
|
||||
});
|
||||
|
||||
group('word-motion edges', () {
|
||||
test('w / b cross punctuation and underscores as their own class', () {
|
||||
// foo_bar is one word (underscore is a word char); the dot is punct.
|
||||
const t = 'foo_bar.baz';
|
||||
expect(applyVim(VimAction.wordForward, _tev(t, 0)).value.selection.extentOffset, 7); // the '.'
|
||||
expect(applyVim(VimAction.wordBackward, _tev(t, 8)).value.selection.extentOffset, 7);
|
||||
});
|
||||
|
||||
test('e on the last word clamps to the final char', () {
|
||||
final r = applyVim(VimAction.wordEnd, _tev('hi', 1));
|
||||
expect(r.value.selection.extentOffset, 1);
|
||||
});
|
||||
});
|
||||
|
||||
group('insert entry', () {
|
||||
|
||||
@@ -17,6 +17,20 @@ void main() {
|
||||
});
|
||||
tearDown(() => f.dispose());
|
||||
|
||||
test('identifies itself', () {
|
||||
final ext = KeybindingsUiExtension();
|
||||
expect(ext.id, 'builtin.keybindings-ui');
|
||||
expect(ext.title, 'Keybindings UI');
|
||||
expect(ext.version, '0.1.0');
|
||||
});
|
||||
|
||||
test('deactivate drops the keymap reference', () async {
|
||||
await f.services.extensions.deactivate('builtin.keybindings-ui');
|
||||
// Re-activating is clean (no retained state).
|
||||
await f.services.extensions.activate('builtin.keybindings-ui');
|
||||
expect(f.services.commands.get('keymap.preset.vim'), isNotNull);
|
||||
});
|
||||
|
||||
test('contributes a switch command per shipped preset', () {
|
||||
expect(f.services.commands.get('keymap.preset.vim'), isNotNull);
|
||||
expect(f.services.commands.get('keymap.preset.default'), isNotNull);
|
||||
|
||||
@@ -22,6 +22,12 @@ void main() {
|
||||
|
||||
bool flag(String name) => f.services.keymap.scope[name] ?? false;
|
||||
|
||||
test('identifies itself', () {
|
||||
expect(ext.id, 'builtin.vim');
|
||||
expect(ext.title, 'Vim');
|
||||
expect(ext.version, '0.1.0');
|
||||
});
|
||||
|
||||
test('inert under the default preset', () async {
|
||||
await f.services.extensions.activate('builtin.vim');
|
||||
expect(ext.modeService!.enabled, isFalse);
|
||||
|
||||
@@ -171,5 +171,13 @@ void main() {
|
||||
test('flush with nothing buffered is a no-op', () {
|
||||
expect(matcher.flush().outcome, SeqOutcome.pending);
|
||||
});
|
||||
|
||||
test('flush of a lone prefix key (no exact) passes it through', () {
|
||||
// `g` is a pure prefix of `g g` with no single-`g` binding.
|
||||
expect(feed('g').outcome, SeqOutcome.pending);
|
||||
final r = matcher.flush();
|
||||
expect(r.outcome, SeqOutcome.unmatched);
|
||||
expect(r.passKey, KeyChord.parse('g'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user