commit 19eb75831b931b7cbe6a95323f941f2836592f02
parent 8aec33e3221fb452198ab98d7bd7fdfb119c3dfb
Author: zeertzjq <zeertzjq@outlook.com>
Date: Tue, 3 Feb 2026 03:03:41 +0800
ci(test): bump Windows runners to windows-2025 and unskip tests (#37666)
Bumping to windows-2025 seems to fix at least one case of spaces having
wrong attributes in TUI tests, which allow unskipping dozens of tests.
Diffstat:
14 files changed, 74 insertions(+), 43 deletions(-)
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
@@ -242,7 +242,7 @@ jobs:
- run: zig build functionaltest -Dluajit=false
zig-build-windows:
- runs-on: windows-2022
+ runs-on: windows-2025
timeout-minutes: 45
name: build using zig build (windows)
steps:
diff --git a/.github/workflows/test_windows.yml b/.github/workflows/test_windows.yml
@@ -11,7 +11,7 @@ on:
jobs:
windows:
- runs-on: windows-2022
+ runs-on: windows-2025
timeout-minutes: 45
strategy:
fail-fast: false
diff --git a/src/nvim/vterm/state.c b/src/nvim/vterm/state.c
@@ -18,7 +18,7 @@
// Primary Device Attributes (DA1) response.
// We make this a global (extern) variable so that we can override it with FFI
// in tests.
-char vterm_primary_device_attr[] = "61;22;52";
+DLLEXPORT char vterm_primary_device_attr[] = "61;22;52";
// Some convenient wrappers to make callback functions easier
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
@@ -5,10 +5,6 @@ local tt = require('test.functional.testterm')
local clear = n.clear
local feed_data = tt.feed_data
-if t.skip(t.is_os('win')) then
- return
-end
-
describe('autoread TUI FocusGained/FocusLost', function()
local f1 = 'xtest-foo'
local screen
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
@@ -81,7 +81,6 @@ describe('autocmd TermClose', function()
end)
it('triggers when long-running terminal job gets stopped', function()
- skip(is_os('win'))
api.nvim_set_option_value('shell', is_os('win') and 'cmd.exe' or 'sh', {})
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
@@ -21,7 +21,7 @@ describe('channels', function()
function! Normalize(data) abort
" Windows: remove ^M
return type([]) == type(a:data)
- \ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
+ \ ? mapnew(a:data, 'substitute(v:val, "\r", "", "g")')
\ : a:data
endfunction
function! OnEvent(id, data, event) dict
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
@@ -48,12 +48,16 @@ describe('jobs', function()
function! Normalize(data) abort
" Windows: remove ^M and term escape sequences
return type([]) == type(a:data)
- \ ? map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
+ \ ? mapnew(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
\ : a:data
endfunction
function! OnEvent(id, data, event) dict
let userdata = get(self, 'user')
let data = Normalize(a:data)
+ " If Normalize() made non-empty data empty, doesn't send a notification.
+ if type([]) == type(data) && len(data) == 1 && !empty(a:data[0]) && empty(data[0])
+ return
+ endif
call rpcnotify(g:channel, a:event, userdata, data)
endfunction
let g:job_opts = {
@@ -719,7 +723,7 @@ describe('jobs', function()
source([[
function PrintArgs(a1, a2, id, data, event)
" Windows: remove ^M
- let normalized = map(a:data, 'substitute(v:val, "\r", "", "g")')
+ let normalized = mapnew(a:data, 'substitute(v:val, "\r", "", "g")')
call rpcnotify(g:channel, '1', a:a1, a:a2, normalized, a:event)
endfunction
let Callback = function('PrintArgs', ["foo", "bar"])
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
@@ -734,7 +734,7 @@ describe('startup', function()
exec([[
func Normalize(data) abort
" Windows: remove ^M and term escape sequences
- return map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
+ return mapnew(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
endfunc
func OnOutput(id, data, event) dict
let g:stdout = Normalize(a:data)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
@@ -167,8 +167,6 @@ describe(':mksession', function()
end)
it('restores CWD for :terminal buffers #11288', function()
- skip(is_os('win'), 'causes rmdir() to fail')
-
local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
cwd_dir = t.fix_slashes(cwd_dir) -- :mksession always uses unix slashes.
local session_path = cwd_dir .. '/' .. session_file
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -114,7 +114,6 @@ describe("preserve and (R)ecover with custom 'directory'", function()
end)
it('killing TUI process without :preserve #22096', function()
- t.skip(t.is_os('win'), 'FIXME: reading swapfile fails on Windows')
local screen0 = Screen.new()
local child_server = new_pipename()
fn.jobstart({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
@@ -235,7 +235,6 @@ describe(':terminal buffer', function()
end)
it('requires bang (!) to close a running job #15402', function()
- skip(is_os('win'), 'Test freezes the CI and makes it time out')
eq('Vim(wqall):E948: Job still running (add ! to end the job)', exc_exec('wqall'))
for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do
matches(
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
@@ -170,13 +170,11 @@ describe('TUI :detach', function()
nvim_set .. ' laststatus=2 background=dark',
}, job_opts)
- --- FIXME: On Windows spaces at the end of a screen line may have wrong attrs.
- --- Remove the {MATCH:} when that's fixed.
tt.feed_data('iHello, World')
screen:expect([[
Hello, World^ |
{100:~ }|*3
- {3:[No Name] [+]{MATCH: *}}{MATCH: *}|
+ {3:[No Name] [+] }|
{5:-- INSERT --} |
{5:-- TERMINAL --} |
]])
@@ -267,7 +265,6 @@ describe('TUI :restart', function()
--- @param s string
local function screen_expect(s)
if is_os('win') then
- s = s:gsub(' +%}%|\n', '{MATCH: *}}{MATCH: *}|\n')
s = s:gsub(' *%} +%|\n', '{MATCH: *}}{MATCH: *}|\n')
s = s:gsub('%}%^ +%|\n', '{MATCH:[ ^]*}}{MATCH:[ ^]*}|\n')
end
@@ -527,10 +524,6 @@ describe('TUI :connect', function()
end)
end)
-if t.skip(is_os('win')) then
- return
-end
-
describe('TUI', function()
local screen --[[@type test.functional.ui.screen]]
local child_session --[[@type test.Session]]
@@ -625,6 +618,7 @@ describe('TUI', function()
end)
it('accepts resize while pager is active', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
child_session:request(
'nvim_exec2',
[[
@@ -829,6 +823,7 @@ describe('TUI', function()
end)
it('interprets <Esc><Nul> as <M-C-Space> #17198', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
feed_data('i\022\027\000')
screen:expect([[
<M-C-Space>^ |
@@ -886,6 +881,7 @@ describe('TUI', function()
end)
local function test_mouse_wheel(esc)
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
child_session:request(
'nvim_exec2',
[[
@@ -1617,6 +1613,7 @@ describe('TUI', function()
end)
it('paste: normal-mode (+CRLF #10872)', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
feed_data(':set ruler | echo')
wait_for_mode('c')
feed_data('\n')
@@ -1854,6 +1851,7 @@ describe('TUI', function()
end)
it("paste: 'nomodifiable' buffer", function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
child_exec_lua([[
vim.bo.modifiable = false
-- Truncate the error message to hide the line number
@@ -1995,6 +1993,7 @@ describe('TUI', function()
end)
it('paste: split "start paste" code', function()
+ t.skip(is_os('win'), 'FIXME: wrong behavior on Windows')
feed_data('i')
wait_for_mode('i')
-- Send split "start paste" sequence.
@@ -2010,6 +2009,7 @@ describe('TUI', function()
end)
it('paste: split "stop paste" code', function()
+ t.skip(is_os('win'), 'FIXME: wrong behavior on Windows')
feed_data('i')
wait_for_mode('i')
-- Send split "stop paste" sequence.
@@ -2062,6 +2062,7 @@ describe('TUI', function()
end)
it('allows termguicolors to be set at runtime', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
screen:set_option('rgb', true)
feed_data(':hi SpecialKey ctermfg=3 guifg=SeaGreen\n')
feed_data('i')
@@ -2186,7 +2187,7 @@ describe('TUI', function()
it('in nvim_list_uis(), sets nvim_set_client_info()', function()
-- $TERM in :terminal.
- local exp_term = is_os('bsd') and 'xterm' or 'xterm-256color'
+ local exp_term = (is_os('bsd') or is_os('win')) and 'xterm' or 'xterm-256color'
local ui_chan = 1
local expected = {
{
@@ -2251,6 +2252,7 @@ describe('TUI', function()
end)
it('allows grid to assume wider ambiwidth chars than host terminal', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
child_session:request(
'nvim_buf_set_lines',
0,
@@ -2295,6 +2297,7 @@ describe('TUI', function()
end)
it('allows grid to assume wider non-ambiwidth chars than host terminal', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
child_session:request(
'nvim_buf_set_lines',
0,
@@ -2433,7 +2436,7 @@ describe('TUI', function()
it('no assert failure on deadly signal #21896', function()
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
- screen:expect([[
+ screen:expect(is_os('win') and { any = '%[Process exited 1%]' } or [[
Nvim: Caught deadly signal 'SIGTERM' |
|
[Process exited 1]^ |
@@ -2445,7 +2448,9 @@ describe('TUI', function()
it('exit status 1 and error message with deadly signal sent to server', function()
local _, server_pid = child_session:request('nvim_call_function', 'getpid', {})
exec_lua([[vim.uv.kill(..., 'sigterm')]], server_pid)
- screen:expect({ any = vim.pesc([[Nvim: Caught deadly signal 'SIGTERM']]) })
+ if not is_os('win') then
+ screen:expect({ any = vim.pesc([[Nvim: Caught deadly signal 'SIGTERM']]) })
+ end
screen:expect({ any = vim.pesc('[Process exited 1]') })
end)
@@ -2505,6 +2510,9 @@ describe('TUI', function()
end)
it('redraws on SIGWINCH even if terminal size is unchanged #23411', function()
+ -- On Windows, SIGWINCH cannot be sent as a signal with uv_kill(), while
+ -- SIGWINCH handlers are only called on terminal resize.
+ t.skip(is_os('win'), 'N/A for Windows')
child_session:request('nvim_echo', { { 'foo' } }, false, {})
screen:expect([[
^ |
@@ -2577,6 +2585,7 @@ describe('TUI', function()
end)
it('emits hyperlinks with OSC 8', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
exec_lua([[
local buf = vim.api.nvim_get_current_buf()
_G.urls = {}
@@ -2684,13 +2693,13 @@ describe('TUI', function()
sleep 500m
vs new
]])
- screen:expect([[
+ screen:expect(([[
^ │ |
{1:~ }│{100:~ }|*6
{1:~ }│ |
- {3:new }{101:{MATCH:<.*[/\]nvim} [-] }|
+ {3:new }{101:{MATCH:<.*%s} [-] }|
|
- ]])
+ ]]):format(is_os('win') and '[/\\]nvim%.exe' or '/nvim'))
end)
-- #28667, #28668
@@ -2734,6 +2743,7 @@ describe('TUI', function()
end
it('argv[0] can be overridden #23953', function()
+ t.skip(is_os('win'), 'N/A for Windows')
if not exec_lua('return pcall(require, "ffi")') then
pending('N/A: missing LuaJIT FFI')
end
@@ -2793,6 +2803,7 @@ describe('TUI', function()
end)
it('with non-tty (pipe) stdout/stderr', function()
+ t.skip(is_os('win'), 'N/A for Windows')
finally(function()
os.remove('testF')
os.remove(testlog)
@@ -2819,6 +2830,7 @@ describe('TUI', function()
end)
it('<C-h> #10134', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows #36660')
local screen = tt.setup_child_nvim({
'--clean',
'--cmd',
@@ -2907,6 +2919,7 @@ describe('TUI', function()
end)
it('no heap-buffer-overflow when changing &columns', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
-- Set a different bg colour and change $TERM to something dumber so the `print_spaces()`
-- codepath in `clear_region()` is hit.
local screen = tt.setup_child_nvim({
@@ -3114,6 +3127,7 @@ describe('TUI FocusGained/FocusLost', function()
it('in terminal-mode', function()
feed_data(':set shell=' .. testprg('shell-test') .. ' shellcmdflag=EXE\n')
+ feed_data(':set shellxquote=\n') -- win: avoid extra quotes
feed_data(':set noshowmode laststatus=0\n')
feed_data(':terminal zia\n')
@@ -3152,6 +3166,7 @@ describe('TUI FocusGained/FocusLost', function()
end)
it('in press-enter prompt', function()
+ t.skip(is_os('win'), 'FIXME: some spaces have wrong attrs on Windows')
feed_data(":echom 'msg1'|echom 'msg2'|echom 'msg3'|echom 'msg4'|echom 'msg5'\n")
-- Execute :messages to provoke the press-enter prompt.
feed_data(':messages\n')
@@ -3224,9 +3239,15 @@ describe("TUI 't_Co' (terminal colors)", function()
-- ansi and no terminal type at all:
- it('no TERM uses 8 colors', function()
- assert_term_colors(nil, nil, 8)
- end)
+ if is_os('win') then
+ it('guessed vtpcon with no TERM uses 256 colors', function()
+ assert_term_colors(nil, nil, 256)
+ end)
+ else
+ it('no TERM uses 8 colors', function()
+ assert_term_colors(nil, nil, 8)
+ end)
+ end
it('TERM=ansi no COLORTERM uses 8 colors', function()
assert_term_colors('ansi', nil, 8)
@@ -3278,12 +3299,12 @@ describe("TUI 't_Co' (terminal colors)", function()
-- screen:
--
- -- FreeBSD falls back to the built-in screen-256colour entry.
+ -- FreeBSD and Windows fall back to the built-in screen-256colour entry.
-- Linux and MacOS have a screen entry in external terminfo with 8 colours,
-- which is raised to 16 by COLORTERM.
it('TERM=screen no COLORTERM uses 8/256 colors', function()
- if is_os('freebsd') then
+ if is_os('freebsd') or is_os('win') then
assert_term_colors('screen', nil, 256)
else
assert_term_colors('screen', nil, 8)
@@ -3291,7 +3312,7 @@ describe("TUI 't_Co' (terminal colors)", function()
end)
it('TERM=screen COLORTERM=screen uses 16/256 colors', function()
- if is_os('freebsd') then
+ if is_os('freebsd') or is_os('win') then
assert_term_colors('screen', 'screen', 256)
else
assert_term_colors('screen', 'screen', 16)
@@ -3560,6 +3581,7 @@ describe('TUI', function()
end)
it('queries the terminal for truecolor support', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
clear()
exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', {
@@ -3663,6 +3685,7 @@ describe('TUI', function()
end)
it('queries the terminal for OSC 52 support with XTGETTCAP', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
clear()
if not exec_lua('return pcall(require, "ffi")') then
pending('N/A: missing LuaJIT FFI')
@@ -3731,6 +3754,7 @@ describe('TUI', function()
end)
it('determines OSC 52 support from DA1 response', function()
+ t.skip(is_os('win'), 'FIXME: does not work on Windows')
clear()
exec_lua([[
-- Check that we do not emit an XTGETTCAP request when DA1 indicates support
@@ -3805,6 +3829,10 @@ describe('TUI', function()
end)
describe('TUI bg color', function()
+ if t.skip(is_os('win')) then
+ return
+ end
+
before_each(clear)
it('is properly set in a nested Nvim instance when background=dark', function()
@@ -4059,7 +4087,7 @@ describe('TUI client', function()
-- No heap-use-after-free when receiving UI events after deadly signal #22184
server:request('nvim_input', ('a'):rep(1000))
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]])
- screen_client:expect([[
+ screen_client:expect(is_os('win') and { any = '%[Process exited 1%]' } or [[
Nvim: Caught deadly signal 'SIGTERM' |
|
[Process exited 1]^ |
@@ -4130,6 +4158,10 @@ describe('TUI client', function()
end
local bufname = api.nvim_buf_get_name(0)
+ local old_title = api.nvim_buf_get_var(0, 'term_title')
+ if not is_os('win') then
+ eq(bufname, old_title)
+ end
-- Normally a title cannot be longer than the 65535-byte buffer as maketitle()
-- limits it length. Use FFI to send a very long title directly.
server_exec_lua(ffi_str_defs .. [[
@@ -4138,7 +4170,7 @@ describe('TUI client', function()
]])
screen_client:expect_unchanged()
assert_log('set_title: title string too long!', testlog)
- eq(bufname, api.nvim_buf_get_var(0, 'term_title'))
+ eq(old_title, api.nvim_buf_get_var(0, 'term_title'))
-- Following escape sequences are not affected.
server:request('nvim_set_option_value', 'title', true, {})
@@ -4148,6 +4180,7 @@ describe('TUI client', function()
end)
it('logs chdir failure properly', function()
+ t.skip(is_os('win'), 'N/A for Windows')
local server, _, screen_client = start_headless_server_and_client(true)
local server_exec_lua = tt.make_lua_executor(server)
if not server_exec_lua('return pcall(require, "ffi")') then
@@ -4210,6 +4243,7 @@ describe('TUI client', function()
end)
it('suspend/resume works with multiple clients', function()
+ t.skip(is_os('win'), 'N/A for Windows')
local server_super, screen_server, screen_client = start_tui_and_remote_client()
local server_super_exec_lua = tt.make_lua_executor(server_super)
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
@@ -283,7 +283,6 @@ describe(':terminal window', function()
end)
it('redraws cursor info in terminal mode', function()
- skip(is_os('win'), '#31587')
command('file AMOGUS | set laststatus=2 ruler')
screen:expect([[
tty ready |
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
@@ -41,10 +41,6 @@ describe('shell command :!', function()
]])
end)
- after_each(function()
- tt.feed_data('\3') -- Ctrl-C
- end)
-
it('displays output without LF/EOF. #4646 #4569 #3772', function()
skip(is_os('win'))
-- NOTE: We use a child nvim (within a :term buffer)
@@ -58,6 +54,13 @@ describe('shell command :!', function()
foo |
{5:-- TERMINAL --} |
]])
+ tt.feed_data('\3') -- Ctrl-C
+ screen:expect([[
+ ^ |
+ {100:~ }|*4
+ |
+ {5:-- TERMINAL --} |
+ ]])
end)
it('throttles shell-command output greater than ~10KB', function()