mirror of
https://github.com/neovim/neovim.git
synced 2025-09-15 15:58:17 +00:00
Merge branch 'master' into s-dash-stdin
This commit is contained in:
@@ -17,4 +17,4 @@ ignore = {
|
||||
}
|
||||
|
||||
-- Ignore whitespace issues in converted Vim legacy tests.
|
||||
files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
|
||||
--files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
|
||||
|
284
test/README.md
284
test/README.md
@@ -1,34 +1,267 @@
|
||||
# Tests
|
||||
Tests
|
||||
=====
|
||||
|
||||
Tests are run by `/cmake/RunTests.cmake` file, using busted.
|
||||
Tests are run by `/cmake/RunTests.cmake` file, using `busted`.
|
||||
|
||||
## Directory structure
|
||||
For some failures, `.nvimlog` (or `$NVIM_LOG_FILE`) may provide insight.
|
||||
|
||||
Directories with tests: `/test/benchmark` for benchmarks, `/test/functional` for
|
||||
functional tests, `/test/unit` for unit tests. `/test/config` contains `*.in`
|
||||
files (currently a single one) which are transformed into `*.lua` files using
|
||||
`configure_file` CMake command: this is for acessing CMake variables in lua
|
||||
tests. `/test/includes` contains include files for use by luajit `ffi.cdef`
|
||||
C definitions parser: normally used to make macros not accessible via this
|
||||
mechanism accessible the other way.
|
||||
---
|
||||
|
||||
Files `/test/*/preload.lua` contain modules which will be preloaded by busted,
|
||||
via `--helper` option. `/test/**/helpers.lua` contain various “library”
|
||||
functions, (intended to be) used by a number of tests and not just a single one.
|
||||
- [Running tests](#running-tests)
|
||||
- [Unit tests](#unit-tests)
|
||||
- [Lint](#lint)
|
||||
- [Environment variables](#environment-variables)
|
||||
|
||||
`/test/*/**/*_spec.lua` are files containing actual tests. Files that do not end
|
||||
with a `_spec.lua` are libraries like `/test/**/helpers.lua`, except that they
|
||||
have some common topic.
|
||||
---
|
||||
|
||||
Tests inside `/test/unit` and `/test/functional` are normally divided into
|
||||
groups by the semantic component they are testing.
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
## Environment variables
|
||||
Neovim uses third-party tooling to execute tests. So be sure, from the
|
||||
repository directory, to build the tools before testing:
|
||||
|
||||
make cmake
|
||||
|
||||
## Executing Tests
|
||||
|
||||
To run all _non-legacy_ (unit + functional) tests:
|
||||
|
||||
make test
|
||||
|
||||
To run only _unit_ tests:
|
||||
|
||||
make unittest
|
||||
|
||||
To run only _functional_ tests:
|
||||
|
||||
make functionaltest
|
||||
|
||||
---
|
||||
|
||||
## Filter Tests
|
||||
|
||||
### Filter by name
|
||||
|
||||
Another filter method is by setting a pattern of test name to `TEST_FILTER`.
|
||||
|
||||
``` lua
|
||||
it('foo api',function()
|
||||
...
|
||||
end)
|
||||
it('bar api',function()
|
||||
...
|
||||
end)
|
||||
```
|
||||
|
||||
To run only test with filter name:
|
||||
|
||||
TEST_TAG='foo.*api' make functionaltest
|
||||
|
||||
### Filter by file
|
||||
|
||||
To run a *specific* unit test:
|
||||
|
||||
TEST_FILE=test/unit/foo.lua make unittest
|
||||
|
||||
To run a *specific* functional test:
|
||||
|
||||
TEST_FILE=test/functional/foo.lua make functionaltest
|
||||
|
||||
To *repeat* a test many times:
|
||||
|
||||
.deps/usr/bin/busted --filter 'foo' --repeat 1000 test/functional/ui/foo_spec.lua
|
||||
|
||||
### Filter by tag
|
||||
|
||||
Tests can be "tagged" by adding `#` before a token in the test description.
|
||||
|
||||
``` lua
|
||||
it('#foo bar baz', function()
|
||||
...
|
||||
end)
|
||||
it('#foo another test', function()
|
||||
...
|
||||
end)
|
||||
```
|
||||
|
||||
To run only the tagged tests:
|
||||
|
||||
TEST_TAG=foo make functionaltest
|
||||
|
||||
**NOTES**:
|
||||
* Tags are mainly used for testing issues (ex: `#1234`), so use the following
|
||||
method.
|
||||
* `TEST_FILE` is not a pattern string like `TEST_TAG` or `TEST_FILTER`. The
|
||||
given value to `TEST_FILE` must be a path to an existing file.
|
||||
* Both `TEST_TAG` and `TEST_FILTER` filter tests by the strings from either
|
||||
`it()` or `describe()` functions.
|
||||
|
||||
---
|
||||
|
||||
### Legacy
|
||||
|
||||
To run all legacy (Vim) integration tests:
|
||||
|
||||
make oldtest
|
||||
|
||||
To run a *single* legacy test, run `make` with `TEST_FILE=test_name.res`. E.g.
|
||||
to run `test_syntax.vim`:
|
||||
|
||||
TEST_FILE=test_syntax.res make oldtest
|
||||
|
||||
- The `.res` extension (instead of `.vim`) is required.
|
||||
- Specify only the test file name, not the full path.
|
||||
|
||||
### Functional tests
|
||||
|
||||
`$GDB` can be set to [run tests under
|
||||
gdbserver](https://github.com/neovim/neovim/pull/1527). If `$VALGRIND` is also
|
||||
set, it will add the `--vgdb=yes` option to valgrind instead of
|
||||
starting gdbserver directly.
|
||||
|
||||
Unit tests
|
||||
----------
|
||||
|
||||
Tests are broadly divided into *unit tests*
|
||||
([test/unit](https://github.com/neovim/neovim/tree/master/test/unit) directory)
|
||||
and *functional tests*
|
||||
([test/functional](https://github.com/neovim/neovim/tree/master/test/functional)
|
||||
directory). Use any of the existing tests as a template to start writing new
|
||||
tests.
|
||||
|
||||
- _Unit_ testing is achieved by compiling the tests as a shared library which is
|
||||
loaded and called by LuaJit [FFI](http://luajit.org/ext_ffi.html).
|
||||
- _Functional_ tests are driven by RPC, so they do not require LuaJit (as
|
||||
opposed to Lua).
|
||||
|
||||
You can learn the [key concepts of Lua in 15
|
||||
minutes](http://learnxinyminutes.com/docs/lua/).
|
||||
|
||||
## Guidelines for writing tests
|
||||
|
||||
- Consider [BDD](http://en.wikipedia.org/wiki/Behavior-driven_development)
|
||||
guidelines for organization and readability of tests. Describe what you're
|
||||
testing (and the environment if applicable) and create specs that assert its
|
||||
behavior.
|
||||
- For testing static functions or functions that have side effects visible only
|
||||
in module-global variables, create accessors for the modified variables. For
|
||||
example, say you are testing a function in misc1.c that modifies a static
|
||||
variable, create a file `test/c-helpers/misc1.c` and add a function that
|
||||
retrieves the value after the function call. Files under `test/c-helpers` will
|
||||
only be compiled when building the test shared library.
|
||||
- Luajit needs to know about type and constant declarations used in function
|
||||
prototypes. The
|
||||
[helpers.lua](https://github.com/neovim/neovim/blob/master/test/unit/helpers.lua)
|
||||
file automatically parses `types.h`, so types used in the tested functions
|
||||
must be moved to it to avoid having to rewrite the declarations in the test
|
||||
files (even though this is how it's currently done currently in the misc1/fs
|
||||
modules, but contributors are encouraged to refactor the declarations).
|
||||
- Macro constants must be rewritten as enums so they can be "visible" to the
|
||||
tests automatically.
|
||||
- Busted supports various "output providers". The
|
||||
**[gtest](https://github.com/Olivine-Labs/busted/pull/394) output provider**
|
||||
shows verbose details that can be useful to diagnose hung tests. Either modify
|
||||
the Makefile or compile with `make
|
||||
CMAKE_EXTRA_FLAGS=-DBUSTED_OUTPUT_TYPE=gtest` to enable it.
|
||||
- **Use busted's `pending()` feature** to skip tests
|
||||
([example](https://github.com/neovim/neovim/commit/5c1dc0fbe7388528875aff9d7b5055ad718014de#diff-bf80b24c724b0004e8418102f68b0679R18)).
|
||||
Do not silently skip the test with `if-else`. If a functional test depends on
|
||||
some external factor (e.g. the existence of `md5sum` on `$PATH`), *and* you
|
||||
can't mock or fake the dependency, then skip the test via `pending()` if the
|
||||
external factor is missing. This ensures that the *total* test-count (success
|
||||
+ fail + error + pending) is the same in all environments.
|
||||
- *Note:* `pending()` is ignored if it is missing an argument _unless_ it is
|
||||
[contained in an `it()`
|
||||
block](https://github.com/neovim/neovim/blob/d21690a66e7eb5ebef18046c7a79ef898966d786/test/functional/ex_cmds/grep_spec.lua#L11).
|
||||
Provide empty function argument if the `pending()` call is outside of
|
||||
`it()`
|
||||
([example](https://github.com/neovim/neovim/commit/5c1dc0fbe7388528875aff9d7b5055ad718014de#diff-bf80b24c724b0004e8418102f68b0679R18)).
|
||||
- Use `make testlint` for using the shipped luacheck program ([supported by
|
||||
syntastic](https://github.com/scrooloose/syntastic/blob/d6b96c079be137c83009827b543a83aa113cc011/doc/syntastic-checkers.txt#L3546))
|
||||
to lint all tests.
|
||||
|
||||
### Where tests go
|
||||
|
||||
- _Unit tests_
|
||||
([test/unit](https://github.com/neovim/neovim/tree/master/test/unit)) should
|
||||
match 1-to-1 with the structure of `src/nvim/`, because they are testing
|
||||
functions directly. E.g. unit-tests for `src/nvim/undo.c` should live in
|
||||
`test/unit/undo_spec.lua`.
|
||||
- _Functional tests_
|
||||
([test/functional](https://github.com/neovim/neovim/tree/master/test/functional))
|
||||
are higher-level (plugins and user input) than unit tests; they are organized
|
||||
by concept.
|
||||
- Try to find an existing `test/functional/*/*_spec.lua` group that makes
|
||||
sense, before creating a new one.
|
||||
|
||||
## Checklist for migrating legacy tests
|
||||
|
||||
**Note:** Only "old style" (`src/testdir/*.in`) legacy tests should be
|
||||
converted. Please _do not_ convert "new style" Vim tests (`src/testdir/*.vim`).
|
||||
The "new style" Vim tests are faster than the old ones, and converting them
|
||||
takes time and effort better spent elsewhere.
|
||||
|
||||
- Remove the test from the Makefile (`src/nvim/testdir/Makefile`).
|
||||
- Remove the associated `test.in`, `test.out`, and `test.ok` files from
|
||||
`src/nvim/testdir/`.
|
||||
- Make sure the lua test ends in `_spec.lua`.
|
||||
- Make sure the test count increases accordingly in the build log.
|
||||
- Make sure the new test contains the same control characters (`^]`, ...) as the
|
||||
old test.
|
||||
- Instead of the actual control characters, use an equivalent textual
|
||||
representation (e.g. `<esc>` instead of `^]`). The
|
||||
`scripts/legacy2luatest.pl` script does some of these conversions
|
||||
automatically.
|
||||
|
||||
## Tips
|
||||
|
||||
- Really long `source([=[...]=])` blocks may break syntax highlighting. Try
|
||||
`:syntax sync fromstart` to fix it.
|
||||
|
||||
|
||||
Lint
|
||||
----
|
||||
|
||||
`make lint` (and `make testlint`) runs [luacheck](https://github.com/mpeterv/luacheck)
|
||||
on the test code.
|
||||
|
||||
If a luacheck warning must be ignored, specify the warning code. Example:
|
||||
|
||||
-- luacheck: ignore 621
|
||||
|
||||
http://luacheck.readthedocs.io/en/stable/warnings.html
|
||||
|
||||
Ignore the smallest applicable scope (e.g. inside a function, not at the top of
|
||||
the file).
|
||||
|
||||
Layout
|
||||
------
|
||||
|
||||
- `/test/benchmark` : benchmarks
|
||||
- `/test/functional` : functional tests
|
||||
- `/test/unit` : unit tests
|
||||
- `/test/config` : contains `*.in` files which are transformed into `*.lua`
|
||||
files using `configure_file` CMake command: this is for acessing CMake
|
||||
variables in lua tests.
|
||||
- `/test/includes` : include-files for use by luajit `ffi.cdef` C definitions
|
||||
parser: normally used to make macros not accessible via this mechanism
|
||||
accessible the other way.
|
||||
- `/test/*/preload.lua` : modules preloaded by busted `--helper` option
|
||||
- `/test/**/helpers.lua` : common utility functions for test code
|
||||
- `/test/*/**/*_spec.lua` : actual tests. Files that do not end with
|
||||
`_spec.lua` are libraries like `/test/**/helpers.lua`, except that they have
|
||||
some common topic.
|
||||
|
||||
Tests in `/test/unit` and `/test/functional` are normally divided into groups
|
||||
by the semantic component they are testing.
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
|
||||
Test behaviour is affected by environment variables. Currently supported
|
||||
(Functional, Unit, Benchmarks) (when Defined; when set to _1_; when defined,
|
||||
treated as Integer; when defined, treated as String; !must be defined to
|
||||
function properly):
|
||||
treated as Integer; when defined, treated as String; when defined, treated as
|
||||
Number; !must be defined to function properly):
|
||||
|
||||
`GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be
|
||||
accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote
|
||||
@@ -99,3 +332,12 @@ get backtrace from).
|
||||
approximately 90% of the tests. Should be used when finding cores is too hard
|
||||
for some reason. Normally (on OS X or when `NVIM_TEST_CORE_GLOB_DIRECTORY` is
|
||||
defined and this variable is not) cores are checked for after each test.
|
||||
|
||||
`NVIM_TEST_RUN_TESTTEST` (U) (1): allows running `test/unit/testtest_spec.lua`
|
||||
used to check how testing infrastructure works.
|
||||
|
||||
`NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: `0`
|
||||
disables tracing (the fastest, but you get no data if tests crash and there was
|
||||
no core dump generated), `1` or empty/undefined leaves only C function cals and
|
||||
returns in the trace (faster then recording everything), `2` records all
|
||||
function calls, returns and lua source lines exuecuted.
|
||||
|
@@ -1,8 +1,8 @@
|
||||
-- Test for benchmarking RE engine.
|
||||
|
||||
local helpers = require('test.functional.helpers')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local insert, source = helpers.insert, helpers.source
|
||||
local clear, execute, wait = helpers.clear, helpers.execute, helpers.wait
|
||||
local clear, command = helpers.clear, helpers.command
|
||||
|
||||
-- Temporary file for gathering benchmarking results for each regexp engine.
|
||||
local result_file = 'benchmark.out'
|
||||
@@ -31,7 +31,7 @@ describe('regexp search', function()
|
||||
clear()
|
||||
source(measure_script)
|
||||
insert('" Benchmark_results:')
|
||||
execute('write! ' .. result_file)
|
||||
command('write! ' .. result_file)
|
||||
end)
|
||||
|
||||
-- At the end of the test run we just print the contents of the result file
|
||||
@@ -46,22 +46,19 @@ describe('regexp search', function()
|
||||
|
||||
it('is working with regexpengine=0', function()
|
||||
local regexpengine = 0
|
||||
execute(string.format(measure_cmd, regexpengine))
|
||||
execute('write')
|
||||
wait()
|
||||
command(string.format(measure_cmd, regexpengine))
|
||||
command('write')
|
||||
end)
|
||||
|
||||
it('is working with regexpengine=1', function()
|
||||
local regexpengine = 1
|
||||
execute(string.format(measure_cmd, regexpengine))
|
||||
execute('write')
|
||||
wait()
|
||||
command(string.format(measure_cmd, regexpengine))
|
||||
command('write')
|
||||
end)
|
||||
|
||||
it('is working with regexpengine=2', function()
|
||||
local regexpengine = 2
|
||||
execute(string.format(measure_cmd, regexpengine))
|
||||
execute('write')
|
||||
wait()
|
||||
command(string.format(measure_cmd, regexpengine))
|
||||
command('write')
|
||||
end)
|
||||
end)
|
||||
|
@@ -5,7 +5,8 @@ for p in ("${TEST_INCLUDE_DIRS}" .. ";"):gmatch("[^;]+") do
|
||||
table.insert(module.include_paths, p)
|
||||
end
|
||||
|
||||
module.test_include_path = "${CMAKE_BINARY_DIR}/test/includes/post"
|
||||
module.test_build_dir = "${CMAKE_BINARY_DIR}"
|
||||
module.test_include_path = module.test_build_dir .. "/test/includes/post"
|
||||
module.test_libnvim_path = "${TEST_LIBNVIM_PATH}"
|
||||
module.test_source_path = "${CMAKE_SOURCE_DIR}"
|
||||
module.test_lua_prg = "${LUA_PRG}"
|
||||
|
@@ -5,11 +5,12 @@ local curbufmeths, ok = helpers.curbufmeths, helpers.ok
|
||||
local funcs = helpers.funcs
|
||||
local request = helpers.request
|
||||
local exc_exec = helpers.exc_exec
|
||||
local execute = helpers.execute
|
||||
local feed_command = helpers.feed_command
|
||||
local insert = helpers.insert
|
||||
local NIL = helpers.NIL
|
||||
local meth_pcall = helpers.meth_pcall
|
||||
local command = helpers.command
|
||||
local bufmeths = helpers.bufmeths
|
||||
|
||||
describe('api/buf', function()
|
||||
before_each(clear)
|
||||
@@ -121,6 +122,15 @@ describe('api/buf', function()
|
||||
local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines
|
||||
local line_count = curbufmeths.line_count
|
||||
|
||||
it('fails correctly when input is not valid', function()
|
||||
eq(1, curbufmeths.get_number())
|
||||
local err, emsg = pcall(bufmeths.set_lines, 1, 1, 2, false, {'b\na'})
|
||||
eq(false, err)
|
||||
local exp_emsg = 'String cannot contain newlines'
|
||||
-- Expected {filename}:{lnum}: {exp_emsg}
|
||||
eq(': ' .. exp_emsg, emsg:sub(-#exp_emsg - 2))
|
||||
end)
|
||||
|
||||
it('has correct line_count when inserting and deleting', function()
|
||||
eq(1, line_count())
|
||||
set_lines(-1, -1, true, {'line'})
|
||||
@@ -246,7 +256,7 @@ describe('api/buf', function()
|
||||
end)
|
||||
|
||||
it("set_line on alternate buffer does not access invalid line (E315)", function()
|
||||
execute('set hidden')
|
||||
feed_command('set hidden')
|
||||
insert('Initial file')
|
||||
command('enew')
|
||||
insert([[
|
||||
@@ -257,7 +267,7 @@ describe('api/buf', function()
|
||||
The
|
||||
Other
|
||||
Buffer]])
|
||||
execute('$')
|
||||
feed_command('$')
|
||||
local retval = exc_exec("call nvim_buf_set_lines(1, 0, 1, v:false, ['test'])")
|
||||
eq(0, retval)
|
||||
end)
|
||||
@@ -271,7 +281,7 @@ describe('api/buf', function()
|
||||
eq(1, funcs.exists('b:lua'))
|
||||
curbufmeths.del_var('lua')
|
||||
eq(0, funcs.exists('b:lua'))
|
||||
eq({false, 'Key "lua" doesn\'t exist'}, meth_pcall(curbufmeths.del_var, 'lua'))
|
||||
eq({false, 'Key does not exist: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
|
||||
curbufmeths.set_var('lua', 1)
|
||||
command('lockvar b:lua')
|
||||
eq({false, 'Key is locked: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
|
||||
|
103
test/functional/api/highlight_spec.lua
Normal file
103
test/functional/api/highlight_spec.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, nvim = helpers.clear, helpers.nvim
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local eq, eval = helpers.eq, helpers.eval
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
|
||||
describe('highlight api',function()
|
||||
local expected_rgb = {
|
||||
background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red,
|
||||
special = Screen.colors.Blue,
|
||||
bold = true,
|
||||
}
|
||||
local expected_cterm = {
|
||||
background = 10,
|
||||
underline = true,
|
||||
}
|
||||
local expected_rgb2 = {
|
||||
background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red,
|
||||
special = Screen.colors.Blue,
|
||||
bold = true,
|
||||
italic = true,
|
||||
reverse = true,
|
||||
undercurl = true,
|
||||
underline = true,
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
command("hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold")
|
||||
end)
|
||||
|
||||
it("nvim_get_hl_by_id", function()
|
||||
local hl_id = eval("hlID('NewHighlight')")
|
||||
eq(expected_cterm, nvim("get_hl_by_id", hl_id, false))
|
||||
|
||||
hl_id = eval("hlID('NewHighlight')")
|
||||
-- Test valid id.
|
||||
eq(expected_rgb, nvim("get_hl_by_id", hl_id, true))
|
||||
|
||||
-- Test invalid id.
|
||||
local err, emsg = pcall(meths.get_hl_by_id, 30000, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test all highlight properties.
|
||||
command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse')
|
||||
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
|
||||
|
||||
-- Test nil argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, { nil }, false)
|
||||
eq(false, err)
|
||||
eq('Wrong type for argument 1, expecting Integer',
|
||||
string.match(emsg, 'Wrong.*'))
|
||||
|
||||
-- Test 0 argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, 0, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: 0',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test -1 argument.
|
||||
err, emsg = pcall(meths.get_hl_by_id, -1, false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight id: -1',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
end)
|
||||
|
||||
it("nvim_get_hl_by_name", function()
|
||||
local expected_normal = { background = Screen.colors.Yellow,
|
||||
foreground = Screen.colors.Red }
|
||||
|
||||
-- Test `Normal` default values.
|
||||
eq({}, nvim("get_hl_by_name", 'Normal', true))
|
||||
|
||||
eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false))
|
||||
eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true))
|
||||
|
||||
-- Test `Normal` modified values.
|
||||
command('hi Normal guifg=red guibg=yellow')
|
||||
eq(expected_normal, nvim("get_hl_by_name", 'Normal', true))
|
||||
|
||||
-- Test invalid name.
|
||||
local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight name: unknown_highlight',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
|
||||
-- Test nil argument.
|
||||
err, emsg = pcall(meths.get_hl_by_name , { nil }, false)
|
||||
eq(false, err)
|
||||
eq('Wrong type for argument 1, expecting String',
|
||||
string.match(emsg, 'Wrong.*'))
|
||||
|
||||
-- Test empty string argument.
|
||||
err, emsg = pcall(meths.get_hl_by_name , '', false)
|
||||
eq(false, err)
|
||||
eq('Invalid highlight name: ',
|
||||
string.match(emsg, 'Invalid.*'))
|
||||
end)
|
||||
end)
|
310
test/functional/api/keymap_spec.lua
Normal file
310
test/functional/api/keymap_spec.lua
Normal file
@@ -0,0 +1,310 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local global_helpers = require('test.helpers')
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local source = helpers.source
|
||||
|
||||
local shallowcopy = global_helpers.shallowcopy
|
||||
|
||||
describe('get_keymap', function()
|
||||
before_each(clear)
|
||||
|
||||
-- Basic mapping and table to be used to describe results
|
||||
local foo_bar_string = 'nnoremap foo bar'
|
||||
local foo_bar_map_table = {
|
||||
lhs='foo',
|
||||
silent=0,
|
||||
rhs='bar',
|
||||
expr=0,
|
||||
sid=0,
|
||||
buffer=0,
|
||||
nowait=0,
|
||||
mode='n',
|
||||
noremap=1,
|
||||
}
|
||||
|
||||
it('returns empty list when no map', function()
|
||||
eq({}, meths.get_keymap('n'))
|
||||
end)
|
||||
|
||||
it('returns list of all applicable mappings', function()
|
||||
command(foo_bar_string)
|
||||
-- Only one mapping available
|
||||
-- Should be the same as the dictionary we supplied earlier
|
||||
-- and the dictionary you would get from maparg
|
||||
-- since this is a global map, and not script local
|
||||
eq({foo_bar_map_table}, meths.get_keymap('n'))
|
||||
eq({funcs.maparg('foo', 'n', false, true)},
|
||||
meths.get_keymap('n')
|
||||
)
|
||||
|
||||
-- Add another mapping
|
||||
command('nnoremap foo_longer bar_longer')
|
||||
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
|
||||
foolong_bar_map_table['lhs'] = 'foo_longer'
|
||||
foolong_bar_map_table['rhs'] = 'bar_longer'
|
||||
|
||||
eq({foolong_bar_map_table, foo_bar_map_table},
|
||||
meths.get_keymap('n')
|
||||
)
|
||||
|
||||
-- Remove a mapping
|
||||
command('unmap foo_longer')
|
||||
eq({foo_bar_map_table},
|
||||
meths.get_keymap('n')
|
||||
)
|
||||
end)
|
||||
|
||||
it('works for other modes', function()
|
||||
-- Add two mappings, one in insert and one normal
|
||||
-- We'll only check the insert mode one
|
||||
command('nnoremap not_going to_check')
|
||||
|
||||
command('inoremap foo bar')
|
||||
-- The table will be the same except for the mode
|
||||
local insert_table = shallowcopy(foo_bar_map_table)
|
||||
insert_table['mode'] = 'i'
|
||||
|
||||
eq({insert_table}, meths.get_keymap('i'))
|
||||
end)
|
||||
|
||||
it('considers scope', function()
|
||||
-- change the map slightly
|
||||
command('nnoremap foo_longer bar_longer')
|
||||
local foolong_bar_map_table = shallowcopy(foo_bar_map_table)
|
||||
foolong_bar_map_table['lhs'] = 'foo_longer'
|
||||
foolong_bar_map_table['rhs'] = 'bar_longer'
|
||||
|
||||
local buffer_table = shallowcopy(foo_bar_map_table)
|
||||
buffer_table['buffer'] = 1
|
||||
|
||||
command('nnoremap <buffer> foo bar')
|
||||
|
||||
-- The buffer mapping should not show up
|
||||
eq({foolong_bar_map_table}, meths.get_keymap('n'))
|
||||
eq({buffer_table}, curbufmeths.get_keymap('n'))
|
||||
end)
|
||||
|
||||
it('considers scope for overlapping maps', function()
|
||||
command('nnoremap foo bar')
|
||||
|
||||
local buffer_table = shallowcopy(foo_bar_map_table)
|
||||
buffer_table['buffer'] = 1
|
||||
|
||||
command('nnoremap <buffer> foo bar')
|
||||
|
||||
eq({foo_bar_map_table}, meths.get_keymap('n'))
|
||||
eq({buffer_table}, curbufmeths.get_keymap('n'))
|
||||
end)
|
||||
|
||||
it('can retrieve mapping for different buffers', function()
|
||||
local original_buffer = curbufmeths.get_number()
|
||||
-- Place something in each of the buffers to make sure they stick around
|
||||
-- and set hidden so we can leave them
|
||||
command('set hidden')
|
||||
command('new')
|
||||
command('normal! ihello 2')
|
||||
command('new')
|
||||
command('normal! ihello 3')
|
||||
|
||||
local final_buffer = curbufmeths.get_number()
|
||||
|
||||
command('nnoremap <buffer> foo bar')
|
||||
-- Final buffer will have buffer mappings
|
||||
local buffer_table = shallowcopy(foo_bar_map_table)
|
||||
buffer_table['buffer'] = final_buffer
|
||||
eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n'))
|
||||
eq({buffer_table}, meths.buf_get_keymap(0, 'n'))
|
||||
|
||||
command('buffer ' .. original_buffer)
|
||||
eq(original_buffer, curbufmeths.get_number())
|
||||
-- Original buffer won't have any mappings
|
||||
eq({}, meths.get_keymap('n'))
|
||||
eq({}, curbufmeths.get_keymap('n'))
|
||||
eq({buffer_table}, meths.buf_get_keymap(final_buffer, 'n'))
|
||||
end)
|
||||
|
||||
-- Test toggle switches for basic options
|
||||
-- @param option The key represented in the `maparg()` result dict
|
||||
local function global_and_buffer_test(map,
|
||||
option,
|
||||
option_token,
|
||||
global_on_result,
|
||||
buffer_on_result,
|
||||
global_off_result,
|
||||
buffer_off_result,
|
||||
new_windows)
|
||||
|
||||
local function make_new_windows(number_of_windows)
|
||||
if new_windows == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
for _=1,number_of_windows do
|
||||
command('new')
|
||||
end
|
||||
end
|
||||
|
||||
local mode = string.sub(map, 1,1)
|
||||
-- Don't run this for the <buffer> mapping, since it doesn't make sense
|
||||
if option_token ~= '<buffer>' then
|
||||
it(string.format( 'returns %d for the key "%s" when %s is used globally with %s (%s)',
|
||||
global_on_result, option, option_token, map, mode), function()
|
||||
make_new_windows(new_windows)
|
||||
command(map .. ' ' .. option_token .. ' foo bar')
|
||||
local result = meths.get_keymap(mode)[1][option]
|
||||
eq(global_on_result, result)
|
||||
end)
|
||||
end
|
||||
|
||||
it(string.format('returns %d for the key "%s" when %s is used for buffers with %s (%s)',
|
||||
buffer_on_result, option, option_token, map, mode), function()
|
||||
make_new_windows(new_windows)
|
||||
command(map .. ' <buffer> ' .. option_token .. ' foo bar')
|
||||
local result = curbufmeths.get_keymap(mode)[1][option]
|
||||
eq(buffer_on_result, result)
|
||||
end)
|
||||
|
||||
-- Don't run these for the <buffer> mapping, since it doesn't make sense
|
||||
if option_token ~= '<buffer>' then
|
||||
it(string.format('returns %d for the key "%s" when %s is not used globally with %s (%s)',
|
||||
global_off_result, option, option_token, map, mode), function()
|
||||
make_new_windows(new_windows)
|
||||
command(map .. ' baz bat')
|
||||
local result = meths.get_keymap(mode)[1][option]
|
||||
eq(global_off_result, result)
|
||||
end)
|
||||
|
||||
it(string.format('returns %d for the key "%s" when %s is not used for buffers with %s (%s)',
|
||||
buffer_off_result, option, option_token, map, mode), function()
|
||||
make_new_windows(new_windows)
|
||||
command(map .. ' <buffer> foo bar')
|
||||
|
||||
local result = curbufmeths.get_keymap(mode)[1][option]
|
||||
eq(buffer_off_result, result)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Standard modes and returns the same values in the dictionary as maparg()
|
||||
local mode_list = {'nnoremap', 'nmap', 'imap', 'inoremap', 'cnoremap'}
|
||||
for mode in pairs(mode_list) do
|
||||
global_and_buffer_test(mode_list[mode], 'silent', '<silent>', 1, 1, 0, 0)
|
||||
global_and_buffer_test(mode_list[mode], 'nowait', '<nowait>', 1, 1, 0, 0)
|
||||
global_and_buffer_test(mode_list[mode], 'expr', '<expr>', 1, 1, 0, 0)
|
||||
end
|
||||
|
||||
-- noremap will now be 2 if script was used, which is not the same as maparg()
|
||||
global_and_buffer_test('nmap', 'noremap', '<script>', 2, 2, 0, 0)
|
||||
global_and_buffer_test('nnoremap', 'noremap', '<script>', 2, 2, 1, 1)
|
||||
|
||||
-- buffer will return the buffer ID, which is not the same as maparg()
|
||||
-- Three of these tests won't run
|
||||
global_and_buffer_test('nnoremap', 'buffer', '<buffer>', nil, 3, nil, nil, 2)
|
||||
|
||||
it('returns script numbers for global maps', function()
|
||||
source([[
|
||||
function! s:maparg_test_function() abort
|
||||
return 'testing'
|
||||
endfunction
|
||||
|
||||
nnoremap fizz :call <SID>maparg_test_function()<CR>
|
||||
]])
|
||||
local sid_result = meths.get_keymap('n')[1]['sid']
|
||||
eq(1, sid_result)
|
||||
eq('testing', meths.call_function('<SNR>' .. sid_result .. '_maparg_test_function', {}))
|
||||
end)
|
||||
|
||||
it('returns script numbers for buffer maps', function()
|
||||
source([[
|
||||
function! s:maparg_test_function() abort
|
||||
return 'testing'
|
||||
endfunction
|
||||
|
||||
nnoremap <buffer> fizz :call <SID>maparg_test_function()<CR>
|
||||
]])
|
||||
local sid_result = curbufmeths.get_keymap('n')[1]['sid']
|
||||
eq(1, sid_result)
|
||||
eq('testing', meths.call_function('<SNR>' .. sid_result .. '_maparg_test_function', {}))
|
||||
end)
|
||||
|
||||
it('works with <F12> and others', function()
|
||||
command('nnoremap <F12> :let g:maparg_test_var = 1<CR>')
|
||||
eq('<F12>', meths.get_keymap('n')[1]['lhs'])
|
||||
eq(':let g:maparg_test_var = 1<CR>', meths.get_keymap('n')[1]['rhs'])
|
||||
end)
|
||||
|
||||
it('works correctly despite various &cpo settings', function()
|
||||
local cpo_table = {
|
||||
silent=0,
|
||||
expr=0,
|
||||
sid=0,
|
||||
buffer=0,
|
||||
nowait=0,
|
||||
noremap=1,
|
||||
}
|
||||
local function cpomap(lhs, rhs, mode)
|
||||
local ret = shallowcopy(cpo_table)
|
||||
ret.lhs = lhs
|
||||
ret.rhs = rhs
|
||||
ret.mode = mode
|
||||
return ret
|
||||
end
|
||||
|
||||
command('set cpo+=B')
|
||||
command('nnoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
|
||||
command('nnoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
|
||||
|
||||
command('set cpo+=B')
|
||||
command('xnoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
|
||||
command('xnoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
|
||||
|
||||
command('set cpo-=B')
|
||||
command('snoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
|
||||
command('snoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
|
||||
|
||||
command('set cpo-=B')
|
||||
command('onoremap \\<C-a><C-a><LT>C-a>\\ \\<C-b><C-b><LT>C-b>\\')
|
||||
command('onoremap <special> \\<C-c><C-c><LT>C-c>\\ \\<C-d><C-d><LT>C-d>\\')
|
||||
|
||||
for _, cmd in ipairs({
|
||||
'set cpo-=B',
|
||||
'set cpo+=B',
|
||||
}) do
|
||||
command(cmd)
|
||||
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'n'),
|
||||
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'n')},
|
||||
meths.get_keymap('n'))
|
||||
eq({cpomap('\\<C-C><C-C><lt>C-c>\\', '\\<C-D><C-D><lt>C-d>\\', 'x'),
|
||||
cpomap('\\<C-A><C-A><lt>C-a>\\', '\\<C-B><C-B><lt>C-b>\\', 'x')},
|
||||
meths.get_keymap('x'))
|
||||
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 's'),
|
||||
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 's')},
|
||||
meths.get_keymap('s'))
|
||||
eq({cpomap('<lt>C-c><C-C><lt>C-c> ', '<lt>C-d><C-D><lt>C-d>', 'o'),
|
||||
cpomap('<lt>C-a><C-A><lt>C-a> ', '<lt>C-b><C-B><lt>C-b>', 'o')},
|
||||
meths.get_keymap('o'))
|
||||
end
|
||||
end)
|
||||
|
||||
it('always uses space for space and bar for bar', function()
|
||||
local space_table = {
|
||||
lhs='| |',
|
||||
rhs='| |',
|
||||
mode='n',
|
||||
silent=0,
|
||||
expr=0,
|
||||
sid=0,
|
||||
buffer=0,
|
||||
nowait=0,
|
||||
noremap=1,
|
||||
}
|
||||
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
|
||||
eq({space_table}, meths.get_keymap('n'))
|
||||
end)
|
||||
end)
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq, clear, eval, execute, nvim, next_message =
|
||||
helpers.eq, helpers.clear, helpers.eval, helpers.execute, helpers.nvim,
|
||||
local eq, clear, eval, command, nvim, next_message =
|
||||
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim,
|
||||
helpers.next_message
|
||||
local meths = helpers.meths
|
||||
|
||||
@@ -16,8 +16,8 @@ describe('notify', function()
|
||||
it('sends the notification/args to the corresponding channel', function()
|
||||
eval('rpcnotify('..channel..', "test-event", 1, 2, 3)')
|
||||
eq({'notification', 'test-event', {1, 2, 3}}, next_message())
|
||||
execute('au FileType lua call rpcnotify('..channel..', "lua!")')
|
||||
execute('set filetype=lua')
|
||||
command('au FileType lua call rpcnotify('..channel..', "lua!")')
|
||||
command('set filetype=lua')
|
||||
eq({'notification', 'lua!', {}}, next_message())
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,12 +1,16 @@
|
||||
-- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate
|
||||
-- `rpcrequest` calls we need the client event loop to be running.
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Paths = require('test.config.paths')
|
||||
|
||||
local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval
|
||||
local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop
|
||||
local nvim_prog, command, funcs = helpers.nvim_prog, helpers.command, helpers.funcs
|
||||
local source, next_message = helpers.source, helpers.next_message
|
||||
local ok = helpers.ok
|
||||
local meths = helpers.meths
|
||||
local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
|
||||
local set_session = helpers.set_session
|
||||
|
||||
describe('server -> client', function()
|
||||
local cid
|
||||
@@ -16,6 +20,22 @@ describe('server -> client', function()
|
||||
cid = nvim('get_api_info')[1]
|
||||
end)
|
||||
|
||||
it('handles unexpected closed stream while preparing RPC response', function()
|
||||
source([[
|
||||
let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ]
|
||||
let ch1 = jobstart(g:_nvim_args, {'rpc': v:true})
|
||||
let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0]
|
||||
call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")')
|
||||
|
||||
let ch2 = jobstart(g:_nvim_args, {'rpc': v:true})
|
||||
let child2_ch = rpcrequest(ch2, "nvim_get_api_info")[0]
|
||||
call rpcnotify(ch2, 'nvim_eval', 'rpcrequest('.child2_ch.', "nvim_get_api_info")')
|
||||
|
||||
call jobstop(ch1)
|
||||
]])
|
||||
eq(2, eval("1+1")) -- Still alive?
|
||||
end)
|
||||
|
||||
describe('simple call', function()
|
||||
it('works', function()
|
||||
local function on_setup()
|
||||
@@ -89,7 +109,28 @@ describe('server -> client', function()
|
||||
end)
|
||||
|
||||
describe('requests and notifications interleaved', function()
|
||||
-- This tests that the following scenario won't happen:
|
||||
it('does not delay notifications during pending request', function()
|
||||
local received = false
|
||||
local function on_setup()
|
||||
eq("retval", funcs.rpcrequest(cid, "doit"))
|
||||
stop()
|
||||
end
|
||||
local function on_request(method)
|
||||
if method == "doit" then
|
||||
funcs.rpcnotify(cid, "headsup")
|
||||
eq(true,received)
|
||||
return "retval"
|
||||
end
|
||||
end
|
||||
local function on_notification(method)
|
||||
if method == "headsup" then
|
||||
received = true
|
||||
end
|
||||
end
|
||||
run(on_request, on_notification, on_setup)
|
||||
end)
|
||||
|
||||
-- This tests the following scenario:
|
||||
--
|
||||
-- server->client [request ] (1)
|
||||
-- client->server [request ] (2) triggered by (1)
|
||||
@@ -104,40 +145,42 @@ describe('server -> client', function()
|
||||
-- only deals with one server->client request at a time. (In other words,
|
||||
-- the client cannot send a response to a request that is not at the top
|
||||
-- of nvim's request stack).
|
||||
--
|
||||
-- But above scenario shoudn't happen by the way notifications are dealt in
|
||||
-- Nvim: they are only sent after there are no pending server->client
|
||||
-- request(the request stack fully unwinds). So (3) is only sent after the
|
||||
-- client returns (6).
|
||||
it('works', function()
|
||||
local expected = 300
|
||||
local notified = 0
|
||||
pending('will close connection if not properly synchronized', function()
|
||||
local function on_setup()
|
||||
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
|
||||
end
|
||||
|
||||
local function on_request(method)
|
||||
eq('notify', method)
|
||||
eq(1, eval('rpcnotify('..cid..', "notification")'))
|
||||
return 'notified!'
|
||||
if method == "notify" then
|
||||
eq(1, eval('rpcnotify('..cid..', "notification")'))
|
||||
return 'notified!'
|
||||
elseif method == "nested" then
|
||||
-- do some busywork, so the first request will return
|
||||
-- before this one
|
||||
for _ = 1, 5 do
|
||||
eq(2, eval("1+1"))
|
||||
end
|
||||
eq(1, eval('rpcnotify('..cid..', "nested_done")'))
|
||||
return 'done!'
|
||||
end
|
||||
end
|
||||
|
||||
local function on_notification(method)
|
||||
eq('notification', method)
|
||||
if notified == expected then
|
||||
stop()
|
||||
return
|
||||
if method == "notification" then
|
||||
eq('done!', eval('rpcrequest('..cid..', "nested")'))
|
||||
elseif method == "nested_done" then
|
||||
-- this should never have been sent
|
||||
ok(false)
|
||||
end
|
||||
notified = notified + 1
|
||||
eq('notified!', eval('rpcrequest('..cid..', "notify")'))
|
||||
end
|
||||
|
||||
run(on_request, on_notification, on_setup)
|
||||
eq(expected, notified)
|
||||
-- ignore disconnect failure, otherwise detected by after_each
|
||||
clear()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('when the client is a recursive vim instance', function()
|
||||
describe('recursive (child) nvim client', function()
|
||||
if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
|
||||
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
|
||||
pending("[Hangs on Travis macOS. #5002]", function() end)
|
||||
@@ -151,7 +194,7 @@ describe('server -> client', function()
|
||||
|
||||
after_each(function() command('call rpcstop(vim)') end)
|
||||
|
||||
it('can send/recieve notifications and make requests', function()
|
||||
it('can send/receive notifications and make requests', function()
|
||||
nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')")
|
||||
|
||||
-- Wait for the notification to complete.
|
||||
@@ -184,7 +227,7 @@ describe('server -> client', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('when using jobstart', function()
|
||||
describe('jobstart()', function()
|
||||
local jobid
|
||||
before_each(function()
|
||||
local channel = nvim('get_api_info')[1]
|
||||
@@ -200,7 +243,7 @@ describe('server -> client', function()
|
||||
\ 'rpc': v:true
|
||||
\ }
|
||||
]])
|
||||
local lua_prog = arg[-1]
|
||||
local lua_prog = Paths.test_lua_prg
|
||||
meths.set_var("args", {lua_prog, 'test/functional/api/rpc_fixture.lua'})
|
||||
jobid = eval("jobstart(g:args, g:job_opts)")
|
||||
neq(0, 'jobid')
|
||||
@@ -219,8 +262,101 @@ describe('server -> client', function()
|
||||
eq("done!",funcs.rpcrequest(jobid, "write_stderr", "fluff\n"))
|
||||
eq({'notification', 'stderr', {0, {'fluff', ''}}}, next_message())
|
||||
funcs.rpcrequest(jobid, "exit")
|
||||
eq({'notification', 'stderr', {0, {''}}}, next_message())
|
||||
eq({'notification', 'exit', {0, 0}}, next_message())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('connecting to another (peer) nvim', function()
|
||||
local function connect_test(server, mode, address)
|
||||
local serverpid = funcs.getpid()
|
||||
local client = spawn(nvim_argv)
|
||||
set_session(client, true)
|
||||
local clientpid = funcs.getpid()
|
||||
neq(serverpid, clientpid)
|
||||
local id = funcs.sockconnect(mode, address, {rpc=true})
|
||||
ok(id > 0)
|
||||
|
||||
funcs.rpcrequest(id, 'nvim_set_current_line', 'hello')
|
||||
local client_id = funcs.rpcrequest(id, 'nvim_get_api_info')[1]
|
||||
|
||||
set_session(server, true)
|
||||
eq(serverpid, funcs.getpid())
|
||||
eq('hello', meths.get_current_line())
|
||||
|
||||
-- method calls work both ways
|
||||
funcs.rpcrequest(client_id, 'nvim_set_current_line', 'howdy!')
|
||||
eq(id, funcs.rpcrequest(client_id, 'nvim_get_api_info')[1])
|
||||
|
||||
set_session(client, true)
|
||||
eq(clientpid, funcs.getpid())
|
||||
eq('howdy!', meths.get_current_line())
|
||||
|
||||
server:close()
|
||||
client:close()
|
||||
end
|
||||
|
||||
it('via named pipe', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverlist()[1]
|
||||
local first = string.sub(address,1,1)
|
||||
ok(first == '/' or first == '\\')
|
||||
connect_test(server, 'pipe', address)
|
||||
end)
|
||||
|
||||
it('via ipv4 address', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverstart("127.0.0.1:")
|
||||
if #address == 0 then
|
||||
pending('no ipv4 stack', function() end)
|
||||
return
|
||||
end
|
||||
eq('127.0.0.1:', string.sub(address,1,10))
|
||||
connect_test(server, 'tcp', address)
|
||||
end)
|
||||
|
||||
it('via ipv6 address', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverstart('::1:')
|
||||
if #address == 0 then
|
||||
pending('no ipv6 stack', function() end)
|
||||
return
|
||||
end
|
||||
eq('::1:', string.sub(address,1,4))
|
||||
connect_test(server, 'tcp', address)
|
||||
end)
|
||||
|
||||
it('via hostname', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverstart("localhost:")
|
||||
eq('localhost:', string.sub(address,1,10))
|
||||
connect_test(server, 'tcp', address)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('connecting to its own pipe address', function()
|
||||
it('does not deadlock', function()
|
||||
if not os.getenv("TRAVIS") and helpers.os_name() == "osx" then
|
||||
-- It does, in fact, deadlock on QuickBuild. #6851
|
||||
pending("deadlocks on QuickBuild", function() end)
|
||||
return
|
||||
end
|
||||
local address = funcs.serverlist()[1]
|
||||
local first = string.sub(address,1,1)
|
||||
ok(first == '/' or first == '\\')
|
||||
local serverpid = funcs.getpid()
|
||||
|
||||
local id = funcs.sockconnect('pipe', address, {rpc=true})
|
||||
|
||||
funcs.rpcrequest(id, 'nvim_set_current_line', 'hello')
|
||||
eq('hello', meths.get_current_line())
|
||||
eq(serverpid, funcs.rpcrequest(id, "nvim_eval", "getpid()"))
|
||||
|
||||
eq(id, funcs.rpcrequest(id, 'nvim_get_api_info')[1])
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -34,7 +34,7 @@ describe('api/tabpage', function()
|
||||
eq(1, funcs.exists('t:lua'))
|
||||
curtabmeths.del_var('lua')
|
||||
eq(0, funcs.exists('t:lua'))
|
||||
eq({false, 'Key "lua" doesn\'t exist'}, meth_pcall(curtabmeths.del_var, 'lua'))
|
||||
eq({false, 'Key does not exist: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
|
||||
curtabmeths.set_var('lua', 1)
|
||||
command('lockvar t:lua')
|
||||
eq({false, 'Key is locked: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
|
||||
|
@@ -81,6 +81,36 @@ describe('api', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_execute_lua', function()
|
||||
it('works', function()
|
||||
meths.execute_lua('vim.api.nvim_set_var("test", 3)', {})
|
||||
eq(3, meths.get_var('test'))
|
||||
|
||||
eq(17, meths.execute_lua('a, b = ...\nreturn a + b', {10,7}))
|
||||
|
||||
eq(NIL, meths.execute_lua('function xx(a,b)\nreturn a..b\nend',{}))
|
||||
eq("xy", meths.execute_lua('return xx(...)', {'x','y'}))
|
||||
end)
|
||||
|
||||
it('reports errors', function()
|
||||
eq({false, 'Error loading lua: [string "<nvim>"]:1: '..
|
||||
"'=' expected near '+'"},
|
||||
meth_pcall(meths.execute_lua, 'a+*b', {}))
|
||||
|
||||
eq({false, 'Error loading lua: [string "<nvim>"]:1: '..
|
||||
"unexpected symbol near '1'"},
|
||||
meth_pcall(meths.execute_lua, '1+2', {}))
|
||||
|
||||
eq({false, 'Error loading lua: [string "<nvim>"]:1: '..
|
||||
"unexpected symbol"},
|
||||
meth_pcall(meths.execute_lua, 'aa=bb\0', {}))
|
||||
|
||||
eq({false, 'Error executing lua: [string "<nvim>"]:1: '..
|
||||
"attempt to call global 'bork' (a nil value)"},
|
||||
meth_pcall(meths.execute_lua, 'bork()', {}))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_input', function()
|
||||
it("VimL error: does NOT fail, updates v:errmsg", function()
|
||||
local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>")
|
||||
@@ -119,7 +149,7 @@ describe('api', function()
|
||||
eq(1, funcs.exists('g:lua'))
|
||||
meths.del_var('lua')
|
||||
eq(0, funcs.exists('g:lua'))
|
||||
eq({false, 'Key "lua" doesn\'t exist'}, meth_pcall(meths.del_var, 'lua'))
|
||||
eq({false, 'Key does not exist: lua'}, meth_pcall(meths.del_var, 'lua'))
|
||||
meths.set_var('lua', 1)
|
||||
command('lockvar lua')
|
||||
eq({false, 'Key is locked: lua'}, meth_pcall(meths.del_var, 'lua'))
|
||||
@@ -153,6 +183,28 @@ describe('api', function()
|
||||
nvim('set_option', 'equalalways', false)
|
||||
ok(not nvim('get_option', 'equalalways'))
|
||||
end)
|
||||
|
||||
it('works to get global value of local options', function()
|
||||
eq(false, nvim('get_option', 'lisp'))
|
||||
eq(8, nvim('get_option', 'shiftwidth'))
|
||||
end)
|
||||
|
||||
it('works to set global value of local options', function()
|
||||
nvim('set_option', 'lisp', true)
|
||||
eq(true, nvim('get_option', 'lisp'))
|
||||
eq(false, helpers.curbuf('get_option', 'lisp'))
|
||||
eq(nil, nvim('command_output', 'setglobal lisp?'):match('nolisp'))
|
||||
eq('nolisp', nvim('command_output', 'setlocal lisp?'):match('nolisp'))
|
||||
nvim('set_option', 'shiftwidth', 20)
|
||||
eq('20', nvim('command_output', 'setglobal shiftwidth?'):match('%d+'))
|
||||
eq('8', nvim('command_output', 'setlocal shiftwidth?'):match('%d+'))
|
||||
end)
|
||||
|
||||
it('most window-local options have no global value', function()
|
||||
local status, err = pcall(nvim, 'get_option', 'foldcolumn')
|
||||
eq(false, status)
|
||||
ok(err:match('Invalid option name') ~= nil)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()
|
||||
@@ -199,6 +251,170 @@ describe('api', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_get_mode', function()
|
||||
it("during normal-mode `g` returns blocking=true", function()
|
||||
nvim("input", "o") -- add a line
|
||||
eq({mode='i', blocking=false}, nvim("get_mode"))
|
||||
nvim("input", [[<C-\><C-N>]])
|
||||
eq(2, nvim("eval", "line('.')"))
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
|
||||
nvim("input", "g")
|
||||
eq({mode='n', blocking=true}, nvim("get_mode"))
|
||||
|
||||
nvim("input", "k") -- complete the operator
|
||||
eq(1, nvim("eval", "line('.')")) -- verify the completed operator
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
end)
|
||||
|
||||
it("returns the correct result multiple consecutive times", function()
|
||||
for _ = 1,5 do
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
end
|
||||
nvim("input", "g")
|
||||
for _ = 1,4 do
|
||||
eq({mode='n', blocking=true}, nvim("get_mode"))
|
||||
end
|
||||
nvim("input", "g")
|
||||
for _ = 1,7 do
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
end
|
||||
end)
|
||||
|
||||
it("during normal-mode CTRL-W, returns blocking=true", function()
|
||||
nvim("input", "<C-W>")
|
||||
eq({mode='n', blocking=true}, nvim("get_mode"))
|
||||
|
||||
nvim("input", "s") -- complete the operator
|
||||
eq(2, nvim("eval", "winnr('$')")) -- verify the completed operator
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
end)
|
||||
|
||||
it("during press-enter prompt returns blocking=true", function()
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
command("echom 'msg1'")
|
||||
command("echom 'msg2'")
|
||||
command("echom 'msg3'")
|
||||
command("echom 'msg4'")
|
||||
command("echom 'msg5'")
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
nvim("input", ":messages<CR>")
|
||||
eq({mode='r', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
|
||||
it("during getchar() returns blocking=false", function()
|
||||
nvim("input", ":let g:test_input = nr2char(getchar())<CR>")
|
||||
-- Events are enabled during getchar(), RPC calls are *not* blocked. #5384
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
eq(0, nvim("eval", "exists('g:test_input')"))
|
||||
nvim("input", "J")
|
||||
eq("J", nvim("eval", "g:test_input"))
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
end)
|
||||
|
||||
-- TODO: bug #6247#issuecomment-286403810
|
||||
it("batched with input", function()
|
||||
eq({mode='n', blocking=false}, nvim("get_mode"))
|
||||
command("echom 'msg1'")
|
||||
command("echom 'msg2'")
|
||||
command("echom 'msg3'")
|
||||
command("echom 'msg4'")
|
||||
command("echom 'msg5'")
|
||||
|
||||
local req = {
|
||||
{'nvim_get_mode', {}},
|
||||
{'nvim_input', {':messages<CR>'}},
|
||||
{'nvim_get_mode', {}},
|
||||
{'nvim_eval', {'1'}},
|
||||
}
|
||||
eq({ { {mode='n', blocking=false},
|
||||
13,
|
||||
{mode='n', blocking=false}, -- TODO: should be blocked=true ?
|
||||
1 },
|
||||
NIL}, meths.call_atomic(req))
|
||||
eq({mode='r', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
it("during insert-mode map-pending, returns blocking=true #6166", function()
|
||||
command("inoremap xx foo")
|
||||
nvim("input", "ix")
|
||||
eq({mode='i', blocking=true}, nvim("get_mode"))
|
||||
end)
|
||||
it("during normal-mode gU, returns blocking=false #6166", function()
|
||||
nvim("input", "gu")
|
||||
eq({mode='no', blocking=false}, nvim("get_mode"))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('RPC (K_EVENT) #6166', function()
|
||||
it('does not complete ("interrupt") normal-mode operator-pending', function()
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'gg')
|
||||
nvim('input', 'gu')
|
||||
-- Make any RPC request (can be non-async: op-pending does not block).
|
||||
nvim('get_current_buf')
|
||||
-- Buffer should not change.
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
-- Now send input to complete the operator.
|
||||
nvim('input', 'j')
|
||||
helpers.expect([[
|
||||
first line
|
||||
second line]])
|
||||
end)
|
||||
|
||||
it('does not complete ("interrupt") `d` #3732', function()
|
||||
local screen = Screen.new(20, 4)
|
||||
screen:attach()
|
||||
command('set listchars=eol:$')
|
||||
command('set list')
|
||||
feed('ia<cr>b<cr>c<cr><Esc>kkk')
|
||||
feed('d')
|
||||
-- Make any RPC request (can be non-async: op-pending does not block).
|
||||
nvim('get_current_buf')
|
||||
screen:expect([[
|
||||
^a$ |
|
||||
b$ |
|
||||
c$ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('does not complete ("interrupt") normal-mode map-pending', function()
|
||||
command("nnoremap dd :let g:foo='it worked...'<CR>")
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'gg')
|
||||
nvim('input', 'd')
|
||||
-- Make any RPC request (must be async, because map-pending blocks).
|
||||
nvim('get_api_info')
|
||||
-- Send input to complete the mapping.
|
||||
nvim('input', 'd')
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
eq('it worked...', helpers.eval('g:foo'))
|
||||
end)
|
||||
it('does not complete ("interrupt") insert-mode map-pending', function()
|
||||
command('inoremap xx foo')
|
||||
command('set timeoutlen=9999')
|
||||
helpers.insert([[
|
||||
FIRST LINE
|
||||
SECOND LINE]])
|
||||
nvim('input', 'ix')
|
||||
-- Make any RPC request (must be async, because map-pending blocks).
|
||||
nvim('get_api_info')
|
||||
-- Send input to complete the mapping.
|
||||
nvim('input', 'x')
|
||||
helpers.expect([[
|
||||
FIRST LINE
|
||||
SECOND LINfooE]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_replace_termcodes', function()
|
||||
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
|
||||
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
|
||||
@@ -219,6 +435,27 @@ describe('api', function()
|
||||
eq('\128\253\44', helpers.nvim('replace_termcodes',
|
||||
'<LeftMouse>', true, true, true))
|
||||
end)
|
||||
|
||||
it('converts keycodes', function()
|
||||
eq('\nx\27x\rx<x', helpers.nvim('replace_termcodes',
|
||||
'<NL>x<Esc>x<CR>x<lt>x', true, true, true))
|
||||
end)
|
||||
|
||||
it('does not convert keycodes if special=false', function()
|
||||
eq('<NL>x<Esc>x<CR>x<lt>x', helpers.nvim('replace_termcodes',
|
||||
'<NL>x<Esc>x<CR>x<lt>x', true, true, false))
|
||||
end)
|
||||
|
||||
it('does not crash when transforming an empty string', function()
|
||||
-- Actually does not test anything, because current code will use NULL for
|
||||
-- an empty string.
|
||||
--
|
||||
-- Problem here is that if String argument has .data in allocated memory
|
||||
-- then `return str` in vim_replace_termcodes body will make Neovim free
|
||||
-- `str.data` twice: once when freeing arguments, then when freeing return
|
||||
-- value.
|
||||
eq('', meths.replace_termcodes('', true, true, true))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_feedkeys', function()
|
||||
@@ -227,13 +464,13 @@ describe('api', function()
|
||||
-- notice the special char(…) \xe2\80\xa6
|
||||
nvim('feedkeys', ':let x1="…"\n', '', true)
|
||||
|
||||
-- Both replace_termcodes and feedkeys escape \x80
|
||||
-- Both nvim_replace_termcodes and nvim_feedkeys escape \x80
|
||||
local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true)
|
||||
nvim('feedkeys', inp, '', true)
|
||||
nvim('feedkeys', inp, '', true) -- escape_csi=true
|
||||
|
||||
-- Disabling CSI escaping in feedkeys
|
||||
-- nvim_feedkeys with CSI escaping disabled
|
||||
inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true)
|
||||
nvim('feedkeys', inp, '', false)
|
||||
nvim('feedkeys', inp, '', false) -- escape_csi=false
|
||||
|
||||
helpers.stop()
|
||||
end
|
||||
@@ -390,7 +627,7 @@ describe('api', function()
|
||||
eq(5, meths.get_var('avar'))
|
||||
end)
|
||||
|
||||
it('throws error on malformated arguments', function()
|
||||
it('throws error on malformed arguments', function()
|
||||
local req = {
|
||||
{'nvim_set_var', {'avar', 1}},
|
||||
{'nvim_set_var'},
|
||||
@@ -417,20 +654,57 @@ describe('api', function()
|
||||
}
|
||||
status, err = pcall(meths.call_atomic, req)
|
||||
eq(false, status)
|
||||
ok(err:match('args must be Array') ~= nil)
|
||||
ok(err:match('Args must be Array') ~= nil)
|
||||
-- call before was done, but not after
|
||||
eq(1, meths.get_var('avar'))
|
||||
eq({''}, meths.buf_get_lines(0, 0, -1, true))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('list_runtime_paths', function()
|
||||
it('returns nothing with empty &runtimepath', function()
|
||||
meths.set_option('runtimepath', '')
|
||||
eq({}, meths.list_runtime_paths())
|
||||
end)
|
||||
it('returns single runtimepath', function()
|
||||
meths.set_option('runtimepath', 'a')
|
||||
eq({'a'}, meths.list_runtime_paths())
|
||||
end)
|
||||
it('returns two runtimepaths', function()
|
||||
meths.set_option('runtimepath', 'a,b')
|
||||
eq({'a', 'b'}, meths.list_runtime_paths())
|
||||
end)
|
||||
it('returns empty strings when appropriate', function()
|
||||
meths.set_option('runtimepath', 'a,,b')
|
||||
eq({'a', '', 'b'}, meths.list_runtime_paths())
|
||||
meths.set_option('runtimepath', ',a,b')
|
||||
eq({'', 'a', 'b'}, meths.list_runtime_paths())
|
||||
meths.set_option('runtimepath', 'a,b,')
|
||||
eq({'a', 'b', ''}, meths.list_runtime_paths())
|
||||
end)
|
||||
it('truncates too long paths', function()
|
||||
local long_path = ('/a'):rep(8192)
|
||||
meths.set_option('runtimepath', long_path)
|
||||
local paths_list = meths.list_runtime_paths()
|
||||
neq({long_path}, paths_list)
|
||||
eq({long_path:sub(1, #(paths_list[1]))}, paths_list)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('can throw exceptions', function()
|
||||
local status, err = pcall(nvim, 'get_option', 'invalid-option')
|
||||
eq(false, status)
|
||||
ok(err:match('Invalid option name') ~= nil)
|
||||
end)
|
||||
|
||||
it("doesn't leak memory on incorrect argument types", function()
|
||||
it('does not truncate error message <1 MB #5984', function()
|
||||
local very_long_name = 'A'..('x'):rep(10000)..'Z'
|
||||
local status, err = pcall(nvim, 'get_option', very_long_name)
|
||||
eq(false, status)
|
||||
eq(very_long_name, err:match('Ax+Z?'))
|
||||
end)
|
||||
|
||||
it("does not leak memory on incorrect argument types", function()
|
||||
local status, err = pcall(nvim, 'set_current_dir',{'not', 'a', 'dir'})
|
||||
eq(false, status)
|
||||
ok(err:match(': Wrong type for argument 1, expecting String') ~= nil)
|
||||
|
@@ -9,6 +9,7 @@ local funcs = helpers.funcs
|
||||
local request = helpers.request
|
||||
local NIL = helpers.NIL
|
||||
local meth_pcall = helpers.meth_pcall
|
||||
local meths = helpers.meths
|
||||
local command = helpers.command
|
||||
|
||||
-- check if str is visible at the beginning of some line
|
||||
@@ -55,6 +56,12 @@ describe('api/win', function()
|
||||
eq('typing\n some dumb text', curbuf_contents())
|
||||
end)
|
||||
|
||||
it('does not leak memory when using invalid window ID with invalid pos',
|
||||
function()
|
||||
eq({false, 'Invalid window id'},
|
||||
meth_pcall(meths.win_set_cursor, 1, {"b\na"}))
|
||||
end)
|
||||
|
||||
it('updates the screen, and also when the window is unfocused', function()
|
||||
insert("prologue")
|
||||
feed('100o<esc>')
|
||||
@@ -139,7 +146,7 @@ describe('api/win', function()
|
||||
eq(1, funcs.exists('w:lua'))
|
||||
curwinmeths.del_var('lua')
|
||||
eq(0, funcs.exists('w:lua'))
|
||||
eq({false, 'Key "lua" doesn\'t exist'}, meth_pcall(curwinmeths.del_var, 'lua'))
|
||||
eq({false, 'Key does not exist: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
|
||||
curwinmeths.set_var('lua', 1)
|
||||
command('lockvar w:lua')
|
||||
eq({false, 'Key is locked: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
|
||||
|
@@ -1,9 +1,13 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local meths = helpers.meths
|
||||
local expect = helpers.expect
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
|
||||
describe('autocmds:', function()
|
||||
before_each(clear)
|
||||
@@ -33,4 +37,22 @@ describe('autocmds:', function()
|
||||
it('v:vim_did_enter is 1 after VimEnter', function()
|
||||
eq(1, eval('v:vim_did_enter'))
|
||||
end)
|
||||
|
||||
describe('BufLeave autocommand', function()
|
||||
it('can wipe out the buffer created by :edit which triggered autocmd',
|
||||
function()
|
||||
meths.set_option('hidden', true)
|
||||
curbufmeths.set_lines(0, 1, false, {
|
||||
'start of test file xx',
|
||||
'end of test file xx'})
|
||||
|
||||
command('autocmd BufLeave * bwipeout yy')
|
||||
eq('Vim(edit):E143: Autocommands unexpectedly deleted new buffer yy',
|
||||
exc_exec('edit yy'))
|
||||
|
||||
expect([[
|
||||
start of test file xx
|
||||
end of test file xx]])
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -4,7 +4,6 @@ local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local execute = helpers.execute
|
||||
local request = helpers.request
|
||||
local source = helpers.source
|
||||
|
||||
@@ -28,7 +27,7 @@ describe('autocmd BufEnter', function()
|
||||
endtry
|
||||
endfunction
|
||||
]])
|
||||
execute("call Test()")
|
||||
command("call Test()")
|
||||
eq(1, eval("exists('g:dir_bufenter')")) -- Did BufEnter for the directory.
|
||||
eq(2, eval("bufnr('%')")) -- Switched to the dir buffer.
|
||||
end)
|
||||
|
117
test/functional/autocmd/cmdline_spec.lua
Normal file
117
test/functional/autocmd/cmdline_spec.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local expect = helpers.expect
|
||||
local next_msg = helpers.next_message
|
||||
local feed = helpers.feed
|
||||
local meths = helpers.meths
|
||||
|
||||
describe('cmdline autocommands', function()
|
||||
local channel
|
||||
before_each(function()
|
||||
clear()
|
||||
channel = meths.get_api_info()[1]
|
||||
meths.set_var("channel",channel)
|
||||
command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)")
|
||||
command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)")
|
||||
command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)")
|
||||
command("autocmd CmdWinLeave * call rpcnotify(g:channel, 'CmdWinLeave', v:event)")
|
||||
end)
|
||||
|
||||
it('works', function()
|
||||
feed(':')
|
||||
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg())
|
||||
feed('redraw<cr>')
|
||||
eq({'notification', 'CmdlineLeave',
|
||||
{{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg())
|
||||
|
||||
feed(':')
|
||||
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg())
|
||||
|
||||
-- note: feed('bork<c-c>') might not consume 'bork'
|
||||
-- due to out-of-band interupt handling
|
||||
feed('bork<esc>')
|
||||
eq({'notification', 'CmdlineLeave',
|
||||
{{cmdtype=':', cmdlevel=1, abort=true}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('can abort cmdline', function()
|
||||
command("autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15")
|
||||
feed(":put! ='ok'<cr>")
|
||||
expect([[
|
||||
ok
|
||||
]])
|
||||
|
||||
feed(":put! ='blah blah'<cr>")
|
||||
expect([[
|
||||
ok
|
||||
]])
|
||||
end)
|
||||
|
||||
it('handles errors correctly', function()
|
||||
clear()
|
||||
local screen = Screen.new(72, 8)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||
[3] = {bold = true, foreground = Screen.colors.SeaGreen4},
|
||||
})
|
||||
command("autocmd CmdlineEnter * echoerr 'FAIL'")
|
||||
command("autocmd CmdlineLeave * echoerr 'very error'")
|
||||
feed(':')
|
||||
screen:expect([[
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
: |
|
||||
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
|
||||
:^ |
|
||||
]])
|
||||
feed("put ='lorem ipsum'<cr>")
|
||||
screen:expect([[
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
: |
|
||||
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
|
||||
:put ='lorem ipsum' |
|
||||
{2:E5500: autocmd has thrown an exception: Vim(echoerr):very error} |
|
||||
|
|
||||
{3:Press ENTER or type command to continue}^ |
|
||||
]])
|
||||
|
||||
feed('<cr>')
|
||||
screen:expect([[
|
||||
|
|
||||
^lorem ipsum |
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('works with nested cmdline', function()
|
||||
feed(':')
|
||||
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg())
|
||||
feed('<c-r>=')
|
||||
eq({'notification', 'CmdlineEnter', {{cmdtype='=', cmdlevel=2}}}, next_msg())
|
||||
feed('<c-f>')
|
||||
eq({'notification', 'CmdWinEnter', {{}}}, next_msg())
|
||||
feed(':')
|
||||
eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=3}}}, next_msg())
|
||||
feed('<c-c>')
|
||||
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=3, abort=true}}}, next_msg())
|
||||
feed('<c-c>')
|
||||
eq({'notification', 'CmdWinLeave', {{}}}, next_msg())
|
||||
feed('1+2<cr>')
|
||||
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg())
|
||||
end)
|
||||
end)
|
@@ -14,17 +14,52 @@ describe('TermClose event', function()
|
||||
nvim('set_option', 'shellcmdflag', 'EXE')
|
||||
end)
|
||||
|
||||
local function eq_err(expected, actual)
|
||||
if expected ~= actual then
|
||||
error('expected: '..tostring(expected)..', actual: '..tostring(actual))
|
||||
end
|
||||
end
|
||||
|
||||
it('triggers when terminal job ends', function()
|
||||
it('triggers when fast-exiting terminal job stops', function()
|
||||
command('autocmd TermClose * let g:test_termclose = 23')
|
||||
command('terminal')
|
||||
command('call jobstop(b:terminal_job_id)')
|
||||
retry(nil, nil, function() eq_err(23, eval('g:test_termclose')) end)
|
||||
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
|
||||
end)
|
||||
|
||||
it('triggers when long-running terminal job gets stopped', function()
|
||||
nvim('set_option', 'shell', 'sh')
|
||||
command('autocmd TermClose * let g:test_termclose = 23')
|
||||
command('terminal')
|
||||
command('call jobstop(b:terminal_job_id)')
|
||||
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
|
||||
end)
|
||||
|
||||
it('kills job trapping SIGTERM', function()
|
||||
nvim('set_option', 'shell', 'sh')
|
||||
nvim('set_option', 'shellcmdflag', '-c')
|
||||
command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]]
|
||||
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
|
||||
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]])
|
||||
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end)
|
||||
|
||||
local start = os.time()
|
||||
command('call jobstop(g:test_job)')
|
||||
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
|
||||
local duration = os.time() - start
|
||||
eq(2, duration)
|
||||
end)
|
||||
|
||||
it('kills pty job trapping SIGHUP and SIGTERM', function()
|
||||
nvim('set_option', 'shell', 'sh')
|
||||
nvim('set_option', 'shellcmdflag', '-c')
|
||||
command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]]
|
||||
.. [[ 'pty': 1,]]
|
||||
.. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
|
||||
.. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]])
|
||||
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_started", 0)')) end)
|
||||
|
||||
local start = os.time()
|
||||
command('call jobstop(g:test_job)')
|
||||
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
|
||||
local duration = os.time() - start
|
||||
-- nvim starts sending kill after 2*KILL_TIMEOUT_MS
|
||||
helpers.ok(4 <= duration)
|
||||
helpers.ok(duration <= 7) -- <= 4 + delta because of slow CI
|
||||
end)
|
||||
|
||||
it('reports the correct <abuf>', function()
|
||||
@@ -35,12 +70,12 @@ describe('TermClose event', function()
|
||||
eq(2, eval('bufnr("%")'))
|
||||
|
||||
command('terminal')
|
||||
retry(nil, nil, function() eq_err(3, eval('bufnr("%")')) end)
|
||||
retry(nil, nil, function() eq(3, eval('bufnr("%")')) end)
|
||||
|
||||
command('buffer 1')
|
||||
retry(nil, nil, function() eq_err(1, eval('bufnr("%")')) end)
|
||||
retry(nil, nil, function() eq(1, eval('bufnr("%")')) end)
|
||||
|
||||
command('3bdelete!')
|
||||
retry(nil, nil, function() eq_err('3', eval('g:abuf')) end)
|
||||
retry(nil, nil, function() eq('3', eval('g:abuf')) end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq
|
||||
local feed, execute, expect, command = helpers.feed, helpers.execute, helpers.expect, helpers.command
|
||||
local feed, command, expect = helpers.feed, helpers.command, helpers.expect
|
||||
local curbufmeths, funcs, neq = helpers.curbufmeths, helpers.funcs, helpers.neq
|
||||
|
||||
describe('TextYankPost', function()
|
||||
@@ -8,11 +8,11 @@ describe('TextYankPost', function()
|
||||
clear()
|
||||
|
||||
-- emulate the clipboard so system clipboard isn't affected
|
||||
execute('let &rtp = "test/functional/fixtures,".&rtp')
|
||||
command('let &rtp = "test/functional/fixtures,".&rtp')
|
||||
|
||||
execute('let g:count = 0')
|
||||
execute('autocmd TextYankPost * let g:event = copy(v:event)')
|
||||
execute('autocmd TextYankPost * let g:count += 1')
|
||||
command('let g:count = 0')
|
||||
command('autocmd TextYankPost * let g:event = copy(v:event)')
|
||||
command('autocmd TextYankPost * let g:count += 1')
|
||||
|
||||
curbufmeths.set_lines(0, -1, true, {
|
||||
'foo\0bar',
|
||||
@@ -61,27 +61,27 @@ describe('TextYankPost', function()
|
||||
regtype = 'V'
|
||||
}, eval('g:event'))
|
||||
|
||||
execute('set debug=msg')
|
||||
command('set debug=msg')
|
||||
-- the regcontents should not be changed without copy.
|
||||
local status, err = pcall(command,'call extend(g:event.regcontents, ["more text"])')
|
||||
eq(status,false)
|
||||
neq(nil, string.find(err, ':E742:'))
|
||||
|
||||
-- can't mutate keys inside the autocommand
|
||||
execute('autocmd! TextYankPost * let v:event.regcontents = 0')
|
||||
command('autocmd! TextYankPost * let v:event.regcontents = 0')
|
||||
status, err = pcall(command,'normal yy')
|
||||
eq(status,false)
|
||||
neq(nil, string.find(err, ':E46:'))
|
||||
|
||||
-- can't add keys inside the autocommand
|
||||
execute('autocmd! TextYankPost * let v:event.mykey = 0')
|
||||
command('autocmd! TextYankPost * let v:event.mykey = 0')
|
||||
status, err = pcall(command,'normal yy')
|
||||
eq(status,false)
|
||||
neq(nil, string.find(err, ':E742:'))
|
||||
end)
|
||||
|
||||
it('is not invoked recursively', function()
|
||||
execute('autocmd TextYankPost * normal "+yy')
|
||||
command('autocmd TextYankPost * normal "+yy')
|
||||
feed('yy')
|
||||
eq({
|
||||
operator = 'y',
|
||||
@@ -134,7 +134,7 @@ describe('TextYankPost', function()
|
||||
feed('"_yy')
|
||||
eq(0, eval('g:count'))
|
||||
|
||||
execute('delete _')
|
||||
command('delete _')
|
||||
eq(0, eval('g:count'))
|
||||
end)
|
||||
|
||||
@@ -155,7 +155,7 @@ describe('TextYankPost', function()
|
||||
regtype = 'V'
|
||||
}, eval('g:event'))
|
||||
|
||||
execute("set clipboard=unnamed")
|
||||
command("set clipboard=unnamed")
|
||||
|
||||
-- regname still shows the name the user requested
|
||||
feed('yy')
|
||||
@@ -176,7 +176,7 @@ describe('TextYankPost', function()
|
||||
end)
|
||||
|
||||
it('works with Ex commands', function()
|
||||
execute('1delete +')
|
||||
command('1delete +')
|
||||
eq({
|
||||
operator = 'd',
|
||||
regcontents = { 'foo\nbar' },
|
||||
@@ -185,7 +185,7 @@ describe('TextYankPost', function()
|
||||
}, eval('g:event'))
|
||||
eq(1, eval('g:count'))
|
||||
|
||||
execute('yank')
|
||||
command('yank')
|
||||
eq({
|
||||
operator = 'y',
|
||||
regcontents = { 'baz text' },
|
||||
@@ -194,7 +194,7 @@ describe('TextYankPost', function()
|
||||
}, eval('g:event'))
|
||||
eq(2, eval('g:count'))
|
||||
|
||||
execute('normal yw')
|
||||
command('normal yw')
|
||||
eq({
|
||||
operator = 'y',
|
||||
regcontents = { 'baz ' },
|
||||
@@ -203,7 +203,7 @@ describe('TextYankPost', function()
|
||||
}, eval('g:event'))
|
||||
eq(3, eval('g:count'))
|
||||
|
||||
execute('normal! dd')
|
||||
command('normal! dd')
|
||||
eq({
|
||||
operator = 'd',
|
||||
regcontents = { 'baz text' },
|
||||
|
@@ -3,7 +3,9 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect, eq, eval = helpers.execute, helpers.expect, helpers.eq, helpers.eval
|
||||
local feed_command, expect, eq, eval = helpers.feed_command, helpers.expect, helpers.eq, helpers.eval
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
|
||||
local function basic_register_test(noblock)
|
||||
insert("some words")
|
||||
@@ -80,25 +82,112 @@ local function basic_register_test(noblock)
|
||||
expect("two and three and one")
|
||||
end
|
||||
|
||||
describe('the unnamed register', function()
|
||||
describe('clipboard', function()
|
||||
before_each(clear)
|
||||
it('works without provider', function()
|
||||
|
||||
it('unnamed register works without provider', function()
|
||||
eq('"', eval('v:register'))
|
||||
basic_register_test()
|
||||
end)
|
||||
|
||||
it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
feed_command('redir @+> | bogus_cmd | redir END')
|
||||
screen:expect([[
|
||||
~ |
|
||||
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
|
||||
E492: Not an editor command: bogus_cmd | redir END |
|
||||
Press ENTER or type command to continue^ |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('invalid g:clipboard shows hint if :redir is not active', function()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
eq('', eval('provider#clipboard#Executable()'))
|
||||
eq('clipboard: invalid g:clipboard', eval('provider#clipboard#Error()'))
|
||||
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
command("let g:clipboard = 'bogus'")
|
||||
-- Explicit clipboard attempt, should show a hint message.
|
||||
feed_command('let @+="foo"')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('valid g:clipboard', function()
|
||||
-- provider#clipboard#Executable() only checks the structure.
|
||||
meths.set_var('clipboard', {
|
||||
['name'] = 'clippy!',
|
||||
['copy'] = { ['+'] = 'any command', ['*'] = 'some other' },
|
||||
['paste'] = { ['+'] = 'any command', ['*'] = 'some other' },
|
||||
})
|
||||
eq('clippy!', eval('provider#clipboard#Executable()'))
|
||||
eq('', eval('provider#clipboard#Error()'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('clipboard usage', function()
|
||||
describe('clipboard', function()
|
||||
local function reset(...)
|
||||
clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp', ...)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
reset()
|
||||
execute('call getreg("*")') -- force load of provider
|
||||
feed_command('call getreg("*")') -- force load of provider
|
||||
end)
|
||||
|
||||
it('has independent "* and unnamed registers per default', function()
|
||||
it('`:redir @+>` invokes clipboard once-per-message', function()
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
-- Assuming CONTRIBUTING.md has >100 lines.
|
||||
assert(eval("g:clip_called_set") > 100)
|
||||
end)
|
||||
|
||||
it('`:redir @">` does NOT invoke clipboard', function()
|
||||
-- :redir to a non-clipboard register, with `:set clipboard=unnamed` does
|
||||
-- NOT propagate to the clipboard. This is consistent with Vim.
|
||||
command("set clipboard=unnamedplus")
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
feed_command('redir @"> | :silent echo system("cat CONTRIBUTING.md") | redir END')
|
||||
eq(0, eval("g:clip_called_set"))
|
||||
end)
|
||||
|
||||
it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184',
|
||||
function()
|
||||
local screen = Screen.new(72, 4)
|
||||
screen:attach()
|
||||
feed_command('redir @+> | bogus_cmd | redir END')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
E492: Not an editor command: bogus_cmd | redir END |
|
||||
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
|
||||
end)
|
||||
|
||||
it('has independent "* and unnamed registers by default', function()
|
||||
insert("some words")
|
||||
feed('^"*dwdw"*P')
|
||||
expect('some ')
|
||||
@@ -139,9 +228,9 @@ describe('clipboard usage', function()
|
||||
eq({'some\ntext', '\nvery binary\n'}, eval("getreg('*', 1, 1)"))
|
||||
end)
|
||||
|
||||
it('support autodectection of regtype', function()
|
||||
execute("let g:test_clip['*'] = ['linewise stuff','']")
|
||||
execute("let g:test_clip['+'] = ['charwise','stuff']")
|
||||
it('autodetects regtype', function()
|
||||
feed_command("let g:test_clip['*'] = ['linewise stuff','']")
|
||||
feed_command("let g:test_clip['+'] = ['charwise','stuff']")
|
||||
eq("V", eval("getregtype('*')"))
|
||||
eq("v", eval("getregtype('+')"))
|
||||
insert("just some text")
|
||||
@@ -156,7 +245,7 @@ describe('clipboard usage', function()
|
||||
insert([[
|
||||
much
|
||||
text]])
|
||||
execute("let g:test_clip['*'] = [['very','block'],'b']")
|
||||
feed_command("let g:test_clip['*'] = [['very','block'],'b']")
|
||||
feed('gg"*P')
|
||||
expect([[
|
||||
very much
|
||||
@@ -169,16 +258,16 @@ describe('clipboard usage', function()
|
||||
eq({{' much', 'ktext', ''}, 'b'}, eval("g:test_clip['+']"))
|
||||
end)
|
||||
|
||||
it('supports setreg', function()
|
||||
execute('call setreg("*", "setted\\ntext", "c")')
|
||||
execute('call setreg("+", "explicitly\\nlines", "l")')
|
||||
it('supports setreg()', function()
|
||||
feed_command('call setreg("*", "setted\\ntext", "c")')
|
||||
feed_command('call setreg("+", "explicitly\\nlines", "l")')
|
||||
feed('"+P"*p')
|
||||
expect([[
|
||||
esetted
|
||||
textxplicitly
|
||||
lines
|
||||
]])
|
||||
execute('call setreg("+", "blocky\\nindeed", "b")')
|
||||
feed_command('call setreg("+", "blocky\\nindeed", "b")')
|
||||
feed('"+p')
|
||||
expect([[
|
||||
esblockyetted
|
||||
@@ -187,14 +276,14 @@ describe('clipboard usage', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('supports let @+ (issue #1427)', function()
|
||||
execute("let @+ = 'some'")
|
||||
execute("let @* = ' other stuff'")
|
||||
it('supports :let @+ (issue #1427)', function()
|
||||
feed_command("let @+ = 'some'")
|
||||
feed_command("let @* = ' other stuff'")
|
||||
eq({{'some'}, 'v'}, eval("g:test_clip['+']"))
|
||||
eq({{' other stuff'}, 'v'}, eval("g:test_clip['*']"))
|
||||
feed('"+p"*p')
|
||||
expect('some other stuff')
|
||||
execute("let @+ .= ' more'")
|
||||
feed_command("let @+ .= ' more'")
|
||||
feed('dd"+p')
|
||||
expect('some more')
|
||||
end)
|
||||
@@ -202,7 +291,7 @@ describe('clipboard usage', function()
|
||||
it('pastes unnamed register if the provider fails', function()
|
||||
insert('the text')
|
||||
feed('yy')
|
||||
execute("let g:cliperror = 1")
|
||||
feed_command("let g:cliperror = 1")
|
||||
feed('"*p')
|
||||
expect([[
|
||||
the text
|
||||
@@ -214,7 +303,7 @@ describe('clipboard usage', function()
|
||||
-- the basic behavior of unnamed register should be the same
|
||||
-- even when handled by clipboard provider
|
||||
before_each(function()
|
||||
execute('set clipboard=unnamed')
|
||||
feed_command('set clipboard=unnamed')
|
||||
end)
|
||||
|
||||
it('works', function()
|
||||
@@ -222,7 +311,7 @@ describe('clipboard usage', function()
|
||||
end)
|
||||
|
||||
it('works with pure text clipboard', function()
|
||||
execute("let g:cliplossy = 1")
|
||||
feed_command("let g:cliplossy = 1")
|
||||
-- expect failure for block mode
|
||||
basic_register_test(true)
|
||||
end)
|
||||
@@ -237,7 +326,7 @@ describe('clipboard usage', function()
|
||||
-- "+ shouldn't have changed
|
||||
eq({''}, eval("g:test_clip['+']"))
|
||||
|
||||
execute("let g:test_clip['*'] = ['linewise stuff','']")
|
||||
feed_command("let g:test_clip['*'] = ['linewise stuff','']")
|
||||
feed('p')
|
||||
expect([[
|
||||
words
|
||||
@@ -247,7 +336,7 @@ describe('clipboard usage', function()
|
||||
it('does not clobber "0 when pasting', function()
|
||||
insert('a line')
|
||||
feed('yy')
|
||||
execute("let g:test_clip['*'] = ['b line','']")
|
||||
feed_command("let g:test_clip['*'] = ['b line','']")
|
||||
feed('"0pp"0p')
|
||||
expect([[
|
||||
a line
|
||||
@@ -258,20 +347,20 @@ describe('clipboard usage', function()
|
||||
|
||||
it('supports v:register and getreg() without parameters', function()
|
||||
eq('*', eval('v:register'))
|
||||
execute("let g:test_clip['*'] = [['some block',''], 'b']")
|
||||
feed_command("let g:test_clip['*'] = [['some block',''], 'b']")
|
||||
eq('some block', eval('getreg()'))
|
||||
eq('\02210', eval('getregtype()'))
|
||||
end)
|
||||
|
||||
it('yanks visual selection when pasting', function()
|
||||
insert("indeed visual")
|
||||
execute("let g:test_clip['*'] = [['clipboard'], 'c']")
|
||||
feed_command("let g:test_clip['*'] = [['clipboard'], 'c']")
|
||||
feed("viwp")
|
||||
eq({{'visual'}, 'v'}, eval("g:test_clip['*']"))
|
||||
expect("indeed clipboard")
|
||||
|
||||
-- explicit "* should do the same
|
||||
execute("let g:test_clip['*'] = [['star'], 'c']")
|
||||
feed_command("let g:test_clip['*'] = [['star'], 'c']")
|
||||
feed('viw"*p')
|
||||
eq({{'clipboard'}, 'v'}, eval("g:test_clip['*']"))
|
||||
expect("indeed star")
|
||||
@@ -280,7 +369,7 @@ describe('clipboard usage', function()
|
||||
it('unamed operations work even if the provider fails', function()
|
||||
insert('the text')
|
||||
feed('yy')
|
||||
execute("let g:cliperror = 1")
|
||||
feed_command("let g:cliperror = 1")
|
||||
feed('p')
|
||||
expect([[
|
||||
the text
|
||||
@@ -294,20 +383,27 @@ describe('clipboard usage', function()
|
||||
match
|
||||
text
|
||||
]])
|
||||
execute('g/match/d')
|
||||
feed_command('g/match/d')
|
||||
eq('match\n', eval('getreg("*")'))
|
||||
feed('u')
|
||||
eval('setreg("*", "---")')
|
||||
execute('g/test/')
|
||||
feed_command('g/test/')
|
||||
feed('<esc>')
|
||||
eq('---', eval('getreg("*")'))
|
||||
end)
|
||||
|
||||
it('works in the cmdline window', function()
|
||||
feed('q:itext<esc>yy')
|
||||
eq({{'text', ''}, 'V'}, eval("g:test_clip['*']"))
|
||||
command("let g:test_clip['*'] = [['star'], 'c']")
|
||||
feed('p')
|
||||
eq('textstar', meths.get_current_line())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('with clipboard=unnamedplus', function()
|
||||
describe('clipboard=unnamedplus', function()
|
||||
before_each(function()
|
||||
execute('set clipboard=unnamedplus')
|
||||
feed_command('set clipboard=unnamedplus')
|
||||
end)
|
||||
|
||||
it('links the "+ and unnamed registers', function()
|
||||
@@ -320,13 +416,13 @@ describe('clipboard usage', function()
|
||||
-- "* shouldn't have changed
|
||||
eq({''}, eval("g:test_clip['*']"))
|
||||
|
||||
execute("let g:test_clip['+'] = ['three']")
|
||||
feed_command("let g:test_clip['+'] = ['three']")
|
||||
feed('p')
|
||||
expect('twothree')
|
||||
end)
|
||||
|
||||
it('and unnamed, yanks to both', function()
|
||||
execute('set clipboard=unnamedplus,unnamed')
|
||||
feed_command('set clipboard=unnamedplus,unnamed')
|
||||
insert([[
|
||||
really unnamed
|
||||
text]])
|
||||
@@ -340,8 +436,8 @@ describe('clipboard usage', function()
|
||||
|
||||
-- unnamedplus takes predecence when pasting
|
||||
eq('+', eval('v:register'))
|
||||
execute("let g:test_clip['+'] = ['the plus','']")
|
||||
execute("let g:test_clip['*'] = ['the star','']")
|
||||
feed_command("let g:test_clip['+'] = ['the plus','']")
|
||||
feed_command("let g:test_clip['*'] = ['the star','']")
|
||||
feed("p")
|
||||
expect([[
|
||||
text
|
||||
@@ -349,6 +445,7 @@ describe('clipboard usage', function()
|
||||
really unnamed
|
||||
the plus]])
|
||||
end)
|
||||
|
||||
it('is updated on global changes', function()
|
||||
insert([[
|
||||
text
|
||||
@@ -356,11 +453,11 @@ describe('clipboard usage', function()
|
||||
match
|
||||
text
|
||||
]])
|
||||
execute('g/match/d')
|
||||
feed_command('g/match/d')
|
||||
eq('match\n', eval('getreg("+")'))
|
||||
feed('u')
|
||||
eval('setreg("+", "---")')
|
||||
execute('g/test/')
|
||||
feed_command('g/test/')
|
||||
feed('<esc>')
|
||||
eq('---', eval('getreg("+")'))
|
||||
end)
|
||||
@@ -375,13 +472,13 @@ describe('clipboard usage', function()
|
||||
|
||||
it('supports :put', function()
|
||||
insert("a line")
|
||||
execute("let g:test_clip['*'] = ['some text']")
|
||||
execute("let g:test_clip['+'] = ['more', 'text', '']")
|
||||
execute(":put *")
|
||||
feed_command("let g:test_clip['*'] = ['some text']")
|
||||
feed_command("let g:test_clip['+'] = ['more', 'text', '']")
|
||||
feed_command(":put *")
|
||||
expect([[
|
||||
a line
|
||||
some text]])
|
||||
execute(":put +")
|
||||
feed_command(":put +")
|
||||
expect([[
|
||||
a line
|
||||
some text
|
||||
@@ -392,9 +489,9 @@ describe('clipboard usage', function()
|
||||
it('supports "+ and "* in registers', function()
|
||||
local screen = Screen.new(60, 10)
|
||||
screen:attach()
|
||||
execute("let g:test_clip['*'] = ['some', 'star data','']")
|
||||
execute("let g:test_clip['+'] = ['such', 'plus', 'stuff']")
|
||||
execute("registers")
|
||||
feed_command("let g:test_clip['*'] = ['some', 'star data','']")
|
||||
feed_command("let g:test_clip['+'] = ['such', 'plus', 'stuff']")
|
||||
feed_command("registers")
|
||||
screen:expect([[
|
||||
~ |
|
||||
~ |
|
||||
@@ -418,17 +515,17 @@ describe('clipboard usage', function()
|
||||
insert('s/s/t/')
|
||||
feed('gg"*y$:<c-r>*<cr>')
|
||||
expect('t/s/t/')
|
||||
execute("let g:test_clip['*'] = ['s/s/u']")
|
||||
feed_command("let g:test_clip['*'] = ['s/s/u']")
|
||||
feed(':<c-r>*<cr>')
|
||||
expect('t/u/t/')
|
||||
end)
|
||||
|
||||
it('supports :redir @*>', function()
|
||||
execute("let g:test_clip['*'] = ['stuff']")
|
||||
execute('redir @*>')
|
||||
feed_command("let g:test_clip['*'] = ['stuff']")
|
||||
feed_command('redir @*>')
|
||||
-- it is made empty
|
||||
eq({{''}, 'v'}, eval("g:test_clip['*']"))
|
||||
execute('let g:test = doesnotexist')
|
||||
feed_command('let g:test = doesnotexist')
|
||||
feed('<cr>')
|
||||
eq({{
|
||||
'',
|
||||
@@ -436,7 +533,7 @@ describe('clipboard usage', function()
|
||||
'E121: Undefined variable: doesnotexist',
|
||||
'E15: Invalid expression: doesnotexist',
|
||||
}, 'v'}, eval("g:test_clip['*']"))
|
||||
execute(':echo "Howdy!"')
|
||||
feed_command(':echo "Howdy!"')
|
||||
eq({{
|
||||
'',
|
||||
'',
|
||||
@@ -448,7 +545,7 @@ describe('clipboard usage', function()
|
||||
end)
|
||||
|
||||
it('handles middleclick correctly', function()
|
||||
execute('set mouse=a')
|
||||
feed_command('set mouse=a')
|
||||
|
||||
local screen = Screen.new(30, 5)
|
||||
screen:attach()
|
||||
@@ -471,7 +568,7 @@ describe('clipboard usage', function()
|
||||
the a target]])
|
||||
|
||||
-- on error, fall back to unnamed register
|
||||
execute("let g:cliperror = 1")
|
||||
feed_command("let g:cliperror = 1")
|
||||
feed('<MiddleMouse><6,1>')
|
||||
expect([[
|
||||
the source
|
||||
|
266
test/functional/core/channels_spec.lua
Normal file
266
test/functional/core/channels_spec.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq,
|
||||
helpers.eval, helpers.next_message, helpers.ok, helpers.source
|
||||
local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths
|
||||
local sleep = helpers.sleep
|
||||
local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
|
||||
local set_session = helpers.set_session
|
||||
local nvim_prog = helpers.nvim_prog
|
||||
local retry = helpers.retry
|
||||
local expect_twostreams = helpers.expect_twostreams
|
||||
|
||||
describe('channels', function()
|
||||
local init = [[
|
||||
function! Normalize(data) abort
|
||||
" Windows: remove ^M
|
||||
return type([]) == type(a:data)
|
||||
\ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
|
||||
\ : a:data
|
||||
endfunction
|
||||
function! OnEvent(id, data, event) dict
|
||||
call rpcnotify(1, a:event, a:id, a:data)
|
||||
endfunction
|
||||
]]
|
||||
before_each(function()
|
||||
clear()
|
||||
source(init)
|
||||
end)
|
||||
|
||||
pending('can connect to socket', function()
|
||||
local server = spawn(nvim_argv)
|
||||
set_session(server)
|
||||
local address = funcs.serverlist()[1]
|
||||
local client = spawn(nvim_argv)
|
||||
set_session(client, true)
|
||||
source(init)
|
||||
|
||||
meths.set_var('address', address)
|
||||
command("let g:id = sockconnect('pipe', address, {'on_data':'OnEvent'})")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
command("call chansend(g:id, msgpackdump([[2,'nvim_set_var',['code',23]]]))")
|
||||
set_session(server, true)
|
||||
retry(nil, 1000, function()
|
||||
eq(23, meths.get_var('code'))
|
||||
end)
|
||||
set_session(client, true)
|
||||
|
||||
command("call chansend(g:id, msgpackdump([[0,0,'nvim_eval',['2+3']]]))")
|
||||
|
||||
|
||||
local res = eval("msgpackdump([[1,0,v:null,5]])")
|
||||
eq({"\148\001\n\192\005"}, res)
|
||||
eq({'notification', 'data', {id, res}}, next_msg())
|
||||
command("call chansend(g:id, msgpackdump([[2,'nvim_command',['quit']]]))")
|
||||
eq({'notification', 'data', {id, {''}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('can use stdio channel', function()
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_stderr': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
function! OnEvent(id, data, event) dict
|
||||
let text = string([a:id, a:data, a:event])
|
||||
call chansend(g:x, text)
|
||||
|
||||
if a:data == ['']
|
||||
call chansend(v:stderr, "*dies*")
|
||||
quit
|
||||
endif
|
||||
endfunction
|
||||
let g:x = stdioopen({'on_stdin':'OnEvent'})
|
||||
call chansend(x, "hello")
|
||||
]])
|
||||
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
eq({ "notification", "stdout", {id, { "hello" } } }, next_msg())
|
||||
|
||||
command("call chansend(id, 'howdy')")
|
||||
eq({"notification", "stdout", {id, {"[1, ['howdy'], 'stdin']"}}}, next_msg())
|
||||
|
||||
command("call chanclose(id, 'stdin')")
|
||||
expect_twostreams({{"notification", "stdout", {id, {"[1, [''], 'stdin']"}}},
|
||||
{'notification', 'stdout', {id, {''}}}},
|
||||
{{"notification", "stderr", {id, {"*dies*"}}},
|
||||
{'notification', 'stderr', {id, {''}}}})
|
||||
eq({"notification", "exit", {3,0}}, next_msg())
|
||||
end)
|
||||
|
||||
local function expect_twoline(id, stream, line1, line2, nobr)
|
||||
local msg = next_msg()
|
||||
local joined = nobr and {line1..line2} or {line1, line2}
|
||||
if not pcall(eq, {"notification", stream, {id, joined}}, msg) then
|
||||
local sep = (not nobr) and "" or nil
|
||||
eq({"notification", stream, {id, {line1, sep}}}, msg)
|
||||
eq({"notification", stream, {id, {line2}}}, next_msg())
|
||||
end
|
||||
end
|
||||
|
||||
it('can use stdio channel with pty', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'pty': v:true,
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
function! OnEvent(id, data, event) dict
|
||||
let text = string([a:id, a:data, a:event])
|
||||
call chansend(g:x, text)
|
||||
endfunction
|
||||
let g:x = stdioopen({'on_stdin':'OnEvent'})
|
||||
]])
|
||||
command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
ok(id > 0)
|
||||
|
||||
command("call chansend(id, 'TEXT\n')")
|
||||
expect_twoline(id, "stdout", "TEXT\r", "[1, ['TEXT', ''], 'stdin']")
|
||||
|
||||
|
||||
command("call chansend(id, 'neovan')")
|
||||
eq({"notification", "stdout", {id, {"neovan"}}}, next_msg())
|
||||
command("call chansend(id, '\127\127im\n')")
|
||||
expect_twoline(id, "stdout", "\b \b\b \bim\r", "[1, ['neovim', ''], 'stdin']")
|
||||
|
||||
command("call chansend(id, 'incomplet\004')")
|
||||
|
||||
local is_freebsd = eval("system('uname') =~? 'FreeBSD'") == 1
|
||||
local bsdlike = is_freebsd or (helpers.os_name() == "osx")
|
||||
print("bsdlike:", bsdlike)
|
||||
local extra = bsdlike and "^D\008\008" or ""
|
||||
expect_twoline(id, "stdout",
|
||||
"incomplet"..extra, "[1, ['incomplet'], 'stdin']", true)
|
||||
|
||||
|
||||
command("call chansend(id, '\004')")
|
||||
if bsdlike then
|
||||
expect_twoline(id, "stdout", extra, "[1, [''], 'stdin']", true)
|
||||
else
|
||||
eq({"notification", "stdout", {id, {"[1, [''], 'stdin']"}}}, next_msg())
|
||||
end
|
||||
|
||||
-- channel is still open
|
||||
command("call chansend(id, 'hi again!\n')")
|
||||
eq({"notification", "stdout", {id, {"hi again!\r", ""}}}, next_msg())
|
||||
end)
|
||||
|
||||
|
||||
it('stdio channel can use rpc and stderr simultaneously', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stderr': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'rpc': v:true,
|
||||
\ }
|
||||
]])
|
||||
meths.set_var("nvim_prog", nvim_prog)
|
||||
meths.set_var("code", [[
|
||||
let id = stdioopen({'rpc':v:true})
|
||||
call rpcnotify(id,"nvim_call_function", "rpcnotify", [1, "message", "hi there!", id])
|
||||
call chansend(v:stderr, "trouble!")
|
||||
]])
|
||||
command("let id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
|
||||
eq({"notification", "message", {"hi there!", 1}}, next_msg())
|
||||
eq({"notification", "stderr", {3, {"trouble!"}}}, next_msg())
|
||||
|
||||
eq(30, eval("rpcrequest(id, 'nvim_eval', '[chansend(v:stderr, \"math??\"), 5*6][1]')"))
|
||||
eq({"notification", "stderr", {3, {"math??"}}}, next_msg())
|
||||
|
||||
local _, err = pcall(command,"call rpcrequest(id, 'nvim_command', 'call chanclose(v:stderr, \"stdin\")')")
|
||||
ok(string.find(err,"E906: invalid stream for channel") ~= nil)
|
||||
|
||||
eq(1, eval("rpcrequest(id, 'nvim_eval', 'chanclose(v:stderr, \"stderr\")')"))
|
||||
eq({"notification", "stderr", {3, {""}}}, next_msg())
|
||||
|
||||
command("call rpcnotify(id, 'nvim_command', 'quit')")
|
||||
eq({"notification", "exit", {3, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
it('can use buffered output mode', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
|
||||
sleep(10)
|
||||
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
eq({"notification", "stdout", {id, {'10 PRINT "NVIM"',
|
||||
'20 GOTO 10', ''}}}, next_msg())
|
||||
eq({"notification", "exit", {id, 0}}, next_msg())
|
||||
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "is no number\nnot at all")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
-- works correctly with no output
|
||||
eq({"notification", "stdout", {id, {''}}}, next_msg())
|
||||
eq({"notification", "exit", {id, 1}}, next_msg())
|
||||
|
||||
end)
|
||||
|
||||
it('can use buffered output mode with no stream callback', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
source([[
|
||||
function! OnEvent(id, data, event) dict
|
||||
call rpcnotify(1, a:event, a:id, a:data, self.stdout)
|
||||
endfunction
|
||||
let g:job_opts = {
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
local id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")]])
|
||||
sleep(10)
|
||||
command([[call chansend(id, "xx\n20 GOTO 10\nzz\n")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
eq({"notification", "exit", {id, 0, {'10 PRINT "NVIM"',
|
||||
'20 GOTO 10', ''}}}, next_msg())
|
||||
|
||||
-- reset dictionary
|
||||
source([[
|
||||
let g:job_opts = {
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'stdout_buffered': v:true,
|
||||
\ }
|
||||
]])
|
||||
command("let id = jobstart(['grep', '^[0-9]'], g:job_opts)")
|
||||
id = eval("g:id")
|
||||
|
||||
command([[call chansend(id, "is no number\nnot at all")]])
|
||||
command("call chanclose(id, 'stdin')")
|
||||
|
||||
-- works correctly with no output
|
||||
eq({"notification", "exit", {id, 1, {''}}}, next_msg())
|
||||
|
||||
end)
|
||||
end)
|
@@ -2,8 +2,12 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local command = helpers.command
|
||||
local eval = helpers.eval
|
||||
local eq, neq = helpers.eq, helpers.neq
|
||||
local eq = helpers.eq
|
||||
local run = helpers.run
|
||||
local funcs = helpers.funcs
|
||||
local nvim_prog = helpers.nvim_prog
|
||||
local redir_exec = helpers.redir_exec
|
||||
local wait = helpers.wait
|
||||
|
||||
describe('v:exiting', function()
|
||||
local cid
|
||||
@@ -29,18 +33,53 @@ describe('v:exiting', function()
|
||||
end
|
||||
run(on_request, nil, on_setup)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('is non-zero after :cquit', function()
|
||||
local function on_setup()
|
||||
command('autocmd VimLeavePre * call rpcrequest('..cid..', "")')
|
||||
command('autocmd VimLeave * call rpcrequest('..cid..', "")')
|
||||
command('cquit')
|
||||
describe(':cquit', function()
|
||||
local function test_cq(cmdline, exit_code, redir_msg)
|
||||
if redir_msg then
|
||||
eq('\n' .. redir_msg, redir_exec(cmdline))
|
||||
wait()
|
||||
eq(2, eval("1+1")) -- Still alive?
|
||||
else
|
||||
funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline})
|
||||
eq(exit_code, eval('v:shell_error'))
|
||||
end
|
||||
local function on_request()
|
||||
neq(0, eval('v:exiting'))
|
||||
return ''
|
||||
end
|
||||
run(on_request, nil, on_setup)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
helpers.clear()
|
||||
end)
|
||||
|
||||
it('exits with non-zero after :cquit', function()
|
||||
test_cq('cquit', 1, nil)
|
||||
end)
|
||||
|
||||
it('exits with non-zero after :cquit 123', function()
|
||||
test_cq('cquit 123', 123, nil)
|
||||
end)
|
||||
|
||||
it('exits with non-zero after :123 cquit', function()
|
||||
test_cq('123 cquit', 123, nil)
|
||||
end)
|
||||
|
||||
it('exits with 0 after :cquit 0', function()
|
||||
test_cq('cquit 0', 0, nil)
|
||||
end)
|
||||
|
||||
it('exits with 0 after :0 cquit', function()
|
||||
test_cq('0 cquit', 0, nil)
|
||||
end)
|
||||
|
||||
it('exits with redir msg for multiple exit codes after :cquit 1 2', function()
|
||||
test_cq('cquit 1 2', nil, 'E488: Trailing characters: cquit 1 2')
|
||||
end)
|
||||
|
||||
it('exits with redir msg for non-number exit code after :cquit X', function()
|
||||
test_cq('cquit X', nil, 'E488: Trailing characters: cquit X')
|
||||
end)
|
||||
|
||||
it('exits with redir msg for negative exit code after :cquit -1', function()
|
||||
test_cq('cquit -1', nil, 'E488: Trailing characters: cquit -1')
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,13 +1,16 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eq, eval, exc_exec, execute, feed, insert, neq, next_msg, nvim,
|
||||
local clear, eq, eval, exc_exec, feed_command, feed, insert, neq, next_msg, nvim,
|
||||
nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear,
|
||||
helpers.eq, helpers.eval, helpers.exc_exec, helpers.execute, helpers.feed,
|
||||
helpers.eq, helpers.eval, helpers.exc_exec, helpers.feed_command, helpers.feed,
|
||||
helpers.insert, helpers.neq, helpers.next_message, helpers.nvim,
|
||||
helpers.nvim_dir, helpers.ok, helpers.source,
|
||||
helpers.write_file, helpers.mkdir, helpers.rmdir
|
||||
local command = helpers.command
|
||||
local wait = helpers.wait
|
||||
local iswin = helpers.iswin
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
local nvim_set = helpers.nvim_set
|
||||
local expect_twostreams = helpers.expect_twostreams
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
describe('jobs', function()
|
||||
@@ -27,15 +30,14 @@ describe('jobs', function()
|
||||
\ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
|
||||
\ : a:data
|
||||
endfunction
|
||||
function! s:OnEvent(id, data, event) dict
|
||||
function! OnEvent(id, data, event) dict
|
||||
let userdata = get(self, 'user')
|
||||
let data = Normalize(a:data)
|
||||
call rpcnotify(g:channel, a:event, userdata, data)
|
||||
endfunction
|
||||
let g:job_opts = {
|
||||
\ 'on_stdout': function('s:OnEvent'),
|
||||
\ 'on_stderr': function('s:OnEvent'),
|
||||
\ 'on_exit': function('s:OnEvent'),
|
||||
\ 'on_stdout': function('OnEvent'),
|
||||
\ 'on_exit': function('OnEvent'),
|
||||
\ 'user': 0
|
||||
\ }
|
||||
]])
|
||||
@@ -49,6 +51,7 @@ describe('jobs', function()
|
||||
nvim('command', "let j = jobstart('echo $VAR', g:job_opts)")
|
||||
end
|
||||
eq({'notification', 'stdout', {0, {'abc', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -61,11 +64,12 @@ describe('jobs', function()
|
||||
end
|
||||
eq({'notification', 'stdout',
|
||||
{0, {(iswin() and [[C:\]] or '/'), ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
it('changes to given `cwd` directory', function()
|
||||
local dir = eval('resolve(tempname())')
|
||||
local dir = eval("resolve(tempname())"):gsub("/", get_pathsep())
|
||||
mkdir(dir)
|
||||
nvim('command', "let g:job_opts.cwd = '" .. dir .. "'")
|
||||
if iswin() then
|
||||
@@ -74,6 +78,7 @@ describe('jobs', function()
|
||||
nvim('command', "let j = jobstart('pwd', g:job_opts)")
|
||||
end
|
||||
eq({'notification', 'stdout', {0, {dir, ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
rmdir(dir)
|
||||
end)
|
||||
@@ -93,7 +98,7 @@ describe('jobs', function()
|
||||
|
||||
it('returns 0 when it fails to start', function()
|
||||
eq("", eval("v:errmsg"))
|
||||
execute("let g:test_jobid = jobstart([])")
|
||||
feed_command("let g:test_jobid = jobstart([])")
|
||||
eq(0, eval("g:test_jobid"))
|
||||
eq("E474:", string.match(eval("v:errmsg"), "E%d*:"))
|
||||
end)
|
||||
@@ -116,8 +121,12 @@ describe('jobs', function()
|
||||
it('invokes callbacks when the job writes and exits', function()
|
||||
-- TODO: hangs on Windows
|
||||
if helpers.pending_win32(pending) then return end
|
||||
nvim('command', "let g:job_opts.on_stderr = function('OnEvent')")
|
||||
nvim('command', "call jobstart('echo', g:job_opts)")
|
||||
eq({'notification', 'stdout', {0, {'', ''}}}, next_msg())
|
||||
expect_twostreams({{'notification', 'stdout', {0, {'', ''}}},
|
||||
{'notification', 'stdout', {0, {''}}}},
|
||||
{{'notification', 'stderr', {0, {''}}}})
|
||||
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -132,6 +141,7 @@ describe('jobs', function()
|
||||
nvim('command', 'call jobsend(j, [123, "xyz", ""])')
|
||||
eq({'notification', 'stdout', {0, {'123', 'xyz', ''}}}, next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -143,6 +153,7 @@ describe('jobs', function()
|
||||
|
||||
nvim('command', "let j = jobstart(['cat', '"..filename.."'], g:job_opts)")
|
||||
eq({'notification', 'stdout', {0, {'abc\ndef', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
os.remove(filename)
|
||||
|
||||
@@ -166,6 +177,7 @@ describe('jobs', function()
|
||||
nvim('command', 'call jobsend(j, "abc\\nxyz")')
|
||||
eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -184,6 +196,7 @@ describe('jobs', function()
|
||||
eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}},
|
||||
next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -194,6 +207,7 @@ describe('jobs', function()
|
||||
eq({'notification', 'stdout', {0, {'some data', 'without\nfinal nl'}}},
|
||||
next_msg())
|
||||
nvim('command', "call jobstop(j)")
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -201,6 +215,7 @@ describe('jobs', function()
|
||||
if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
|
||||
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
|
||||
nvim('command', 'call jobclose(j, "stdin")')
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -237,6 +252,7 @@ describe('jobs', function()
|
||||
local pid = eval('jobpid(j)')
|
||||
eq(0,os.execute('ps -p '..pid..' > /dev/null'))
|
||||
nvim('command', 'call jobstop(j)')
|
||||
eq({'notification', 'stdout', {0, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||
neq(0,os.execute('ps -p '..pid..' > /dev/null'))
|
||||
end)
|
||||
@@ -268,6 +284,7 @@ describe('jobs', function()
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
local data = {n = 5, s = 'str', l = {1}}
|
||||
eq({'notification', 'stdout', {data, {'foo', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {data, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {data, 0}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -281,7 +298,6 @@ describe('jobs', function()
|
||||
|
||||
it('can omit data callbacks', function()
|
||||
nvim('command', 'unlet g:job_opts.on_stdout')
|
||||
nvim('command', 'unlet g:job_opts.on_stderr')
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
eq({'notification', 'exit', {5, 0}}, next_msg())
|
||||
@@ -292,11 +308,13 @@ describe('jobs', function()
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', [[call jobstart('echo "foo"', g:job_opts)]])
|
||||
eq({'notification', 'stdout', {5, {'foo', ''}}}, next_msg())
|
||||
eq({'notification', 'stdout', {5, {''}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('will pass return code with the exit event', function()
|
||||
nvim('command', 'let g:job_opts.user = 5')
|
||||
nvim('command', "call jobstart('exit 55', g:job_opts)")
|
||||
eq({'notification', 'stdout', {5, {''}}}, next_msg())
|
||||
eq({'notification', 'exit', {5, 55}}, next_msg())
|
||||
end)
|
||||
|
||||
@@ -339,6 +357,14 @@ describe('jobs', function()
|
||||
end)
|
||||
|
||||
it('requires funcrefs for script-local (s:) functions', function()
|
||||
local screen = Screen.new(60, 5)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}
|
||||
})
|
||||
|
||||
-- Pass job callback names _without_ `function(...)`.
|
||||
source([[
|
||||
function! s:OnEvent(id, data, event) dict
|
||||
@@ -348,14 +374,10 @@ describe('jobs', function()
|
||||
\ 'on_stdout': 's:OnEvent',
|
||||
\ 'on_stderr': 's:OnEvent',
|
||||
\ 'on_exit': 's:OnEvent',
|
||||
\ 'user': 2349
|
||||
\ })
|
||||
]])
|
||||
|
||||
-- The behavior is asynchronous, retry until a time limit.
|
||||
helpers.retry(nil, 10000, function()
|
||||
eq("E120:", string.match(eval("v:errmsg"), "E%d*:"))
|
||||
end)
|
||||
screen:expect("{2:E120: Using <SID> not in a script context: s:OnEvent}",nil,nil,nil,true)
|
||||
end)
|
||||
|
||||
it('does not repeat output with slow output handlers', function()
|
||||
@@ -374,7 +396,7 @@ describe('jobs', function()
|
||||
call jobwait([jobstart(cmd, d)])
|
||||
call rpcnotify(g:channel, 'data', d.data)
|
||||
]])
|
||||
eq({'notification', 'data', {{{'1', ''}, {'2', ''}, {'3', ''}, {'4', ''}, {'5', ''}}}}, next_msg())
|
||||
eq({'notification', 'data', {{{'1', ''}, {'2', ''}, {'3', ''}, {'4', ''}, {'5', ''}, {''}}}}, next_msg())
|
||||
end)
|
||||
|
||||
it('jobstart() works with partial functions', function()
|
||||
@@ -469,7 +491,7 @@ describe('jobs', function()
|
||||
end)
|
||||
|
||||
it('will return -2 when interrupted', function()
|
||||
execute('call rpcnotify(g:channel, "ready") | '..
|
||||
feed_command('call rpcnotify(g:channel, "ready") | '..
|
||||
'call rpcnotify(g:channel, "wait", '..
|
||||
'jobwait([jobstart("sleep 10; exit 55")]))')
|
||||
eq({'notification', 'ready', {}}, next_msg())
|
||||
@@ -495,7 +517,8 @@ describe('jobs', function()
|
||||
elseif self.state == 2
|
||||
let self.state = 3
|
||||
call jobsend(a:id, "line3\n")
|
||||
else
|
||||
elseif self.state == 3
|
||||
let self.state = 4
|
||||
call rpcnotify(g:channel, 'w', printf('job %d closed', self.counter))
|
||||
call jobclose(a:id, 'stdin')
|
||||
endif
|
||||
@@ -513,7 +536,7 @@ describe('jobs', function()
|
||||
\ ])
|
||||
endfunction
|
||||
]])
|
||||
execute('call Run()')
|
||||
feed_command('call Run()')
|
||||
local r
|
||||
for i = 10, 1, -1 do
|
||||
r = next_msg()
|
||||
@@ -550,6 +573,7 @@ describe('jobs', function()
|
||||
|
||||
-- FIXME need to wait until jobsend succeeds before calling jobstop
|
||||
pending('will only emit the "exit" event after "stdout" and "stderr"', function()
|
||||
nvim('command', "let g:job_opts.on_stderr = function('s:OnEvent')")
|
||||
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
|
||||
local jobid = nvim('eval', 'j')
|
||||
nvim('eval', 'jobsend(j, "abcdef")')
|
||||
@@ -636,7 +660,7 @@ describe('jobs', function()
|
||||
-- there won't be any more messages, and the test would hang.
|
||||
helpers.sleep(100)
|
||||
local err = exc_exec('call jobpid(j)')
|
||||
eq('Vim(call):E900: Invalid job id', err)
|
||||
eq('Vim(call):E900: Invalid channel id', err)
|
||||
|
||||
-- cleanup
|
||||
eq(other_pid, eval('jobpid(' .. other_jobid .. ')'))
|
||||
@@ -667,19 +691,20 @@ describe("pty process teardown", function()
|
||||
it("does not prevent/delay exit. #4798 #4900", function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
-- Use a nested nvim (in :term) to test without --headless.
|
||||
execute(":terminal '"..helpers.nvim_prog
|
||||
feed_command(":terminal '"..helpers.nvim_prog
|
||||
.."' -u NONE -i NONE --cmd '"..nvim_set.."' "
|
||||
-- Use :term again in the _nested_ nvim to get a PTY process.
|
||||
-- Use `sleep` to simulate a long-running child of the PTY.
|
||||
.."' +terminal +'!(sleep 300 &)' +qa")
|
||||
.."+terminal +'!(sleep 300 &)' +qa")
|
||||
|
||||
-- Exiting should terminate all descendants (PTY, its children, ...).
|
||||
screen:expect([[
|
||||
|
|
||||
^ |
|
||||
[Process exited 0] |
|
||||
|
|
||||
|
|
||||
|
|
||||
-- TERMINAL -- |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
56
test/functional/core/path_spec.lua
Normal file
56
test/functional/core/path_spec.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local command = helpers.command
|
||||
local iswin = helpers.iswin
|
||||
|
||||
describe('path collapse', function()
|
||||
local targetdir
|
||||
local expected_path
|
||||
|
||||
local function join_path(...)
|
||||
local pathsep = (iswin() and '\\' or '/')
|
||||
return table.concat({...}, pathsep)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
targetdir = join_path('test', 'functional', 'fixtures')
|
||||
clear()
|
||||
command('edit '..join_path(targetdir, 'tty-test.c'))
|
||||
expected_path = eval('expand("%:p")')
|
||||
end)
|
||||
|
||||
it('with /./ segment #7117', function()
|
||||
command('edit '..join_path(targetdir, '.', 'tty-test.c'))
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
|
||||
it('with ./ prefix #7117', function()
|
||||
command('edit '..join_path('.', targetdir, 'tty-test.c'))
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
|
||||
it('with ./ prefix, after directory change #7117', function()
|
||||
command('edit '..join_path('.', targetdir, 'tty-test.c'))
|
||||
command('cd test')
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
|
||||
it('with /../ segment #7117', function()
|
||||
command('edit '..join_path(targetdir, '..', 'fixtures', 'tty-test.c'))
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
|
||||
it('with ../ and different starting directory #7117', function()
|
||||
command('cd test')
|
||||
command('edit '..join_path('..', targetdir, 'tty-test.c'))
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
|
||||
it('with ./../ and different starting directory #7117', function()
|
||||
command('cd test')
|
||||
command('edit '..join_path('.', '..', targetdir, 'tty-test.c'))
|
||||
eq(expected_path, eval('expand("%:p")'))
|
||||
end)
|
||||
end)
|
96
test/functional/core/startup_spec.lua
Normal file
96
test/functional/core/startup_spec.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
local nvim_prog = helpers.nvim_prog
|
||||
local nvim_set = helpers.nvim_set
|
||||
local read_file = helpers.read_file
|
||||
local retry = helpers.retry
|
||||
local iswin = helpers.iswin
|
||||
|
||||
describe('startup', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
end)
|
||||
after_each(function()
|
||||
os.remove('Xtest_startup_ttyout')
|
||||
end)
|
||||
|
||||
it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function()
|
||||
-- system() puts a pipe at both ends.
|
||||
local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
|
||||
'--cmd', nvim_set,
|
||||
'-c', [[echo has('ttyin') has('ttyout')]],
|
||||
'+q' })
|
||||
eq('0 0', out)
|
||||
end)
|
||||
it('with --embed: has("ttyin")==0 has("ttyout")==0', function()
|
||||
local screen = Screen.new(25, 3)
|
||||
-- Remote UI connected by --embed.
|
||||
screen:attach()
|
||||
command([[echo has('ttyin') has('ttyout')]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
0 0 |
|
||||
]])
|
||||
end)
|
||||
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
|
||||
local screen = Screen.new(25, 3)
|
||||
screen:attach()
|
||||
if iswin() then
|
||||
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
|
||||
end
|
||||
-- Running in :terminal
|
||||
command([[exe printf("terminal %s -u NONE -i NONE --cmd \"]]
|
||||
..nvim_set..[[\" ]]
|
||||
..[[-c \"echo has('ttyin') has('ttyout')\""]]
|
||||
..[[, shellescape(v:progpath))]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
1 1 |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
it('output to pipe: has("ttyin")==1 has("ttyout")==0', function()
|
||||
local screen = Screen.new(25, 5)
|
||||
screen:attach()
|
||||
if iswin() then
|
||||
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
|
||||
end
|
||||
-- Running in :terminal
|
||||
command([[exe printf("terminal %s -u NONE -i NONE --cmd \"]]
|
||||
..nvim_set..[[\" ]]
|
||||
..[[-c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]]
|
||||
..[[-c q | cat -v"]] -- Output to a pipe.
|
||||
..[[, shellescape(v:progpath))]])
|
||||
retry(nil, 3000, function()
|
||||
screen:sleep(1)
|
||||
eq('1\n0\n', -- stdin is a TTY, stdout is a pipe
|
||||
read_file('Xtest_startup_ttyout'))
|
||||
end)
|
||||
end)
|
||||
it('input from pipe: has("ttyin")==0 has("ttyout")==1', function()
|
||||
local screen = Screen.new(25, 5)
|
||||
screen:attach()
|
||||
if iswin() then
|
||||
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
|
||||
end
|
||||
-- Running in :terminal
|
||||
command([[exe printf("terminal echo foo | ]] -- Input from a pipe.
|
||||
..[[%s -u NONE -i NONE --cmd \"]]
|
||||
..nvim_set..[[\" ]]
|
||||
..[[-c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]]
|
||||
..[[-c q -- -"]]
|
||||
..[[, shellescape(v:progpath))]])
|
||||
retry(nil, 3000, function()
|
||||
screen:sleep(1)
|
||||
eq('0\n1\n', -- stdin is a pipe, stdout is a TTY
|
||||
read_file('Xtest_startup_ttyout'))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local lfs = require('lfs')
|
||||
local neq, eq, execute = helpers.neq, helpers.eq, helpers.execute
|
||||
local neq, eq, command = helpers.neq, helpers.eq, helpers.command
|
||||
local clear, curbufmeths = helpers.clear, helpers.curbufmeths
|
||||
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
|
||||
local insert = helpers.insert
|
||||
@@ -10,17 +10,17 @@ describe('api functions', function()
|
||||
before_each(clear)
|
||||
|
||||
it("work", function()
|
||||
execute("call nvim_command('let g:test = 1')")
|
||||
command("call nvim_command('let g:test = 1')")
|
||||
eq(1, eval("nvim_get_var('test')"))
|
||||
|
||||
local buf = eval("nvim_get_current_buf()")
|
||||
execute("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])")
|
||||
command("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])")
|
||||
expect([[
|
||||
aa
|
||||
bb]])
|
||||
|
||||
execute("call nvim_win_set_cursor(0, [1, 1])")
|
||||
execute("call nvim_input('ax<esc>')")
|
||||
command("call nvim_win_set_cursor(0, [1, 1])")
|
||||
command("call nvim_input('ax<esc>')")
|
||||
expect([[
|
||||
aax
|
||||
bb]])
|
||||
@@ -57,7 +57,7 @@ describe('api functions', function()
|
||||
eq(bnr, bhnd)
|
||||
eq(wid, whnd)
|
||||
|
||||
execute("new") -- creates new buffer and new window
|
||||
command("new") -- creates new buffer and new window
|
||||
local bnr2 = eval("bufnr('')")
|
||||
local bhnd2 = eval("nvim_get_current_buf()")
|
||||
local wid2 = eval("win_getid()")
|
||||
@@ -69,7 +69,7 @@ describe('api functions', function()
|
||||
-- 0 is synonymous to the current buffer
|
||||
eq(bnr2, eval("nvim_buf_get_number(0)"))
|
||||
|
||||
execute("bn") -- show old buffer in new window
|
||||
command("bn") -- show old buffer in new window
|
||||
eq(bnr, eval("nvim_get_current_buf()"))
|
||||
eq(bnr, eval("bufnr('')"))
|
||||
eq(bnr, eval("nvim_buf_get_number(0)"))
|
||||
@@ -81,7 +81,7 @@ describe('api functions', function()
|
||||
curbufmeths.set_lines(0, -1, true, {"aa\0", "b\0b"})
|
||||
eq({'aa\n', 'b\nb'}, eval("nvim_buf_get_lines(0, 0, -1, 1)"))
|
||||
|
||||
execute('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
|
||||
command('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
|
||||
eq({'aa\0', 'xx', '\0yy'}, curbufmeths.get_lines(0, -1, 1))
|
||||
end)
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('api functions', function()
|
||||
|
||||
it('have metadata accessible with api_info()', function()
|
||||
local api_keys = eval("sort(keys(api_info()))")
|
||||
eq({'error_types', 'functions', 'types', 'version'}, api_keys)
|
||||
eq({'error_types', 'functions', 'types', 'ui_events', 'version'}, api_keys)
|
||||
end)
|
||||
|
||||
it('are highlighted by vim.vim syntax file', function()
|
||||
@@ -124,9 +124,9 @@ describe('api functions', function()
|
||||
[5] = {bold = true, foreground = Screen.colors.Blue},
|
||||
})
|
||||
|
||||
execute("set ft=vim")
|
||||
execute("let &rtp='build/runtime/,'.&rtp")
|
||||
execute("syntax on")
|
||||
command("set ft=vim")
|
||||
command("let &rtp='build/runtime/,'.&rtp")
|
||||
command("syntax on")
|
||||
insert([[
|
||||
call bufnr('%')
|
||||
call nvim_input('typing...')
|
||||
|
302
test/functional/eval/buf_functions_spec.lua
Normal file
302
test/functional/eval/buf_functions_spec.lua
Normal file
@@ -0,0 +1,302 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local lfs = require('lfs')
|
||||
|
||||
local eq = helpers.eq
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local bufmeths = helpers.bufmeths
|
||||
local winmeths = helpers.winmeths
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
local curwinmeths = helpers.curwinmeths
|
||||
local curtabmeths = helpers.curtabmeths
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
|
||||
local fname = 'Xtest-functional-eval-buf_functions'
|
||||
local fname2 = fname .. '.2'
|
||||
local dirname = fname .. '.d'
|
||||
|
||||
before_each(clear)
|
||||
|
||||
for _, func in ipairs({'bufname(%s)', 'bufnr(%s)', 'bufwinnr(%s)',
|
||||
'getbufline(%s, 1)', 'getbufvar(%s, "changedtick")',
|
||||
'setbufvar(%s, "f", 0)'}) do
|
||||
local funcname = func:match('%w+')
|
||||
describe(funcname .. '() function', function()
|
||||
it('errors out when receives v:true/v:false/v:null', function()
|
||||
-- Not compatible with Vim: in Vim it always results in buffer not found
|
||||
-- without any error messages.
|
||||
for _, var in ipairs({'v:true', 'v:false', 'v:null'}) do
|
||||
eq('Vim(call):E5300: Expected a Number or a String',
|
||||
exc_exec('call ' .. func:format(var)))
|
||||
end
|
||||
end)
|
||||
it('errors out when receives invalid argument', function()
|
||||
eq('Vim(call):E745: Expected a Number or a String, List found',
|
||||
exc_exec('call ' .. func:format('[]')))
|
||||
eq('Vim(call):E728: Expected a Number or a String, Dictionary found',
|
||||
exc_exec('call ' .. func:format('{}')))
|
||||
eq('Vim(call):E805: Expected a Number or a String, Float found',
|
||||
exc_exec('call ' .. func:format('0.0')))
|
||||
eq('Vim(call):E703: Expected a Number or a String, Funcref found',
|
||||
exc_exec('call ' .. func:format('function("tr")')))
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
describe('bufname() function', function()
|
||||
it('returns empty string when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq('', funcs.bufname(2))
|
||||
eq('', funcs.bufname('non-existent-buffer'))
|
||||
eq('', funcs.bufname('#'))
|
||||
command('edit ' .. fname2)
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq('', funcs.bufname('X'))
|
||||
end)
|
||||
before_each(function()
|
||||
lfs.mkdir(dirname)
|
||||
end)
|
||||
after_each(function()
|
||||
lfs.rmdir(dirname)
|
||||
end)
|
||||
it('returns expected buffer name', function()
|
||||
eq('', funcs.bufname('%')) -- Buffer has no name yet
|
||||
command('file ' .. fname)
|
||||
local wd = lfs.currentdir()
|
||||
local sep = get_pathsep()
|
||||
local curdirname = funcs.fnamemodify(wd, ':t')
|
||||
for _, arg in ipairs({'%', 1, 'X', wd}) do
|
||||
eq(fname, funcs.bufname(arg))
|
||||
meths.set_current_dir('..')
|
||||
eq(curdirname .. sep .. fname, funcs.bufname(arg))
|
||||
meths.set_current_dir(curdirname)
|
||||
meths.set_current_dir(dirname)
|
||||
eq(wd .. sep .. fname, funcs.bufname(arg))
|
||||
meths.set_current_dir('..')
|
||||
eq(fname, funcs.bufname(arg))
|
||||
command('enew')
|
||||
end
|
||||
eq('', funcs.bufname('%'))
|
||||
eq('', funcs.bufname('$'))
|
||||
eq(2, funcs.bufnr('%'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('bufnr() function', function()
|
||||
it('returns -1 when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq(-1, funcs.bufnr(2))
|
||||
eq(-1, funcs.bufnr('non-existent-buffer'))
|
||||
eq(-1, funcs.bufnr('#'))
|
||||
command('edit ' .. fname2)
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq(-1, funcs.bufnr('X'))
|
||||
end)
|
||||
it('returns expected buffer number', function()
|
||||
eq(1, funcs.bufnr('%'))
|
||||
command('file ' .. fname)
|
||||
local wd = lfs.currentdir()
|
||||
local curdirname = funcs.fnamemodify(wd, ':t')
|
||||
eq(1, funcs.bufnr(fname))
|
||||
eq(1, funcs.bufnr(wd))
|
||||
eq(1, funcs.bufnr(curdirname))
|
||||
eq(1, funcs.bufnr('X'))
|
||||
end)
|
||||
it('returns number of last buffer with "$"', function()
|
||||
eq(1, funcs.bufnr('$'))
|
||||
command('new')
|
||||
eq(2, funcs.bufnr('$'))
|
||||
command('new')
|
||||
eq(3, funcs.bufnr('$'))
|
||||
command('only')
|
||||
eq(3, funcs.bufnr('$'))
|
||||
eq(3, funcs.bufnr('%'))
|
||||
command('buffer 1')
|
||||
eq(3, funcs.bufnr('$'))
|
||||
eq(1, funcs.bufnr('%'))
|
||||
command('bwipeout 2')
|
||||
eq(3, funcs.bufnr('$'))
|
||||
eq(1, funcs.bufnr('%'))
|
||||
command('bwipeout 3')
|
||||
eq(1, funcs.bufnr('$'))
|
||||
eq(1, funcs.bufnr('%'))
|
||||
command('new')
|
||||
eq(4, funcs.bufnr('$'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('bufwinnr() function', function()
|
||||
it('returns -1 when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq(-1, funcs.bufwinnr(2))
|
||||
eq(-1, funcs.bufwinnr('non-existent-buffer'))
|
||||
eq(-1, funcs.bufwinnr('#'))
|
||||
command('split ' .. fname2) -- It would be OK if there was one window
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq(-1, funcs.bufwinnr('X'))
|
||||
end)
|
||||
before_each(function()
|
||||
lfs.mkdir(dirname)
|
||||
end)
|
||||
after_each(function()
|
||||
lfs.rmdir(dirname)
|
||||
end)
|
||||
it('returns expected window number', function()
|
||||
eq(1, funcs.bufwinnr('%'))
|
||||
command('file ' .. fname)
|
||||
command('vsplit')
|
||||
command('split ' .. fname2)
|
||||
eq(2, funcs.bufwinnr(fname))
|
||||
eq(1, funcs.bufwinnr(fname2))
|
||||
eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
|
||||
meths.set_current_dir(dirname)
|
||||
eq(2, funcs.bufwinnr(fname))
|
||||
eq(1, funcs.bufwinnr(fname2))
|
||||
eq(-1, funcs.bufwinnr(fname:sub(1, #fname - 1)))
|
||||
eq(1, funcs.bufwinnr('%'))
|
||||
eq(2, funcs.bufwinnr(1))
|
||||
eq(1, funcs.bufwinnr(2))
|
||||
eq(-1, funcs.bufwinnr(3))
|
||||
eq(1, funcs.bufwinnr('$'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('getbufline() function', function()
|
||||
it('returns empty list when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq({}, funcs.getbufline(2, 1))
|
||||
eq({}, funcs.getbufline('non-existent-buffer', 1))
|
||||
eq({}, funcs.getbufline('#', 1))
|
||||
command('edit ' .. fname2)
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq({}, funcs.getbufline('X', 1))
|
||||
end)
|
||||
it('returns empty list when range is invalid', function()
|
||||
eq({}, funcs.getbufline(1, 0))
|
||||
curbufmeths.set_lines(0, 1, false, {'foo', 'bar', 'baz'})
|
||||
eq({}, funcs.getbufline(1, 2, 1))
|
||||
eq({}, funcs.getbufline(1, -10, -20))
|
||||
eq({}, funcs.getbufline(1, -2, -1))
|
||||
eq({}, funcs.getbufline(1, -1, 9999))
|
||||
end)
|
||||
it('returns expected lines', function()
|
||||
meths.set_option('hidden', true)
|
||||
command('file ' .. fname)
|
||||
curbufmeths.set_lines(0, 1, false, {'foo\0', '\0bar', 'baz'})
|
||||
command('edit ' .. fname2)
|
||||
curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
|
||||
eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, 9999))
|
||||
eq({'abc\n', '\ndef', 'ghi'}, funcs.getbufline(2, 1, 9999))
|
||||
eq({'foo\n', '\nbar', 'baz'}, funcs.getbufline(1, 1, '$'))
|
||||
eq({'baz'}, funcs.getbufline(1, '$', '$'))
|
||||
eq({'baz'}, funcs.getbufline(1, '$', 9999))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('getbufvar() function', function()
|
||||
it('returns empty list when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq('', funcs.getbufvar(2, '&autoindent'))
|
||||
eq('', funcs.getbufvar('non-existent-buffer', '&autoindent'))
|
||||
eq('', funcs.getbufvar('#', '&autoindent'))
|
||||
command('edit ' .. fname2)
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq('', funcs.getbufvar('X', '&autoindent'))
|
||||
end)
|
||||
it('returns empty list when variable/option/etc was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq('', funcs.getbufvar(1, '&autondent'))
|
||||
eq('', funcs.getbufvar(1, 'changedtic'))
|
||||
end)
|
||||
it('returns expected option value', function()
|
||||
eq(0, funcs.getbufvar(1, '&autoindent'))
|
||||
eq(0, funcs.getbufvar(1, '&l:autoindent'))
|
||||
eq(0, funcs.getbufvar(1, '&g:autoindent'))
|
||||
-- Also works with global-only options
|
||||
eq(0, funcs.getbufvar(1, '&hidden'))
|
||||
eq(0, funcs.getbufvar(1, '&l:hidden'))
|
||||
eq(0, funcs.getbufvar(1, '&g:hidden'))
|
||||
-- Also works with window-local options
|
||||
eq(0, funcs.getbufvar(1, '&number'))
|
||||
eq(0, funcs.getbufvar(1, '&l:number'))
|
||||
eq(0, funcs.getbufvar(1, '&g:number'))
|
||||
command('new')
|
||||
-- But with window-local options it probably does not what you expect
|
||||
curwinmeths.set_option('number', true)
|
||||
-- (note that current window’s buffer is 2, but getbufvar() receives 1)
|
||||
eq(2, bufmeths.get_number(curwinmeths.get_buf()))
|
||||
eq(1, funcs.getbufvar(1, '&number'))
|
||||
eq(1, funcs.getbufvar(1, '&l:number'))
|
||||
-- You can get global value though, if you find this useful.
|
||||
eq(0, funcs.getbufvar(1, '&g:number'))
|
||||
end)
|
||||
it('returns expected variable value', function()
|
||||
eq(2, funcs.getbufvar(1, 'changedtick'))
|
||||
curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'})
|
||||
eq(3, funcs.getbufvar(1, 'changedtick'))
|
||||
curbufmeths.set_var('test', true)
|
||||
eq(true, funcs.getbufvar(1, 'test'))
|
||||
eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
|
||||
command('new')
|
||||
eq(3, funcs.getbufvar(1, 'changedtick'))
|
||||
eq(true, funcs.getbufvar(1, 'test'))
|
||||
eq({test=true, changedtick=3}, funcs.getbufvar(1, ''))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('setbufvar() function', function()
|
||||
it('throws the error or ignores the input when buffer was not found', function()
|
||||
command('file ' .. fname)
|
||||
eq(0,
|
||||
exc_exec('call setbufvar(2, "&autoindent", 0)'))
|
||||
eq('Vim(call):E94: No matching buffer for non-existent-buffer',
|
||||
exc_exec('call setbufvar("non-existent-buffer", "&autoindent", 0)'))
|
||||
eq(0,
|
||||
exc_exec('call setbufvar("#", "&autoindent", 0)'))
|
||||
command('edit ' .. fname2)
|
||||
eq(2, funcs.bufnr('%'))
|
||||
eq('Vim(call):E93: More than one match for X',
|
||||
exc_exec('call setbufvar("X", "&autoindent", 0)'))
|
||||
end)
|
||||
it('may set options, including window-local and global values', function()
|
||||
local buf1 = meths.get_current_buf()
|
||||
eq(false, curwinmeths.get_option('number'))
|
||||
command('split')
|
||||
command('new')
|
||||
eq(2, bufmeths.get_number(curwinmeths.get_buf()))
|
||||
funcs.setbufvar(1, '&number', true)
|
||||
local windows = curtabmeths.list_wins()
|
||||
eq(false, winmeths.get_option(windows[1], 'number'))
|
||||
eq(true, winmeths.get_option(windows[2], 'number'))
|
||||
eq(false, winmeths.get_option(windows[3], 'number'))
|
||||
eq(false, winmeths.get_option(meths.get_current_win(), 'number'))
|
||||
|
||||
eq(false, meths.get_option('hidden'))
|
||||
funcs.setbufvar(1, '&hidden', true)
|
||||
eq(true, meths.get_option('hidden'))
|
||||
|
||||
eq(false, bufmeths.get_option(buf1, 'autoindent'))
|
||||
funcs.setbufvar(1, '&autoindent', true)
|
||||
eq(true, bufmeths.get_option(buf1, 'autoindent'))
|
||||
eq('Vim(call):E355: Unknown option: xxx',
|
||||
exc_exec('call setbufvar(1, "&xxx", 0)'))
|
||||
end)
|
||||
it('may set variables', function()
|
||||
local buf1 = meths.get_current_buf()
|
||||
command('split')
|
||||
command('new')
|
||||
eq(2, curbufmeths.get_number())
|
||||
funcs.setbufvar(1, 'number', true)
|
||||
eq(true, bufmeths.get_var(buf1, 'number'))
|
||||
eq('Vim(call):E461: Illegal variable name: b:',
|
||||
exc_exec('call setbufvar(1, "", 0)'))
|
||||
eq(true, bufmeths.get_var(buf1, 'number'))
|
||||
funcs.setbufvar(1, 'changedtick', true)
|
||||
-- eq(true, bufmeths.get_var(buf1, 'changedtick'))
|
||||
eq(2, funcs.getbufvar(1, 'changedtick'))
|
||||
end)
|
||||
end)
|
24
test/functional/eval/container_functions_spec.lua
Normal file
24
test/functional/eval/container_functions_spec.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local meths = helpers.meths
|
||||
local clear = helpers.clear
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('extend()', function()
|
||||
it('suceeds to extend list with itself', function()
|
||||
meths.set_var('l', {1, {}})
|
||||
eq({1, {}, 1, {}}, eval('extend(l, l)'))
|
||||
eq({1, {}, 1, {}}, meths.get_var('l'))
|
||||
|
||||
meths.set_var('l', {1, {}})
|
||||
eq({1, {}, 1, {}}, eval('extend(l, l, 0)'))
|
||||
eq({1, {}, 1, {}}, meths.get_var('l'))
|
||||
|
||||
meths.set_var('l', {1, {}})
|
||||
eq({1, 1, {}, {}}, eval('extend(l, l, 1)'))
|
||||
eq({1, 1, {}, {}}, meths.get_var('l'))
|
||||
end)
|
||||
end)
|
29
test/functional/eval/function_spec.lua
Normal file
29
test/functional/eval/function_spec.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
|
||||
local max_func_args = 20 -- from eval.h
|
||||
local range = helpers.funcs.range
|
||||
|
||||
before_each(clear)
|
||||
|
||||
it('printf()', function()
|
||||
local printf = helpers.funcs.printf
|
||||
local rep = helpers.funcs['repeat']
|
||||
local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,'
|
||||
eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args))))
|
||||
local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
|
||||
eq('Vim(call):E740: Too many arguments for function printf', ret)
|
||||
end)
|
||||
|
||||
it('rpcnotify()', function()
|
||||
local rpcnotify = helpers.funcs.rpcnotify
|
||||
local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args)))
|
||||
eq(1, ret)
|
||||
ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
|
||||
eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
|
||||
end)
|
||||
end)
|
@@ -1,13 +1,13 @@
|
||||
local lfs = require('lfs')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, execute, eval, eq = helpers.clear, helpers.execute, helpers.eval, helpers.eq
|
||||
local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
lfs.mkdir('test-glob')
|
||||
|
||||
-- Long path might cause "Press ENTER" prompt; use :silent to avoid it.
|
||||
execute('silent cd test-glob')
|
||||
command('silent cd test-glob')
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
|
17
test/functional/eval/hostname_spec.lua
Normal file
17
test/functional/eval/hostname_spec.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local ok = helpers.ok
|
||||
local call = helpers.call
|
||||
local clear = helpers.clear
|
||||
|
||||
describe('hostname()', function()
|
||||
before_each(clear)
|
||||
|
||||
it('returns hostname string', function()
|
||||
local actual = call('hostname')
|
||||
ok(string.len(actual) > 0)
|
||||
if call('executable', 'hostname') == 1 then
|
||||
local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '')
|
||||
helpers.eq(expected, actual)
|
||||
end
|
||||
end)
|
||||
end)
|
440
test/functional/eval/input_spec.lua
Normal file
440
test/functional/eval/input_spec.lua
Normal file
@@ -0,0 +1,440 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
local eq = helpers.eq
|
||||
local feed = helpers.feed
|
||||
local meths = helpers.meths
|
||||
local clear = helpers.clear
|
||||
local source = helpers.source
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
local screen
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
screen = Screen.new(25, 5)
|
||||
screen:attach()
|
||||
source([[
|
||||
hi Test ctermfg=Red guifg=Red term=bold
|
||||
function CustomCompl(...)
|
||||
return 'TEST'
|
||||
endfunction
|
||||
function CustomListCompl(...)
|
||||
return ['FOO']
|
||||
endfunction
|
||||
|
||||
highlight RBP1 guibg=Red
|
||||
highlight RBP2 guibg=Yellow
|
||||
highlight RBP3 guibg=Green
|
||||
highlight RBP4 guibg=Blue
|
||||
let g:NUM_LVLS = 4
|
||||
function Redraw()
|
||||
redraw!
|
||||
return ''
|
||||
endfunction
|
||||
cnoremap <expr> {REDRAW} Redraw()
|
||||
function RainBowParens(cmdline)
|
||||
let ret = []
|
||||
let i = 0
|
||||
let lvl = 0
|
||||
while i < len(a:cmdline)
|
||||
if a:cmdline[i] is# '('
|
||||
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
|
||||
let lvl += 1
|
||||
elseif a:cmdline[i] is# ')'
|
||||
let lvl -= 1
|
||||
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
|
||||
endif
|
||||
let i += 1
|
||||
endwhile
|
||||
return ret
|
||||
endfunction
|
||||
]])
|
||||
screen:set_default_attr_ids({
|
||||
EOB={bold = true, foreground = Screen.colors.Blue1},
|
||||
T={foreground=Screen.colors.Red},
|
||||
RBP1={background=Screen.colors.Red},
|
||||
RBP2={background=Screen.colors.Yellow},
|
||||
RBP3={background=Screen.colors.Green},
|
||||
RBP4={background=Screen.colors.Blue},
|
||||
})
|
||||
end)
|
||||
|
||||
describe('input()', function()
|
||||
it('works with multiline prompts', function()
|
||||
feed([[:call input("Test\nFoo")<CR>]])
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
Test |
|
||||
Foo^ |
|
||||
]])
|
||||
end)
|
||||
it('works with multiline prompts and :echohl', function()
|
||||
feed([[:echohl Test | call input("Test\nFoo")<CR>]])
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Test} |
|
||||
{T:Foo}^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo}^ |
|
||||
]])
|
||||
end)
|
||||
it('allows unequal numeric arguments when using multiple args', function()
|
||||
command('echohl Test')
|
||||
feed([[:call input(1, 2)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}2^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}^ |
|
||||
]])
|
||||
end)
|
||||
it('allows unequal numeric values when using {opts} dictionary', function()
|
||||
command('echohl Test')
|
||||
meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
|
||||
feed([[:echo input(opts)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}2^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}^ |
|
||||
]])
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:3} |
|
||||
]])
|
||||
end)
|
||||
it('works with redraw', function()
|
||||
command('echohl Test')
|
||||
meths.set_var('opts', {prompt='Foo>', default='Bar'})
|
||||
feed([[:echo inputdialog(opts)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
end)
|
||||
it('allows omitting everything with dictionary argument', function()
|
||||
command('echohl Test')
|
||||
feed([[:call input({})<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
^ |
|
||||
]])
|
||||
end)
|
||||
it('supports completion', function()
|
||||
feed(':let var = input("", "", "custom,CustomCompl")<CR>')
|
||||
feed('<Tab><CR>')
|
||||
eq('TEST', meths.get_var('var'))
|
||||
|
||||
feed(':let var = input({"completion": "customlist,CustomListCompl"})<CR>')
|
||||
feed('<Tab><CR>')
|
||||
eq('FOO', meths.get_var('var'))
|
||||
end)
|
||||
it('supports cancelreturn', function()
|
||||
feed(':let var = input({"cancelreturn": "BAR"})<CR>')
|
||||
feed('<Esc>')
|
||||
eq('BAR', meths.get_var('var'))
|
||||
end)
|
||||
it('supports default string', function()
|
||||
feed(':let var = input("", "DEF1")<CR>')
|
||||
feed('<CR>')
|
||||
eq('DEF1', meths.get_var('var'))
|
||||
|
||||
feed(':let var = input({"default": "DEF2"})<CR>')
|
||||
feed('<CR>')
|
||||
eq('DEF2', meths.get_var('var'))
|
||||
end)
|
||||
it('errors out on invalid inputs', function()
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input([])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input("", [])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input("", "", [])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input({"prompt": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input({"cancelreturn": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input({"default": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call input({"completion": []})'))
|
||||
eq('Vim(call):E5050: {opts} must be the only argument',
|
||||
exc_exec('call input({}, "default")'))
|
||||
eq('Vim(call):E118: Too many arguments for function: input',
|
||||
exc_exec('call input("prompt> ", "default", "file", "extra")'))
|
||||
end)
|
||||
it('supports highlighting', function()
|
||||
command('nnoremap <expr> X input({"highlight": "RainBowParens"})[-1]')
|
||||
feed([[X]])
|
||||
feed('(())')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{RBP1:(}{RBP2:()}{RBP1:)}^ |
|
||||
]])
|
||||
end)
|
||||
it('is not hidden by :silent', function()
|
||||
feed([[:silent call input('Foo: ')<CR>]])
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
Foo: ^ |
|
||||
|
|
||||
]])
|
||||
feed('Bar')
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
Foo: Bar^ |
|
||||
|
|
||||
]])
|
||||
feed('<CR>')
|
||||
end)
|
||||
end)
|
||||
describe('inputdialog()', function()
|
||||
it('works with multiline prompts', function()
|
||||
feed([[:call inputdialog("Test\nFoo")<CR>]])
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
Test |
|
||||
Foo^ |
|
||||
]])
|
||||
end)
|
||||
it('works with multiline prompts and :echohl', function()
|
||||
feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]])
|
||||
screen:expect([[
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Test} |
|
||||
{T:Foo}^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo}^ |
|
||||
]])
|
||||
end)
|
||||
it('allows unequal numeric arguments when using multiple args', function()
|
||||
command('echohl Test')
|
||||
feed([[:call inputdialog(1, 2)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}2^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}^ |
|
||||
]])
|
||||
end)
|
||||
it('allows unequal numeric values when using {opts} dictionary', function()
|
||||
command('echohl Test')
|
||||
meths.set_var('opts', {prompt=1, default=2, cancelreturn=3})
|
||||
feed([[:echo input(opts)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}2^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:1}^ |
|
||||
]])
|
||||
feed('<Esc>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:3} |
|
||||
]])
|
||||
end)
|
||||
it('works with redraw', function()
|
||||
command('echohl Test')
|
||||
meths.set_var('opts', {prompt='Foo>', default='Bar'})
|
||||
feed([[:echo input(opts)<CR>]])
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Bar^ |
|
||||
]])
|
||||
feed('<BS>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
command('redraw!')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{T:Foo>}Ba^ |
|
||||
]])
|
||||
end)
|
||||
it('allows omitting everything with dictionary argument', function()
|
||||
command('echohl Test')
|
||||
feed(':echo inputdialog({})<CR>')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
^ |
|
||||
]])
|
||||
end)
|
||||
it('supports completion', function()
|
||||
feed(':let var = inputdialog({"completion": "customlist,CustomListCompl"})<CR>')
|
||||
feed('<Tab><CR>')
|
||||
eq('FOO', meths.get_var('var'))
|
||||
end)
|
||||
it('supports cancelreturn', function()
|
||||
feed(':let var = inputdialog("", "", "CR1")<CR>')
|
||||
feed('<Esc>')
|
||||
eq('CR1', meths.get_var('var'))
|
||||
|
||||
feed(':let var = inputdialog({"cancelreturn": "BAR"})<CR>')
|
||||
feed('<Esc>')
|
||||
eq('BAR', meths.get_var('var'))
|
||||
end)
|
||||
it('supports default string', function()
|
||||
feed(':let var = inputdialog("", "DEF1")<CR>')
|
||||
feed('<CR>')
|
||||
eq('DEF1', meths.get_var('var'))
|
||||
|
||||
feed(':let var = inputdialog({"default": "DEF2"})<CR>')
|
||||
feed('<CR>')
|
||||
eq('DEF2', meths.get_var('var'))
|
||||
end)
|
||||
it('errors out on invalid inputs', function()
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog([])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog("", [])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog("", "", [])'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog({"prompt": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog({"cancelreturn": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog({"default": []})'))
|
||||
eq('Vim(call):E730: using List as a String',
|
||||
exc_exec('call inputdialog({"completion": []})'))
|
||||
eq('Vim(call):E5050: {opts} must be the only argument',
|
||||
exc_exec('call inputdialog({}, "default")'))
|
||||
eq('Vim(call):E118: Too many arguments for function: inputdialog',
|
||||
exc_exec('call inputdialog("prompt> ", "default", "file", "extra")'))
|
||||
end)
|
||||
it('supports highlighting', function()
|
||||
command('nnoremap <expr> X inputdialog({"highlight": "RainBowParens"})[-1]')
|
||||
feed([[X]])
|
||||
feed('(())')
|
||||
screen:expect([[
|
||||
|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{EOB:~ }|
|
||||
{RBP1:(}{RBP2:()}{RBP1:)}^ |
|
||||
]])
|
||||
end)
|
||||
end)
|
@@ -4,16 +4,17 @@ local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local redir_exec = helpers.redir_exec
|
||||
local NIL = helpers.NIL
|
||||
local source = helpers.source
|
||||
|
||||
describe('json_decode() function', function()
|
||||
local restart = function(...)
|
||||
clear(...)
|
||||
execute('language C')
|
||||
execute([[
|
||||
source([[
|
||||
language C
|
||||
function Eq(exp, act)
|
||||
let act = a:act
|
||||
let exp = a:exp
|
||||
@@ -45,8 +46,6 @@ describe('json_decode() function', function()
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
]])
|
||||
execute([[
|
||||
function EvalEq(exp, act_expr)
|
||||
let act = eval(a:act_expr)
|
||||
if Eq(a:exp, act)
|
||||
@@ -441,7 +440,7 @@ describe('json_decode() function', function()
|
||||
local sp_decode_eq = function(expected, json)
|
||||
meths.set_var('__json', json)
|
||||
speq(expected, 'json_decode(g:__json)')
|
||||
execute('unlet! g:__json')
|
||||
command('unlet! g:__json')
|
||||
end
|
||||
|
||||
it('parses strings with NUL properly', function()
|
||||
@@ -527,7 +526,7 @@ end)
|
||||
describe('json_encode() function', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
execute('language C')
|
||||
command('language C')
|
||||
end)
|
||||
|
||||
it('dumps strings', function()
|
||||
@@ -576,94 +575,94 @@ describe('json_encode() function', function()
|
||||
|
||||
it('cannot dump generic mapping with generic mapping keys and values',
|
||||
function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('call add(todump._VAL, [todumpv1, todumpv2])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, [todumpv1, todumpv2])')
|
||||
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('cannot dump generic mapping with ext key', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('cannot dump generic mapping with array key', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('cannot dump generic mapping with UINT64_MAX key', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('cannot dump generic mapping with floating-point key', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump generic mapping with STR special key and NUL', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump generic mapping with BIN special key and NUL', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
|
||||
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump STR special mapping with NUL and NL', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
|
||||
eq('"\\u0000\\n"', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump BIN special mapping with NUL and NL', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
|
||||
eq('"\\u0000\\n"', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('cannot dump special ext mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special array mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
eq('[5, [""]]', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special UINT64_MAX mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
eq('18446744073709551615', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special INT64_MIN mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
execute('let todump._VAL = [-1, 2, 0, 0]')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
command('let todump._VAL = [-1, 2, 0, 0]')
|
||||
eq('-9223372036854775808', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special BOOLEAN true mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
||||
eq('true', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special BOOLEAN false mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
||||
eq('false', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump special NIL mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
||||
eq('null', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
@@ -673,7 +672,7 @@ describe('json_encode() function', function()
|
||||
end)
|
||||
|
||||
it('fails to dump a partial', function()
|
||||
execute('function T() dict\nendfunction')
|
||||
command('function T() dict\nendfunction')
|
||||
eq('Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference',
|
||||
exc_exec('call json_encode(function("T", [1, 2], {}))'))
|
||||
end)
|
||||
@@ -684,56 +683,56 @@ describe('json_encode() function', function()
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive list', function()
|
||||
execute('let todump = [[[]]]')
|
||||
execute('call add(todump[0][0], todump)')
|
||||
command('let todump = [[[]]]')
|
||||
command('call add(todump[0][0], todump)')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive dict', function()
|
||||
execute('let todump = {"d": {"d": {}}}')
|
||||
execute('call extend(todump.d.d, {"d": todump})')
|
||||
command('let todump = {"d": {"d": {}}}')
|
||||
command('call extend(todump.d.d, {"d": todump})')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump dict with two same dicts inside', function()
|
||||
execute('let inter = {}')
|
||||
execute('let todump = {"a": inter, "b": inter}')
|
||||
command('let inter = {}')
|
||||
command('let todump = {"a": inter, "b": inter}')
|
||||
eq('{"a": {}, "b": {}}', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('can dump list with two same lists inside', function()
|
||||
execute('let inter = []')
|
||||
execute('let todump = [inter, inter]')
|
||||
command('let inter = []')
|
||||
command('let todump = [inter, inter]')
|
||||
eq('[[], []]', eval('json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive list in a special dict', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
execute('call add(todump._VAL, todump)')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
command('call add(todump._VAL, todump)')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) map in a special dict', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('call add(todump._VAL, ["", todump])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, ["", todump])')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}')
|
||||
execute('call add(todump._VAL[0][1], todump._VAL)')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}')
|
||||
command('call add(todump._VAL[0][1], todump._VAL)')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) special list in a special dict',
|
||||
function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
execute('call add(todump._VAL, ["", todump._VAL])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
command('call add(todump._VAL, ["", todump._VAL])')
|
||||
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
|
||||
exc_exec('call json_encode(todump)'))
|
||||
end)
|
||||
@@ -777,4 +776,11 @@ describe('json_encode() function', function()
|
||||
it('can dump NULL dictionary', function()
|
||||
eq('{}', eval('json_encode(v:_null_dict)'))
|
||||
end)
|
||||
|
||||
it('fails to parse NULL strings and lists', function()
|
||||
eq('Vim(call):E474: Attempt to decode a blank string',
|
||||
exc_exec('call json_decode($XXX_UNEXISTENT_VAR_XXX)'))
|
||||
eq('Vim(call):E474: Attempt to decode a blank string',
|
||||
exc_exec('call json_decode(v:_null_list)'))
|
||||
end)
|
||||
end)
|
||||
|
159
test/functional/eval/map_functions_spec.lua
Normal file
159
test/functional/eval/map_functions_spec.lua
Normal file
@@ -0,0 +1,159 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local funcs = helpers.funcs
|
||||
local nvim = helpers.nvim
|
||||
local source = helpers.source
|
||||
local command = helpers.command
|
||||
|
||||
describe('maparg()', function()
|
||||
before_each(clear)
|
||||
|
||||
local foo_bar_map_table = {
|
||||
lhs='foo',
|
||||
silent=0,
|
||||
rhs='bar',
|
||||
expr=0,
|
||||
sid=0,
|
||||
buffer=0,
|
||||
nowait=0,
|
||||
mode='n',
|
||||
noremap=1,
|
||||
}
|
||||
|
||||
it('returns a dictionary', function()
|
||||
nvim('command', 'nnoremap foo bar')
|
||||
eq('bar', funcs.maparg('foo'))
|
||||
eq(foo_bar_map_table, funcs.maparg('foo', 'n', false, true))
|
||||
end)
|
||||
|
||||
it('returns 1 for silent when <silent> is used', function()
|
||||
nvim('command', 'nnoremap <silent> foo bar')
|
||||
eq(1, funcs.maparg('foo', 'n', false, true)['silent'])
|
||||
|
||||
nvim('command', 'nnoremap baz bat')
|
||||
eq(0, funcs.maparg('baz', 'n', false, true)['silent'])
|
||||
end)
|
||||
|
||||
it('returns an empty string when no map is present', function()
|
||||
eq('', funcs.maparg('not a mapping'))
|
||||
end)
|
||||
|
||||
it('returns an empty dictionary when no map is present and dict is requested', function()
|
||||
eq({}, funcs.maparg('not a mapping', 'n', false, true))
|
||||
end)
|
||||
|
||||
it('returns the same value for noremap and <script>', function()
|
||||
nvim('command', 'inoremap <script> hello world')
|
||||
nvim('command', 'inoremap this that')
|
||||
eq(
|
||||
funcs.maparg('hello', 'i', false, true)['noremap'],
|
||||
funcs.maparg('this', 'i', false, true)['noremap']
|
||||
)
|
||||
end)
|
||||
|
||||
it('returns a boolean for buffer', function()
|
||||
-- Open enough windows to know we aren't on buffer number 1
|
||||
nvim('command', 'new')
|
||||
nvim('command', 'new')
|
||||
nvim('command', 'new')
|
||||
nvim('command', 'cnoremap <buffer> this that')
|
||||
eq(1, funcs.maparg('this', 'c', false, true)['buffer'])
|
||||
|
||||
-- Global will return 0 always
|
||||
nvim('command', 'nnoremap other another')
|
||||
eq(0, funcs.maparg('other', 'n', false, true)['buffer'])
|
||||
end)
|
||||
|
||||
it('returns script numbers', function()
|
||||
source([[
|
||||
function! s:maparg_test_function() abort
|
||||
return 'testing'
|
||||
endfunction
|
||||
|
||||
nnoremap fizz :call <SID>maparg_test_function()<CR>
|
||||
]])
|
||||
eq(1, funcs.maparg('fizz', 'n', false, true)['sid'])
|
||||
eq('testing', nvim('call_function', '<SNR>1_maparg_test_function', {}))
|
||||
end)
|
||||
|
||||
it('works with <F12> and others', function()
|
||||
source([[
|
||||
let g:maparg_test_var = 0
|
||||
|
||||
nnoremap <F12> :let g:maparg_test_var = 1<CR>
|
||||
]])
|
||||
eq(0, eval('g:maparg_test_var'))
|
||||
source([[
|
||||
call feedkeys("\<F12>")
|
||||
]])
|
||||
eq(1, eval('g:maparg_test_var'))
|
||||
|
||||
eq(':let g:maparg_test_var = 1<CR>', funcs.maparg('<F12>', 'n', false, true)['rhs'])
|
||||
end)
|
||||
|
||||
it('works with <expr>', function()
|
||||
source([[
|
||||
let counter = 0
|
||||
inoremap <expr> <C-L> ListItem()
|
||||
inoremap <expr> <C-R> ListReset()
|
||||
|
||||
func ListItem()
|
||||
let g:counter += 1
|
||||
return g:counter . '. '
|
||||
endfunc
|
||||
|
||||
func ListReset()
|
||||
let g:counter = 0
|
||||
return ''
|
||||
endfunc
|
||||
|
||||
call feedkeys("i\<C-L>")
|
||||
]])
|
||||
eq(1, eval('g:counter'))
|
||||
|
||||
local map_dict = funcs.maparg('<C-L>', 'i', false, true)
|
||||
eq(1, map_dict['expr'])
|
||||
eq('i', map_dict['mode'])
|
||||
end)
|
||||
|
||||
it('works with combining characters', function()
|
||||
-- Using addacutes to make combining character better visible
|
||||
local function ac(s)
|
||||
local acute = '\204\129' -- U+0301 COMBINING ACUTE ACCENT
|
||||
local ret = s:gsub('`', acute)
|
||||
return ret
|
||||
end
|
||||
command(ac([[
|
||||
nnoremap a b`
|
||||
nnoremap c` d
|
||||
nnoremap e` f`
|
||||
]]))
|
||||
eq(ac('b`'), funcs.maparg(ac('a')))
|
||||
eq(ac(''), funcs.maparg(ac('c')))
|
||||
eq(ac('d'), funcs.maparg(ac('c`')))
|
||||
eq(ac('f`'), funcs.maparg(ac('e`')))
|
||||
|
||||
local function acmap(lhs, rhs)
|
||||
return {
|
||||
lhs = ac(lhs),
|
||||
rhs = ac(rhs),
|
||||
|
||||
buffer = 0,
|
||||
expr = 0,
|
||||
mode = 'n',
|
||||
noremap = 1,
|
||||
nowait = 0,
|
||||
sid = 0,
|
||||
silent = 0,
|
||||
}
|
||||
end
|
||||
|
||||
eq({}, funcs.maparg(ac('c'), 'n', 0, 1))
|
||||
eq(acmap('a', 'b`'), funcs.maparg(ac('a'), 'n', 0, 1))
|
||||
eq(acmap('c`', 'd'), funcs.maparg(ac('c`'), 'n', 0, 1))
|
||||
eq(acmap('e`', 'f`'), funcs.maparg(ac('e`'), 'n', 0, 1))
|
||||
end)
|
||||
end)
|
61
test/functional/eval/match_functions_spec.lua
Normal file
61
test/functional/eval/match_functions_spec.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local command = helpers.command
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('setmatches()', function()
|
||||
it('correctly handles case when both group and pattern entries are numbers',
|
||||
function()
|
||||
command('hi def link 1 PreProc')
|
||||
eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}}))
|
||||
eq({{
|
||||
group='1',
|
||||
pattern='2',
|
||||
id=3,
|
||||
priority=4,
|
||||
}}, funcs.getmatches())
|
||||
eq(0, funcs.setmatches({{group=1, pattern=2, id=3, priority=4, conceal=5}}))
|
||||
eq({{
|
||||
group='1',
|
||||
pattern='2',
|
||||
id=3,
|
||||
priority=4,
|
||||
conceal='5',
|
||||
}}, funcs.getmatches())
|
||||
eq(0, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}))
|
||||
eq({{
|
||||
group='1',
|
||||
pos1={2},
|
||||
pos2={6},
|
||||
id=3,
|
||||
priority=4,
|
||||
conceal='5',
|
||||
}}, funcs.getmatches())
|
||||
end)
|
||||
|
||||
it('fails with -1 if highlight group is not defined', function()
|
||||
eq(-1, funcs.setmatches({{group=1, pattern=2, id=3, priority=4}}))
|
||||
eq({}, funcs.getmatches())
|
||||
eq(-1, funcs.setmatches({{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}))
|
||||
eq({}, funcs.getmatches())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('matchadd()', function()
|
||||
it('correctly works when first two arguments and conceal are numbers at once',
|
||||
function()
|
||||
command('hi def link 1 PreProc')
|
||||
eq(4, funcs.matchadd(1, 2, 3, 4, {conceal=5}))
|
||||
eq({{
|
||||
group='1',
|
||||
pattern='2',
|
||||
priority=3,
|
||||
id=4,
|
||||
conceal='5',
|
||||
}}, funcs.getmatches())
|
||||
end)
|
||||
end)
|
51
test/functional/eval/minmax_functions_spec.lua
Normal file
51
test/functional/eval/minmax_functions_spec.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local redir_exec = helpers.redir_exec
|
||||
|
||||
before_each(clear)
|
||||
for _, func in ipairs({'min', 'max'}) do
|
||||
describe(func .. '()', function()
|
||||
it('gives a single error message when multiple values failed conversions',
|
||||
function()
|
||||
eq('\nE745: Using a List as a Number\n0',
|
||||
redir_exec('echo ' .. func .. '([-5, [], [], [], 5])'))
|
||||
eq('\nE745: Using a List as a Number\n0',
|
||||
redir_exec('echo ' .. func .. '({1:-5, 2:[], 3:[], 4:[], 5:5})'))
|
||||
for errmsg, errinput in pairs({
|
||||
['E745: Using a List as a Number'] = '[]',
|
||||
['E805: Using a Float as a Number'] = '0.0',
|
||||
['E703: Using a Funcref as a Number'] = 'function("tr")',
|
||||
['E728: Using a Dictionary as a Number'] = '{}',
|
||||
}) do
|
||||
eq('\n' .. errmsg .. '\n0',
|
||||
redir_exec('echo ' .. func .. '([' .. errinput .. '])'))
|
||||
eq('\n' .. errmsg .. '\n0',
|
||||
redir_exec('echo ' .. func .. '({1:' .. errinput .. '})'))
|
||||
end
|
||||
end)
|
||||
it('works with arrays/dictionaries with zero items', function()
|
||||
eq(0, funcs[func]({}))
|
||||
eq(0, eval(func .. '({})'))
|
||||
end)
|
||||
it('works with arrays/dictionaries with one item', function()
|
||||
eq(5, funcs[func]({5}))
|
||||
eq(5, funcs[func]({test=5}))
|
||||
end)
|
||||
it('works with NULL arrays/dictionaries', function()
|
||||
eq(0, eval(func .. '(v:_null_list)'))
|
||||
eq(0, eval(func .. '(v:_null_dict)'))
|
||||
end)
|
||||
it('errors out for invalid types', function()
|
||||
for _, errinput in ipairs({'1', 'v:true', 'v:false', 'v:null',
|
||||
'function("tr")', '""'}) do
|
||||
eq(('\nE712: Argument of %s() must be a List or Dictionary\n0'):format(
|
||||
func),
|
||||
redir_exec('echo ' .. func .. '(' .. errinput .. ')'))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
@@ -1,5 +1,5 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, execute, write_file = helpers.clear, helpers.execute, helpers.write_file
|
||||
local clear, command, write_file = helpers.clear, helpers.command, helpers.write_file
|
||||
local eq, eval = helpers.eq, helpers.eval
|
||||
|
||||
describe("modeline", function()
|
||||
@@ -12,7 +12,7 @@ describe("modeline", function()
|
||||
|
||||
it('does not crash with a large version number', function()
|
||||
write_file(tempfile, 'vim100000000000000000000000')
|
||||
execute('e! ' .. tempfile)
|
||||
command('e! ' .. tempfile)
|
||||
|
||||
eq(2, eval('1+1')) -- Still alive?
|
||||
end)
|
||||
|
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local eval, eq = helpers.eval, helpers.eq
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
local nvim = helpers.nvim
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
@@ -331,13 +331,14 @@ describe('msgpack*() functions', function()
|
||||
obj_test('are able to dump and restore floating-point value', {0.125})
|
||||
|
||||
it('can restore and dump UINT64_MAX', function()
|
||||
execute('let dumped = ["\\xCF" . repeat("\\xFF", 8)]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
execute('let dumped2 = msgpackdump(parsed)')
|
||||
command('let dumped = ["\\xCF" . repeat("\\xFF", 8)]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped2 = msgpackdump(parsed)')
|
||||
eq(1, eval('type(parsed[0]) == type(0) ' ..
|
||||
'|| parsed[0]._TYPE is v:msgpack_types.integer'))
|
||||
if eval('type(parsed[0]) == type(0)') == 1 then
|
||||
eq(1, eval('0xFFFFFFFFFFFFFFFF == parsed[0]'))
|
||||
command('call assert_equal(0xFFFFFFFFFFFFFFFF, parsed[0])')
|
||||
eq({}, eval('v:errors'))
|
||||
else
|
||||
eq({_TYPE={}, _VAL={1, 3, 0x7FFFFFFF, 0x7FFFFFFF}}, eval('parsed[0]'))
|
||||
end
|
||||
@@ -345,13 +346,14 @@ describe('msgpack*() functions', function()
|
||||
end)
|
||||
|
||||
it('can restore and dump INT64_MIN', function()
|
||||
execute('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
execute('let dumped2 = msgpackdump(parsed)')
|
||||
command('let dumped = ["\\xD3\\x80" . repeat("\\n", 7)]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped2 = msgpackdump(parsed)')
|
||||
eq(1, eval('type(parsed[0]) == type(0) ' ..
|
||||
'|| parsed[0]._TYPE is v:msgpack_types.integer'))
|
||||
if eval('type(parsed[0]) == type(0)') == 1 then
|
||||
eq(1, eval('-0x8000000000000000 == parsed[0]'))
|
||||
command('call assert_equal(-0x7fffffffffffffff - 1, parsed[0])')
|
||||
eq({}, eval('v:errors'))
|
||||
else
|
||||
eq({_TYPE={}, _VAL={-1, 2, 0, 0}}, eval('parsed[0]'))
|
||||
end
|
||||
@@ -359,33 +361,33 @@ describe('msgpack*() functions', function()
|
||||
end)
|
||||
|
||||
it('can restore and dump BIN string with zero byte', function()
|
||||
execute('let dumped = ["\\xC4\\x01\\n"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
execute('let dumped2 = msgpackdump(parsed)')
|
||||
command('let dumped = ["\\xC4\\x01\\n"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped2 = msgpackdump(parsed)')
|
||||
eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
|
||||
eq(1, eval('parsed[0]._TYPE is v:msgpack_types.binary'))
|
||||
eq(1, eval('dumped ==# dumped2'))
|
||||
end)
|
||||
|
||||
it('can restore and dump STR string with zero byte', function()
|
||||
execute('let dumped = ["\\xA1\\n"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
execute('let dumped2 = msgpackdump(parsed)')
|
||||
command('let dumped = ["\\xA1\\n"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped2 = msgpackdump(parsed)')
|
||||
eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
|
||||
eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string'))
|
||||
eq(1, eval('dumped ==# dumped2'))
|
||||
end)
|
||||
|
||||
it('can restore and dump BIN string with NL', function()
|
||||
execute('let dumped = ["\\xC4\\x01", ""]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
execute('let dumped2 = msgpackdump(parsed)')
|
||||
command('let dumped = ["\\xC4\\x01", ""]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped2 = msgpackdump(parsed)')
|
||||
eq({"\n"}, eval('parsed'))
|
||||
eq(1, eval('dumped ==# dumped2'))
|
||||
end)
|
||||
|
||||
it('dump and restore special mapping with floating-point value', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}')
|
||||
eq({0.125}, eval('msgpackparse(msgpackdump([todump]))'))
|
||||
end)
|
||||
end)
|
||||
@@ -394,52 +396,53 @@ describe('msgpackparse() function', function()
|
||||
before_each(clear)
|
||||
|
||||
it('restores nil as v:null', function()
|
||||
execute('let dumped = ["\\xC0"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\xC0"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq('[v:null]', eval('string(parsed)'))
|
||||
end)
|
||||
|
||||
it('restores boolean false as v:false', function()
|
||||
execute('let dumped = ["\\xC2"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\xC2"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({false}, eval('parsed'))
|
||||
end)
|
||||
|
||||
it('restores boolean true as v:true', function()
|
||||
execute('let dumped = ["\\xC3"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\xC3"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({true}, eval('parsed'))
|
||||
end)
|
||||
|
||||
it('restores FIXSTR as special dict', function()
|
||||
execute('let dumped = ["\\xa2ab"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\xa2ab"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({{_TYPE={}, _VAL={'ab'}}}, eval('parsed'))
|
||||
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
|
||||
end)
|
||||
|
||||
it('restores BIN 8 as string', function()
|
||||
execute('let dumped = ["\\xC4\\x02ab"]')
|
||||
command('let dumped = ["\\xC4\\x02ab"]')
|
||||
eq({'ab'}, eval('msgpackparse(dumped)'))
|
||||
end)
|
||||
|
||||
it('restores FIXEXT1 as special dictionary', function()
|
||||
execute('let dumped = ["\\xD4\\x10", ""]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\xD4\\x10", ""]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, eval('parsed'))
|
||||
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
|
||||
end)
|
||||
|
||||
it('restores MAP with BIN key as special dictionary', function()
|
||||
execute('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({{_TYPE={}, _VAL={{'a', ''}}}}, eval('parsed'))
|
||||
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
|
||||
end)
|
||||
|
||||
it('restores MAP with duplicate STR keys as special dictionary', function()
|
||||
execute('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
|
||||
-- FIXME Internal error bug
|
||||
command('silent! let parsed = msgpackparse(dumped)')
|
||||
eq({{_TYPE={}, _VAL={ {{_TYPE={}, _VAL={'a'}}, ''},
|
||||
{{_TYPE={}, _VAL={'a'}}, ''}}} }, eval('parsed'))
|
||||
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
|
||||
@@ -448,8 +451,8 @@ describe('msgpackparse() function', function()
|
||||
end)
|
||||
|
||||
it('restores MAP with MAP key as special dictionary', function()
|
||||
execute('let dumped = ["\\x81\\x80\\xC4\\n"]')
|
||||
execute('let parsed = msgpackparse(dumped)')
|
||||
command('let dumped = ["\\x81\\x80\\xC4\\n"]')
|
||||
command('let parsed = msgpackparse(dumped)')
|
||||
eq({{_TYPE={}, _VAL={{{}, ''}}}}, eval('parsed'))
|
||||
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
|
||||
end)
|
||||
@@ -460,7 +463,7 @@ describe('msgpackparse() function', function()
|
||||
eval(cmd)
|
||||
eval(cmd) -- do it again (try to force segfault)
|
||||
local api_info = eval(cmd) -- do it again
|
||||
eq({'error_types', 'functions', 'types', 'version'}, api_info)
|
||||
eq({'error_types', 'functions', 'types', 'ui_events', 'version'}, api_info)
|
||||
end)
|
||||
|
||||
it('fails when called with no arguments', function()
|
||||
@@ -494,7 +497,7 @@ describe('msgpackparse() function', function()
|
||||
end)
|
||||
|
||||
it('fails to parse a partial', function()
|
||||
execute('function T() dict\nendfunction')
|
||||
command('function T() dict\nendfunction')
|
||||
eq('Vim(call):E686: Argument of msgpackparse() must be a List',
|
||||
exc_exec('call msgpackparse(function("T", [1, 2], {}))'))
|
||||
end)
|
||||
@@ -514,10 +517,10 @@ describe('msgpackdump() function', function()
|
||||
end)
|
||||
|
||||
it('can dump generic mapping with generic mapping keys and values', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('call add(todump._VAL, [todumpv1, todumpv2])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, [todumpv1, todumpv2])')
|
||||
eq({'\129\128\128'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
@@ -530,130 +533,130 @@ describe('msgpackdump() function', function()
|
||||
end)
|
||||
|
||||
it('can v:null', function()
|
||||
execute('let todump = v:null')
|
||||
command('let todump = v:null')
|
||||
end)
|
||||
|
||||
it('can dump special bool mapping (true)', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
||||
eq({'\195'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special bool mapping (false)', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
||||
eq({'\194'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special nil mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
||||
eq({'\192'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special ext mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||
eq({'\212\005', ''}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special array mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||
eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special UINT64_MAX mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
execute('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||
eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump special INT64_MIN mapping', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
execute('let todump._VAL = [-1, 2, 0, 0]')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||
command('let todump._VAL = [-1, 2, 0, 0]')
|
||||
eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a function reference', function()
|
||||
execute('let Todump = function("tr")')
|
||||
command('let Todump = function("tr")')
|
||||
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',
|
||||
exc_exec('call msgpackdump([Todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a partial', function()
|
||||
execute('function T() dict\nendfunction')
|
||||
execute('let Todump = function("T", [1, 2], {})')
|
||||
command('function T() dict\nendfunction')
|
||||
command('let Todump = function("T", [1, 2], {})')
|
||||
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, itself: attempt to dump function reference',
|
||||
exc_exec('call msgpackdump([Todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a function reference in a list', function()
|
||||
execute('let todump = [function("tr")]')
|
||||
command('let todump = [function("tr")]')
|
||||
eq('Vim(call):E5004: Error while dumping msgpackdump() argument, index 0, index 0: attempt to dump function reference',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive list', function()
|
||||
execute('let todump = [[[]]]')
|
||||
execute('call add(todump[0][0], todump)')
|
||||
command('let todump = [[[]]]')
|
||||
command('call add(todump[0][0], todump)')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 0, index 0',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive dict', function()
|
||||
execute('let todump = {"d": {"d": {}}}')
|
||||
execute('call extend(todump.d.d, {"d": todump})')
|
||||
command('let todump = {"d": {"d": {}}}')
|
||||
command('call extend(todump.d.d, {"d": todump})')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key \'d\', key \'d\', key \'d\'',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump dict with two same dicts inside', function()
|
||||
execute('let inter = {}')
|
||||
execute('let todump = {"a": inter, "b": inter}')
|
||||
command('let inter = {}')
|
||||
command('let todump = {"a": inter, "b": inter}')
|
||||
eq({"\130\161a\128\161b\128"}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('can dump list with two same lists inside', function()
|
||||
execute('let inter = []')
|
||||
execute('let todump = [inter, inter]')
|
||||
command('let inter = []')
|
||||
command('let todump = [inter, inter]')
|
||||
eq({"\146\144\144"}, eval('msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive list in a special dict', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
execute('call add(todump._VAL, todump)')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
command('call add(todump._VAL, todump)')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (key) map in a special dict', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('call add(todump._VAL, [todump, 0])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, [todump, 0])')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 1',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) map in a special dict', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
execute('call add(todump._VAL, [0, todump])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||
command('call add(todump._VAL, [0, todump])')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key 0 at index 0 from special map',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (key) map in a special dict, _VAL reference', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
|
||||
execute('call add(todump._VAL[0][0], todump._VAL)')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
|
||||
command('call add(todump._VAL[0][0], todump._VAL)')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [[[[...@0], []]]] at index 0 from special map, index 0',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) map in a special dict, _VAL reference', function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
|
||||
execute('call add(todump._VAL[0][1], todump._VAL)')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[[], []]]}')
|
||||
command('call add(todump._VAL[0][1], todump._VAL)')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in key [] at index 0 from special map, index 0',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
|
||||
it('fails to dump a recursive (val) special list in a special dict',
|
||||
function()
|
||||
execute('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
execute('call add(todump._VAL, [0, todump._VAL])')
|
||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}')
|
||||
command('call add(todump._VAL, [0, todump._VAL])')
|
||||
eq('Vim(call):E5005: Unable to dump msgpackdump() argument, index 0: container references itself in index 0, index 1',
|
||||
exc_exec('call msgpackdump([todump])'))
|
||||
end)
|
||||
@@ -689,7 +692,7 @@ describe('msgpackdump() function', function()
|
||||
end)
|
||||
|
||||
it('fails to dump a partial', function()
|
||||
execute('function T() dict\nendfunction')
|
||||
command('function T() dict\nendfunction')
|
||||
eq('Vim(call):E686: Argument of msgpackdump() must be a List',
|
||||
exc_exec('call msgpackdump(function("T", [1, 2], {}))'))
|
||||
end)
|
||||
|
138
test/functional/eval/null_spec.lua
Normal file
138
test/functional/eval/null_spec.lua
Normal file
@@ -0,0 +1,138 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
local redir_exec = helpers.redir_exec
|
||||
local exc_exec = helpers.exc_exec
|
||||
local command = helpers.command
|
||||
local clear = helpers.clear
|
||||
local meths = helpers.meths
|
||||
local funcs = helpers.funcs
|
||||
local eq = helpers.eq
|
||||
|
||||
describe('NULL', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
command('let L = v:_null_list')
|
||||
command('let D = v:_null_dict')
|
||||
command('let S = $XXX_NONEXISTENT_VAR_XXX')
|
||||
end)
|
||||
local tmpfname = 'Xtest-functional-viml-null'
|
||||
after_each(function()
|
||||
os.remove(tmpfname)
|
||||
end)
|
||||
local null_test = function(name, cmd, err)
|
||||
it(name, function()
|
||||
eq(err, exc_exec(cmd))
|
||||
end)
|
||||
end
|
||||
local null_expr_test = function(name, expr, err, val, after)
|
||||
it(name, function()
|
||||
eq((err == 0) and ('') or ('\n' .. err),
|
||||
redir_exec('let g:_var = ' .. expr))
|
||||
if val == nil then
|
||||
eq(0, funcs.exists('g:_var'))
|
||||
else
|
||||
eq(val, meths.get_var('_var'))
|
||||
end
|
||||
if after ~= nil then
|
||||
after()
|
||||
end
|
||||
end)
|
||||
end
|
||||
describe('list', function()
|
||||
-- Incorrect behaviour
|
||||
|
||||
-- FIXME map() should not return 0 without error
|
||||
null_expr_test('does not crash map()', 'map(L, "v:val")', 0, 0)
|
||||
-- FIXME map() should not return 0 without error
|
||||
null_expr_test('does not crash filter()', 'filter(L, "1")', 0, 0)
|
||||
-- FIXME map() should at least return L
|
||||
null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 0)
|
||||
-- FIXME filter() should at least return L
|
||||
null_expr_test('makes filter() return v:_null_list', 'map(L, "1") is# L', 0, 0)
|
||||
-- FIXME add() should not return 1 at all
|
||||
null_expr_test('does not crash add()', 'add(L, 0)', 0, 1)
|
||||
null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0)
|
||||
null_expr_test('does not crash extend() (second position)', 'extend([1], L)', 0, {1})
|
||||
-- FIXME should be accepted by inputlist()
|
||||
null_expr_test('is accepted as an empty list by inputlist()',
|
||||
'[feedkeys("\\n"), inputlist(L)]', 'E686: Argument of inputlist() must be a List', {0, 0})
|
||||
-- FIXME should be accepted by writefile(), return {0, {}}
|
||||
null_expr_test('is accepted as an empty list by writefile()',
|
||||
('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
|
||||
'E484: Can\'t open file ' .. tmpfname, {0, {}})
|
||||
-- FIXME should give error message
|
||||
null_expr_test('does not crash remove()', 'remove(L, 0)', 0, 0)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setqflist()', 'setqflist(L)', 0, -1)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, -1)
|
||||
-- FIXME should return 0
|
||||
null_expr_test('is accepted by setmatches()', 'setmatches(L)', 0, -1)
|
||||
-- FIXME should return empty list or error out
|
||||
null_expr_test('is accepted by sort()', 'sort(L)', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is accepted by sort()', 'sort(L) is L', 0, 0)
|
||||
-- FIXME should not error out
|
||||
null_test('is accepted by :cexpr', 'cexpr L', 'Vim(cexpr):E777: String or List expected')
|
||||
-- FIXME should not error out
|
||||
null_test('is accepted by :lexpr', 'lexpr L', 'Vim(lexpr):E777: String or List expected')
|
||||
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
|
||||
|
||||
-- Subjectable behaviour
|
||||
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is equal to empty list', 'L == []', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is equal to empty list (reverse order)', '[] == L', 0, 0)
|
||||
-- FIXME Should return 1
|
||||
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
|
||||
|
||||
-- Crashes
|
||||
|
||||
-- null_expr_test('does not crash setreg', 'setreg("x", L)', 0, 0)
|
||||
-- null_expr_test('does not crash setline', 'setline(1, L)', 0, 0)
|
||||
-- null_expr_test('does not crash system()', 'system("cat", L)', 0, '')
|
||||
-- null_expr_test('does not crash systemlist()', 'systemlist("cat", L)', 0, {})
|
||||
|
||||
-- Correct behaviour
|
||||
null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
|
||||
eq({''}, curbufmeths.get_lines(0, -1, false))
|
||||
end)
|
||||
null_expr_test('is identical to itself', 'L is L', 0, 1)
|
||||
null_expr_test('can be sliced', 'L[:]', 0, {})
|
||||
null_expr_test('can be copied', 'copy(L)', 0, {})
|
||||
null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {})
|
||||
null_expr_test('does not crash when indexed', 'L[1]',
|
||||
'E684: list index out of range: 1\nE15: Invalid expression: L[1]', nil)
|
||||
null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0)
|
||||
null_expr_test('does not crash col()', 'col(L)', 0, 0)
|
||||
null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
|
||||
null_expr_test('does not crash line()', 'line(L)', 0, 0)
|
||||
null_expr_test('does not crash count()', 'count(L, 1)', 0, 0)
|
||||
null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1)
|
||||
null_expr_test('is empty', 'empty(L)', 0, 1)
|
||||
null_expr_test('does not crash get()', 'get(L, 1, 10)', 0, 10)
|
||||
null_expr_test('has zero length', 'len(L)', 0, 0)
|
||||
null_expr_test('is accepted as an empty list by max()', 'max(L)', 0, 0)
|
||||
null_expr_test('is accepted as an empty list by min()', 'min(L)', 0, 0)
|
||||
null_expr_test('is stringified correctly', 'string(L)', 0, '[]')
|
||||
null_expr_test('is JSON encoded correctly', 'json_encode(L)', 0, '[]')
|
||||
null_test('does not crash lockvar', 'lockvar! L', 0)
|
||||
null_expr_test('can be added to itself', '(L + L)', 0, {})
|
||||
null_expr_test('can be added to itself', '(L + L) is L', 0, 1)
|
||||
null_expr_test('can be added to non-empty list', '([1] + L)', 0, {1})
|
||||
null_expr_test('can be added to non-empty list (reversed)', '(L + [1])', 0, {1})
|
||||
null_expr_test('is equal to itself', 'L == L', 0, 1)
|
||||
null_expr_test('is not not equal to itself', 'L != L', 0, 0)
|
||||
null_expr_test('counts correctly', 'count([L], L)', 0, 1)
|
||||
end)
|
||||
describe('dict', function()
|
||||
it('does not crash when indexing NULL dict', function()
|
||||
eq('\nE716: Key not present in Dictionary: test\nE15: Invalid expression: v:_null_dict.test',
|
||||
redir_exec('echo v:_null_dict.test'))
|
||||
end)
|
||||
null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
|
||||
null_expr_test('makes extend do nothing', 'extend({1: 2}, D)', 0, {['1']=2})
|
||||
end)
|
||||
end)
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok
|
||||
local neq, execute, funcs = helpers.neq, helpers.execute, helpers.funcs
|
||||
local neq, command, funcs = helpers.neq, helpers.command, helpers.funcs
|
||||
local reltime, reltimestr, reltimefloat = funcs.reltime, funcs.reltimestr, funcs.reltimefloat
|
||||
|
||||
describe('reltimestr(), reltimefloat()', function()
|
||||
@@ -8,7 +8,7 @@ describe('reltimestr(), reltimefloat()', function()
|
||||
|
||||
it('Checks', function()
|
||||
local now = reltime()
|
||||
execute('sleep 10m')
|
||||
command('sleep 10m')
|
||||
local later = reltime()
|
||||
local elapsed = reltime(now)
|
||||
|
||||
|
@@ -1,20 +1,27 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local nvim, eq, neq, eval = helpers.nvim, helpers.eq, helpers.neq, helpers.eval
|
||||
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
|
||||
local command = helpers.command
|
||||
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
|
||||
local os_name = helpers.os_name
|
||||
|
||||
local function clear_serverlist()
|
||||
for _, server in pairs(funcs.serverlist()) do
|
||||
funcs.serverstop(server)
|
||||
end
|
||||
end
|
||||
|
||||
describe('serverstart(), serverstop()', function()
|
||||
before_each(clear)
|
||||
|
||||
it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
|
||||
-- Unset $NVIM_LISTEN_ADDRESS
|
||||
nvim('command', 'let $NVIM_LISTEN_ADDRESS = ""')
|
||||
command('let $NVIM_LISTEN_ADDRESS = ""')
|
||||
|
||||
local s = eval('serverstart()')
|
||||
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
|
||||
eq(s, eval('$NVIM_LISTEN_ADDRESS'))
|
||||
nvim('command', "call serverstop('"..s.."')")
|
||||
command("call serverstop('"..s.."')")
|
||||
eq('', eval('$NVIM_LISTEN_ADDRESS'))
|
||||
end)
|
||||
|
||||
@@ -47,10 +54,48 @@ describe('serverstart(), serverstop()', function()
|
||||
end)
|
||||
|
||||
it('serverstop() ignores invalid input', function()
|
||||
nvim('command', "call serverstop('')")
|
||||
nvim('command', "call serverstop('bogus-socket-name')")
|
||||
command("call serverstop('')")
|
||||
command("call serverstop('bogus-socket-name')")
|
||||
end)
|
||||
|
||||
it('parses endpoints correctly', function()
|
||||
clear_serverlist()
|
||||
eq({}, funcs.serverlist())
|
||||
|
||||
local s = funcs.serverstart('127.0.0.1:0') -- assign random port
|
||||
if #s > 0 then
|
||||
assert(string.match(s, '127.0.0.1:%d+'))
|
||||
eq(s, funcs.serverlist()[1])
|
||||
clear_serverlist()
|
||||
end
|
||||
|
||||
s = funcs.serverstart('127.0.0.1:') -- assign random port
|
||||
if #s > 0 then
|
||||
assert(string.match(s, '127.0.0.1:%d+'))
|
||||
eq(s, funcs.serverlist()[1])
|
||||
clear_serverlist()
|
||||
end
|
||||
|
||||
local expected = {}
|
||||
local v4 = '127.0.0.1:12345'
|
||||
s = funcs.serverstart(v4)
|
||||
if #s > 0 then
|
||||
table.insert(expected, v4)
|
||||
funcs.serverstart(v4) -- exists already; ignore
|
||||
end
|
||||
|
||||
local v6 = '::1:12345'
|
||||
s = funcs.serverstart(v6)
|
||||
if #s > 0 then
|
||||
table.insert(expected, v6)
|
||||
funcs.serverstart(v6) -- exists already; ignore
|
||||
end
|
||||
eq(expected, funcs.serverlist())
|
||||
clear_serverlist()
|
||||
|
||||
funcs.serverstart('127.0.0.1:65536') -- invalid port
|
||||
eq({}, funcs.serverlist())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('serverlist()', function()
|
||||
@@ -75,7 +120,7 @@ describe('serverlist()', function()
|
||||
-- The new servers should be at the end of the list.
|
||||
for i = 1, #servs do
|
||||
eq(servs[i], new_servs[i + n])
|
||||
nvim('command', "call serverstop('"..servs[i].."')")
|
||||
command("call serverstop('"..servs[i].."')")
|
||||
end
|
||||
-- After serverstop() the servers should NOT be in the list.
|
||||
eq(n, eval('len(serverlist())'))
|
||||
|
@@ -3,7 +3,7 @@ local setpos = helpers.funcs.setpos
|
||||
local getpos = helpers.funcs.getpos
|
||||
local insert = helpers.insert
|
||||
local clear = helpers.clear
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
local eval = helpers.eval
|
||||
local eq = helpers.eq
|
||||
local exc_exec = helpers.exc_exec
|
||||
@@ -16,7 +16,7 @@ describe('setpos() function', function()
|
||||
First line of text
|
||||
Second line of text
|
||||
Third line of text]])
|
||||
execute('new')
|
||||
command('new')
|
||||
insert([[
|
||||
Line of text 1
|
||||
Line of text 2
|
||||
@@ -34,7 +34,8 @@ describe('setpos() function', function()
|
||||
it('can set lowercase marks in the current buffer', function()
|
||||
setpos("'d", {0, 2, 1, 0})
|
||||
eq(getpos("'d"), {0, 2, 1, 0})
|
||||
execute('undo', 'call setpos("\'d", [2, 3, 1, 0])')
|
||||
command('undo')
|
||||
command('call setpos("\'d", [2, 3, 1, 0])')
|
||||
eq(getpos("'d"), {0, 3, 1, 0})
|
||||
end)
|
||||
it('can set lowercase marks in other buffers', function()
|
||||
@@ -42,7 +43,7 @@ describe('setpos() function', function()
|
||||
eq(0, retval)
|
||||
setpos("'d", {1, 2, 1, 0})
|
||||
eq(getpos("'d"), {0, 0, 0, 0})
|
||||
execute('wincmd w')
|
||||
command('wincmd w')
|
||||
eq(eval('bufnr("%")'), 1)
|
||||
eq(getpos("'d"), {0, 2, 1, 0})
|
||||
end)
|
||||
|
41
test/functional/eval/sort_spec.lua
Normal file
41
test/functional/eval/sort_spec.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local NIL = helpers.NIL
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local meths = helpers.meths
|
||||
local funcs = helpers.funcs
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('sort()', function()
|
||||
it('errors out when sorting special values', function()
|
||||
eq('Vim(call):E907: Using a special value as a Float',
|
||||
exc_exec('call sort([v:true, v:false], "f")'))
|
||||
end)
|
||||
|
||||
it('sorts “wrong” values between -0.0001 and 0.0001, preserving order',
|
||||
function()
|
||||
meths.set_var('list', {true, false, NIL, {}, {a=42}, 'check',
|
||||
0.0001, -0.0001})
|
||||
command('call insert(g:list, function("tr"))')
|
||||
local error_lines = funcs.split(
|
||||
funcs.execute('silent! call sort(g:list, "f")'), '\n')
|
||||
local errors = {}
|
||||
for _, err in ipairs(error_lines) do
|
||||
errors[err] = true
|
||||
end
|
||||
eq({
|
||||
['E891: Using a Funcref as a Float']=true,
|
||||
['E892: Using a String as a Float']=true,
|
||||
['E893: Using a List as a Float']=true,
|
||||
['E894: Using a Dictionary as a Float']=true,
|
||||
['E907: Using a special value as a Float']=true,
|
||||
}, errors)
|
||||
eq('[-1.0e-4, function(\'tr\'), v:true, v:false, v:null, [], {\'a\': 42}, \'check\', 1.0e-4]',
|
||||
eval('string(g:list)'))
|
||||
end)
|
||||
end)
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local exc_exec = helpers.exc_exec
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
local funcs = helpers.funcs
|
||||
local clear = helpers.clear
|
||||
local eval = helpers.eval
|
||||
@@ -12,7 +12,7 @@ describe('Special values', function()
|
||||
before_each(clear)
|
||||
|
||||
it('do not cause error when freed', function()
|
||||
execute([[
|
||||
command([[
|
||||
function Test()
|
||||
try
|
||||
return v:true
|
||||
@@ -109,7 +109,7 @@ describe('Special values', function()
|
||||
it('does not work with +=/-=/.=', function()
|
||||
meths.set_var('true', true)
|
||||
meths.set_var('false', false)
|
||||
execute('let null = v:null')
|
||||
command('let null = v:null')
|
||||
|
||||
eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let true += 1'))
|
||||
eq('Vim(let):E734: Wrong variable type for +=', exc_exec('let false += 1'))
|
||||
@@ -168,4 +168,11 @@ describe('Special values', function()
|
||||
'Expected True but got v:null',
|
||||
}, meths.get_vvar('errors'))
|
||||
end)
|
||||
|
||||
describe('compat', function()
|
||||
it('v:count is distinct from count', function()
|
||||
command('let count = []') -- v:count is readonly
|
||||
eq(1, eval('count is# g:["count"]'))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -7,7 +7,6 @@ local eval = helpers.eval
|
||||
local exc_exec = helpers.exc_exec
|
||||
local redir_exec = helpers.redir_exec
|
||||
local funcs = helpers.funcs
|
||||
local write_file = helpers.write_file
|
||||
local NIL = helpers.NIL
|
||||
local source = helpers.source
|
||||
local dedent = helpers.dedent
|
||||
@@ -105,10 +104,8 @@ describe('string() function', function()
|
||||
end)
|
||||
|
||||
describe('used to represent funcrefs', function()
|
||||
local fname = 'Xtest-functional-eval-string_spec-fref-script.vim'
|
||||
|
||||
before_each(function()
|
||||
write_file(fname, [[
|
||||
source([[
|
||||
function Test1()
|
||||
endfunction
|
||||
|
||||
@@ -120,11 +117,6 @@ describe('string() function', function()
|
||||
|
||||
let g:Test2_f = function('s:Test2')
|
||||
]])
|
||||
command('source ' .. fname)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
os.remove(fname)
|
||||
end)
|
||||
|
||||
it('dumps references to built-in functions', function()
|
||||
|
@@ -1,7 +1,11 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq, call, clear, eval, execute, feed, nvim =
|
||||
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.execute,
|
||||
|
||||
local nvim_dir = helpers.nvim_dir
|
||||
local eq, call, clear, eval, feed_command, feed, nvim =
|
||||
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
|
||||
helpers.feed, helpers.nvim
|
||||
local command = helpers.command
|
||||
local iswin = helpers.iswin
|
||||
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
|
||||
@@ -31,8 +35,7 @@ describe('system()', function()
|
||||
|
||||
describe('command passed as a List', function()
|
||||
local function printargs_path()
|
||||
return helpers.nvim_dir..'/printargs-test'
|
||||
.. (helpers.os_name() == 'windows' and '.exe' or '')
|
||||
return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '')
|
||||
end
|
||||
|
||||
it('sets v:shell_error if cmd[0] is not executable', function()
|
||||
@@ -43,10 +46,10 @@ describe('system()', function()
|
||||
it('parameter validation does NOT modify v:shell_error', function()
|
||||
-- 1. Call system() with invalid parameters.
|
||||
-- 2. Assert that v:shell_error was NOT set.
|
||||
execute('call system({})')
|
||||
feed_command('call system({})')
|
||||
eq('E475: Invalid argument: expected String or List', eval('v:errmsg'))
|
||||
eq(0, eval('v:shell_error'))
|
||||
execute('call system([])')
|
||||
feed_command('call system([])')
|
||||
eq('E474: Invalid argument', eval('v:errmsg'))
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
@@ -57,9 +60,9 @@ describe('system()', function()
|
||||
|
||||
-- 1. Call system() with invalid parameters.
|
||||
-- 2. Assert that v:shell_error was NOT modified.
|
||||
execute('call system({})')
|
||||
feed_command('call system({})')
|
||||
eq(old_val, eval('v:shell_error'))
|
||||
execute('call system([])')
|
||||
feed_command('call system([])')
|
||||
eq(old_val, eval('v:shell_error'))
|
||||
end)
|
||||
|
||||
@@ -86,23 +89,32 @@ describe('system()', function()
|
||||
end)
|
||||
|
||||
it('does NOT run in shell', function()
|
||||
if helpers.os_name() ~= 'windows' then
|
||||
if not iswin() then
|
||||
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
|
||||
it('sets v:shell_error', function()
|
||||
eval([[system("sh -c 'exit'")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[system("sh -c 'exit 1'")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[system("sh -c 'exit 5'")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[system('this-should-not-exist')]])
|
||||
eq(127, eval('v:shell_error'))
|
||||
if iswin() then
|
||||
eval([[system("cmd.exe /c exit")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[system("cmd.exe /c exit 1")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[system("cmd.exe /c exit 5")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[system('this-should-not-exist')]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
else
|
||||
eval([[system("sh -c 'exit'")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[system("sh -c 'exit 1'")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[system("sh -c 'exit 5'")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[system('this-should-not-exist')]])
|
||||
eq(127, eval('v:shell_error'))
|
||||
end
|
||||
end)
|
||||
|
||||
describe('executes shell function if passed a string', function()
|
||||
@@ -118,6 +130,40 @@ describe('system()', function()
|
||||
screen:detach()
|
||||
end)
|
||||
|
||||
if iswin() then
|
||||
it('with shell=cmd.exe', function()
|
||||
command('set shell=cmd.exe')
|
||||
eq('""\n', eval([[system('echo ""')]]))
|
||||
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||
eq('a \nb\n', eval([[system('echo a & echo b')]]))
|
||||
eq('a \n', eval([[system('echo a 2>&1')]]))
|
||||
eval([[system('cd "C:\Program Files"')]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
end)
|
||||
|
||||
it('with shell=cmd', function()
|
||||
command('set shell=cmd')
|
||||
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||
end)
|
||||
|
||||
it('with shell=$COMSPEC', function()
|
||||
local comspecshell = eval("fnamemodify($COMSPEC, ':t')")
|
||||
if comspecshell == 'cmd.exe' then
|
||||
command('set shell=$COMSPEC')
|
||||
eq('"a b"\n', eval([[system('echo "a b"')]]))
|
||||
else
|
||||
pending('$COMSPEC is not cmd.exe: ' .. comspecshell)
|
||||
end
|
||||
end)
|
||||
|
||||
it('works with powershell', function()
|
||||
helpers.set_shell_powershell()
|
||||
eq('a\nb\n', eval([[system('echo a b')]]))
|
||||
eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]]))
|
||||
eq('a b\n', eval([[system('echo "a b"')]]))
|
||||
end)
|
||||
end
|
||||
|
||||
it('`echo` and waits for its return', function()
|
||||
feed(':call system("echo")<cr>')
|
||||
screen:expect([[
|
||||
@@ -178,11 +224,15 @@ describe('system()', function()
|
||||
|
||||
describe('passing no input', function()
|
||||
it('returns the program output', function()
|
||||
eq("echoed", eval('system("echo -n echoed")'))
|
||||
if iswin() then
|
||||
eq("echoed\n", eval('system("echo echoed")'))
|
||||
else
|
||||
eq("echoed", eval('system("echo -n echoed")'))
|
||||
end
|
||||
end)
|
||||
it('to backgrounded command does not crash', function()
|
||||
-- This is indeterminate, just exercise the codepath. May get E5677.
|
||||
execute('call system("echo -n echoed &")')
|
||||
feed_command('call system("echo -n echoed &")')
|
||||
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
|
||||
if v_errnum then
|
||||
eq("E5677:", v_errnum)
|
||||
@@ -197,7 +247,7 @@ describe('system()', function()
|
||||
end)
|
||||
it('to backgrounded command does not crash', function()
|
||||
-- This is indeterminate, just exercise the codepath. May get E5677.
|
||||
execute('call system("cat - &")')
|
||||
feed_command('call system("cat - &")')
|
||||
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
|
||||
if v_errnum then
|
||||
eq("E5677:", v_errnum)
|
||||
@@ -275,21 +325,30 @@ describe('system()', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
|
||||
describe('systemlist()', function()
|
||||
-- Similar to `system()`, but returns List instead of String.
|
||||
before_each(clear)
|
||||
|
||||
it('sets the v:shell_error variable', function()
|
||||
eval([[systemlist("sh -c 'exit'")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[systemlist("sh -c 'exit 1'")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[systemlist("sh -c 'exit 5'")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[systemlist('this-should-not-exist')]])
|
||||
eq(127, eval('v:shell_error'))
|
||||
it('sets v:shell_error', function()
|
||||
if iswin() then
|
||||
eval([[systemlist("cmd.exe /c exit")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[systemlist("cmd.exe /c exit 1")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[systemlist("cmd.exe /c exit 5")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[systemlist('this-should-not-exist')]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
else
|
||||
eval([[systemlist("sh -c 'exit'")]])
|
||||
eq(0, eval('v:shell_error'))
|
||||
eval([[systemlist("sh -c 'exit 1'")]])
|
||||
eq(1, eval('v:shell_error'))
|
||||
eval([[systemlist("sh -c 'exit 5'")]])
|
||||
eq(5, eval('v:shell_error'))
|
||||
eval([[systemlist('this-should-not-exist')]])
|
||||
eq(127, eval('v:shell_error'))
|
||||
end
|
||||
end)
|
||||
|
||||
describe('exectues shell function', function()
|
||||
@@ -387,6 +446,7 @@ describe('systemlist()', function()
|
||||
after_each(delete_file(fname))
|
||||
|
||||
it('replaces NULs by newline characters', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
eq({'part1\npart2\npart3'}, eval('systemlist("cat '..fname..'")'))
|
||||
end)
|
||||
end)
|
||||
|
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval
|
||||
local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
|
||||
local clear, execute, funcs = helpers.clear, helpers.execute, helpers.funcs
|
||||
local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
|
||||
describe('timers', function()
|
||||
@@ -17,14 +17,14 @@ describe('timers', function()
|
||||
end)
|
||||
|
||||
it('works one-shot', function()
|
||||
execute("call timer_start(50, 'MyHandler')")
|
||||
command("call timer_start(50, 'MyHandler')")
|
||||
eq(0,eval("g:val"))
|
||||
run(nil, nil, nil, 200)
|
||||
eq(1,eval("g:val"))
|
||||
end)
|
||||
|
||||
it('works one-shot when repeat=0', function()
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': 0})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': 0})")
|
||||
eq(0,eval("g:val"))
|
||||
run(nil, nil, nil, 200)
|
||||
eq(1,eval("g:val"))
|
||||
@@ -32,14 +32,14 @@ describe('timers', function()
|
||||
|
||||
|
||||
it('works with repeat two', function()
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': 2})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': 2})")
|
||||
eq(0,eval("g:val"))
|
||||
run(nil, nil, nil, 300)
|
||||
eq(2,eval("g:val"))
|
||||
end)
|
||||
|
||||
it('are triggered during sleep', function()
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': 2})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': 2})")
|
||||
nvim_async("command", "sleep 10")
|
||||
eq(0,eval("g:val"))
|
||||
run(nil, nil, nil, 300)
|
||||
@@ -49,7 +49,7 @@ describe('timers', function()
|
||||
it('works with zero timeout', function()
|
||||
-- timer_start does still not invoke the callback immediately
|
||||
eq(0,eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
|
||||
run(nil, nil, nil, 300)
|
||||
run(nil, nil, nil, 400)
|
||||
eq(1000,eval("g:val"))
|
||||
end)
|
||||
|
||||
@@ -63,12 +63,12 @@ describe('timers', function()
|
||||
end)
|
||||
|
||||
it('are paused when event processing is disabled', function()
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
run(nil, nil, nil, 100)
|
||||
local count = eval("g:val")
|
||||
-- shows two line error message and thus invokes the return prompt.
|
||||
-- if we start to allow event processing here, we need to change this test.
|
||||
execute("throw 'fatal error'")
|
||||
feed(':throw "fatal error"<CR>')
|
||||
run(nil, nil, nil, 300)
|
||||
feed("<cr>")
|
||||
local diff = eval("g:val") - count
|
||||
@@ -76,7 +76,7 @@ describe('timers', function()
|
||||
end)
|
||||
|
||||
it('are triggered in blocking getchar() call', function()
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
nvim_async("command", "let g:c = getchar()")
|
||||
run(nil, nil, nil, 300)
|
||||
feed("c")
|
||||
@@ -157,7 +157,7 @@ describe('timers', function()
|
||||
endif
|
||||
endfunc
|
||||
]])
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': -1})")
|
||||
eq(0,eval("g:val"))
|
||||
run(nil, nil, nil, 300)
|
||||
eq(3,eval("g:val"))
|
||||
@@ -170,8 +170,8 @@ describe('timers', function()
|
||||
let g:val2 += 1
|
||||
endfunc
|
||||
]])
|
||||
execute("call timer_start(50, 'MyHandler', {'repeat': 3})")
|
||||
execute("call timer_start(100, 'MyHandler2', {'repeat': 2})")
|
||||
command("call timer_start(50, 'MyHandler', {'repeat': 3})")
|
||||
command("call timer_start(100, 'MyHandler2', {'repeat': 2})")
|
||||
run(nil, nil, nil, 300)
|
||||
eq(3,eval("g:val"))
|
||||
eq(2,eval("g:val2"))
|
||||
@@ -186,7 +186,7 @@ describe('timers', function()
|
||||
let g:val += 1
|
||||
endfunc
|
||||
]])
|
||||
execute("call timer_start(5, 'MyHandler', {'repeat': 1})")
|
||||
command("call timer_start(5, 'MyHandler', {'repeat': 1})")
|
||||
run(nil, nil, nil, 300)
|
||||
eq(1,eval("g:val"))
|
||||
end)
|
||||
@@ -201,7 +201,7 @@ describe('timers', function()
|
||||
echo "evil"
|
||||
endfunc
|
||||
]])
|
||||
execute("call timer_start(100, 'MyHandler', {'repeat': 1})")
|
||||
command("call timer_start(100, 'MyHandler', {'repeat': 1})")
|
||||
feed(":good")
|
||||
screen:sleep(200)
|
||||
screen:expect([[
|
||||
|
@@ -80,6 +80,13 @@ describe('writefile()', function()
|
||||
eq('a\0\0\0b', read_file(fname))
|
||||
end)
|
||||
|
||||
it('writes with s and S', function()
|
||||
eq(0, funcs.writefile({'\na\nb\n'}, fname, 'bs'))
|
||||
eq('\0a\0b\0', read_file(fname))
|
||||
eq(0, funcs.writefile({'a\n\n\nb'}, fname, 'bS'))
|
||||
eq('a\0\0\0b', read_file(fname))
|
||||
end)
|
||||
|
||||
it('correctly overwrites file', function()
|
||||
eq(0, funcs.writefile({'\na\nb\n'}, fname, 'b'))
|
||||
eq('\0a\0b\0', read_file(fname))
|
||||
@@ -115,6 +122,8 @@ describe('writefile()', function()
|
||||
eq('\nE729: using Funcref as a String',
|
||||
redir_exec(('call writefile(%s)'):format(args:format('function("tr")'))))
|
||||
end
|
||||
eq('\nE5060: Unknown flag: «»',
|
||||
redir_exec(('call writefile([], "%s", "bs«»")'):format(fname)))
|
||||
eq('TEST', read_file(fname))
|
||||
end)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
local helpers = require("test.functional.helpers")(after_each)
|
||||
local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
|
||||
local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
|
||||
local ok = helpers.ok
|
||||
local clear = helpers.clear
|
||||
|
||||
@@ -9,15 +9,15 @@ describe(":argument", function()
|
||||
end)
|
||||
|
||||
it("does not restart :terminal buffer", function()
|
||||
execute("terminal")
|
||||
command("terminal")
|
||||
helpers.feed([[<C-\><C-N>]])
|
||||
execute("argadd")
|
||||
command("argadd")
|
||||
helpers.feed([[<C-\><C-N>]])
|
||||
local bufname_before = funcs.bufname("%")
|
||||
local bufnr_before = funcs.bufnr("%")
|
||||
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
|
||||
|
||||
execute("argument 1")
|
||||
command("argument 1")
|
||||
helpers.feed([[<C-\><C-N>]])
|
||||
|
||||
local bufname_after = funcs.bufname("%")
|
||||
|
@@ -1,7 +1,7 @@
|
||||
-- Specs for bang/filter commands
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local feed, execute, clear = helpers.feed, helpers.execute, helpers.clear
|
||||
local feed, command, clear = helpers.feed, helpers.command, helpers.clear
|
||||
local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
@@ -28,7 +28,7 @@ describe('issues', function()
|
||||
end)
|
||||
|
||||
it('#3269 Last line of shell output is not truncated', function()
|
||||
execute([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
|
||||
command([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
|
||||
feed([[\l]])
|
||||
screen:expect([[
|
||||
~ |
|
||||
|
@@ -6,7 +6,7 @@ local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq = helpers.eq
|
||||
local call = helpers.call
|
||||
local clear = helpers.clear
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
@@ -58,7 +58,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(0, lwd(globalwin))
|
||||
eq(0, lwd(globalwin, tabnr))
|
||||
|
||||
execute('bot split')
|
||||
command('bot split')
|
||||
local localwin = call('winnr')
|
||||
-- Initial window is still using globalDir
|
||||
eq(globalDir, cwd(localwin))
|
||||
@@ -66,7 +66,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(0, lwd(globalwin))
|
||||
eq(0, lwd(globalwin, tabnr))
|
||||
|
||||
execute('silent l' .. cmd .. ' ' .. directories.window)
|
||||
command('silent l' .. cmd .. ' ' .. directories.window)
|
||||
-- From window with local dir, the original window
|
||||
-- is still reporting the global dir
|
||||
eq(globalDir, cwd(globalwin))
|
||||
@@ -80,7 +80,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(1, lwd(localwin))
|
||||
eq(1, lwd(localwin, tabnr))
|
||||
|
||||
execute('tabnew')
|
||||
command('tabnew')
|
||||
-- From new tab page, original window reports global dir
|
||||
eq(globalDir, cwd(globalwin, tabnr))
|
||||
eq(0, lwd(globalwin, tabnr))
|
||||
@@ -100,8 +100,8 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(0, lwd(-1, 0))
|
||||
eq(0, lwd(-1, globaltab))
|
||||
|
||||
execute('tabnew')
|
||||
execute('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
command('tabnew')
|
||||
command('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
local localtab = call('tabpagenr')
|
||||
|
||||
-- From local tab page, original tab reports globalDir
|
||||
@@ -114,7 +114,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(1, lwd(-1, 0))
|
||||
eq(1, lwd(-1, localtab))
|
||||
|
||||
execute('tabnext')
|
||||
command('tabnext')
|
||||
-- From original tab page, local reports as such
|
||||
eq(globalDir .. '/' .. directories.tab, cwd(-1, localtab))
|
||||
eq(1, lwd(-1, localtab))
|
||||
@@ -128,13 +128,13 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
end)
|
||||
|
||||
it('works with tab-local pwd', function()
|
||||
execute('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
command('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
eq(directories.start, cwd(-1, -1))
|
||||
eq(0, lwd(-1, -1))
|
||||
end)
|
||||
|
||||
it('works with window-local pwd', function()
|
||||
execute('silent l' .. cmd .. ' ' .. directories.window)
|
||||
command('silent l' .. cmd .. ' ' .. directories.window)
|
||||
eq(directories.start, cwd(-1, -1))
|
||||
eq(0, lwd(-1, -1))
|
||||
end)
|
||||
@@ -145,18 +145,18 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
local globalDir = directories.start
|
||||
|
||||
-- Create a new tab and change directory
|
||||
execute('tabnew')
|
||||
execute('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
command('tabnew')
|
||||
command('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
|
||||
-- Create a new tab and verify it has inherited the directory
|
||||
execute('tabnew')
|
||||
command('tabnew')
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
|
||||
-- Change tab and change back, verify that directories are correct
|
||||
execute('tabnext')
|
||||
command('tabnext')
|
||||
eq(globalDir, tcwd())
|
||||
execute('tabprevious')
|
||||
command('tabprevious')
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
end)
|
||||
end)
|
||||
@@ -164,7 +164,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
it('works', function()
|
||||
local globalDir = directories.start
|
||||
-- Create a new tab first and verify that is has the same working dir
|
||||
execute('tabnew')
|
||||
command('tabnew')
|
||||
eq(globalDir, cwd())
|
||||
eq(globalDir, tcwd()) -- has no tab-local directory
|
||||
eq(0, tlwd())
|
||||
@@ -172,7 +172,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(0, wlwd())
|
||||
|
||||
-- Change tab-local working directory and verify it is different
|
||||
execute('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
command('silent t' .. cmd .. ' ' .. directories.tab)
|
||||
eq(globalDir .. '/' .. directories.tab, cwd())
|
||||
eq(cwd(), tcwd()) -- working directory maches tab directory
|
||||
eq(1, tlwd())
|
||||
@@ -180,46 +180,46 @@ for _, cmd in ipairs {'cd', 'chdir'} do
|
||||
eq(0, wlwd())
|
||||
|
||||
-- Create a new window in this tab to test `:lcd`
|
||||
execute('new')
|
||||
command('new')
|
||||
eq(1, tlwd()) -- Still tab-local working directory
|
||||
eq(0, wlwd()) -- Still no window-local working directory
|
||||
eq(globalDir .. '/' .. directories.tab, cwd())
|
||||
execute('silent l' .. cmd .. ' ../' .. directories.window)
|
||||
command('silent l' .. cmd .. ' ../' .. directories.window)
|
||||
eq(globalDir .. '/' .. directories.window, cwd())
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
eq(1, wlwd())
|
||||
|
||||
-- Verify the first window still has the tab local directory
|
||||
execute('wincmd w')
|
||||
command('wincmd w')
|
||||
eq(globalDir .. '/' .. directories.tab, cwd())
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
eq(0, wlwd()) -- No window-local directory
|
||||
|
||||
-- Change back to initial tab and verify working directory has stayed
|
||||
execute('tabnext')
|
||||
command('tabnext')
|
||||
eq(globalDir, cwd() )
|
||||
eq(0, tlwd())
|
||||
eq(0, wlwd())
|
||||
|
||||
-- Verify global changes don't affect local ones
|
||||
execute('silent ' .. cmd .. ' ' .. directories.global)
|
||||
command('silent ' .. cmd .. ' ' .. directories.global)
|
||||
eq(globalDir .. '/' .. directories.global, cwd())
|
||||
execute('tabnext')
|
||||
command('tabnext')
|
||||
eq(globalDir .. '/' .. directories.tab, cwd())
|
||||
eq(globalDir .. '/' .. directories.tab, tcwd())
|
||||
eq(0, wlwd()) -- Still no window-local directory in this window
|
||||
|
||||
-- Unless the global change happened in a tab with local directory
|
||||
execute('silent ' .. cmd .. ' ..')
|
||||
command('silent ' .. cmd .. ' ..')
|
||||
eq(globalDir, cwd() )
|
||||
eq(0 , tlwd())
|
||||
eq(0 , wlwd())
|
||||
-- Which also affects the first tab
|
||||
execute('tabnext')
|
||||
command('tabnext')
|
||||
eq(globalDir, cwd())
|
||||
|
||||
-- But not in a window with its own local directory
|
||||
execute('tabnext | wincmd w')
|
||||
command('tabnext | wincmd w')
|
||||
eq(globalDir .. '/' .. directories.window, cwd() )
|
||||
eq(0 , tlwd())
|
||||
eq(globalDir .. '/' .. directories.window, wcwd())
|
||||
@@ -280,8 +280,8 @@ describe("getcwd()", function ()
|
||||
end)
|
||||
|
||||
it("returns empty string if working directory does not exist", function()
|
||||
execute("cd "..directories.global)
|
||||
execute("call delete('../"..directories.global.."', 'd')")
|
||||
command("cd "..directories.global)
|
||||
command("call delete('../"..directories.global.."', 'd')")
|
||||
eq("", helpers.eval("getcwd()"))
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, feed, source = helpers.clear, helpers.feed, helpers.source
|
||||
local execute = helpers.execute
|
||||
local command = helpers.command
|
||||
|
||||
describe("CTRL-C (mapped)", function()
|
||||
before_each(function()
|
||||
@@ -20,7 +20,7 @@ describe("CTRL-C (mapped)", function()
|
||||
nnoremap <C-C> <NOP>
|
||||
]])
|
||||
|
||||
execute("silent edit! test/functional/fixtures/bigfile.txt")
|
||||
command("silent edit! test/functional/fixtures/bigfile.txt")
|
||||
local screen = Screen.new(52, 6)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
@@ -41,13 +41,13 @@ describe("CTRL-C (mapped)", function()
|
||||
|
||||
local function test_ctrl_c(ms)
|
||||
feed(":global/^/p<CR>")
|
||||
helpers.sleep(ms)
|
||||
screen:sleep(ms)
|
||||
feed("<C-C>")
|
||||
screen:expect([[Interrupt]], nil, nil, nil, true)
|
||||
end
|
||||
|
||||
-- The test is time-sensitive. Try different sleep values.
|
||||
local ms_values = {1, 10, 100}
|
||||
local ms_values = {100, 1000, 10000}
|
||||
for i, ms in ipairs(ms_values) do
|
||||
if i < #ms_values then
|
||||
local status, _ = pcall(test_ctrl_c, ms)
|
||||
|
@@ -9,7 +9,7 @@ local eval = helpers.eval
|
||||
describe('dictionary change notifications', function()
|
||||
local channel
|
||||
|
||||
setup(function()
|
||||
before_each(function()
|
||||
clear()
|
||||
channel = nvim('get_api_info')[1]
|
||||
nvim('set_var', 'channel', channel)
|
||||
@@ -18,19 +18,15 @@ describe('dictionary change notifications', function()
|
||||
-- the same set of tests are applied to top-level dictionaries(g:, b:, w: and
|
||||
-- t:) and a dictionary variable, so we generate them in the following
|
||||
-- function.
|
||||
local function gentests(dict_expr, dict_expr_suffix, dict_init)
|
||||
if not dict_expr_suffix then
|
||||
dict_expr_suffix = ''
|
||||
end
|
||||
|
||||
local function gentests(dict_expr, dict_init)
|
||||
local function update(opval, key)
|
||||
if not key then
|
||||
key = 'watched'
|
||||
end
|
||||
if opval == '' then
|
||||
nvim('command', "unlet "..dict_expr..dict_expr_suffix..key)
|
||||
command(('unlet %s[\'%s\']'):format(dict_expr, key))
|
||||
else
|
||||
nvim('command', "let "..dict_expr..dict_expr_suffix..key.." "..opval)
|
||||
command(('let %s[\'%s\'] %s'):format(dict_expr, key, opval))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,9 +44,9 @@ describe('dictionary change notifications', function()
|
||||
eq({'notification', 'values', {key, vals}}, next_msg())
|
||||
end
|
||||
|
||||
describe('watcher', function()
|
||||
describe(dict_expr .. ' watcher', function()
|
||||
if dict_init then
|
||||
setup(function()
|
||||
before_each(function()
|
||||
source(dict_init)
|
||||
end)
|
||||
end
|
||||
@@ -58,7 +54,7 @@ describe('dictionary change notifications', function()
|
||||
before_each(function()
|
||||
source([[
|
||||
function! g:Changed(dict, key, value)
|
||||
if a:dict != ]]..dict_expr..[[ |
|
||||
if a:dict isnot ]]..dict_expr..[[ |
|
||||
throw 'invalid dict'
|
||||
endif
|
||||
call rpcnotify(g:channel, 'values', a:key, a:value)
|
||||
@@ -143,6 +139,32 @@ describe('dictionary change notifications', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('is triggered for empty keys', function()
|
||||
command([[
|
||||
call dictwatcheradd(]]..dict_expr..[[, "", "g:Changed")
|
||||
]])
|
||||
update('= 1', '')
|
||||
verify_value({new = 1}, '')
|
||||
update('= 2', '')
|
||||
verify_value({old = 1, new = 2}, '')
|
||||
command([[
|
||||
call dictwatcherdel(]]..dict_expr..[[, "", "g:Changed")
|
||||
]])
|
||||
end)
|
||||
|
||||
it('is triggered for empty keys when using catch-all *', function()
|
||||
command([[
|
||||
call dictwatcheradd(]]..dict_expr..[[, "*", "g:Changed")
|
||||
]])
|
||||
update('= 1', '')
|
||||
verify_value({new = 1}, '')
|
||||
update('= 2', '')
|
||||
verify_value({old = 1, new = 2}, '')
|
||||
command([[
|
||||
call dictwatcherdel(]]..dict_expr..[[, "*", "g:Changed")
|
||||
]])
|
||||
end)
|
||||
|
||||
-- test a sequence of updates of different types to ensure proper memory
|
||||
-- management(with ASAN)
|
||||
local function test_updates(tests)
|
||||
@@ -190,10 +212,10 @@ describe('dictionary change notifications', function()
|
||||
gentests('b:')
|
||||
gentests('w:')
|
||||
gentests('t:')
|
||||
gentests('g:dict_var', '.', 'let g:dict_var = {}')
|
||||
gentests('g:dict_var', 'let g:dict_var = {}')
|
||||
|
||||
describe('multiple watchers on the same dict/key', function()
|
||||
setup(function()
|
||||
before_each(function()
|
||||
source([[
|
||||
function! g:Watcher1(dict, key, value)
|
||||
call rpcnotify(g:channel, '1', a:key, a:value)
|
||||
@@ -213,13 +235,37 @@ describe('dictionary change notifications', function()
|
||||
end)
|
||||
|
||||
it('only removes watchers that fully match dict, key and callback', function()
|
||||
nvim('command', 'let g:key = "value"')
|
||||
eq({'notification', '1', {'key', {new = 'value'}}}, next_msg())
|
||||
eq({'notification', '2', {'key', {new = 'value'}}}, next_msg())
|
||||
nvim('command', 'call dictwatcherdel(g:, "key", "g:Watcher1")')
|
||||
nvim('command', 'let g:key = "v2"')
|
||||
eq({'notification', '2', {'key', {old = 'value', new = 'v2'}}}, next_msg())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('errors out when adding to v:_null_dict', function()
|
||||
command([[
|
||||
function! g:Watcher1(dict, key, value)
|
||||
call rpcnotify(g:channel, '1', a:key, a:value)
|
||||
endfunction
|
||||
]])
|
||||
eq('Vim(call):E46: Cannot change read-only variable "dictwatcheradd() argument"',
|
||||
exc_exec('call dictwatcheradd(v:_null_dict, "x", "g:Watcher1")'))
|
||||
end)
|
||||
|
||||
describe('errors', function()
|
||||
before_each(function()
|
||||
source([[
|
||||
function! g:Watcher1(dict, key, value)
|
||||
call rpcnotify(g:channel, '1', a:key, a:value)
|
||||
endfunction
|
||||
function! g:Watcher2(dict, key, value)
|
||||
call rpcnotify(g:channel, '2', a:key, a:value)
|
||||
endfunction
|
||||
]])
|
||||
end)
|
||||
|
||||
-- WARNING: This suite depends on the above tests
|
||||
it('fails to remove if no watcher with matching callback is found', function()
|
||||
eq("Vim(call):Couldn't find a watcher matching key and callback",
|
||||
@@ -236,15 +282,24 @@ describe('dictionary change notifications', function()
|
||||
command('call dictwatcherdel(g:, "key", "g:InvalidCb")')
|
||||
end)
|
||||
|
||||
it('fails with empty keys', function()
|
||||
eq("Vim(call):E713: Cannot use empty key for Dictionary",
|
||||
exc_exec('call dictwatcheradd(g:, "", "g:Watcher1")'))
|
||||
eq("Vim(call):E713: Cannot use empty key for Dictionary",
|
||||
exc_exec('call dictwatcherdel(g:, "", "g:Watcher1")'))
|
||||
it('fails to remove watcher from v:_null_dict', function()
|
||||
eq("Vim(call):Couldn't find a watcher matching key and callback",
|
||||
exc_exec('call dictwatcherdel(v:_null_dict, "x", "g:Watcher2")'))
|
||||
end)
|
||||
|
||||
--[[
|
||||
[ it("fails to add/remove if the callback doesn't exist", function()
|
||||
[ eq("Vim(call):Function g:InvalidCb doesn't exist",
|
||||
[ exc_exec('call dictwatcheradd(g:, "key", "g:InvalidCb")'))
|
||||
[ eq("Vim(call):Function g:InvalidCb doesn't exist",
|
||||
[ exc_exec('call dictwatcherdel(g:, "key", "g:InvalidCb")'))
|
||||
[ end)
|
||||
]]
|
||||
|
||||
it('does not fail to replace a watcher function', function()
|
||||
source([[
|
||||
let g:key = 'v2'
|
||||
call dictwatcheradd(g:, "key", "g:Watcher2")
|
||||
function! g:ReplaceWatcher2()
|
||||
function! g:Watcher2(dict, key, value)
|
||||
call rpcnotify(g:channel, '2b', a:key, a:value)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
|
||||
local clear, feed, feed_command = helpers.clear, helpers.feed, helpers.feed_command
|
||||
|
||||
describe(":drop", function()
|
||||
local screen
|
||||
@@ -15,7 +15,7 @@ describe(":drop", function()
|
||||
[2] = {reverse = true},
|
||||
[3] = {bold = true},
|
||||
})
|
||||
execute("set laststatus=2")
|
||||
feed_command("set laststatus=2")
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
@@ -23,7 +23,7 @@ describe(":drop", function()
|
||||
end)
|
||||
|
||||
it("works like :e when called with only one window open", function()
|
||||
execute("drop tmp1.vim")
|
||||
feed_command("drop tmp1.vim")
|
||||
screen:expect([[
|
||||
^ |
|
||||
{0:~ }|
|
||||
@@ -39,10 +39,10 @@ describe(":drop", function()
|
||||
end)
|
||||
|
||||
it("switches to an open window showing the buffer", function()
|
||||
execute("edit tmp1")
|
||||
execute("vsplit")
|
||||
execute("edit tmp2")
|
||||
execute("drop tmp1")
|
||||
feed_command("edit tmp1")
|
||||
feed_command("vsplit")
|
||||
feed_command("edit tmp2")
|
||||
feed_command("drop tmp1")
|
||||
screen:expect([[
|
||||
{2:|}^ |
|
||||
{0:~ }{2:|}{0:~ }|
|
||||
@@ -58,11 +58,11 @@ describe(":drop", function()
|
||||
end)
|
||||
|
||||
it("splits off a new window when a buffer can't be abandoned", function()
|
||||
execute("edit tmp1")
|
||||
execute("vsplit")
|
||||
execute("edit tmp2")
|
||||
feed_command("edit tmp1")
|
||||
feed_command("vsplit")
|
||||
feed_command("edit tmp2")
|
||||
feed("iABC<esc>")
|
||||
execute("drop tmp3")
|
||||
feed_command("drop tmp3")
|
||||
screen:expect([[
|
||||
^ {2:|} |
|
||||
{0:~ }{2:|}{0:~ }|
|
||||
|
321
test/functional/ex_cmds/echo_spec.lua
Normal file
321
test/functional/ex_cmds/echo_spec.lua
Normal file
@@ -0,0 +1,321 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local NIL = helpers.NIL
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local meths = helpers.meths
|
||||
local funcs = helpers.funcs
|
||||
local source = helpers.source
|
||||
local dedent = helpers.dedent
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local redir_exec = helpers.redir_exec
|
||||
|
||||
describe(':echo', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
source([[
|
||||
function String(s)
|
||||
return execute('echo a:s')[1:]
|
||||
endfunction
|
||||
]])
|
||||
end)
|
||||
|
||||
describe('used to represent floating-point values', function()
|
||||
it('dumps NaN values', function()
|
||||
eq('str2float(\'nan\')', eval('String(str2float(\'nan\'))'))
|
||||
end)
|
||||
|
||||
it('dumps infinite values', function()
|
||||
eq('str2float(\'inf\')', eval('String(str2float(\'inf\'))'))
|
||||
eq('-str2float(\'inf\')', eval('String(str2float(\'-inf\'))'))
|
||||
end)
|
||||
|
||||
it('dumps regular values', function()
|
||||
eq('1.5', funcs.String(1.5))
|
||||
eq('1.56e-20', funcs.String(1.56000e-020))
|
||||
eq('0.0', eval('String(0.0)'))
|
||||
end)
|
||||
|
||||
it('dumps special v: values', function()
|
||||
eq('v:true', eval('String(v:true)'))
|
||||
eq('v:false', eval('String(v:false)'))
|
||||
eq('v:null', eval('String(v:null)'))
|
||||
eq('v:true', funcs.String(true))
|
||||
eq('v:false', funcs.String(false))
|
||||
eq('v:null', funcs.String(NIL))
|
||||
end)
|
||||
|
||||
it('dumps values with at most six digits after the decimal point',
|
||||
function()
|
||||
eq('1.234568e-20', funcs.String(1.23456789123456789123456789e-020))
|
||||
eq('1.234568', funcs.String(1.23456789123456789123456789))
|
||||
end)
|
||||
|
||||
it('dumps values with at most seven digits before the decimal point',
|
||||
function()
|
||||
eq('1234567.891235', funcs.String(1234567.89123456789123456789))
|
||||
eq('1.234568e7', funcs.String(12345678.9123456789123456789))
|
||||
end)
|
||||
|
||||
it('dumps negative values', function()
|
||||
eq('-1.5', funcs.String(-1.5))
|
||||
eq('-1.56e-20', funcs.String(-1.56000e-020))
|
||||
eq('-1.234568e-20', funcs.String(-1.23456789123456789123456789e-020))
|
||||
eq('-1.234568', funcs.String(-1.23456789123456789123456789))
|
||||
eq('-1234567.891235', funcs.String(-1234567.89123456789123456789))
|
||||
eq('-1.234568e7', funcs.String(-12345678.9123456789123456789))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent numbers', function()
|
||||
it('dumps regular values', function()
|
||||
eq('0', funcs.String(0))
|
||||
eq('-1', funcs.String(-1))
|
||||
eq('1', funcs.String(1))
|
||||
end)
|
||||
|
||||
it('dumps large values', function()
|
||||
eq('2147483647', funcs.String(2^31-1))
|
||||
eq('-2147483648', funcs.String(-2^31))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent strings', function()
|
||||
it('dumps regular strings', function()
|
||||
eq('test', funcs.String('test'))
|
||||
end)
|
||||
|
||||
it('dumps empty strings', function()
|
||||
eq('', funcs.String(''))
|
||||
end)
|
||||
|
||||
it('dumps strings with \' inside', function()
|
||||
eq('\'\'\'', funcs.String('\'\'\''))
|
||||
eq('a\'b\'\'', funcs.String('a\'b\'\''))
|
||||
eq('\'b\'\'d', funcs.String('\'b\'\'d'))
|
||||
eq('a\'b\'c\'d', funcs.String('a\'b\'c\'d'))
|
||||
end)
|
||||
|
||||
it('dumps NULL strings', function()
|
||||
eq('', eval('String($XXX_UNEXISTENT_VAR_XXX)'))
|
||||
end)
|
||||
|
||||
it('dumps NULL lists', function()
|
||||
eq('[]', eval('String(v:_null_list)'))
|
||||
end)
|
||||
|
||||
it('dumps NULL dictionaries', function()
|
||||
eq('{}', eval('String(v:_null_dict)'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent funcrefs', function()
|
||||
before_each(function()
|
||||
source([[
|
||||
function Test1()
|
||||
endfunction
|
||||
|
||||
function s:Test2() dict
|
||||
endfunction
|
||||
|
||||
function g:Test3() dict
|
||||
endfunction
|
||||
|
||||
let g:Test2_f = function('s:Test2')
|
||||
]])
|
||||
end)
|
||||
|
||||
it('dumps references to built-in functions', function()
|
||||
eq('function', eval('String(function("function"))'))
|
||||
end)
|
||||
|
||||
it('dumps references to user functions', function()
|
||||
eq('Test1', eval('String(function("Test1"))'))
|
||||
eq('g:Test3', eval('String(function("g:Test3"))'))
|
||||
end)
|
||||
|
||||
it('dumps references to script functions', function()
|
||||
eq('<SNR>2_Test2', eval('String(Test2_f)'))
|
||||
end)
|
||||
|
||||
it('dumps partials with self referencing a partial', function()
|
||||
source([[
|
||||
function TestDict() dict
|
||||
endfunction
|
||||
let d = {}
|
||||
let TestDictRef = function('TestDict', d)
|
||||
let d.tdr = TestDictRef
|
||||
]])
|
||||
eq(dedent([[
|
||||
|
||||
function('TestDict', {'tdr': function('TestDict', {...@1})})
|
||||
function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
|
||||
redir_exec('echo String(d.tdr)'))
|
||||
end)
|
||||
|
||||
it('dumps automatically created partials', function()
|
||||
eq('function(\'<SNR>2_Test2\', {\'f\': function(\'<SNR>2_Test2\')})',
|
||||
eval('String({"f": Test2_f}.f)'))
|
||||
eq('function(\'<SNR>2_Test2\', [1], {\'f\': function(\'<SNR>2_Test2\', [1])})',
|
||||
eval('String({"f": function(Test2_f, [1])}.f)'))
|
||||
end)
|
||||
|
||||
it('dumps manually created partials', function()
|
||||
eq('function(\'Test3\', [1, 2], {})',
|
||||
eval('String(function("Test3", [1, 2], {}))'))
|
||||
eq('function(\'Test3\', {})',
|
||||
eval('String(function("Test3", {}))'))
|
||||
eq('function(\'Test3\', [1, 2])',
|
||||
eval('String(function("Test3", [1, 2]))'))
|
||||
end)
|
||||
|
||||
it('does not crash or halt when dumping partials with reference cycles in self',
|
||||
function()
|
||||
meths.set_var('d', {v=true})
|
||||
eq(dedent([[
|
||||
|
||||
{'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
|
||||
{'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
|
||||
redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
|
||||
end)
|
||||
|
||||
it('does not show errors when dumping partials referencing the same dictionary',
|
||||
function()
|
||||
command('let d = {}')
|
||||
-- Regression for “eval/typval_encode: Dump empty dictionary before
|
||||
-- checking for refcycle”, results in error.
|
||||
eq('[function(\'tr\', {}), function(\'tr\', {})]', eval('String([function("tr", d), function("tr", d)])'))
|
||||
-- Regression for “eval: Work with reference cycles in partials (self)
|
||||
-- properly”, results in crash.
|
||||
eval('extend(d, {"a": 1})')
|
||||
eq('[function(\'tr\', {\'a\': 1}), function(\'tr\', {\'a\': 1})]', eval('String([function("tr", d), function("tr", d)])'))
|
||||
end)
|
||||
|
||||
it('does not crash or halt when dumping partials with reference cycles in arguments',
|
||||
function()
|
||||
meths.set_var('l', {})
|
||||
eval('add(l, l)')
|
||||
-- Regression: the below line used to crash (add returns original list and
|
||||
-- there was error in dumping partials). Tested explicitly in
|
||||
-- test/unit/api/private_helpers_spec.lua.
|
||||
eval('add(l, function("Test1", l))')
|
||||
eq(dedent([=[
|
||||
|
||||
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])
|
||||
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]),
|
||||
redir_exec('echo String(function("Test1", l))'))
|
||||
end)
|
||||
|
||||
it('does not crash or halt when dumping partials with reference cycles in self and arguments',
|
||||
function()
|
||||
meths.set_var('d', {v=true})
|
||||
meths.set_var('l', {})
|
||||
eval('add(l, l)')
|
||||
eval('add(l, function("Test1", l))')
|
||||
eval('add(l, function("Test1", d))')
|
||||
eq(dedent([=[
|
||||
|
||||
{'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
|
||||
{'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
|
||||
redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent lists', function()
|
||||
it('dumps empty list', function()
|
||||
eq('[]', funcs.String({}))
|
||||
end)
|
||||
|
||||
it('dumps nested lists', function()
|
||||
eq('[[[[[]]]]]', funcs.String({{{{{}}}}}))
|
||||
end)
|
||||
|
||||
it('dumps nested non-empty lists', function()
|
||||
eq('[1, [[3, [[5], 4]], 2]]', funcs.String({1, {{3, {{5}, 4}}, 2}}))
|
||||
end)
|
||||
|
||||
it('does not error when dumping recursive lists', function()
|
||||
meths.set_var('l', {})
|
||||
eval('add(l, l)')
|
||||
eq(0, exc_exec('echo String(l)'))
|
||||
end)
|
||||
|
||||
it('dumps recursive lists without error', function()
|
||||
meths.set_var('l', {})
|
||||
eval('add(l, l)')
|
||||
eq('\n[[...@0]]\n[[...@0]]', redir_exec('echo String(l)'))
|
||||
eq('\n[[[...@1]]]\n[[[...@1]]]', redir_exec('echo String([l])'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent dictionaries', function()
|
||||
it('dumps empty dictionary', function()
|
||||
eq('{}', eval('String({})'))
|
||||
end)
|
||||
|
||||
it('dumps list with two same empty dictionaries, also in partials', function()
|
||||
command('let d = {}')
|
||||
eq('[{}, {}]', eval('String([d, d])'))
|
||||
eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])'))
|
||||
eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])'))
|
||||
end)
|
||||
|
||||
it('dumps non-empty dictionary', function()
|
||||
eq('{\'t\'\'est\': 1}', funcs.String({['t\'est']=1}))
|
||||
end)
|
||||
|
||||
it('does not error when dumping recursive dictionaries', function()
|
||||
meths.set_var('d', {d=1})
|
||||
eval('extend(d, {"d": d})')
|
||||
eq(0, exc_exec('echo String(d)'))
|
||||
end)
|
||||
|
||||
it('dumps recursive dictionaries without the error', function()
|
||||
meths.set_var('d', {d=1})
|
||||
eval('extend(d, {"d": d})')
|
||||
eq('\n{\'d\': {...@0}}\n{\'d\': {...@0}}',
|
||||
redir_exec('echo String(d)'))
|
||||
eq('\n{\'out\': {\'d\': {...@1}}}\n{\'out\': {\'d\': {...@1}}}',
|
||||
redir_exec('echo String({"out": d})'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('used to represent special values', function()
|
||||
local function chr(n)
|
||||
return ('%c'):format(n)
|
||||
end
|
||||
local function ctrl(c)
|
||||
return ('%c'):format(c:upper():byte() - 0x40)
|
||||
end
|
||||
it('displays hex as hex', function()
|
||||
-- Regression: due to missing (uint8_t) cast \x80 was represented as
|
||||
-- ~@<80>.
|
||||
eq('<80>', funcs.String(chr(0x80)))
|
||||
eq('<81>', funcs.String(chr(0x81)))
|
||||
eq('<8e>', funcs.String(chr(0x8e)))
|
||||
eq('<c2>', funcs.String(('«'):sub(1, 1)))
|
||||
eq('«', funcs.String(('«'):sub(1, 2)))
|
||||
end)
|
||||
it('displays ASCII control characters using ^X notation', function()
|
||||
eq('^C', funcs.String(ctrl('c')))
|
||||
eq('^A', funcs.String(ctrl('a')))
|
||||
eq('^F', funcs.String(ctrl('f')))
|
||||
end)
|
||||
it('prints CR, NL and tab as-is', function()
|
||||
eq('\n', funcs.String('\n'))
|
||||
eq('\r', funcs.String('\r'))
|
||||
eq('\t', funcs.String('\t'))
|
||||
end)
|
||||
it('prints non-printable UTF-8 in <> notation', function()
|
||||
-- SINGLE SHIFT TWO, unicode control
|
||||
eq('<8e>', funcs.String(funcs.nr2char(0x8E)))
|
||||
-- Surrogate pair: U+1F0A0 PLAYING CARD BACK is represented in UTF-16 as
|
||||
-- 0xD83C 0xDCA0. This is not valid in UTF-8.
|
||||
eq('<d83c>', funcs.String(funcs.nr2char(0xD83C)))
|
||||
eq('<dca0>', funcs.String(funcs.nr2char(0xDCA0)))
|
||||
eq('<d83c><dca0>', funcs.String(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0)))
|
||||
end)
|
||||
end)
|
||||
end)
|
@@ -1,7 +1,8 @@
|
||||
local helpers = require("test.functional.helpers")(after_each)
|
||||
local eq, execute, funcs = helpers.eq, helpers.execute, helpers.funcs
|
||||
local eq, command, funcs = helpers.eq, helpers.command, helpers.funcs
|
||||
local ok = helpers.ok
|
||||
local clear = helpers.clear
|
||||
local feed = helpers.feed
|
||||
|
||||
describe(":edit", function()
|
||||
before_each(function()
|
||||
@@ -9,13 +10,13 @@ describe(":edit", function()
|
||||
end)
|
||||
|
||||
it("without arguments does not restart :terminal buffer", function()
|
||||
execute("terminal")
|
||||
helpers.feed([[<C-\><C-N>]])
|
||||
command("terminal")
|
||||
feed([[<C-\><C-N>]])
|
||||
local bufname_before = funcs.bufname("%")
|
||||
local bufnr_before = funcs.bufnr("%")
|
||||
helpers.ok(nil ~= string.find(bufname_before, "^term://")) -- sanity
|
||||
|
||||
execute("edit")
|
||||
command("edit")
|
||||
|
||||
local bufname_after = funcs.bufname("%")
|
||||
local bufnr_after = funcs.bufnr("%")
|
||||
|
@@ -1,5 +1,5 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, execute, feed = helpers.clear, helpers.execute, helpers.feed
|
||||
local clear, feed_command, feed = helpers.clear, helpers.feed_command, helpers.feed
|
||||
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
|
||||
|
||||
describe('&encoding', function()
|
||||
@@ -12,10 +12,10 @@ describe('&encoding', function()
|
||||
end)
|
||||
|
||||
it('cannot be changed after setup', function()
|
||||
execute('set encoding=latin1')
|
||||
feed_command('set encoding=latin1')
|
||||
-- error message expected
|
||||
feed('<cr>')
|
||||
neq(nil, string.find(eval('v:errmsg'), '^E474:'))
|
||||
neq(nil, string.find(eval('v:errmsg'), '^E519:'))
|
||||
eq('utf-8', eval('&encoding'))
|
||||
-- check nvim is still in utf-8 mode
|
||||
eq(3, eval('strwidth("Bär")'))
|
||||
@@ -25,13 +25,13 @@ describe('&encoding', function()
|
||||
clear('--cmd', 'set enc=latin1')
|
||||
-- error message expected
|
||||
feed('<cr>')
|
||||
neq(nil, string.find(eval('v:errmsg'), '^E474:'))
|
||||
neq(nil, string.find(eval('v:errmsg'), '^E519:'))
|
||||
eq('utf-8', eval('&encoding'))
|
||||
eq(3, eval('strwidth("Bär")'))
|
||||
end)
|
||||
|
||||
it('can be set to utf-8 without error', function()
|
||||
execute('set encoding=utf-8')
|
||||
feed_command('set encoding=utf-8')
|
||||
eq("", eval('v:errmsg'))
|
||||
|
||||
clear('--cmd', 'set enc=utf-8')
|
||||
|
35
test/functional/ex_cmds/file_spec.lua
Normal file
35
test/functional/ex_cmds/file_spec.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
local rmdir = helpers.rmdir
|
||||
|
||||
describe(':file', function()
|
||||
local swapdir = lfs.currentdir()..'/Xtest-file_spec'
|
||||
before_each(function()
|
||||
clear()
|
||||
rmdir(swapdir)
|
||||
lfs.mkdir(swapdir)
|
||||
end)
|
||||
after_each(function()
|
||||
command('%bwipeout!')
|
||||
rmdir(swapdir)
|
||||
end)
|
||||
|
||||
it("rename does not lose swapfile #6487", function()
|
||||
local testfile = 'test-file_spec'
|
||||
local testfile_renamed = testfile..'-renamed'
|
||||
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may
|
||||
-- attempt to create a swapfile in different directory.
|
||||
command('set directory^='..swapdir..'//')
|
||||
command('set swapfile fileformat=unix undolevels=-1')
|
||||
|
||||
command('edit! '..testfile)
|
||||
-- Before #6487 this gave "E301: Oops, lost the swap file !!!" on Windows.
|
||||
command('file '..testfile_renamed)
|
||||
eq(testfile_renamed..'.swp',
|
||||
string.match(funcs.execute('swapname'), '[^%%]+$'))
|
||||
end)
|
||||
end)
|
@@ -1,6 +1,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, execute, feed, ok, eval =
|
||||
helpers.clear, helpers.execute, helpers.feed, helpers.ok, helpers.eval
|
||||
local clear, feed_command, feed, ok, eval =
|
||||
helpers.clear, helpers.feed_command, helpers.feed, helpers.ok, helpers.eval
|
||||
|
||||
describe(':grep', function()
|
||||
before_each(clear)
|
||||
@@ -11,10 +11,10 @@ describe(':grep', function()
|
||||
return
|
||||
end
|
||||
|
||||
execute([[set grepprg=grep\ -r]])
|
||||
feed_command([[set grepprg=grep\ -r]])
|
||||
-- Change to test directory so that the test does not run too long.
|
||||
execute('cd test')
|
||||
execute('grep a **/*')
|
||||
feed_command('cd test')
|
||||
feed_command('grep a **/*')
|
||||
feed('<cr>') -- Press ENTER
|
||||
ok(eval('len(getqflist())') > 9000) -- IT'S OVER 9000!!1
|
||||
end)
|
||||
|
43
test/functional/ex_cmds/highlight_spec.lua
Normal file
43
test/functional/ex_cmds/highlight_spec.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local helpers = require("test.functional.helpers")(after_each)
|
||||
local eq, command = helpers.eq, helpers.command
|
||||
local clear = helpers.clear
|
||||
local eval, exc_exec = helpers.eval, helpers.exc_exec
|
||||
|
||||
describe(':highlight', function()
|
||||
local screen
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
screen = Screen.new()
|
||||
screen:attach()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
screen:detach()
|
||||
end)
|
||||
|
||||
it('invalid color name', function()
|
||||
eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818',
|
||||
exc_exec("highlight normal ctermfg=#181818"))
|
||||
eq('Vim(highlight):E421: Color name or number not recognized: ctermbg=#181818',
|
||||
exc_exec("highlight normal ctermbg=#181818"))
|
||||
end)
|
||||
|
||||
it('invalid group name', function()
|
||||
eq('Vim(highlight):E411: highlight group not found: foo',
|
||||
exc_exec("highlight foo"))
|
||||
end)
|
||||
|
||||
it('"Normal" foreground with red', function()
|
||||
eq('', eval('synIDattr(hlID("Normal"), "fg", "cterm")'))
|
||||
command('highlight normal ctermfg=red')
|
||||
eq('9', eval('synIDattr(hlID("Normal"), "fg", "cterm")'))
|
||||
end)
|
||||
|
||||
it('"Normal" background with red', function()
|
||||
eq('', eval('synIDattr(hlID("Normal"), "bg", "cterm")'))
|
||||
command('highlight normal ctermbg=red')
|
||||
eq('9', eval('synIDattr(hlID("Normal"), "bg", "cterm")'))
|
||||
end)
|
||||
end)
|
@@ -1,23 +1,25 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, execute, nvim = helpers.clear, helpers.execute, helpers.nvim
|
||||
local expect, feed, command = helpers.expect, helpers.feed, helpers.command
|
||||
local clear, command, nvim = helpers.clear, helpers.command, helpers.nvim
|
||||
local expect, feed = helpers.expect, helpers.feed
|
||||
local eq, eval = helpers.eq, helpers.eval
|
||||
local funcs = helpers.funcs
|
||||
|
||||
|
||||
describe(':emenu', function()
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
execute('nnoremenu Test.Test inormal<ESC>')
|
||||
execute('inoremenu Test.Test insert')
|
||||
execute('vnoremenu Test.Test x')
|
||||
execute('cnoremenu Test.Test cmdmode')
|
||||
command('nnoremenu Test.Test inormal<ESC>')
|
||||
command('inoremenu Test.Test insert')
|
||||
command('vnoremenu Test.Test x')
|
||||
command('cnoremenu Test.Test cmdmode')
|
||||
|
||||
execute('nnoremenu Edit.Paste p')
|
||||
execute('cnoremenu Edit.Paste <C-R>"')
|
||||
command('nnoremenu Edit.Paste p')
|
||||
command('cnoremenu Edit.Paste <C-R>"')
|
||||
end)
|
||||
|
||||
it('executes correct bindings in normal mode without using API', function()
|
||||
execute('emenu Test.Test')
|
||||
command('emenu Test.Test')
|
||||
expect('normal')
|
||||
end)
|
||||
|
||||
@@ -56,3 +58,572 @@ describe(':emenu', function()
|
||||
eq('thiscmdmode', eval('getcmdline()'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('menu_get', function()
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
command('nnoremenu &Test.Test inormal<ESC>')
|
||||
command('inoremenu Test.Test insert')
|
||||
command('vnoremenu Test.Test x')
|
||||
command('cnoremenu Test.Test cmdmode')
|
||||
command('menu Test.Nested.test level1')
|
||||
command('menu Test.Nested.Nested2 level2')
|
||||
|
||||
command('nnoremenu <script> Export.Script p')
|
||||
command('tmenu Export.Script This is the tooltip')
|
||||
command('menu ]Export.hidden thisoneshouldbehidden')
|
||||
|
||||
command('nnoremenu Edit.Paste p')
|
||||
command('cnoremenu Edit.Paste <C-R>"')
|
||||
end)
|
||||
|
||||
it("path='', modes='a'", function()
|
||||
local m = funcs.menu_get("","a");
|
||||
-- HINT: To print the expected table and regenerate the tests:
|
||||
-- print(require('pl.pretty').dump(m))
|
||||
local expected = {
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "insert",
|
||||
silent = 0
|
||||
},
|
||||
s = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "x",
|
||||
silent = 0
|
||||
},
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "inormal<Esc>",
|
||||
silent = 0
|
||||
},
|
||||
v = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "x",
|
||||
silent = 0
|
||||
},
|
||||
c = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "cmdmode",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
name = "Nested",
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
o = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level1",
|
||||
silent = 0
|
||||
},
|
||||
v = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level1",
|
||||
silent = 0
|
||||
},
|
||||
s = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level1",
|
||||
silent = 0
|
||||
},
|
||||
n = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level1",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "test",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
mappings = {
|
||||
o = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level2",
|
||||
silent = 0
|
||||
},
|
||||
v = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level2",
|
||||
silent = 0
|
||||
},
|
||||
s = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level2",
|
||||
silent = 0
|
||||
},
|
||||
n = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "level2",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Nested2",
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
name = "Export",
|
||||
submenus = {
|
||||
{
|
||||
tooltip = "This is the tooltip",
|
||||
hidden = 0,
|
||||
name = "Script",
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "p",
|
||||
silent = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
name = "Edit",
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
c = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "<C-R>\"",
|
||||
silent = 0
|
||||
},
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "p",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Paste",
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
name = "]Export",
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
o = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "thisoneshouldbehidden",
|
||||
silent = 0
|
||||
},
|
||||
v = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "thisoneshouldbehidden",
|
||||
silent = 0
|
||||
},
|
||||
s = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "thisoneshouldbehidden",
|
||||
silent = 0
|
||||
},
|
||||
n = {
|
||||
sid = 0,
|
||||
noremap = 0,
|
||||
enabled = 1,
|
||||
rhs = "thisoneshouldbehidden",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "hidden",
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
hidden = 1
|
||||
}
|
||||
}
|
||||
eq(expected, m)
|
||||
end)
|
||||
|
||||
it('matching path, default modes', function()
|
||||
local m = funcs.menu_get("Export", "a")
|
||||
local expected = {
|
||||
{
|
||||
tooltip = "This is the tooltip",
|
||||
hidden = 0,
|
||||
name = "Script",
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "p",
|
||||
silent = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eq(expected, m)
|
||||
end)
|
||||
|
||||
it('no path, matching modes', function()
|
||||
local m = funcs.menu_get("","i")
|
||||
local expected = {
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "insert",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
}
|
||||
}
|
||||
eq(expected, m)
|
||||
end)
|
||||
|
||||
it('matching path and modes', function()
|
||||
local m = funcs.menu_get("Test","i")
|
||||
local expected = {
|
||||
{
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "insert",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test",
|
||||
hidden = 0
|
||||
}
|
||||
}
|
||||
eq(expected, m)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('menu_get', function()
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
end)
|
||||
|
||||
it('returns <keycode> representation of special keys', function()
|
||||
command('nnoremenu &Test.Test inormal<ESC>')
|
||||
command('inoremenu &Test.Test2 <Tab><Esc>')
|
||||
command('vnoremenu &Test.Test3 yA<C-R>0<Tab>xyz<Esc>')
|
||||
command('inoremenu &Test.Test4 <c-r>*')
|
||||
command('inoremenu &Test.Test5 <c-R>+')
|
||||
command('nnoremenu &Test.Test6 <Nop>')
|
||||
command('nnoremenu &Test.Test7 <NOP>')
|
||||
command('nnoremenu &Test.Test8 <NoP>')
|
||||
command('nnoremenu &Test.Test9 ""')
|
||||
|
||||
local m = funcs.menu_get("");
|
||||
local expected = {
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
submenus = {
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "inormal<Esc>",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "<Tab><Esc>",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test2",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
s = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "yA<C-R>0<Tab>xyz<Esc>",
|
||||
silent = 0
|
||||
},
|
||||
v = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "yA<C-R>0<Tab>xyz<Esc>",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test3",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "<C-R>*",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test4",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
i = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "<C-R>+",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test5",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test6",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test7",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test8",
|
||||
hidden = 0
|
||||
},
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "\"\"",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test9",
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
}
|
||||
}
|
||||
|
||||
eq(m, expected)
|
||||
end)
|
||||
|
||||
it('works with right-aligned text and spaces', function()
|
||||
command('nnoremenu &Test<Tab>Y.Test<Tab>X\\ x inormal<Alt-j>')
|
||||
command('nnoremenu &Test\\ 1.Test\\ 2 Wargl')
|
||||
command('nnoremenu &Test4.Test<Tab>3 i space<Esc>')
|
||||
|
||||
local m = funcs.menu_get("");
|
||||
local expected = {
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
actext = "Y",
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "inormal<Alt-j>",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
hidden = 0,
|
||||
actext = "X x",
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
},
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
submenus = {
|
||||
{
|
||||
priority = 500,
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "Wargl",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
name = "Test 2",
|
||||
hidden = 0
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test 1"
|
||||
},
|
||||
{
|
||||
shortcut = "T",
|
||||
hidden = 0,
|
||||
submenus = {
|
||||
{
|
||||
mappings = {
|
||||
n = {
|
||||
sid = 1,
|
||||
noremap = 1,
|
||||
enabled = 1,
|
||||
rhs = "i space<Esc>",
|
||||
silent = 0
|
||||
}
|
||||
},
|
||||
hidden = 0,
|
||||
actext = "3",
|
||||
priority = 500,
|
||||
name = "Test"
|
||||
}
|
||||
},
|
||||
priority = 500,
|
||||
name = "Test4"
|
||||
}
|
||||
}
|
||||
|
||||
eq(m, expected)
|
||||
end)
|
||||
end)
|
||||
|
49
test/functional/ex_cmds/mksession_spec.lua
Normal file
49
test/functional/ex_cmds/mksession_spec.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
local lfs = require('lfs')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
|
||||
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
|
||||
|
||||
describe(':mksession', function()
|
||||
local session_file = file_prefix .. '.vim'
|
||||
local tab_dir = file_prefix .. '.d'
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
lfs.mkdir(tab_dir)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
os.remove(session_file)
|
||||
lfs.rmdir(tab_dir)
|
||||
end)
|
||||
|
||||
it('restores tab-local working directories', function()
|
||||
local tmpfile_base = file_prefix .. '-tmpfile'
|
||||
local cwd_dir = funcs.getcwd()
|
||||
|
||||
-- :mksession does not save empty tabs, so create some buffers.
|
||||
command('edit ' .. tmpfile_base .. '1')
|
||||
command('tabnew')
|
||||
command('edit ' .. tmpfile_base .. '2')
|
||||
command('tcd ' .. tab_dir)
|
||||
command('tabfirst')
|
||||
command('mksession ' .. session_file)
|
||||
|
||||
-- Create a new test instance of Nvim.
|
||||
clear()
|
||||
|
||||
command('source ' .. session_file)
|
||||
-- First tab should have the original working directory.
|
||||
command('tabnext 1')
|
||||
eq(cwd_dir, funcs.getcwd())
|
||||
-- Second tab should have the tab-local working directory.
|
||||
command('tabnext 2')
|
||||
eq(cwd_dir .. get_pathsep() .. tab_dir, funcs.getcwd())
|
||||
end)
|
||||
end)
|
67
test/functional/ex_cmds/mkview_spec.lua
Normal file
67
test/functional/ex_cmds/mkview_spec.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
local lfs = require('lfs')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local command = helpers.command
|
||||
local get_pathsep = helpers.get_pathsep
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
local rmdir = helpers.rmdir
|
||||
|
||||
local file_prefix = 'Xtest-functional-ex_cmds-mkview_spec'
|
||||
|
||||
describe(':mkview', function()
|
||||
local tmp_file_base = file_prefix .. '-tmpfile'
|
||||
local local_dir = file_prefix .. '.d'
|
||||
local view_dir = file_prefix .. '.view.d'
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
lfs.mkdir(view_dir)
|
||||
lfs.mkdir(local_dir)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
-- Remove any views created in the view directory
|
||||
rmdir(view_dir)
|
||||
lfs.rmdir(local_dir)
|
||||
end)
|
||||
|
||||
it('viewoption curdir restores local current directory', function()
|
||||
local cwd_dir = funcs.getcwd()
|
||||
local set_view_dir_command = 'set viewdir=' .. cwd_dir ..
|
||||
get_pathsep() .. view_dir
|
||||
|
||||
-- By default the local current directory should save
|
||||
command(set_view_dir_command)
|
||||
command('edit ' .. tmp_file_base .. '1')
|
||||
command('lcd ' .. local_dir)
|
||||
command('mkview')
|
||||
|
||||
-- Create a new instance of Nvim to remove the 'lcd'
|
||||
clear()
|
||||
|
||||
-- Disable saving the local current directory for the second view
|
||||
command(set_view_dir_command)
|
||||
command('set viewoptions-=curdir')
|
||||
command('edit ' .. tmp_file_base .. '2')
|
||||
command('lcd ' .. local_dir)
|
||||
command('mkview')
|
||||
|
||||
-- Create a new instance of Nvim to test saved 'lcd' option
|
||||
clear()
|
||||
command(set_view_dir_command)
|
||||
|
||||
-- Load the view without a saved local current directory
|
||||
command('edit ' .. tmp_file_base .. '2')
|
||||
command('loadview')
|
||||
-- The view's current directory should not have changed
|
||||
eq(cwd_dir, funcs.getcwd())
|
||||
-- Load the view with a saved local current directory
|
||||
command('edit ' .. tmp_file_base .. '1')
|
||||
command('loadview')
|
||||
-- The view's local directory should have been saved
|
||||
eq(cwd_dir .. get_pathsep() .. local_dir, funcs.getcwd())
|
||||
end)
|
||||
|
||||
end)
|
@@ -1,16 +1,18 @@
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local buf, eq, execute = helpers.curbufmeths, helpers.eq, helpers.execute
|
||||
local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command
|
||||
local feed, nvim_prog, wait = helpers.feed, helpers.nvim_prog, helpers.wait
|
||||
local ok, set_session, spawn = helpers.ok, helpers.set_session, helpers.spawn
|
||||
local eval = helpers.eval
|
||||
|
||||
local shada_file = 'test.shada'
|
||||
local shada_file = 'Xtest.shada'
|
||||
|
||||
local function _clear()
|
||||
set_session(spawn({nvim_prog, '--embed', '-u', 'NONE', '--cmd',
|
||||
set_session(spawn({nvim_prog, '--embed', '-u', 'NONE',
|
||||
-- Need shada for these tests.
|
||||
'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
|
||||
'-i', shada_file,
|
||||
'--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
|
||||
end
|
||||
|
||||
describe(':oldfiles', function()
|
||||
@@ -27,12 +29,12 @@ describe(':oldfiles', function()
|
||||
it('shows most recently used files', function()
|
||||
local screen = Screen.new(100, 5)
|
||||
screen:attach()
|
||||
execute('edit testfile1')
|
||||
execute('edit testfile2')
|
||||
execute('wshada ' .. shada_file)
|
||||
execute('rshada! ' .. shada_file)
|
||||
feed_command('edit testfile1')
|
||||
feed_command('edit testfile2')
|
||||
feed_command('wshada')
|
||||
feed_command('rshada!')
|
||||
local oldfiles = helpers.meths.get_vvar('oldfiles')
|
||||
execute('oldfiles')
|
||||
feed_command('oldfiles')
|
||||
screen:expect([[
|
||||
testfile2 |
|
||||
1: ]].. add_padding(oldfiles[1]) ..[[ |
|
||||
@@ -41,6 +43,38 @@ describe(':oldfiles', function()
|
||||
Press ENTER or type command to continue^ |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('can be filtered with :filter', function()
|
||||
feed_command('edit file_one.txt')
|
||||
local file1 = buf.get_name()
|
||||
feed_command('edit file_two.txt')
|
||||
local file2 = buf.get_name()
|
||||
feed_command('edit another.txt')
|
||||
local another = buf.get_name()
|
||||
feed_command('wshada')
|
||||
feed_command('rshada!')
|
||||
|
||||
local function get_oldfiles(cmd)
|
||||
local t = eval([[split(execute(']]..cmd..[['), "\n")]])
|
||||
for i, _ in ipairs(t) do
|
||||
t[i] = t[i]:gsub('^%d+:%s+', '')
|
||||
end
|
||||
table.sort(t)
|
||||
return t
|
||||
end
|
||||
|
||||
local oldfiles = get_oldfiles('oldfiles')
|
||||
eq({another, file1, file2}, oldfiles)
|
||||
|
||||
oldfiles = get_oldfiles('filter file_ oldfiles')
|
||||
eq({file1, file2}, oldfiles)
|
||||
|
||||
oldfiles = get_oldfiles('filter /another/ oldfiles')
|
||||
eq({another}, oldfiles)
|
||||
|
||||
oldfiles = get_oldfiles('filter! file_ oldfiles')
|
||||
eq({another}, oldfiles)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe(':browse oldfiles', function()
|
||||
@@ -50,14 +84,13 @@ describe(':browse oldfiles', function()
|
||||
|
||||
before_each(function()
|
||||
_clear()
|
||||
execute('edit testfile1')
|
||||
feed_command('edit testfile1')
|
||||
filename = buf.get_name()
|
||||
execute('edit testfile2')
|
||||
feed_command('edit testfile2')
|
||||
filename2 = buf.get_name()
|
||||
execute('wshada ' .. shada_file)
|
||||
feed_command('wshada')
|
||||
wait()
|
||||
_clear()
|
||||
execute('rshada! ' .. shada_file)
|
||||
|
||||
-- Ensure nvim is out of "Press ENTER..." prompt.
|
||||
feed('<cr>')
|
||||
@@ -70,7 +103,7 @@ describe(':browse oldfiles', function()
|
||||
ok(filename == oldfiles[1] or filename == oldfiles[2])
|
||||
ok(filename2 == oldfiles[1] or filename2 == oldfiles[2])
|
||||
|
||||
execute('browse oldfiles')
|
||||
feed_command('browse oldfiles')
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
|
12
test/functional/ex_cmds/print_commands_spec.lua
Normal file
12
test/functional/ex_cmds/print_commands_spec.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, eq, command, funcs =
|
||||
helpers.clear, helpers.eq, helpers.command, helpers.funcs
|
||||
|
||||
describe(':z^', function()
|
||||
before_each(clear)
|
||||
|
||||
it('correctly sets the cursor after :z^', function()
|
||||
command('z^')
|
||||
eq(1, funcs.line('.'))
|
||||
end)
|
||||
end)
|
111
test/functional/ex_cmds/quickfix_commands_spec.lua
Normal file
111
test/functional/ex_cmds/quickfix_commands_spec.lua
Normal file
@@ -0,0 +1,111 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local clear = helpers.clear
|
||||
local funcs = helpers.funcs
|
||||
local command = helpers.command
|
||||
local exc_exec = helpers.exc_exec
|
||||
local write_file = helpers.write_file
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
local source = helpers.source
|
||||
|
||||
local file_base = 'Xtest-functional-ex_cmds-quickfix_commands'
|
||||
|
||||
before_each(clear)
|
||||
|
||||
for _, c in ipairs({'l', 'c'}) do
|
||||
local file = ('%s.%s'):format(file_base, c)
|
||||
local filecmd = c .. 'file'
|
||||
local getfcmd = c .. 'getfile'
|
||||
local addfcmd = c .. 'addfile'
|
||||
local getlist = (c == 'c') and funcs.getqflist or (
|
||||
function() return funcs.getloclist(0) end)
|
||||
|
||||
describe((':%s*file commands'):format(c), function()
|
||||
before_each(function()
|
||||
write_file(file, ([[
|
||||
%s-1.res:700:10:Line 700
|
||||
%s-2.res:800:15:Line 800
|
||||
]]):format(file, file))
|
||||
end)
|
||||
after_each(function()
|
||||
os.remove(file)
|
||||
end)
|
||||
|
||||
it('work', function()
|
||||
command(('%s %s'):format(filecmd, file))
|
||||
-- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual
|
||||
-- results. First line (i.e. `{lnum=…`) was obtained from legacy test.
|
||||
local list = {
|
||||
{lnum=700, col=10, text='Line 700',
|
||||
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
|
||||
{lnum=800, col=15, text='Line 800',
|
||||
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
|
||||
}
|
||||
eq(list, getlist())
|
||||
eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
|
||||
eq(('%s-2.res'):format(file), funcs.bufname(list[2].bufnr))
|
||||
|
||||
-- Run cfile/lfile from a modified buffer
|
||||
command('enew!')
|
||||
curbufmeths.set_lines(1, 1, true, {'Quickfix'})
|
||||
eq(('Vim(%s):E37: No write since last change (add ! to override)'):format(
|
||||
filecmd),
|
||||
exc_exec(('%s %s'):format(filecmd, file)))
|
||||
|
||||
write_file(file, ([[
|
||||
%s-3.res:900:30:Line 900
|
||||
]]):format(file))
|
||||
command(('%s %s'):format(addfcmd, file))
|
||||
list[#list + 1] = {
|
||||
lnum=900, col=30, text='Line 900',
|
||||
nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='',
|
||||
}
|
||||
eq(list, getlist())
|
||||
eq(('%s-3.res'):format(file), funcs.bufname(list[3].bufnr))
|
||||
|
||||
write_file(file, ([[
|
||||
%s-1.res:222:77:Line 222
|
||||
%s-2.res:333:88:Line 333
|
||||
]]):format(file, file))
|
||||
command('enew!')
|
||||
command(('%s %s'):format(getfcmd, file))
|
||||
list = {
|
||||
{lnum=222, col=77, text='Line 222',
|
||||
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
|
||||
{lnum=333, col=88, text='Line 333',
|
||||
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
|
||||
}
|
||||
eq(list, getlist())
|
||||
eq(('%s-1.res'):format(file), funcs.bufname(list[1].bufnr))
|
||||
eq(('%s-2.res'):format(file), funcs.bufname(list[2].bufnr))
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
describe('quickfix', function()
|
||||
it('location-list update on buffer modification', function()
|
||||
source([[
|
||||
new
|
||||
setl bt=nofile
|
||||
let lines = ['Line 1', 'Line 2', 'Line 3', 'Line 4', 'Line 5']
|
||||
call append(0, lines)
|
||||
new
|
||||
setl bt=nofile
|
||||
call append(0, lines)
|
||||
let qf_item = {
|
||||
\ 'lnum': 4,
|
||||
\ 'text': "This is the error line.",
|
||||
\ }
|
||||
let qf_item['bufnr'] = bufnr('%')
|
||||
call setloclist(0, [qf_item])
|
||||
wincmd p
|
||||
let qf_item['bufnr'] = bufnr('%')
|
||||
call setloclist(0, [qf_item])
|
||||
1del _
|
||||
call append(0, ['New line 1', 'New line 2', 'New line 3'])
|
||||
silent ll
|
||||
]])
|
||||
eq({0, 6, 1, 0, 1}, funcs.getcurpos())
|
||||
end)
|
||||
end)
|
@@ -1,19 +1,18 @@
|
||||
-- Tests for :recover
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local execute, eq, clear, eval, feed, expect, source =
|
||||
helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
|
||||
local feed_command, eq, clear, eval, feed, expect, source =
|
||||
helpers.feed_command, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
|
||||
helpers.expect, helpers.source
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
local command = helpers.command
|
||||
local ok = helpers.ok
|
||||
local rmdir = helpers.rmdir
|
||||
|
||||
describe(':recover', function()
|
||||
before_each(clear)
|
||||
|
||||
it('fails if given a non-existent swapfile', function()
|
||||
local swapname = 'bogus-swapfile'
|
||||
execute('recover '..swapname) -- This should not segfault. #2117
|
||||
feed_command('recover '..swapname) -- This should not segfault. #2117
|
||||
eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
|
||||
end)
|
||||
|
||||
@@ -23,30 +22,29 @@ describe(':preserve', function()
|
||||
local swapdir = lfs.currentdir()..'/testdir_recover_spec'
|
||||
before_each(function()
|
||||
clear()
|
||||
helpers.rmdir(swapdir)
|
||||
rmdir(swapdir)
|
||||
lfs.mkdir(swapdir)
|
||||
end)
|
||||
after_each(function()
|
||||
helpers.rmdir(swapdir)
|
||||
command('%bwipeout!')
|
||||
rmdir(swapdir)
|
||||
end)
|
||||
|
||||
it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
|
||||
local testfile = 'testfile_recover_spec'
|
||||
-- Put swapdir at the start of the 'directory' list. #1836
|
||||
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may
|
||||
-- attempt to create a swapfile in different directory.
|
||||
local init = [[
|
||||
set directory^=]]..swapdir..[[//
|
||||
set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
|
||||
set swapfile fileformat=unix undolevels=-1
|
||||
]]
|
||||
|
||||
source(init)
|
||||
execute('set swapfile fileformat=unix undolevels=-1')
|
||||
-- Put swapdir at the start of the 'directory' list. #1836
|
||||
execute('set directory^='..swapdir..'//')
|
||||
execute('edit '..testfile)
|
||||
command('edit! '..testfile)
|
||||
feed('isometext<esc>')
|
||||
execute('preserve')
|
||||
source('redir => g:swapname | swapname | redir END')
|
||||
command('preserve')
|
||||
source('redir => g:swapname | silent swapname | redir END')
|
||||
|
||||
local swappath1 = eval('g:swapname')
|
||||
|
||||
@@ -59,19 +57,20 @@ describe(':preserve', function()
|
||||
source(init)
|
||||
|
||||
-- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
|
||||
execute('autocmd SwapExists * let v:swapchoice = "r"')
|
||||
execute('silent edit '..testfile)
|
||||
source('redir => g:swapname | swapname | redir END')
|
||||
command('autocmd SwapExists * let v:swapchoice = "r"')
|
||||
command('silent edit! '..testfile)
|
||||
source('redir => g:swapname | silent swapname | redir END')
|
||||
|
||||
local swappath2 = eval('g:swapname')
|
||||
|
||||
-- swapfile from session 1 should end in .swp
|
||||
assert(testfile..'.swp' == string.match(swappath1, '[^%%]+$'))
|
||||
|
||||
-- swapfile from session 2 should end in .swo
|
||||
assert(testfile..'.swo' == string.match(swappath2, '[^%%]+$'))
|
||||
|
||||
expect('sometext')
|
||||
-- swapfile from session 1 should end in .swp
|
||||
eq(testfile..'.swp', string.match(swappath1, '[^%%]+$'))
|
||||
-- swapfile from session 2 should end in .swo
|
||||
eq(testfile..'.swo', string.match(swappath2, '[^%%]+$'))
|
||||
-- Verify that :swapname was not truncated (:help 'shortmess').
|
||||
ok(nil == string.find(swappath1, '%.%.%.'))
|
||||
ok(nil == string.find(swappath2, '%.%.%.'))
|
||||
end)
|
||||
|
||||
end)
|
||||
|
75
test/functional/ex_cmds/script_spec.lua
Normal file
75
test/functional/ex_cmds/script_spec.lua
Normal file
@@ -0,0 +1,75 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
local meths = helpers.meths
|
||||
local clear = helpers.clear
|
||||
local dedent = helpers.dedent
|
||||
local source = helpers.source
|
||||
local exc_exec = helpers.exc_exec
|
||||
local missing_provider = helpers.missing_provider
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('script_get-based command', function()
|
||||
local garbage = ')}{+*({}]*[;(+}{&[]}{*])('
|
||||
|
||||
local function test_garbage_exec(cmd, check_neq)
|
||||
describe(cmd, function()
|
||||
it('works correctly when skipping oneline variant', function()
|
||||
eq(true, pcall(source, (dedent([[
|
||||
if 0
|
||||
%s %s
|
||||
endif
|
||||
]])):format(cmd, garbage)))
|
||||
eq('', meths.command_output('messages'))
|
||||
if check_neq then
|
||||
neq(0, exc_exec(dedent([[
|
||||
%s %s
|
||||
]])):format(cmd, garbage))
|
||||
end
|
||||
end)
|
||||
it('works correctly when skipping HEREdoc variant', function()
|
||||
eq(true, pcall(source, (dedent([[
|
||||
if 0
|
||||
%s << EOF
|
||||
%s
|
||||
EOF
|
||||
endif
|
||||
]])):format(cmd, garbage)))
|
||||
eq('', meths.command_output('messages'))
|
||||
if check_neq then
|
||||
eq(true, pcall(source, (dedent([[
|
||||
let g:exc = 0
|
||||
try
|
||||
%s << EOF
|
||||
%s
|
||||
EOF
|
||||
catch
|
||||
let g:exc = v:exception
|
||||
endtry
|
||||
]])):format(cmd, garbage)))
|
||||
neq(0, meths.get_var('exc'))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
clear()
|
||||
|
||||
-- Built-in scripts
|
||||
test_garbage_exec('lua', true)
|
||||
|
||||
-- Provider-based scripts
|
||||
test_garbage_exec('ruby', not missing_provider('ruby'))
|
||||
test_garbage_exec('python', not missing_provider('python'))
|
||||
test_garbage_exec('python3', not missing_provider('python3'))
|
||||
|
||||
-- Missing scripts
|
||||
test_garbage_exec('tcl', false)
|
||||
test_garbage_exec('mzscheme', false)
|
||||
test_garbage_exec('perl', false)
|
||||
|
||||
-- Not really a script
|
||||
test_garbage_exec('xxxinvalidlanguagexxx', true)
|
||||
end)
|
17
test/functional/ex_cmds/syntax_spec.lua
Normal file
17
test/functional/ex_cmds/syntax_spec.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local eq = helpers.eq
|
||||
local clear = helpers.clear
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
describe(':syntax', function()
|
||||
before_each(clear)
|
||||
|
||||
describe('keyword', function()
|
||||
it('does not crash when group name contains unprintable characters',
|
||||
function()
|
||||
eq('Vim(syntax):E669: Unprintable character in group name',
|
||||
exc_exec('syntax keyword \024 foo bar'))
|
||||
end)
|
||||
end)
|
||||
end)
|
@@ -5,7 +5,7 @@ local clear = helpers.clear
|
||||
local insert = helpers.insert
|
||||
local feed = helpers.feed
|
||||
local expect = helpers.expect
|
||||
local execute = helpers.execute
|
||||
local feed_command = helpers.feed_command
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
describe(':undojoin command', function()
|
||||
@@ -14,10 +14,10 @@ describe(':undojoin command', function()
|
||||
insert([[
|
||||
Line of text 1
|
||||
Line of text 2]])
|
||||
execute('goto 1')
|
||||
feed_command('goto 1')
|
||||
end)
|
||||
it('joins changes in a buffer', function()
|
||||
execute('undojoin | delete')
|
||||
feed_command('undojoin | delete')
|
||||
expect([[
|
||||
Line of text 2]])
|
||||
feed('u')
|
||||
@@ -26,7 +26,7 @@ describe(':undojoin command', function()
|
||||
end)
|
||||
it('does not corrupt undolist when connected with redo', function()
|
||||
feed('ixx<esc>')
|
||||
execute('undojoin | redo')
|
||||
feed_command('undojoin | redo')
|
||||
expect([[
|
||||
xxLine of text 1
|
||||
Line of text 2]])
|
||||
|
@@ -1,15 +1,29 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq, eval, clear, write_file, execute, source, insert =
|
||||
local lfs = require('lfs')
|
||||
local eq, eval, clear, write_file, source, insert =
|
||||
helpers.eq, helpers.eval, helpers.clear, helpers.write_file,
|
||||
helpers.execute, helpers.source, helpers.insert
|
||||
helpers.source, helpers.insert
|
||||
local redir_exec = helpers.redir_exec
|
||||
local exc_exec = helpers.exc_exec
|
||||
local command = helpers.command
|
||||
local feed_command = helpers.feed_command
|
||||
local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
|
||||
local fname = 'Xtest-functional-ex_cmds-write'
|
||||
local fname_bak = fname .. '~'
|
||||
local fname_broken = fname_bak .. 'broken'
|
||||
|
||||
describe(':write', function()
|
||||
local function cleanup()
|
||||
os.remove('test_bkc_file.txt')
|
||||
os.remove('test_bkc_link.txt')
|
||||
os.remove('test_fifo')
|
||||
os.remove(fname)
|
||||
os.remove(fname_bak)
|
||||
os.remove(fname_broken)
|
||||
end
|
||||
before_each(function()
|
||||
clear()
|
||||
@@ -20,9 +34,9 @@ describe(':write', function()
|
||||
end)
|
||||
|
||||
it('&backupcopy=auto preserves symlinks', function()
|
||||
execute('set backupcopy=auto')
|
||||
command('set backupcopy=auto')
|
||||
write_file('test_bkc_file.txt', 'content0')
|
||||
execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
|
||||
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
|
||||
source([[
|
||||
edit test_bkc_link.txt
|
||||
call setline(1, ['content1'])
|
||||
@@ -33,9 +47,9 @@ describe(':write', function()
|
||||
end)
|
||||
|
||||
it('&backupcopy=no replaces symlink with new file', function()
|
||||
execute('set backupcopy=no')
|
||||
command('set backupcopy=no')
|
||||
write_file('test_bkc_file.txt', 'content0')
|
||||
execute("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
|
||||
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
|
||||
source([[
|
||||
edit test_bkc_link.txt
|
||||
call setline(1, ['content1'])
|
||||
@@ -56,11 +70,41 @@ describe(':write', function()
|
||||
insert(text)
|
||||
|
||||
-- Blocks until a consumer reads the FIFO.
|
||||
execute("write >> test_fifo")
|
||||
feed_command("write >> test_fifo")
|
||||
|
||||
-- Read the FIFO, this will unblock the :write above.
|
||||
local fifo = assert(io.open("test_fifo"))
|
||||
eq(text.."\n", fifo:read("*all"))
|
||||
fifo:close()
|
||||
end)
|
||||
|
||||
it('errors out correctly', function()
|
||||
command('let $HOME=""')
|
||||
eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~'))
|
||||
-- Message from check_overwrite
|
||||
eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
|
||||
redir_exec('write .'))
|
||||
meths.set_option('writeany', true)
|
||||
-- Message from buf_write
|
||||
eq(('\nE502: "." is a directory'),
|
||||
redir_exec('write .'))
|
||||
funcs.mkdir(fname_bak)
|
||||
meths.set_option('backupdir', '.')
|
||||
meths.set_option('backup', true)
|
||||
write_file(fname, 'content0')
|
||||
eq(0, exc_exec('edit ' .. fname))
|
||||
funcs.setline(1, 'TTY')
|
||||
eq('Vim(write):E510: Can\'t make backup file (add ! to override)',
|
||||
exc_exec('write'))
|
||||
meths.set_option('backup', false)
|
||||
funcs.setfperm(fname, 'r--------')
|
||||
eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
|
||||
exc_exec('write'))
|
||||
os.remove(fname)
|
||||
os.remove(fname_bak)
|
||||
write_file(fname_bak, 'TTYX')
|
||||
lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true)
|
||||
eq('Vim(write):E166: Can\'t open linked file for writing',
|
||||
exc_exec('write!'))
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,20 +1,21 @@
|
||||
-- Specs for :wundo and underlying functions
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local execute, clear, eval, feed, spawn, nvim_prog, set_session =
|
||||
helpers.execute, helpers.clear, helpers.eval, helpers.feed, helpers.spawn,
|
||||
local command, clear, eval, spawn, nvim_prog, set_session =
|
||||
helpers.command, helpers.clear, helpers.eval, helpers.spawn,
|
||||
helpers.nvim_prog, helpers.set_session
|
||||
|
||||
|
||||
describe(':wundo', function()
|
||||
before_each(clear)
|
||||
after_each(function()
|
||||
os.remove(eval('getcwd()') .. '/foo')
|
||||
end)
|
||||
|
||||
it('safely fails on new, non-empty buffer', function()
|
||||
feed('iabc<esc>')
|
||||
execute('wundo foo') -- This should not segfault. #1027
|
||||
command('normal! iabc')
|
||||
command('wundo foo') -- This should not segfault. #1027
|
||||
--TODO: check messages for error message
|
||||
|
||||
os.remove(eval('getcwd()') .. '/foo') --cleanup
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -23,7 +24,7 @@ describe('u_* functions', function()
|
||||
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
|
||||
'-c', 'set undodir=. undofile'})
|
||||
set_session(session)
|
||||
execute('echo "True"') -- Should not error out due to crashed Neovim
|
||||
command('echo "True"') -- Should not error out due to crashed Neovim
|
||||
session:close()
|
||||
end)
|
||||
end)
|
||||
|
@@ -1,8 +1,8 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local execute, eq, neq, spawn, nvim_prog, set_session, wait, write_file
|
||||
= helpers.execute, helpers.eq, helpers.neq, helpers.spawn,
|
||||
helpers.nvim_prog, helpers.set_session, helpers.wait, helpers.write_file
|
||||
local command, eq, neq, spawn, nvim_prog, set_session, write_file =
|
||||
helpers.command, helpers.eq, helpers.neq, helpers.spawn,
|
||||
helpers.nvim_prog, helpers.set_session, helpers.write_file
|
||||
|
||||
describe(':wshada', function()
|
||||
local shada_file = 'wshada_test'
|
||||
@@ -24,8 +24,7 @@ describe(':wshada', function()
|
||||
it('creates a shada file', function()
|
||||
-- file should _not_ exist
|
||||
eq(nil, lfs.attributes(shada_file))
|
||||
execute('wsh! '..shada_file)
|
||||
wait()
|
||||
command('wsh! '..shada_file)
|
||||
-- file _should_ exist
|
||||
neq(nil, lfs.attributes(shada_file))
|
||||
end)
|
||||
@@ -40,8 +39,7 @@ describe(':wshada', function()
|
||||
eq(text, io.open(shada_file):read())
|
||||
neq(nil, lfs.attributes(shada_file))
|
||||
|
||||
execute('wsh! '..shada_file)
|
||||
wait()
|
||||
command('wsh! '..shada_file)
|
||||
|
||||
-- File should have been overwritten with a shada file.
|
||||
local fp = io.open(shada_file, 'r')
|
||||
|
BIN
test/functional/fixtures/api_level_2.mpack
Normal file
BIN
test/functional/fixtures/api_level_2.mpack
Normal file
Binary file not shown.
BIN
test/functional/fixtures/api_level_3.mpack
Normal file
BIN
test/functional/fixtures/api_level_3.mpack
Normal file
Binary file not shown.
@@ -5,7 +5,13 @@ let s:methods = {}
|
||||
let g:cliplossy = 0
|
||||
let g:cliperror = 0
|
||||
|
||||
" Count how many times the clipboard was invoked.
|
||||
let g:clip_called_get = 0
|
||||
let g:clip_called_set = 0
|
||||
|
||||
function! s:methods.get(reg)
|
||||
let g:clip_called_get += 1
|
||||
|
||||
if g:cliperror
|
||||
return 0
|
||||
end
|
||||
@@ -19,6 +25,8 @@ function! s:methods.get(reg)
|
||||
endfunction
|
||||
|
||||
function! s:methods.set(lines, regtype, reg)
|
||||
let g:clip_called_set += 1
|
||||
|
||||
if a:reg == '"'
|
||||
call s:methods.set(a:lines,a:regtype,'+')
|
||||
call s:methods.set(a:lines,a:regtype,'*')
|
||||
|
593
test/functional/fixtures/bigfile_oneline.txt
Normal file
593
test/functional/fixtures/bigfile_oneline.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -1,3 +1,6 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
@@ -1,40 +1,49 @@
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <uv.h>
|
||||
|
||||
uv_tty_t tty;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
bool owns_tty(void)
|
||||
{
|
||||
HWND consoleWnd = GetConsoleWindow();
|
||||
DWORD dwProcessId;
|
||||
GetWindowThreadProcessId(consoleWnd, &dwProcessId);
|
||||
return GetCurrentProcessId() == dwProcessId;
|
||||
}
|
||||
# include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
bool owns_tty(void)
|
||||
{
|
||||
return getsid(0) == getpid();
|
||||
}
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// -V:STRUCT_CAST:641
|
||||
#define STRUCT_CAST(Type, obj) ((Type *)(obj))
|
||||
#define is_terminal(stream) (uv_guess_handle(fileno(stream)) == UV_TTY)
|
||||
#define BUF_SIZE 0xfff
|
||||
#define CTRL_C 0x03
|
||||
|
||||
static void walk_cb(uv_handle_t *handle, void *arg) {
|
||||
uv_tty_t tty;
|
||||
uv_tty_t tty_out;
|
||||
|
||||
bool owns_tty(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// XXX: We need to make proper detect owns tty
|
||||
// HWND consoleWnd = GetConsoleWindow();
|
||||
// DWORD dwProcessId;
|
||||
// GetWindowThreadProcessId(consoleWnd, &dwProcessId);
|
||||
// return GetCurrentProcessId() == dwProcessId;
|
||||
return true;
|
||||
#else
|
||||
return getsid(0) == getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void walk_cb(uv_handle_t *handle, void *arg)
|
||||
{
|
||||
if (!uv_is_closing(handle)) {
|
||||
uv_close(handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
static void sig_handler(int signum)
|
||||
{
|
||||
switch(signum) {
|
||||
switch (signum) {
|
||||
case SIGWINCH: {
|
||||
int width, height;
|
||||
uv_tty_get_winsize(&tty, &width, &height);
|
||||
@@ -48,15 +57,15 @@ static void sig_handler(int signum)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// static void sigwinch_cb(uv_signal_t *handle, int signum)
|
||||
// {
|
||||
// int width, height;
|
||||
// uv_tty_t *tty = handle->data;
|
||||
// uv_tty_get_winsize(tty, &width, &height);
|
||||
// fprintf(stderr, "rows: %d, cols: %d\n", height, width);
|
||||
// }
|
||||
#ifdef WIN32
|
||||
static void sigwinch_cb(uv_signal_t *handle, int signum)
|
||||
{
|
||||
int width, height;
|
||||
uv_tty_get_winsize(&tty_out, &width, &height);
|
||||
fprintf(stderr, "rows: %d, cols: %d\n", height, width);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
|
||||
{
|
||||
@@ -74,7 +83,7 @@ static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
|
||||
int *interrupted = stream->data;
|
||||
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (buf->base[i] == 3) {
|
||||
if (buf->base[i] == CTRL_C) {
|
||||
(*interrupted)++;
|
||||
}
|
||||
}
|
||||
@@ -82,12 +91,14 @@ static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
|
||||
uv_loop_t write_loop;
|
||||
uv_loop_init(&write_loop);
|
||||
uv_tty_t out;
|
||||
uv_tty_init(&write_loop, &out, 1, 0);
|
||||
uv_tty_init(&write_loop, &out, fileno(stdout), 0);
|
||||
|
||||
uv_write_t req;
|
||||
uv_buf_t b = {.base = buf->base, .len = (size_t)cnt};
|
||||
uv_write(&req, (uv_stream_t *)&out, &b, 1, NULL);
|
||||
uv_write(&req, STRUCT_CAST(uv_stream_t, &out), &b, 1, NULL);
|
||||
uv_run(&write_loop, UV_RUN_DEFAULT);
|
||||
uv_close((uv_handle_t *)&out, NULL);
|
||||
|
||||
uv_close(STRUCT_CAST(uv_handle_t, &out), NULL);
|
||||
uv_run(&write_loop, UV_RUN_DEFAULT);
|
||||
if (uv_loop_close(&write_loop)) {
|
||||
abort();
|
||||
@@ -131,7 +142,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (argc > 1) {
|
||||
int count = atoi(argv[1]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
printf("line%d\n", i);
|
||||
}
|
||||
fflush(stdout);
|
||||
@@ -142,11 +153,17 @@ int main(int argc, char **argv)
|
||||
uv_prepare_t prepare;
|
||||
uv_prepare_init(uv_default_loop(), &prepare);
|
||||
uv_prepare_start(&prepare, prepare_cb);
|
||||
// uv_tty_t tty;
|
||||
#ifndef WIN32
|
||||
uv_tty_init(uv_default_loop(), &tty, fileno(stderr), 1);
|
||||
#else
|
||||
uv_tty_init(uv_default_loop(), &tty, fileno(stdin), 1);
|
||||
uv_tty_init(uv_default_loop(), &tty_out, fileno(stdout), 0);
|
||||
int width, height;
|
||||
uv_tty_get_winsize(&tty_out, &width, &height);
|
||||
#endif
|
||||
uv_tty_set_mode(&tty, UV_TTY_MODE_RAW);
|
||||
tty.data = &interrupted;
|
||||
uv_read_start((uv_stream_t *)&tty, alloc_cb, read_cb);
|
||||
uv_read_start(STRUCT_CAST(uv_stream_t, &tty), alloc_cb, read_cb);
|
||||
#ifndef WIN32
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
@@ -154,15 +171,17 @@ int main(int argc, char **argv)
|
||||
sa.sa_handler = sig_handler;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGWINCH, &sa, NULL);
|
||||
// uv_signal_t sigwinch_watcher;
|
||||
// uv_signal_init(uv_default_loop(), &sigwinch_watcher);
|
||||
// sigwinch_watcher.data = &tty;
|
||||
// uv_signal_start(&sigwinch_watcher, sigwinch_cb, SIGWINCH);
|
||||
#else
|
||||
uv_signal_t sigwinch_watcher;
|
||||
uv_signal_init(uv_default_loop(), &sigwinch_watcher);
|
||||
uv_signal_start(&sigwinch_watcher, sigwinch_cb, SIGWINCH);
|
||||
#endif
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
#ifndef WIN32
|
||||
// XXX: Without this the SIGHUP handler is skipped on some systems.
|
||||
sleep(100);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ local Session = require('nvim.session')
|
||||
local TcpStream = require('nvim.tcp_stream')
|
||||
local SocketStream = require('nvim.socket_stream')
|
||||
local ChildProcessStream = require('nvim.child_process_stream')
|
||||
local Paths = require('test.config.paths')
|
||||
|
||||
local check_cores = global_helpers.check_cores
|
||||
local check_logs = global_helpers.check_logs
|
||||
@@ -16,30 +17,30 @@ local eq = global_helpers.eq
|
||||
local ok = global_helpers.ok
|
||||
local map = global_helpers.map
|
||||
local filter = global_helpers.filter
|
||||
local dedent = global_helpers.dedent
|
||||
|
||||
local start_dir = lfs.currentdir()
|
||||
-- XXX: NVIM_PROG takes precedence, QuickBuild sets it.
|
||||
local nvim_prog = os.getenv('NVIM_PROG') or os.getenv('NVIM_PRG') or 'build/bin/nvim'
|
||||
local nvim_prog = (
|
||||
os.getenv('NVIM_PROG')
|
||||
or os.getenv('NVIM_PRG')
|
||||
or Paths.test_build_dir .. '/bin/nvim'
|
||||
)
|
||||
-- Default settings for the test session.
|
||||
local nvim_set = 'set shortmess+=I background=light noswapfile noautoindent'
|
||||
..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
|
||||
..' belloff= noshowcmd noruler'
|
||||
..' belloff= noshowcmd noruler nomore'
|
||||
local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N',
|
||||
'--cmd', nvim_set, '--embed'}
|
||||
|
||||
local mpack = require('mpack')
|
||||
|
||||
local tmpname = global_helpers.tmpname
|
||||
local uname = global_helpers.uname
|
||||
|
||||
-- Formulate a path to the directory containing nvim. We use this to
|
||||
-- help run test executables. It helps to keep the tests working, even
|
||||
-- when the build is not in the default location.
|
||||
-- Directory containing nvim.
|
||||
local nvim_dir = nvim_prog:gsub("[/\\][^/\\]+$", "")
|
||||
if nvim_dir == nvim_prog then
|
||||
nvim_dir = "."
|
||||
end
|
||||
|
||||
local mpack = require('mpack')
|
||||
local tmpname = global_helpers.tmpname
|
||||
local uname = global_helpers.uname
|
||||
local prepend_argv
|
||||
|
||||
if os.getenv('VALGRIND') then
|
||||
@@ -75,8 +76,8 @@ end
|
||||
|
||||
local session, loop_running, last_error
|
||||
|
||||
local function set_session(s)
|
||||
if session then
|
||||
local function set_session(s, keep)
|
||||
if session and not keep then
|
||||
session:close()
|
||||
end
|
||||
session = s
|
||||
@@ -99,6 +100,22 @@ local function next_message()
|
||||
return session:next_message()
|
||||
end
|
||||
|
||||
local function expect_twostreams(msgs1, msgs2)
|
||||
local pos1, pos2 = 1, 1
|
||||
while pos1 <= #msgs1 or pos2 <= #msgs2 do
|
||||
local msg = next_message()
|
||||
if pos1 <= #msgs1 and pcall(eq, msgs1[pos1], msg) then
|
||||
pos1 = pos1 + 1
|
||||
elseif pos2 <= #msgs2 then
|
||||
eq(msgs2[pos2], msg)
|
||||
pos2 = pos2 + 1
|
||||
else
|
||||
-- already failed, but show the right error message
|
||||
eq(msgs1[pos1], msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function call_and_stop_on_error(...)
|
||||
local status, result = copcall(...) -- luacheck: ignore
|
||||
if not status then
|
||||
@@ -173,7 +190,7 @@ local os_name = (function()
|
||||
end)()
|
||||
|
||||
local function iswin()
|
||||
return os_name() == 'windows'
|
||||
return package.config:sub(1,1) == '\\'
|
||||
end
|
||||
|
||||
-- Executes a VimL function.
|
||||
@@ -191,28 +208,6 @@ local function nvim_feed(input)
|
||||
end
|
||||
end
|
||||
|
||||
local function dedent(str)
|
||||
-- find minimum common indent across lines
|
||||
local indent = nil
|
||||
for line in str:gmatch('[^\n]+') do
|
||||
local line_indent = line:match('^%s+') or ''
|
||||
if indent == nil or #line_indent < #indent then
|
||||
indent = line_indent
|
||||
end
|
||||
end
|
||||
if indent == nil or #indent == 0 then
|
||||
-- no minimum common indent
|
||||
return str
|
||||
end
|
||||
-- create a pattern for the indent
|
||||
indent = indent:gsub('%s', '[ \t]')
|
||||
-- strip it from the first line
|
||||
str = str:gsub('^'..indent, '')
|
||||
-- strip it from the remaining lines
|
||||
str = str:gsub('[\n]'..indent, '\n')
|
||||
return str
|
||||
end
|
||||
|
||||
local function feed(...)
|
||||
for _, v in ipairs({...}) do
|
||||
nvim_feed(dedent(v))
|
||||
@@ -267,12 +262,13 @@ local function retry(max, max_ms, fn)
|
||||
return result
|
||||
end
|
||||
if (max and tries >= max) or (luv.now() - start_time > timeout) then
|
||||
break
|
||||
if type(result) == "string" then
|
||||
result = "\nretry() attempts: "..tostring(tries).."\n"..result
|
||||
end
|
||||
error(result)
|
||||
end
|
||||
tries = tries + 1
|
||||
end
|
||||
-- Do not use pcall() for the final attempt, let the failure bubble up.
|
||||
return fn()
|
||||
end
|
||||
|
||||
local function clear(...)
|
||||
@@ -325,7 +321,7 @@ end
|
||||
|
||||
-- Executes an ex-command by user input. Because nvim_input() is used, VimL
|
||||
-- errors will not manifest as client (lua) errors. Use command() for that.
|
||||
local function execute(...)
|
||||
local function feed_command(...)
|
||||
for _, v in ipairs({...}) do
|
||||
if v:sub(1, 1) ~= '/' then
|
||||
-- not a search command, prefix with colon
|
||||
@@ -339,7 +335,14 @@ end
|
||||
-- Dedent the given text and write it to the file name.
|
||||
local function write_file(name, text, dont_dedent)
|
||||
local file = io.open(name, 'w')
|
||||
if not dont_dedent then
|
||||
if type(text) == 'table' then
|
||||
-- Byte blob
|
||||
local bytes = text
|
||||
text = ''
|
||||
for _, char in ipairs(bytes) do
|
||||
text = ('%s%c'):format(text, char)
|
||||
end
|
||||
elseif not dont_dedent then
|
||||
text = dedent(text)
|
||||
end
|
||||
file:write(text)
|
||||
@@ -357,18 +360,30 @@ local function read_file(name)
|
||||
return ret
|
||||
end
|
||||
|
||||
local sourced_fnames = {}
|
||||
local function source(code)
|
||||
local fname = tmpname()
|
||||
write_file(fname, code)
|
||||
nvim_command('source '..fname)
|
||||
os.remove(fname)
|
||||
-- DO NOT REMOVE FILE HERE.
|
||||
-- do_source() has a habit of checking whether files are “same” by using inode
|
||||
-- and device IDs. If you run two source() calls in quick succession there is
|
||||
-- a good chance that underlying filesystem will reuse the inode, making files
|
||||
-- appear as “symlinks” to do_source when it checks FileIDs. With current
|
||||
-- setup linux machines (both QB, travis and mine(ZyX-I) with XFS) do reuse
|
||||
-- inodes, Mac OS machines (again, both QB and travis) do not.
|
||||
--
|
||||
-- Files appearing as “symlinks” mean that both the first and the second
|
||||
-- source() calls will use same SID, which may fail some tests which check for
|
||||
-- exact numbers after `<SNR>` in e.g. function names.
|
||||
sourced_fnames[#sourced_fnames + 1] = fname
|
||||
return fname
|
||||
end
|
||||
|
||||
local function set_shell_powershell()
|
||||
source([[
|
||||
set shell=powershell shellquote=\" shellpipe=\| shellredir=>
|
||||
set shellcmdflag=\ -ExecutionPolicy\ RemoteSigned\ -Command
|
||||
set shellcmdflag=\ -NoLogo\ -NoProfile\ -ExecutionPolicy\ RemoteSigned\ -Command
|
||||
let &shellxquote=' '
|
||||
]])
|
||||
end
|
||||
@@ -405,14 +420,21 @@ local function curbuf(method, ...)
|
||||
end
|
||||
|
||||
local function wait()
|
||||
-- Execute 'vim_eval' (a deferred function) to block
|
||||
-- Execute 'nvim_eval' (a deferred function) to block
|
||||
-- until all pending input is processed.
|
||||
session:request('vim_eval', '1')
|
||||
session:request('nvim_eval', '1')
|
||||
end
|
||||
|
||||
-- sleeps the test runner (_not_ the nvim instance)
|
||||
local function sleep(ms)
|
||||
run(nil, nil, nil, ms)
|
||||
local function notification_cb(method, _)
|
||||
if method == "redraw" then
|
||||
error("Screen is attached; use screen:sleep() instead.")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
run(nil, notification_cb, nil, ms)
|
||||
end
|
||||
|
||||
local function curbuf_contents()
|
||||
@@ -445,21 +467,27 @@ end
|
||||
|
||||
local function do_rmdir(path)
|
||||
if lfs.attributes(path, 'mode') ~= 'directory' then
|
||||
return nil
|
||||
return -- Don't complain.
|
||||
end
|
||||
for file in lfs.dir(path) do
|
||||
if file ~= '.' and file ~= '..' then
|
||||
local abspath = path..'/'..file
|
||||
if lfs.attributes(abspath, 'mode') == 'directory' then
|
||||
local ret = do_rmdir(abspath) -- recurse
|
||||
if not ret then
|
||||
return nil
|
||||
end
|
||||
do_rmdir(abspath) -- recurse
|
||||
else
|
||||
local ret, err = os.remove(abspath)
|
||||
if not ret then
|
||||
error('os.remove: '..err)
|
||||
return nil
|
||||
if not session then
|
||||
error('os.remove: '..err)
|
||||
else
|
||||
-- Try Nvim delete(): it handles `readonly` attribute on Windows,
|
||||
-- and avoids Lua cross-version/platform incompatibilities.
|
||||
if -1 == nvim_call('delete', abspath) then
|
||||
local hint = (os_name() == 'windows'
|
||||
and ' (hint: try :%bwipeout! before rmdir())' or '')
|
||||
error('delete() failed'..hint..': '..abspath)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -468,7 +496,6 @@ local function do_rmdir(path)
|
||||
if not ret then
|
||||
error('lfs.rmdir('..path..'): '..err)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function rmdir(path)
|
||||
@@ -500,17 +527,6 @@ local exc_exec = function(cmd)
|
||||
return ret
|
||||
end
|
||||
|
||||
local function redir_exec(cmd)
|
||||
nvim_command(([[
|
||||
redir => g:__output
|
||||
silent! execute "%s"
|
||||
redir END
|
||||
]]):format(cmd:gsub('\n', '\\n'):gsub('[\\"]', '\\%0')))
|
||||
local ret = nvim_eval('get(g:, "__output", 0)')
|
||||
nvim_command('unlet! g:__output')
|
||||
return ret
|
||||
end
|
||||
|
||||
local function create_callindex(func)
|
||||
local table = {}
|
||||
setmetatable(table, {
|
||||
@@ -570,7 +586,91 @@ local curbufmeths = create_callindex(curbuf)
|
||||
local curwinmeths = create_callindex(curwin)
|
||||
local curtabmeths = create_callindex(curtab)
|
||||
|
||||
local M = {
|
||||
local function redir_exec(cmd)
|
||||
meths.set_var('__redir_exec_cmd', cmd)
|
||||
nvim_command([[
|
||||
redir => g:__redir_exec_output
|
||||
silent! execute g:__redir_exec_cmd
|
||||
redir END
|
||||
]])
|
||||
local ret = meths.get_var('__redir_exec_output')
|
||||
meths.del_var('__redir_exec_output')
|
||||
meths.del_var('__redir_exec_cmd')
|
||||
return ret
|
||||
end
|
||||
|
||||
local function get_pathsep()
|
||||
return funcs.fnamemodify('.', ':p'):sub(-1)
|
||||
end
|
||||
|
||||
-- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
|
||||
-- Useful for communicating with child instances.
|
||||
local function new_pipename()
|
||||
-- HACK: Start a server temporarily, get the name, then stop it.
|
||||
local pipename = nvim_eval('serverstart()')
|
||||
funcs.serverstop(pipename)
|
||||
return pipename
|
||||
end
|
||||
|
||||
local function missing_provider(provider)
|
||||
if provider == 'ruby' then
|
||||
local prog = funcs['provider#' .. provider .. '#Detect']()
|
||||
return prog == '' and (provider .. ' not detected') or false
|
||||
elseif provider == 'python' or provider == 'python3' then
|
||||
local py_major_version = (provider == 'python3' and 3 or 2)
|
||||
local errors = funcs['provider#pythonx#Detect'](py_major_version)[2]
|
||||
return errors ~= '' and errors or false
|
||||
else
|
||||
assert(false, 'Unknown provider: ' .. provider)
|
||||
end
|
||||
end
|
||||
|
||||
local function alter_slashes(obj)
|
||||
if not iswin() then
|
||||
return obj
|
||||
end
|
||||
if type(obj) == 'string' then
|
||||
local ret = obj:gsub('/', '\\')
|
||||
return ret
|
||||
elseif type(obj) == 'table' then
|
||||
local ret = {}
|
||||
for k, v in pairs(obj) do
|
||||
ret[k] = alter_slashes(v)
|
||||
end
|
||||
return ret
|
||||
else
|
||||
assert(false, 'Could only alter slashes for tables of strings and strings')
|
||||
end
|
||||
end
|
||||
|
||||
local function hexdump(str)
|
||||
local len = string.len( str )
|
||||
local dump = ""
|
||||
local hex = ""
|
||||
local asc = ""
|
||||
|
||||
for i = 1, len do
|
||||
if 1 == i % 8 then
|
||||
dump = dump .. hex .. asc .. "\n"
|
||||
hex = string.format( "%04x: ", i - 1 )
|
||||
asc = ""
|
||||
end
|
||||
|
||||
local ord = string.byte( str, i )
|
||||
hex = hex .. string.format( "%02x ", ord )
|
||||
if ord >= 32 and ord <= 126 then
|
||||
asc = asc .. string.char( ord )
|
||||
else
|
||||
asc = asc .. "."
|
||||
end
|
||||
end
|
||||
|
||||
return dump .. hex
|
||||
.. string.rep( " ", 8 - len % 8 ) .. asc
|
||||
|
||||
end
|
||||
|
||||
local module = {
|
||||
prepend_argv = prepend_argv,
|
||||
clear = clear,
|
||||
connect = connect,
|
||||
@@ -582,12 +682,13 @@ local M = {
|
||||
insert = insert,
|
||||
iswin = iswin,
|
||||
feed = feed,
|
||||
execute = execute,
|
||||
feed_command = feed_command,
|
||||
eval = nvim_eval,
|
||||
call = nvim_call,
|
||||
command = nvim_command,
|
||||
request = request,
|
||||
next_message = next_message,
|
||||
expect_twostreams = expect_twostreams,
|
||||
run = run,
|
||||
stop = stop,
|
||||
eq = eq,
|
||||
@@ -600,6 +701,7 @@ local M = {
|
||||
nvim = nvim,
|
||||
nvim_async = nvim_async,
|
||||
nvim_prog = nvim_prog,
|
||||
nvim_argv = nvim_argv,
|
||||
nvim_set = nvim_set,
|
||||
nvim_dir = nvim_dir,
|
||||
buffer = buffer,
|
||||
@@ -635,14 +737,22 @@ local M = {
|
||||
tmpname = tmpname,
|
||||
meth_pcall = meth_pcall,
|
||||
NIL = mpack.NIL,
|
||||
get_pathsep = get_pathsep,
|
||||
missing_provider = missing_provider,
|
||||
alter_slashes = alter_slashes,
|
||||
hexdump = hexdump,
|
||||
new_pipename = new_pipename,
|
||||
}
|
||||
|
||||
return function(after_each)
|
||||
if after_each then
|
||||
after_each(function()
|
||||
for _, fname in ipairs(sourced_fnames) do
|
||||
os.remove(fname)
|
||||
end
|
||||
check_logs()
|
||||
check_cores('build/bin/nvim')
|
||||
end)
|
||||
end
|
||||
return M
|
||||
return module
|
||||
end
|
||||
|
43
test/functional/insert/ctrl_o_spec.lua
Normal file
43
test/functional/insert/ctrl_o_spec.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local expect = helpers.expect
|
||||
local feed = helpers.feed
|
||||
local insert = helpers.insert
|
||||
|
||||
describe('insert-mode Ctrl-O', function()
|
||||
before_each(clear)
|
||||
|
||||
it('enters command mode for one command', function()
|
||||
feed('ihello world<C-o>')
|
||||
feed(':let ctrlo = "test"<CR>')
|
||||
feed('iii')
|
||||
expect('hello worldiii')
|
||||
eq(1, eval('ctrlo ==# "test"'))
|
||||
end)
|
||||
|
||||
it('re-enters insert mode at the end of the line when running startinsert', function()
|
||||
-- #6962
|
||||
feed('ihello world<C-o>')
|
||||
feed(':startinsert<CR>')
|
||||
feed('iii')
|
||||
expect('hello worldiii')
|
||||
end)
|
||||
|
||||
it('re-enters insert mode at the beginning of the line when running startinsert', function()
|
||||
insert('hello world')
|
||||
feed('0<C-o>')
|
||||
feed(':startinsert<CR>')
|
||||
feed('aaa')
|
||||
expect('aaahello world')
|
||||
end)
|
||||
|
||||
it('re-enters insert mode in the middle of the line when running startinsert', function()
|
||||
insert('hello world')
|
||||
feed('bi<C-o>')
|
||||
feed(':startinsert<CR>')
|
||||
feed('ooo')
|
||||
expect('hello oooworld')
|
||||
end)
|
||||
end)
|
19
test/functional/insert/ctrl_r_spec.lua
Normal file
19
test/functional/insert/ctrl_r_spec.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed = helpers.clear, helpers.feed
|
||||
local expect, command = helpers.expect, helpers.command
|
||||
|
||||
describe('insert-mode Ctrl-R', function()
|
||||
before_each(clear)
|
||||
|
||||
it('works', function()
|
||||
command("let @@ = 'test'")
|
||||
feed('i<C-r>"')
|
||||
expect('test')
|
||||
end)
|
||||
|
||||
it('works with multi-byte text', function()
|
||||
command("let @@ = 'påskägg'")
|
||||
feed('i<C-r>"')
|
||||
expect('påskägg')
|
||||
end)
|
||||
end)
|
@@ -3,7 +3,7 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe('filename recognition', function()
|
||||
setup(clear)
|
||||
@@ -17,17 +17,17 @@ describe('filename recognition', function()
|
||||
fourth test for URL:\\machine.name\tmp\vimtest2d, and other text]])
|
||||
|
||||
-- Go to the first URL and append it to the beginning
|
||||
execute('/^first', '/tmp', 'call append(0, expand("<cfile>"))')
|
||||
feed_command('/^first', '/tmp', 'call append(0, expand("<cfile>"))')
|
||||
|
||||
-- Repeat for the second URL
|
||||
-- this time, navigate to the word "URL" instead of "tmp"
|
||||
execute('/^second', '/URL', 'call append(1, expand("<cfile>"))')
|
||||
feed_command('/^second', '/URL', 'call append(1, expand("<cfile>"))')
|
||||
|
||||
-- Repeat for the remaining URLs. This time, the 'isfname' option must be
|
||||
-- set to allow '\' in filenames
|
||||
execute('set isf=@,48-57,/,.,-,_,+,,,$,:,~,\\')
|
||||
execute('/^third', '/name', 'call append(2, expand("<cfile>"))')
|
||||
execute('/^fourth', '/URL', 'call append(3, expand("<cfile>"))')
|
||||
feed_command('set isf=@,48-57,/,.,-,_,+,,,$,:,~,\\')
|
||||
feed_command('/^third', '/name', 'call append(2, expand("<cfile>"))')
|
||||
feed_command('/^fourth', '/URL', 'call append(3, expand("<cfile>"))')
|
||||
|
||||
-- Delete the initial text, which now starts at line 5
|
||||
feed('5GdG')
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,9 @@
|
||||
-- vim: set foldmethod=marker foldmarker=[[,]] :
|
||||
-- Test for autocommand that changes current buffer on BufEnter event.
|
||||
-- Check if modelines are interpreted for the correct buffer.
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe('BufEnter with modelines', function()
|
||||
setup(clear)
|
||||
@@ -20,34 +19,34 @@ describe('BufEnter with modelines', function()
|
||||
this is a test
|
||||
end of test file Xxx]])
|
||||
|
||||
execute('au BufEnter Xxx brew')
|
||||
feed_command('au BufEnter Xxx brew')
|
||||
|
||||
-- Write test file Xxx
|
||||
execute('/start of')
|
||||
execute('.,/end of/w! Xxx')
|
||||
execute('set ai modeline modelines=3')
|
||||
feed_command('/start of')
|
||||
feed_command('.,/end of/w! Xxx')
|
||||
feed_command('set ai modeline modelines=3')
|
||||
|
||||
-- Split to Xxx, autocmd will do :brew
|
||||
execute('sp Xxx')
|
||||
feed_command('sp Xxx')
|
||||
|
||||
-- Append text with autoindent to this file
|
||||
feed('G?this is a<CR>')
|
||||
feed('othis should be auto-indented<Esc>')
|
||||
|
||||
-- Go to Xxx, no autocmd anymore
|
||||
execute('au! BufEnter Xxx')
|
||||
execute('buf Xxx')
|
||||
feed_command('au! BufEnter Xxx')
|
||||
feed_command('buf Xxx')
|
||||
|
||||
-- Append text without autoindent to Xxx
|
||||
feed('G?this is a<CR>')
|
||||
feed('othis should be in column 1<Esc>')
|
||||
execute('wq')
|
||||
feed_command('wq')
|
||||
|
||||
-- Include Xxx in the current file
|
||||
feed('G:r Xxx<CR>')
|
||||
|
||||
-- Vim issue #57 do not move cursor on <c-o> when autoindent is set
|
||||
execute('set fo+=r')
|
||||
feed_command('set fo+=r')
|
||||
feed('G')
|
||||
feed('o# abcdef<Esc>2hi<CR><c-o>d0<Esc>')
|
||||
feed('o# abcdef<Esc>2hi<c-o>d0<Esc>')
|
||||
|
@@ -3,11 +3,13 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local command, expect = helpers.command, helpers.expect
|
||||
local wait = helpers.wait
|
||||
|
||||
describe('test5', function()
|
||||
setup(clear)
|
||||
|
||||
-- luacheck: ignore 621 (Indentation)
|
||||
it('is working', function()
|
||||
insert([[
|
||||
start of test file Xxx
|
||||
@@ -18,35 +20,37 @@ describe('test5', function()
|
||||
this is a test
|
||||
end of test file Xxx]])
|
||||
|
||||
execute('w! Xxx0')
|
||||
execute('au BufLeave Xxx bwipe')
|
||||
execute('/start of')
|
||||
command('w! Xxx0')
|
||||
command('au BufLeave Xxx bwipe')
|
||||
command('/start of')
|
||||
|
||||
-- Write test file Xxx.
|
||||
execute('.,/end of/w! Xxx')
|
||||
command('.,/end of/w! Xxx')
|
||||
|
||||
-- Split to Xxx.
|
||||
execute('sp Xxx')
|
||||
command('sp Xxx')
|
||||
|
||||
-- Delete buffer Xxx, now we're back here.
|
||||
execute('bwipe')
|
||||
command('bwipe')
|
||||
feed('G?this is a<cr>')
|
||||
feed('othis is some more text<esc>')
|
||||
wait()
|
||||
|
||||
-- Append some text to this file.
|
||||
|
||||
-- Write current file contents.
|
||||
execute('?start?,$yank A')
|
||||
command('?start?,$yank A')
|
||||
|
||||
-- Delete current buffer, get an empty one.
|
||||
execute('bwipe!')
|
||||
command('bwipe!')
|
||||
-- Append an extra line to the output register.
|
||||
feed('ithis is another test line<esc>:yank A<cr>')
|
||||
wait()
|
||||
|
||||
-- Output results
|
||||
execute('%d')
|
||||
execute('0put a')
|
||||
execute('$d')
|
||||
command('%d')
|
||||
command('0put a')
|
||||
command('$d')
|
||||
|
||||
-- Assert buffer contents.
|
||||
expect([[
|
||||
|
@@ -2,8 +2,9 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, dedent, eq = helpers.execute, helpers.dedent, helpers.eq
|
||||
local command, dedent, eq = helpers.command, helpers.dedent, helpers.eq
|
||||
local curbuf_contents = helpers.curbuf_contents
|
||||
local wait = helpers.wait
|
||||
|
||||
describe('argument list', function()
|
||||
setup(clear)
|
||||
@@ -16,10 +17,11 @@ describe('argument list', function()
|
||||
this is a test
|
||||
this is a test
|
||||
end of test file Xxx]])
|
||||
wait()
|
||||
|
||||
command('au BufReadPost Xxx2 next Xxx2 Xxx1')
|
||||
command('/^start of')
|
||||
|
||||
execute('au BufReadPost Xxx2 next Xxx2 Xxx1')
|
||||
execute('/^start of')
|
||||
|
||||
-- Write test file Xxx1
|
||||
feed('A1<Esc>:.,/end of/w! Xxx1<cr>')
|
||||
|
||||
@@ -28,29 +30,31 @@ describe('argument list', function()
|
||||
|
||||
-- Write test file Xxx3
|
||||
feed('$r3:.,/end of/w! Xxx3<cr>')
|
||||
wait()
|
||||
|
||||
-- Redefine arglist; go to Xxx1
|
||||
execute('next! Xxx1 Xxx2 Xxx3')
|
||||
|
||||
command('next! Xxx1 Xxx2 Xxx3')
|
||||
|
||||
-- Open window for all args
|
||||
execute('all')
|
||||
|
||||
command('all')
|
||||
|
||||
-- Write contents of Xxx1
|
||||
execute('%yank A')
|
||||
command('%yank A')
|
||||
|
||||
-- Append contents of last window (Xxx1)
|
||||
feed('')
|
||||
execute('%yank A')
|
||||
|
||||
-- should now be in Xxx2
|
||||
execute('rew')
|
||||
|
||||
-- Append contents of Xxx2
|
||||
execute('%yank A')
|
||||
wait()
|
||||
command('%yank A')
|
||||
|
||||
execute('%d')
|
||||
execute('0put=@a')
|
||||
execute('$d')
|
||||
-- should now be in Xxx2
|
||||
command('rew')
|
||||
|
||||
-- Append contents of Xxx2
|
||||
command('%yank A')
|
||||
|
||||
command('%d')
|
||||
command('0put=@a')
|
||||
command('$d')
|
||||
|
||||
eq(dedent([[
|
||||
start of test file Xxx1
|
||||
@@ -74,8 +78,8 @@ describe('argument list', function()
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
os.remove('Xxx1')
|
||||
os.remove('Xxx2')
|
||||
os.remove('Xxx3')
|
||||
os.remove('Xxx1')
|
||||
os.remove('Xxx2')
|
||||
os.remove('Xxx3')
|
||||
end)
|
||||
end)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe(':ball', function()
|
||||
setup(clear)
|
||||
@@ -14,44 +14,44 @@ describe(':ball', function()
|
||||
this is a test
|
||||
end of test file Xxx]])
|
||||
|
||||
execute('w! Xxx0')
|
||||
feed_command('w! Xxx0')
|
||||
feed('gg')
|
||||
|
||||
-- Write test file Xxx1
|
||||
feed('A1:.,/end of/w! Xxx1<cr>')
|
||||
execute('sp Xxx1')
|
||||
execute('close')
|
||||
feed_command('sp Xxx1')
|
||||
feed_command('close')
|
||||
|
||||
-- Write test file Xxx2
|
||||
feed('$r2:.,/end of/w! Xxx2<cr>')
|
||||
execute('sp Xxx2')
|
||||
execute('close')
|
||||
feed_command('sp Xxx2')
|
||||
feed_command('close')
|
||||
|
||||
-- Write test file Xxx3
|
||||
feed('$r3:.,/end of/w! Xxx3<cr>')
|
||||
execute('sp Xxx3')
|
||||
execute('close')
|
||||
feed_command('sp Xxx3')
|
||||
feed_command('close')
|
||||
|
||||
execute('au BufReadPost Xxx2 bwipe')
|
||||
feed_command('au BufReadPost Xxx2 bwipe')
|
||||
|
||||
-- Open window for all args, close Xxx2
|
||||
feed('$r4:ball<cr>')
|
||||
|
||||
|
||||
-- Write contents of this file
|
||||
execute('%yank A')
|
||||
|
||||
feed_command('%yank A')
|
||||
|
||||
-- Append contents of second window (Xxx1)
|
||||
feed('')
|
||||
execute('%yank A')
|
||||
feed_command('%yank A')
|
||||
|
||||
-- Append contents of last window (this file)
|
||||
feed('')
|
||||
execute('%yank A')
|
||||
feed_command('%yank A')
|
||||
|
||||
execute('bf')
|
||||
execute('%d')
|
||||
execute('0put=@a')
|
||||
execute('$d')
|
||||
feed_command('bf')
|
||||
feed_command('%d')
|
||||
feed_command('0put=@a')
|
||||
feed_command('$d')
|
||||
|
||||
expect([[
|
||||
start of test file Xxx4
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local feed, source = helpers.feed, helpers.source
|
||||
local clear, execute, expect, eq, eval = helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.eval
|
||||
local clear, feed_command, expect, eq, eval = helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.eval
|
||||
local write_file, wait, dedent = helpers.write_file, helpers.wait, helpers.dedent
|
||||
local io = require('io')
|
||||
|
||||
@@ -25,15 +25,15 @@ describe('autocommands that delete and unload buffers:', function()
|
||||
before_each(clear)
|
||||
|
||||
it('BufWritePre, BufUnload', function()
|
||||
execute('au BufWritePre Xxx1 bunload')
|
||||
execute('au BufWritePre Xxx2 bwipe')
|
||||
execute('e Xxx2')
|
||||
feed_command('au BufWritePre Xxx1 bunload')
|
||||
feed_command('au BufWritePre Xxx2 bwipe')
|
||||
feed_command('e Xxx2')
|
||||
eq('Xxx2', eval('bufname("%")'))
|
||||
execute('e Xxx1')
|
||||
feed_command('e Xxx1')
|
||||
eq('Xxx1', eval('bufname("%")'))
|
||||
-- The legacy test file did not check the error message.
|
||||
execute('let v:errmsg = "no error"')
|
||||
execute('write')
|
||||
feed_command('let v:errmsg = "no error"')
|
||||
feed_command('write')
|
||||
-- Discard all "hit enter" prompts and messages.
|
||||
feed('<C-L>')
|
||||
eq('E203: Autocommands deleted or unloaded buffer to be written',
|
||||
@@ -41,11 +41,11 @@ describe('autocommands that delete and unload buffers:', function()
|
||||
eq('Xxx2', eval('bufname("%")'))
|
||||
expect(text2)
|
||||
-- Start editing Xxx2.
|
||||
execute('e! Xxx2')
|
||||
feed_command('e! Xxx2')
|
||||
-- The legacy test file did not check the error message.
|
||||
execute('let v:errmsg = "no error"')
|
||||
feed_command('let v:errmsg = "no error"')
|
||||
-- Write Xxx2, will delete the buffer and give an error msg.
|
||||
execute('w')
|
||||
feed_command('w')
|
||||
-- Discard all "hit enter" prompts and messages.
|
||||
feed('<C-L>')
|
||||
eq('E203: Autocommands deleted or unloaded buffer to be written',
|
||||
@@ -73,17 +73,17 @@ describe('autocommands that delete and unload buffers:', function()
|
||||
au BufUnload * call CloseAll()
|
||||
au VimLeave * call WriteToOut()
|
||||
]])
|
||||
execute('e Xxx2')
|
||||
feed_command('e Xxx2')
|
||||
-- Discard all "hit enter" prompts and messages.
|
||||
feed('<C-L>')
|
||||
execute('e Xxx1')
|
||||
feed_command('e Xxx1')
|
||||
-- Discard all "hit enter" prompts and messages.
|
||||
feed('<C-L>')
|
||||
execute('e Makefile') -- an existing file
|
||||
feed_command('e Makefile') -- an existing file
|
||||
feed('<C-L>')
|
||||
execute('sp new2')
|
||||
feed_command('sp new2')
|
||||
feed('<C-L>')
|
||||
execute('q')
|
||||
feed_command('q')
|
||||
wait()
|
||||
eq('VimLeave done',
|
||||
string.match(io.open('test.out', 'r'):read('*all'), "^%s*(.-)%s*$"))
|
||||
|
@@ -1,22 +0,0 @@
|
||||
-- Test for Bufleave autocommand that deletes the buffer we are about to edit.
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, insert = helpers.clear, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
|
||||
describe('BufLeave autocommand', function()
|
||||
setup(clear)
|
||||
|
||||
it('is working', function()
|
||||
insert([[
|
||||
start of test file xx
|
||||
end of test file xx]])
|
||||
|
||||
execute('au BufLeave * bwipe yy')
|
||||
execute('e yy')
|
||||
|
||||
expect([[
|
||||
start of test file xx
|
||||
end of test file xx]])
|
||||
end)
|
||||
end)
|
@@ -14,8 +14,8 @@
|
||||
|
||||
local helpers= require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local clear, execute, expect, eq, neq, dedent, write_file, feed =
|
||||
helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.neq,
|
||||
local clear, feed_command, expect, eq, neq, dedent, write_file, feed =
|
||||
helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq,
|
||||
helpers.dedent, helpers.write_file, helpers.feed
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
@@ -66,26 +66,26 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
|
||||
it('FileReadPost (using gzip)', function()
|
||||
prepare_gz_file('Xtestfile', text1)
|
||||
execute('let $GZIP = ""')
|
||||
feed_command('let $GZIP = ""')
|
||||
--execute('au FileChangedShell * echo "caught FileChangedShell"')
|
||||
execute('set bin')
|
||||
execute("au FileReadPost *.gz '[,']!gzip -d")
|
||||
feed_command('set bin')
|
||||
feed_command("au FileReadPost *.gz '[,']!gzip -d")
|
||||
-- Read and decompress the testfile.
|
||||
execute('$r Xtestfile.gz')
|
||||
feed_command('$r Xtestfile.gz')
|
||||
expect('\n'..text1)
|
||||
end)
|
||||
|
||||
it('BufReadPre, BufReadPost (using gzip)', function()
|
||||
prepare_gz_file('Xtestfile', text1)
|
||||
local gzip_data = io.open('Xtestfile.gz'):read('*all')
|
||||
execute('let $GZIP = ""')
|
||||
feed_command('let $GZIP = ""')
|
||||
-- Setup autocommands to decompress before reading and re-compress afterwards.
|
||||
execute("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))")
|
||||
execute("au BufReadPre *.gz call rename(expand('<afile>:r'), expand('<afile>'))")
|
||||
execute("au BufReadPost *.gz call rename(expand('<afile>'), expand('<afile>:r'))")
|
||||
execute("au BufReadPost *.gz exe '!gzip ' . shellescape(expand('<afile>:r'))")
|
||||
feed_command("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))")
|
||||
feed_command("au BufReadPre *.gz call rename(expand('<afile>:r'), expand('<afile>'))")
|
||||
feed_command("au BufReadPost *.gz call rename(expand('<afile>'), expand('<afile>:r'))")
|
||||
feed_command("au BufReadPost *.gz exe '!gzip ' . shellescape(expand('<afile>:r'))")
|
||||
-- Edit compressed file.
|
||||
execute('e! Xtestfile.gz')
|
||||
feed_command('e! Xtestfile.gz')
|
||||
-- Discard all prompts and messages.
|
||||
feed('<C-L>')
|
||||
-- Expect the decompressed file in the buffer.
|
||||
@@ -94,13 +94,15 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
eq(gzip_data, io.open('Xtestfile.gz'):read('*all'))
|
||||
end)
|
||||
|
||||
-- luacheck: ignore 621 (Indentation)
|
||||
-- luacheck: ignore 611 (Line contains only whitespaces)
|
||||
it('FileReadPre, FileReadPost', function()
|
||||
prepare_gz_file('Xtestfile', text1)
|
||||
execute('au! FileReadPre *.gz exe "silent !gzip -d " . shellescape(expand("<afile>"))')
|
||||
execute('au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))')
|
||||
execute("au! FileReadPost *.gz '[,']s/l/L/")
|
||||
feed_command('au! FileReadPre *.gz exe "silent !gzip -d " . shellescape(expand("<afile>"))')
|
||||
feed_command('au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))')
|
||||
feed_command("au! FileReadPost *.gz '[,']s/l/L/")
|
||||
-- Read compressed file.
|
||||
execute('$r Xtestfile.gz')
|
||||
feed_command('$r Xtestfile.gz')
|
||||
-- Discard all prompts and messages.
|
||||
feed('<C-L>')
|
||||
expect([[
|
||||
@@ -121,17 +123,17 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
end
|
||||
|
||||
it('FileAppendPre, FileAppendPost', function()
|
||||
execute('au BufNewFile *.c read Xtest.c')
|
||||
feed_command('au BufNewFile *.c read Xtest.c')
|
||||
-- Will load Xtest.c.
|
||||
execute('e! foo.c')
|
||||
execute("au FileAppendPre *.out '[,']s/new/NEW/")
|
||||
execute('au FileAppendPost *.out !cat Xtest.c >>test.out')
|
||||
feed_command('e! foo.c')
|
||||
feed_command("au FileAppendPre *.out '[,']s/new/NEW/")
|
||||
feed_command('au FileAppendPost *.out !cat Xtest.c >>test.out')
|
||||
-- Append it to the output file.
|
||||
execute('w>>test.out')
|
||||
feed_command('w>>test.out')
|
||||
-- Discard all prompts and messages.
|
||||
feed('<C-L>')
|
||||
-- Expect the decompressed file in the buffer.
|
||||
execute('e test.out')
|
||||
feed_command('e test.out')
|
||||
expect([[
|
||||
|
||||
/*
|
||||
@@ -166,18 +168,18 @@ describe('file reading, writing and bufnew and filter autocommands', function()
|
||||
* Here is a new .c file
|
||||
*/]]))
|
||||
-- Need temp files here.
|
||||
execute('set shelltemp')
|
||||
execute('au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")')
|
||||
execute('au FilterReadPre *.out exe "silent !sed s/e/E/ " . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))')
|
||||
execute('au FilterReadPre *.out exe "silent !rm " . shellescape(expand("<afile>")) . ".t"')
|
||||
execute("au FilterReadPost *.out '[,']s/x/X/g")
|
||||
feed_command('set shelltemp')
|
||||
feed_command('au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")')
|
||||
feed_command('au FilterReadPre *.out exe "silent !sed s/e/E/ " . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))')
|
||||
feed_command('au FilterReadPre *.out exe "silent !rm " . shellescape(expand("<afile>")) . ".t"')
|
||||
feed_command("au FilterReadPost *.out '[,']s/x/X/g")
|
||||
-- Edit the output file.
|
||||
execute('e! test.out')
|
||||
execute('23,$!cat')
|
||||
feed_command('e! test.out')
|
||||
feed_command('23,$!cat')
|
||||
-- Discard all prompts and messages.
|
||||
feed('<C-L>')
|
||||
-- Remove CR for when sed adds them.
|
||||
execute([[23,$s/\r$//]])
|
||||
feed_command([[23,$s/\r$//]])
|
||||
expect([[
|
||||
startstart
|
||||
start of testfile
|
||||
|
@@ -3,12 +3,19 @@
|
||||
-- - "./dir", in directory relative to file
|
||||
-- - "dir", in directory relative to current dir
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
local insert, eq = helpers.insert, helpers.eq
|
||||
local neq, eval = helpers.neq, helpers.eval
|
||||
local clear, execute = helpers.clear, helpers.execute
|
||||
local wait, write_file = helpers.wait, helpers.write_file
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local lfs = require('lfs')
|
||||
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
local wait = helpers.wait
|
||||
local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local clear = helpers.clear
|
||||
local insert = helpers.insert
|
||||
local command = helpers.command
|
||||
local write_file = helpers.write_file
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
|
||||
local function ls_dir_sorted(dirname)
|
||||
local files = {}
|
||||
@@ -36,7 +43,7 @@ describe("'directory' option", function()
|
||||
clear()
|
||||
end)
|
||||
teardown(function()
|
||||
execute('qall!')
|
||||
command('qall!')
|
||||
helpers.rmdir('Xtest.je')
|
||||
helpers.rmdir('Xtest2')
|
||||
os.remove('Xtest1')
|
||||
@@ -49,21 +56,22 @@ describe("'directory' option", function()
|
||||
line 3 Abcdefghij
|
||||
end of testfile]])
|
||||
|
||||
execute('set swapfile')
|
||||
execute('set dir=.,~')
|
||||
meths.set_option('swapfile', true)
|
||||
curbufmeths.set_option('swapfile', true)
|
||||
meths.set_option('directory', '.')
|
||||
|
||||
-- sanity check: files should not exist yet.
|
||||
eq(nil, lfs.attributes('.Xtest1.swp'))
|
||||
|
||||
execute('e! Xtest1')
|
||||
command('edit! Xtest1')
|
||||
wait()
|
||||
eq('Xtest1', eval('buffer_name("%")'))
|
||||
eq('Xtest1', funcs.buffer_name('%'))
|
||||
-- Verify that the swapfile exists. In the legacy test this was done by
|
||||
-- reading the output from :!ls.
|
||||
neq(nil, lfs.attributes('.Xtest1.swp'))
|
||||
|
||||
execute('set dir=./Xtest2,.,~')
|
||||
execute('e Xtest1')
|
||||
meths.set_option('directory', './Xtest2,.')
|
||||
command('edit Xtest1')
|
||||
wait()
|
||||
|
||||
-- swapfile should no longer exist in CWD.
|
||||
@@ -71,9 +79,9 @@ describe("'directory' option", function()
|
||||
|
||||
eq({ "Xtest1.swp", "Xtest3" }, ls_dir_sorted("Xtest2"))
|
||||
|
||||
execute('set dir=Xtest.je,~')
|
||||
execute('e Xtest2/Xtest3')
|
||||
eq(1, eval('&swapfile'))
|
||||
meths.set_option('directory', 'Xtest.je')
|
||||
command('edit Xtest2/Xtest3')
|
||||
eq(true, curbufmeths.get_option('swapfile'))
|
||||
wait()
|
||||
|
||||
eq({ "Xtest3" }, ls_dir_sorted("Xtest2"))
|
||||
|
@@ -4,11 +4,12 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local feed, insert = helpers.feed, helpers.insert
|
||||
local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
|
||||
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
|
||||
|
||||
describe('alignment', function()
|
||||
setup(clear)
|
||||
|
||||
-- luacheck: ignore 621 (Indentation)
|
||||
it('is working', function()
|
||||
insert([[
|
||||
test for :left
|
||||
@@ -19,7 +20,7 @@ describe('alignment', function()
|
||||
asdfa a
|
||||
xasdfa a
|
||||
asxxdfa a
|
||||
|
||||
|
||||
test for :center
|
||||
a a
|
||||
fa afd asdf
|
||||
@@ -28,7 +29,7 @@ describe('alignment', function()
|
||||
asdfa a
|
||||
xasdfa asdfasdfasdfasdfasdf
|
||||
asxxdfa a
|
||||
|
||||
|
||||
test for :right
|
||||
a a
|
||||
fa a
|
||||
@@ -111,34 +112,34 @@ describe('alignment', function()
|
||||
asxxdfa axxxoikey
|
||||
asxa;ofa axxxoikey
|
||||
asdfaqwer axxxoikey
|
||||
|
||||
xxxxx xx xxxxxx
|
||||
|
||||
xxxxx xx xxxxxx
|
||||
xxxxxxx xxxxxxxxx xxx xxxx xxxxx xxxxx xxx xx
|
||||
xxxxxxxxxxxxxxxxxx xxxxx xxxx, xxxx xxxx xxxx xxxx xxx xx xx
|
||||
xx xxxxxxx. xxxx xxxx.
|
||||
|
||||
|
||||
> xx xx, xxxx xxxx xxx xxxx xxx xxxxx xxx xxx xxxxxxx xxx xxxxx
|
||||
> xxxxxx xxxxxxx: xxxx xxxxxxx, xx xxxxxx xxxx xxxxxxxxxx
|
||||
|
||||
|
||||
aa aa aa aa
|
||||
bb bb bb bb
|
||||
cc cc cc cc]])
|
||||
|
||||
execute('set tw=65')
|
||||
feed_command('set tw=65')
|
||||
|
||||
feed([[:/^\s*test for :left/,/^\s*test for :center/ left<cr>]])
|
||||
feed([[:/^\s*test for :center/,/^\s*test for :right/ center<cr>]])
|
||||
feed([[:/^\s*test for :right/,/^xxx/-1 right<cr>]])
|
||||
|
||||
execute('set fo+=tcroql tw=72')
|
||||
feed_command('set fo+=tcroql tw=72')
|
||||
|
||||
feed('/xxxxxxxx$<cr>')
|
||||
feed('0gq6kk<cr>')
|
||||
|
||||
-- Undo/redo here to make the next undo only work on the following changes.
|
||||
feed('u<cr>')
|
||||
execute('map gg :.,.+2s/^/x/<CR>kk:set tw=3<CR>gqq')
|
||||
execute('/^aa')
|
||||
feed_command('map gg :.,.+2s/^/x/<CR>kk:set tw=3<CR>gqq')
|
||||
feed_command('/^aa')
|
||||
feed('ggu<cr>')
|
||||
|
||||
-- Assert buffer contents.
|
||||
@@ -151,7 +152,7 @@ describe('alignment', function()
|
||||
asdfa a
|
||||
xasdfa a
|
||||
asxxdfa a
|
||||
|
||||
|
||||
test for :center
|
||||
a a
|
||||
fa afd asdf
|
||||
@@ -160,7 +161,7 @@ describe('alignment', function()
|
||||
asdfa a
|
||||
xasdfa asdfasdfasdfasdfasdf
|
||||
asxxdfa a
|
||||
|
||||
|
||||
test for :right
|
||||
a a
|
||||
fa a
|
||||
@@ -243,14 +244,14 @@ describe('alignment', function()
|
||||
asxxdfa axxxoikey
|
||||
asxa;ofa axxxoikey
|
||||
asdfaqwer axxxoikey
|
||||
|
||||
|
||||
xxxxx xx xxxxxx xxxxxxx xxxxxxxxx xxx xxxx xxxxx xxxxx xxx xx
|
||||
xxxxxxxxxxxxxxxxxx xxxxx xxxx, xxxx xxxx xxxx xxxx xxx xx xx xx xxxxxxx.
|
||||
xxxx xxxx.
|
||||
|
||||
|
||||
> xx xx, xxxx xxxx xxx xxxx xxx xxxxx xxx xxx xxxxxxx xxx xxxxx xxxxxx
|
||||
> xxxxxxx: xxxx xxxxxxx, xx xxxxxx xxxx xxxxxxxxxx
|
||||
|
||||
|
||||
aa aa aa aa
|
||||
bb bb bb bb
|
||||
cc cc cc cc]])
|
||||
|
@@ -1,11 +1,15 @@
|
||||
-- Tests for not doing smart indenting when it isn't set.
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
|
||||
local feed = helpers.feed
|
||||
local clear = helpers.clear
|
||||
local insert = helpers.insert
|
||||
local expect = helpers.expect
|
||||
local feed_command = helpers.feed_command
|
||||
|
||||
describe('unset smart indenting', function()
|
||||
setup(clear)
|
||||
before_each(clear)
|
||||
|
||||
it('is working', function()
|
||||
insert([[
|
||||
@@ -15,8 +19,8 @@ describe('unset smart indenting', function()
|
||||
test text
|
||||
test text]])
|
||||
|
||||
execute('set nocin nosi ai')
|
||||
execute('/some')
|
||||
feed_command('set nocin nosi ai')
|
||||
feed_command('/some')
|
||||
feed('2cc#test<Esc>')
|
||||
|
||||
expect([[
|
||||
|
@@ -3,11 +3,12 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local feed, insert = helpers.feed, helpers.insert
|
||||
local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
|
||||
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
|
||||
|
||||
describe([[performing "r<Tab>" with 'smarttab' and 'expandtab' set/not set, and "dv_"]], function()
|
||||
setup(clear)
|
||||
|
||||
-- luacheck: ignore 621 (Indentation)
|
||||
it('is working', function()
|
||||
insert([[
|
||||
start text
|
||||
@@ -19,24 +20,24 @@ describe([[performing "r<Tab>" with 'smarttab' and 'expandtab' set/not set, and
|
||||
test text
|
||||
Second line beginning with whitespace]])
|
||||
|
||||
execute('set smarttab expandtab ts=8 sw=4')
|
||||
feed_command('set smarttab expandtab ts=8 sw=4')
|
||||
-- Make sure that backspace works, no matter what termcap is used.
|
||||
execute('set t_kD=x7f t_kb=x08')
|
||||
feed_command('set t_kD=x7f t_kb=x08')
|
||||
|
||||
execute('/some')
|
||||
feed_command('/some')
|
||||
feed('r ')
|
||||
execute('set noexpandtab')
|
||||
execute('/other')
|
||||
feed_command('set noexpandtab')
|
||||
feed_command('/other')
|
||||
feed('r <cr>')
|
||||
-- Test replacing with Tabs and then backspacing to undo it.
|
||||
feed('0wR <bs><bs><bs><esc><cr>')
|
||||
-- Test replacing with Tabs.
|
||||
feed('0wR <esc><cr>')
|
||||
-- Test that copyindent works with expandtab set.
|
||||
execute('set expandtab smartindent copyindent ts=8 sw=8 sts=8')
|
||||
feed_command('set expandtab smartindent copyindent ts=8 sw=8 sts=8')
|
||||
feed('o{<cr>x<esc>')
|
||||
execute('set nosol')
|
||||
execute('/Second line/')
|
||||
feed_command('set nosol')
|
||||
feed_command('/Second line/')
|
||||
-- Test "dv_"
|
||||
feed('fwdv_')
|
||||
|
||||
|
@@ -1,11 +1,10 @@
|
||||
-- vim: set foldmethod=marker foldmarker=[[,]] :
|
||||
-- Tests Blockwise Visual when there are TABs before the text.
|
||||
-- First test for undo working properly when executing commands from a register.
|
||||
-- Also test this in an empty buffer.
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe('blockwise visual', function()
|
||||
setup(clear)
|
||||
@@ -26,15 +25,15 @@ Ox jAy kdd]])
|
||||
|
||||
feed(":let @a = 'Ox<C-v><Esc>jAy<C-v><Esc>kdd'<cr>")
|
||||
feed('G0k@au')
|
||||
execute('new')
|
||||
feed_command('new')
|
||||
feed('@auY')
|
||||
execute('quit')
|
||||
feed_command('quit')
|
||||
feed('GP')
|
||||
execute('/start here')
|
||||
feed_command('/start here')
|
||||
feed('"by$<C-v>jjlld')
|
||||
execute('/456')
|
||||
feed_command('/456')
|
||||
feed('<C-v>jj"bP')
|
||||
execute('$-3,$d')
|
||||
feed_command('$-3,$d')
|
||||
|
||||
expect([[
|
||||
123start here56
|
||||
|
@@ -1,9 +1,8 @@
|
||||
-- vim: set foldmethod=marker foldmarker=[[,]] :
|
||||
-- Tests for [ CTRL-I with a count and CTRL-W CTRL-I with a count
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe('CTRL-W CTRL-I', function()
|
||||
setup(clear)
|
||||
@@ -20,18 +19,18 @@ describe('CTRL-W CTRL-I', function()
|
||||
test text]])
|
||||
|
||||
-- Search for the second occurence of start and append to register
|
||||
execute('/start')
|
||||
feed_command('/start')
|
||||
feed('2[<C-i>')
|
||||
execute('yank A')
|
||||
feed_command('yank A')
|
||||
|
||||
-- Same as above but using different keystrokes.
|
||||
feed('?start<cr>')
|
||||
feed('2<C-w><Tab>')
|
||||
execute('yank A')
|
||||
feed_command('yank A')
|
||||
|
||||
-- Clean buffer and put register
|
||||
feed('ggdG"ap')
|
||||
execute('1d')
|
||||
feed_command('1d')
|
||||
|
||||
-- The buffer should now contain:
|
||||
expect([[
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed = helpers.clear, helpers.feed
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
describe('line ending', function()
|
||||
setup(clear)
|
||||
@@ -14,8 +14,8 @@ describe('line ending', function()
|
||||
this one does<C-V><C-M>
|
||||
and the last one doesn't]], '<ESC>')
|
||||
|
||||
execute('set ta tx')
|
||||
execute('e!')
|
||||
feed_command('set ta tx')
|
||||
feed_command('e!')
|
||||
|
||||
expect("this lines ends in a\r\n"..
|
||||
"this one doesn't\n"..
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, insert = helpers.clear, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local command, expect = helpers.command, helpers.expect
|
||||
local wait = helpers.wait
|
||||
|
||||
describe(':edit', function()
|
||||
setup(clear)
|
||||
@@ -12,31 +13,32 @@ describe(':edit', function()
|
||||
The result should be in Xfile1: "fooPIPEbar", in Xfile2: "fooSLASHbar"
|
||||
foo|bar
|
||||
foo/bar]])
|
||||
wait()
|
||||
|
||||
-- Prepare some test files
|
||||
execute('$-1w! Xfile1')
|
||||
execute('$w! Xfile2')
|
||||
execute('w! Xfile0')
|
||||
command('$-1w! Xfile1')
|
||||
command('$w! Xfile2')
|
||||
command('w! Xfile0')
|
||||
|
||||
-- Open Xfile using '+' range
|
||||
execute('edit +1 Xfile1')
|
||||
execute('s/|/PIPE/')
|
||||
execute('yank A')
|
||||
execute('w! Xfile1')
|
||||
command('edit +1 Xfile1')
|
||||
command('s/|/PIPE/')
|
||||
command('yank A')
|
||||
command('w! Xfile1')
|
||||
|
||||
-- Open Xfile2 using '|' range
|
||||
execute('edit Xfile2|1')
|
||||
execute("s/\\//SLASH/")
|
||||
execute('yank A')
|
||||
execute('w! Xfile2')
|
||||
command('edit Xfile2|1')
|
||||
command("s/\\//SLASH/")
|
||||
command('yank A')
|
||||
command('w! Xfile2')
|
||||
|
||||
-- Clean first buffer and put @a
|
||||
execute('bf')
|
||||
execute('%d')
|
||||
execute('0put a')
|
||||
command('bf')
|
||||
command('%d')
|
||||
command('0put a')
|
||||
|
||||
-- Remove empty line
|
||||
execute('$d')
|
||||
command('$d')
|
||||
|
||||
-- The buffer should now contain
|
||||
expect([[
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local feed_command, expect = helpers.feed_command, helpers.expect
|
||||
|
||||
if helpers.pending_win32(pending) then return end
|
||||
|
||||
@@ -21,30 +21,30 @@ describe('jump to a tag with hidden set', function()
|
||||
|
||||
SECTION_OFF]])
|
||||
|
||||
execute('w! Xxx')
|
||||
execute('set hidden')
|
||||
feed_command('w! Xxx')
|
||||
feed_command('set hidden')
|
||||
|
||||
-- Create a link from test25.dir to the current directory.
|
||||
execute('!rm -f test25.dir')
|
||||
execute('!ln -s . test25.dir')
|
||||
feed_command('!rm -f test25.dir')
|
||||
feed_command('!ln -s . test25.dir')
|
||||
|
||||
-- Create tags.text, with the current directory name inserted.
|
||||
execute('/tags line')
|
||||
execute('r !pwd')
|
||||
feed_command('/tags line')
|
||||
feed_command('r !pwd')
|
||||
feed('d$/test<cr>')
|
||||
feed('hP:.w! tags.test<cr>')
|
||||
|
||||
-- Try jumping to a tag in the current file, but with a path that contains a
|
||||
-- symbolic link. When wrong, this will give the ATTENTION message. The next
|
||||
-- space will then be eaten by hit-return, instead of moving the cursor to 'd'.
|
||||
execute('set tags=tags.test')
|
||||
feed_command('set tags=tags.test')
|
||||
feed('G<C-]> x:yank a<cr>')
|
||||
execute('!rm -f Xxx test25.dir tags.test')
|
||||
feed_command('!rm -f Xxx test25.dir tags.test')
|
||||
|
||||
-- Put @a and remove empty line
|
||||
execute('%d')
|
||||
execute('0put a')
|
||||
execute('$d')
|
||||
feed_command('%d')
|
||||
feed_command('0put a')
|
||||
feed_command('$d')
|
||||
|
||||
-- Assert buffer contents.
|
||||
expect("#efine SECTION_OFF 3")
|
||||
|
@@ -1,9 +1,11 @@
|
||||
-- Test for :execute, :while and :if
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
|
||||
local clear = helpers.clear
|
||||
local execute, expect = helpers.execute, helpers.expect
|
||||
local expect = helpers.expect
|
||||
local source = helpers.source
|
||||
local command = helpers.command
|
||||
|
||||
describe(':execute, :while and :if', function()
|
||||
setup(clear)
|
||||
@@ -37,7 +39,7 @@ describe(':execute, :while and :if', function()
|
||||
]])
|
||||
|
||||
-- Remove empty line
|
||||
execute('1d')
|
||||
command('1d')
|
||||
|
||||
-- Assert buffer contents.
|
||||
expect([[
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user