feat(test): rest of test suite
This commit is contained in:
parent
093782330a
commit
21407be376
3 changed files with 439 additions and 57 deletions
|
|
@ -2,41 +2,164 @@ describe('cp.diff', function()
|
|||
local diff = require('cp.diff')
|
||||
|
||||
describe('get_available_backends', function()
|
||||
it('returns vim and git backends')
|
||||
it('returns vim and git backends', function()
|
||||
local backends = diff.get_available_backends()
|
||||
assert.same({'vim', 'git'}, backends)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_backend', function()
|
||||
it('returns vim backend by name')
|
||||
it('returns git backend by name')
|
||||
it('returns nil for invalid name')
|
||||
it('returns vim backend by name', function()
|
||||
local backend = diff.get_backend('vim')
|
||||
assert.is_not_nil(backend)
|
||||
assert.equals('vim', backend.name)
|
||||
end)
|
||||
|
||||
it('returns git backend by name', function()
|
||||
local backend = diff.get_backend('git')
|
||||
assert.is_not_nil(backend)
|
||||
assert.equals('git', backend.name)
|
||||
end)
|
||||
|
||||
it('returns nil for invalid name', function()
|
||||
local backend = diff.get_backend('invalid')
|
||||
assert.is_nil(backend)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('is_git_available', function()
|
||||
it('returns true when git command succeeds')
|
||||
it('returns false when git command fails')
|
||||
it('returns true when git command succeeds', function()
|
||||
local mock_system = stub(vim, 'system')
|
||||
mock_system.returns({ code = 0 })
|
||||
|
||||
local result = diff.is_git_available()
|
||||
assert.is_true(result)
|
||||
|
||||
mock_system:revert()
|
||||
end)
|
||||
|
||||
it('returns false when git command fails', function()
|
||||
local mock_system = stub(vim, 'system')
|
||||
mock_system.returns({ code = 1 })
|
||||
|
||||
local result = diff.is_git_available()
|
||||
assert.is_false(result)
|
||||
|
||||
mock_system:revert()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_best_backend', function()
|
||||
it('returns preferred backend when available')
|
||||
it('falls back to vim when git unavailable')
|
||||
it('defaults to vim backend')
|
||||
it('returns preferred backend when available', function()
|
||||
local mock_is_available = stub(diff, 'is_git_available')
|
||||
mock_is_available.returns(true)
|
||||
|
||||
local backend = diff.get_best_backend('git')
|
||||
assert.equals('git', backend.name)
|
||||
|
||||
mock_is_available:revert()
|
||||
end)
|
||||
|
||||
it('falls back to vim when git unavailable', function()
|
||||
local mock_is_available = stub(diff, 'is_git_available')
|
||||
mock_is_available.returns(false)
|
||||
|
||||
local backend = diff.get_best_backend('git')
|
||||
assert.equals('vim', backend.name)
|
||||
|
||||
mock_is_available:revert()
|
||||
end)
|
||||
|
||||
it('defaults to vim backend', function()
|
||||
local backend = diff.get_best_backend()
|
||||
assert.equals('vim', backend.name)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('vim backend', function()
|
||||
it('returns content as-is')
|
||||
it('returns nil highlights')
|
||||
it('returns content as-is', function()
|
||||
local backend = diff.get_backend('vim')
|
||||
local result = backend.render('expected', 'actual')
|
||||
|
||||
assert.same({'actual'}, result.content)
|
||||
assert.is_nil(result.highlights)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('git backend', function()
|
||||
it('creates temp files for diff')
|
||||
it('returns raw diff output')
|
||||
it('cleans up temp files')
|
||||
it('handles no differences')
|
||||
it('handles git command failure')
|
||||
it('creates temp files for diff', function()
|
||||
local mock_system = stub(vim, 'system')
|
||||
local mock_tempname = stub(vim.fn, 'tempname')
|
||||
local mock_writefile = stub(vim.fn, 'writefile')
|
||||
local mock_delete = stub(vim.fn, 'delete')
|
||||
|
||||
mock_tempname.returns('/tmp/expected', '/tmp/actual')
|
||||
mock_system.returns({ code = 1, stdout = 'diff output' })
|
||||
|
||||
local backend = diff.get_backend('git')
|
||||
backend.render('expected text', 'actual text')
|
||||
|
||||
assert.stub(mock_writefile).was_called(2)
|
||||
assert.stub(mock_delete).was_called(2)
|
||||
|
||||
mock_system:revert()
|
||||
mock_tempname:revert()
|
||||
mock_writefile:revert()
|
||||
mock_delete:revert()
|
||||
end)
|
||||
|
||||
it('returns raw diff output', function()
|
||||
local mock_system = stub(vim, 'system')
|
||||
local mock_tempname = stub(vim.fn, 'tempname')
|
||||
local mock_writefile = stub(vim.fn, 'writefile')
|
||||
local mock_delete = stub(vim.fn, 'delete')
|
||||
|
||||
mock_tempname.returns('/tmp/expected', '/tmp/actual')
|
||||
mock_system.returns({ code = 1, stdout = 'git diff output' })
|
||||
|
||||
local backend = diff.get_backend('git')
|
||||
local result = backend.render('expected', 'actual')
|
||||
|
||||
assert.equals('git diff output', result.raw_diff)
|
||||
|
||||
mock_system:revert()
|
||||
mock_tempname:revert()
|
||||
mock_writefile:revert()
|
||||
mock_delete:revert()
|
||||
end)
|
||||
|
||||
it('handles no differences', function()
|
||||
local mock_system = stub(vim, 'system')
|
||||
local mock_tempname = stub(vim.fn, 'tempname')
|
||||
local mock_writefile = stub(vim.fn, 'writefile')
|
||||
local mock_delete = stub(vim.fn, 'delete')
|
||||
|
||||
mock_tempname.returns('/tmp/expected', '/tmp/actual')
|
||||
mock_system.returns({ code = 0 })
|
||||
|
||||
local backend = diff.get_backend('git')
|
||||
local result = backend.render('same', 'same')
|
||||
|
||||
assert.same({'same'}, result.content)
|
||||
assert.same({}, result.highlights)
|
||||
|
||||
mock_system:revert()
|
||||
mock_tempname:revert()
|
||||
mock_writefile:revert()
|
||||
mock_delete:revert()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('render_diff', function()
|
||||
it('uses best available backend')
|
||||
it('passes parameters to backend')
|
||||
it('uses best available backend', function()
|
||||
local mock_get_best = spy.on(diff, 'get_best_backend')
|
||||
local mock_backend = { render = function() return {} end }
|
||||
mock_get_best.returns(mock_backend)
|
||||
|
||||
diff.render_diff('expected', 'actual', 'vim')
|
||||
|
||||
assert.spy(mock_get_best).was_called_with('vim')
|
||||
mock_get_best:revert()
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -1,39 +1,174 @@
|
|||
describe('cp.highlight', function()
|
||||
local highlight = require('cp.highlight')
|
||||
|
||||
describe('parse_diff_line', function()
|
||||
it('parses added text markers {+text+}')
|
||||
it('removes removed text markers [-text-]')
|
||||
it('handles mixed add/remove markers')
|
||||
it('calculates correct highlight positions')
|
||||
it('handles text without markers')
|
||||
it('handles empty text')
|
||||
end)
|
||||
|
||||
describe('parse_git_diff', function()
|
||||
it('skips git diff headers')
|
||||
it('processes added lines')
|
||||
it('ignores removed lines')
|
||||
it('handles unchanged lines')
|
||||
it('sets correct line numbers')
|
||||
it('handles empty diff output')
|
||||
it('skips git diff headers', function()
|
||||
local diff_output = [[
|
||||
diff --git a/test b/test
|
||||
index 1234567..abcdefg 100644
|
||||
--- a/test
|
||||
+++ b/test
|
||||
@@ -1,3 +1,3 @@
|
||||
hello
|
||||
+world
|
||||
-goodbye
|
||||
]]
|
||||
local result = highlight.parse_git_diff(diff_output)
|
||||
assert.same({'hello', 'world'}, result.content)
|
||||
end)
|
||||
|
||||
it('processes added lines', function()
|
||||
local diff_output = '+hello w{+o+}rld'
|
||||
local result = highlight.parse_git_diff(diff_output)
|
||||
assert.same({'hello world'}, result.content)
|
||||
assert.equals(1, #result.highlights)
|
||||
assert.equals('CpDiffAdded', result.highlights[1].highlight_group)
|
||||
end)
|
||||
|
||||
it('ignores removed lines', function()
|
||||
local diff_output = 'hello\n-removed line\n+kept line'
|
||||
local result = highlight.parse_git_diff(diff_output)
|
||||
assert.same({'hello', 'kept line'}, result.content)
|
||||
end)
|
||||
|
||||
it('handles unchanged lines', function()
|
||||
local diff_output = 'unchanged line\n+added line'
|
||||
local result = highlight.parse_git_diff(diff_output)
|
||||
assert.same({'unchanged line', 'added line'}, result.content)
|
||||
end)
|
||||
|
||||
it('sets correct line numbers', function()
|
||||
local diff_output = '+first {+added+}\n+second {+text+}'
|
||||
local result = highlight.parse_git_diff(diff_output)
|
||||
assert.equals(0, result.highlights[1].line)
|
||||
assert.equals(1, result.highlights[2].line)
|
||||
end)
|
||||
|
||||
it('handles empty diff output', function()
|
||||
local result = highlight.parse_git_diff('')
|
||||
assert.same({}, result.content)
|
||||
assert.same({}, result.highlights)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('apply_highlights', function()
|
||||
it('clears existing highlights')
|
||||
it('applies extmarks with correct positions')
|
||||
it('uses correct highlight groups')
|
||||
it('handles empty highlights')
|
||||
it('clears existing highlights', function()
|
||||
local mock_clear = spy.on(vim.api, 'nvim_buf_clear_namespace')
|
||||
local bufnr = 1
|
||||
local namespace = 100
|
||||
|
||||
highlight.apply_highlights(bufnr, {}, namespace)
|
||||
|
||||
assert.spy(mock_clear).was_called_with(bufnr, namespace, 0, -1)
|
||||
mock_clear:revert()
|
||||
end)
|
||||
|
||||
it('applies extmarks with correct positions', function()
|
||||
local mock_extmark = spy.on(vim.api, 'nvim_buf_set_extmark')
|
||||
local bufnr = 1
|
||||
local namespace = 100
|
||||
local highlights = {
|
||||
{
|
||||
line = 0,
|
||||
col_start = 5,
|
||||
col_end = 10,
|
||||
highlight_group = 'CpDiffAdded'
|
||||
}
|
||||
}
|
||||
|
||||
highlight.apply_highlights(bufnr, highlights, namespace)
|
||||
|
||||
assert.spy(mock_extmark).was_called_with(
|
||||
bufnr, namespace, 0, 5,
|
||||
{
|
||||
end_col = 10,
|
||||
hl_group = 'CpDiffAdded',
|
||||
priority = 100
|
||||
}
|
||||
)
|
||||
mock_extmark:revert()
|
||||
end)
|
||||
|
||||
it('uses correct highlight groups', function()
|
||||
local mock_extmark = spy.on(vim.api, 'nvim_buf_set_extmark')
|
||||
local highlights = {
|
||||
{
|
||||
line = 0,
|
||||
col_start = 0,
|
||||
col_end = 5,
|
||||
highlight_group = 'CpDiffAdded'
|
||||
}
|
||||
}
|
||||
|
||||
highlight.apply_highlights(1, highlights, 100)
|
||||
|
||||
local call_args = mock_extmark.calls[1].vals
|
||||
assert.equals('CpDiffAdded', call_args[4].hl_group)
|
||||
mock_extmark:revert()
|
||||
end)
|
||||
|
||||
it('handles empty highlights', function()
|
||||
local mock_extmark = spy.on(vim.api, 'nvim_buf_set_extmark')
|
||||
|
||||
highlight.apply_highlights(1, {}, 100)
|
||||
|
||||
assert.spy(mock_extmark).was_not_called()
|
||||
mock_extmark:revert()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('create_namespace', function()
|
||||
it('creates unique namespace')
|
||||
it('creates unique namespace', function()
|
||||
local mock_create = stub(vim.api, 'nvim_create_namespace')
|
||||
mock_create.returns(42)
|
||||
|
||||
local result = highlight.create_namespace()
|
||||
|
||||
assert.equals(42, result)
|
||||
assert.stub(mock_create).was_called_with('cp_diff_highlights')
|
||||
mock_create:revert()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('parse_and_apply_diff', function()
|
||||
it('parses diff and applies to buffer')
|
||||
it('sets buffer content')
|
||||
it('applies highlights')
|
||||
it('returns content lines')
|
||||
it('parses diff and applies to buffer', function()
|
||||
local mock_set_lines = spy.on(vim.api, 'nvim_buf_set_lines')
|
||||
local mock_apply = spy.on(highlight, 'apply_highlights')
|
||||
local bufnr = 1
|
||||
local namespace = 100
|
||||
local diff_output = '+hello {+world+}'
|
||||
|
||||
local result = highlight.parse_and_apply_diff(bufnr, diff_output, namespace)
|
||||
|
||||
assert.same({'hello world'}, result)
|
||||
assert.spy(mock_set_lines).was_called_with(bufnr, 0, -1, false, {'hello world'})
|
||||
assert.spy(mock_apply).was_called()
|
||||
|
||||
mock_set_lines:revert()
|
||||
mock_apply:revert()
|
||||
end)
|
||||
|
||||
it('sets buffer content', function()
|
||||
local mock_set_lines = spy.on(vim.api, 'nvim_buf_set_lines')
|
||||
|
||||
highlight.parse_and_apply_diff(1, '+test line', 100)
|
||||
|
||||
assert.spy(mock_set_lines).was_called_with(1, 0, -1, false, {'test line'})
|
||||
mock_set_lines:revert()
|
||||
end)
|
||||
|
||||
it('applies highlights', function()
|
||||
local mock_apply = spy.on(highlight, 'apply_highlights')
|
||||
|
||||
highlight.parse_and_apply_diff(1, '+hello {+world+}', 100)
|
||||
|
||||
assert.spy(mock_apply).was_called()
|
||||
mock_apply:revert()
|
||||
end)
|
||||
|
||||
it('returns content lines', function()
|
||||
local result = highlight.parse_and_apply_diff(1, '+first\n+second', 100)
|
||||
assert.same({'first', 'second'}, result)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -2,29 +2,153 @@ describe('cp.test_render', function()
|
|||
local test_render = require('cp.test_render')
|
||||
|
||||
describe('get_status_info', function()
|
||||
it('returns AC for pass status')
|
||||
it('returns WA for fail status with normal exit codes')
|
||||
it('returns TLE for timeout status')
|
||||
it('returns RTE for fail with signal codes (>= 128)')
|
||||
it('returns empty for pending status')
|
||||
it('returns AC for pass status', function()
|
||||
local test_case = { status = 'pass' }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('AC', result.text)
|
||||
assert.equals('CpTestAC', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns WA for fail status with normal exit codes', function()
|
||||
local test_case = { status = 'fail', code = 1 }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('WA', result.text)
|
||||
assert.equals('CpTestError', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns TLE for timeout status', function()
|
||||
local test_case = { status = 'timeout' }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('TLE', result.text)
|
||||
assert.equals('CpTestError', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns TLE for timed out fail status', function()
|
||||
local test_case = { status = 'fail', timed_out = true }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('TLE', result.text)
|
||||
assert.equals('CpTestError', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns RTE for fail with signal codes (>= 128)', function()
|
||||
local test_case = { status = 'fail', code = 139 }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('RTE', result.text)
|
||||
assert.equals('CpTestError', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns empty for pending status', function()
|
||||
local test_case = { status = 'pending' }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('', result.text)
|
||||
assert.equals('CpTestPending', result.highlight_group)
|
||||
end)
|
||||
|
||||
it('returns running indicator for running status', function()
|
||||
local test_case = { status = 'running' }
|
||||
local result = test_render.get_status_info(test_case)
|
||||
assert.equals('...', result.text)
|
||||
assert.equals('CpTestPending', result.highlight_group)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('render_test_list', function()
|
||||
it('renders test cases with CP terminology')
|
||||
it('shows current test with > prefix')
|
||||
it('displays input only for current test')
|
||||
it('handles empty test cases')
|
||||
it('preserves input line breaks')
|
||||
it('renders test cases with CP terminology', function()
|
||||
local test_state = {
|
||||
test_cases = {
|
||||
{ status = 'pass', input = '5' },
|
||||
{ status = 'fail', code = 1, input = '3' },
|
||||
},
|
||||
current_index = 1,
|
||||
}
|
||||
local result = test_render.render_test_list(test_state)
|
||||
assert.equals('> 1. AC', result[1])
|
||||
assert.equals(' 2. WA', result[3])
|
||||
end)
|
||||
|
||||
it('shows current test with > prefix', function()
|
||||
local test_state = {
|
||||
test_cases = {
|
||||
{ status = 'pass', input = '' },
|
||||
{ status = 'pass', input = '' },
|
||||
},
|
||||
current_index = 2,
|
||||
}
|
||||
local result = test_render.render_test_list(test_state)
|
||||
assert.equals(' 1. AC', result[1])
|
||||
assert.equals('> 2. AC', result[2])
|
||||
end)
|
||||
|
||||
it('displays input only for current test', function()
|
||||
local test_state = {
|
||||
test_cases = {
|
||||
{ status = 'pass', input = '5 3' },
|
||||
{ status = 'pass', input = '2 4' },
|
||||
},
|
||||
current_index = 1,
|
||||
}
|
||||
local result = test_render.render_test_list(test_state)
|
||||
assert.equals('> 1. AC', result[1])
|
||||
assert.equals(' 5 3', result[2])
|
||||
assert.equals(' 2. AC', result[3])
|
||||
end)
|
||||
|
||||
it('handles empty test cases', function()
|
||||
local test_state = { test_cases = {}, current_index = 1 }
|
||||
local result = test_render.render_test_list(test_state)
|
||||
assert.equals(0, #result)
|
||||
end)
|
||||
|
||||
it('preserves input line breaks', function()
|
||||
local test_state = {
|
||||
test_cases = {
|
||||
{ status = 'pass', input = '5\n3\n1' },
|
||||
},
|
||||
current_index = 1,
|
||||
}
|
||||
local result = test_render.render_test_list(test_state)
|
||||
assert.equals('> 1. AC', result[1])
|
||||
assert.equals(' 5', result[2])
|
||||
assert.equals(' 3', result[3])
|
||||
assert.equals(' 1', result[4])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('render_status_bar', function()
|
||||
it('formats time and exit code')
|
||||
it('handles missing time')
|
||||
it('handles missing exit code')
|
||||
it('returns empty for nil test case')
|
||||
it('formats time and exit code', function()
|
||||
local test_case = { time_ms = 45.7, code = 0 }
|
||||
local result = test_render.render_status_bar(test_case)
|
||||
assert.equals('46ms │ Exit: 0', result)
|
||||
end)
|
||||
|
||||
it('handles missing time', function()
|
||||
local test_case = { code = 0 }
|
||||
local result = test_render.render_status_bar(test_case)
|
||||
assert.equals('Exit: 0', result)
|
||||
end)
|
||||
|
||||
it('handles missing exit code', function()
|
||||
local test_case = { time_ms = 123 }
|
||||
local result = test_render.render_status_bar(test_case)
|
||||
assert.equals('123ms', result)
|
||||
end)
|
||||
|
||||
it('returns empty for nil test case', function()
|
||||
local result = test_render.render_status_bar(nil)
|
||||
assert.equals('', result)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('setup_highlights', function()
|
||||
it('sets up all highlight groups')
|
||||
it('sets up all highlight groups', function()
|
||||
local mock_set_hl = spy.on(vim.api, 'nvim_set_hl')
|
||||
test_render.setup_highlights()
|
||||
|
||||
assert.spy(mock_set_hl).was_called(5)
|
||||
assert.spy(mock_set_hl).was_called_with(0, 'CpTestAC', { fg = '#10b981', bold = true })
|
||||
assert.spy(mock_set_hl).was_called_with(0, 'CpTestError', { fg = '#ef4444', bold = true })
|
||||
|
||||
mock_set_hl:revert()
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue