update lua API to 1-based indices; add renderer
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 11s
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 11s
This commit is contained in:
@@ -6,7 +6,7 @@ describe('Buffer', function()
|
||||
withbuf({}, function()
|
||||
local buf = Buffer.from_nr()
|
||||
buf:all():replace 'bleh'
|
||||
local actual_lines = vim.api.nvim_buf_get_lines(buf.buf, 0, -1, false)
|
||||
local actual_lines = vim.api.nvim_buf_get_lines(buf.bufnr, 0, -1, false)
|
||||
assert.are.same({ 'bleh' }, actual_lines)
|
||||
end)
|
||||
end)
|
||||
@@ -18,8 +18,8 @@ describe('Buffer', function()
|
||||
'three',
|
||||
}, function()
|
||||
local buf = Buffer.from_nr()
|
||||
buf:lines(1, -2):replace 'too'
|
||||
local actual_lines = vim.api.nvim_buf_get_lines(buf.buf, 0, -1, false)
|
||||
buf:lines(2, -2):replace 'too'
|
||||
local actual_lines = vim.api.nvim_buf_get_lines(buf.bufnr, 0, -1, false)
|
||||
assert.are.same({
|
||||
'one',
|
||||
'too',
|
||||
|
||||
@@ -4,12 +4,12 @@ local withbuf = loadfile './spec/withbuf.lua'()
|
||||
describe('Pos', function()
|
||||
it('get a char from a given position', function()
|
||||
withbuf({ 'asdf', 'bleh', 'a', '', 'goo' }, function()
|
||||
assert.are.same('a', Pos.new(nil, 0, 0):char())
|
||||
assert.are.same('d', Pos.new(nil, 0, 2):char())
|
||||
assert.are.same('f', Pos.new(nil, 0, 3):char())
|
||||
assert.are.same('a', Pos.new(nil, 2, 0):char())
|
||||
assert.are.same('', Pos.new(nil, 3, 0):char())
|
||||
assert.are.same('o', Pos.new(nil, 4, 2):char())
|
||||
assert.are.same('a', Pos.new(nil, 1, 1):char())
|
||||
assert.are.same('d', Pos.new(nil, 1, 3):char())
|
||||
assert.are.same('f', Pos.new(nil, 1, 4):char())
|
||||
assert.are.same('a', Pos.new(nil, 3, 1):char())
|
||||
assert.are.same('', Pos.new(nil, 4, 1):char())
|
||||
assert.are.same('o', Pos.new(nil, 5, 3):char())
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -23,47 +23,47 @@ describe('Pos', function()
|
||||
it('get the next position', function()
|
||||
withbuf({ 'asdf', 'bleh', 'a', '', 'goo' }, function()
|
||||
-- line 1: a => s
|
||||
assert.are.same(Pos.new(nil, 0, 1), Pos.new(nil, 0, 0):next())
|
||||
assert.are.same(Pos.new(nil, 1, 2), Pos.new(nil, 1, 1):next())
|
||||
-- line 1: d => f
|
||||
assert.are.same(Pos.new(nil, 0, 3), Pos.new(nil, 0, 2):next())
|
||||
assert.are.same(Pos.new(nil, 1, 4), Pos.new(nil, 1, 3):next())
|
||||
-- line 1 => 2
|
||||
assert.are.same(Pos.new(nil, 1, 0), Pos.new(nil, 0, 3):next())
|
||||
assert.are.same(Pos.new(nil, 2, 1), Pos.new(nil, 1, 4):next())
|
||||
-- line 3 => 4
|
||||
assert.are.same(Pos.new(nil, 3, 0), Pos.new(nil, 2, 0):next())
|
||||
assert.are.same(Pos.new(nil, 4, 1), Pos.new(nil, 3, 1):next())
|
||||
-- line 4 => 5
|
||||
assert.are.same(Pos.new(nil, 4, 0), Pos.new(nil, 3, 0):next())
|
||||
assert.are.same(Pos.new(nil, 5, 1), Pos.new(nil, 4, 1):next())
|
||||
-- end returns nil
|
||||
assert.are.same(nil, Pos.new(nil, 4, 2):next())
|
||||
assert.are.same(nil, Pos.new(nil, 5, 3):next())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('get the previous position', function()
|
||||
withbuf({ 'asdf', 'bleh', 'a', '', 'goo' }, function()
|
||||
-- line 1: s => a
|
||||
assert.are.same(Pos.new(nil, 0, 0), Pos.new(nil, 0, 1):next(-1))
|
||||
assert.are.same(Pos.new(nil, 1, 1), Pos.new(nil, 1, 2):next(-1))
|
||||
-- line 1: f => d
|
||||
assert.are.same(Pos.new(nil, 0, 2), Pos.new(nil, 0, 3):next(-1))
|
||||
assert.are.same(Pos.new(nil, 1, 3), Pos.new(nil, 1, 4):next(-1))
|
||||
-- line 2 => 1
|
||||
assert.are.same(Pos.new(nil, 0, 3), Pos.new(nil, 1, 0):next(-1))
|
||||
assert.are.same(Pos.new(nil, 1, 4), Pos.new(nil, 2, 1):next(-1))
|
||||
-- line 4 => 3
|
||||
assert.are.same(Pos.new(nil, 2, 0), Pos.new(nil, 3, 0):next(-1))
|
||||
assert.are.same(Pos.new(nil, 3, 1), Pos.new(nil, 4, 1):next(-1))
|
||||
-- line 5 => 4
|
||||
assert.are.same(Pos.new(nil, 3, 0), Pos.new(nil, 4, 0):next(-1))
|
||||
assert.are.same(Pos.new(nil, 4, 1), Pos.new(nil, 5, 1):next(-1))
|
||||
-- beginning returns nil
|
||||
assert.are.same(nil, Pos.new(nil, 0, 0):next(-1))
|
||||
assert.are.same(nil, Pos.new(nil, 1, 1):next(-1))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('find matching brackets', function()
|
||||
withbuf({ 'asdf ({} def <[{}]>) ;lkj' }, function()
|
||||
-- outer parens are matched:
|
||||
assert.are.same(Pos.new(nil, 0, 19), Pos.new(nil, 0, 5):find_match())
|
||||
assert.are.same(Pos.new(nil, 1, 20), Pos.new(nil, 1, 6):find_match())
|
||||
-- outer parens are matched (backward):
|
||||
assert.are.same(Pos.new(nil, 0, 5), Pos.new(nil, 0, 19):find_match())
|
||||
assert.are.same(Pos.new(nil, 1, 6), Pos.new(nil, 1, 20):find_match())
|
||||
-- no potential match returns nil
|
||||
assert.are.same(nil, Pos.new(nil, 0, 0):find_match())
|
||||
assert.are.same(nil, Pos.new(nil, 1, 1):find_match())
|
||||
-- watchdog expires before an otherwise valid match is found:
|
||||
assert.are.same(nil, Pos.new(nil, 0, 5):find_match(2))
|
||||
assert.are.same(nil, Pos.new(nil, 1, 6):find_match(2))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('Range', function()
|
||||
|
||||
it('get from positions: v in single line', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 0, 3), 'v')
|
||||
local range = Range.new(Pos.new(nil, 1, 2), Pos.new(nil, 1, 4), 'v')
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'ine' }, lines)
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('Range', function()
|
||||
|
||||
it('get from positions: v across multiple lines', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 2, 4), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 3, 5), 'v')
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'quick brown fox', 'jumps' }, lines)
|
||||
end)
|
||||
@@ -47,7 +47,7 @@ describe('Range', function()
|
||||
|
||||
it('get from positions: V', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 0), Pos.new(nil, 0, Pos.MAX_COL), 'V')
|
||||
local range = Range.new(Pos.new(nil, 1, 1), Pos.new(nil, 1, Pos.MAX_COL), 'V')
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'line one' }, lines)
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('Range', function()
|
||||
|
||||
it('get from positions: V across multiple lines', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 0), Pos.new(nil, 2, Pos.MAX_COL), 'V')
|
||||
local range = Range.new(Pos.new(nil, 2, 1), Pos.new(nil, 3, Pos.MAX_COL), 'V')
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'the quick brown fox', 'jumps over a lazy dog' }, lines)
|
||||
end)
|
||||
@@ -66,7 +66,7 @@ describe('Range', function()
|
||||
|
||||
it('get from line', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.from_line(nil, 0)
|
||||
local range = Range.from_line(nil, 1)
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'line one' }, lines)
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('Range', function()
|
||||
|
||||
it('get from lines', function()
|
||||
withbuf({ 'line one', 'and line two', 'and line 3' }, function()
|
||||
local range = Range.from_lines(nil, 0, 1)
|
||||
local range = Range.from_lines(nil, 1, 2)
|
||||
local lines = range:lines()
|
||||
assert.are.same({ 'line one', 'and line two' }, lines)
|
||||
|
||||
@@ -88,35 +88,35 @@ describe('Range', function()
|
||||
|
||||
it('replace within line', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 1, 8), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 2, 9), 'v')
|
||||
range:replace 'quack'
|
||||
|
||||
local text = Range.from_line(nil, 1):text()
|
||||
local text = Range.from_line(nil, 2):text()
|
||||
assert.are.same('the quack brown fox', text)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('delete within line', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 1, 9), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 2, 10), 'v')
|
||||
range:replace ''
|
||||
|
||||
local text = Range.from_line(nil, 1):text()
|
||||
local text = Range.from_line(nil, 2):text()
|
||||
assert.are.same('the brown fox', text)
|
||||
end)
|
||||
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 1, 9), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 2, 10), 'v')
|
||||
range:replace(nil)
|
||||
|
||||
local text = Range.from_line(nil, 1):text()
|
||||
local text = Range.from_line(nil, 2):text()
|
||||
assert.are.same('the brown fox', text)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('replace across multiple lines: v', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 2, 4), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 3, 5), 'v')
|
||||
range:replace 'plane flew'
|
||||
|
||||
local lines = Range.from_buf_text():lines()
|
||||
@@ -130,7 +130,7 @@ describe('Range', function()
|
||||
|
||||
it('replace a line', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.from_line(nil, 1)
|
||||
local range = Range.from_line(nil, 2)
|
||||
range:replace 'the rabbit'
|
||||
|
||||
local lines = Range.from_buf_text():lines()
|
||||
@@ -145,7 +145,7 @@ describe('Range', function()
|
||||
|
||||
it('replace multiple lines', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.from_lines(nil, 1, 2)
|
||||
local range = Range.from_lines(nil, 2, 3)
|
||||
range:replace 'the rabbit'
|
||||
|
||||
local lines = Range.from_buf_text():lines()
|
||||
@@ -159,7 +159,7 @@ describe('Range', function()
|
||||
|
||||
it('delete single line', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.from_line(nil, 1)
|
||||
local range = Range.from_line(nil, 2)
|
||||
range:replace(nil) -- delete lines
|
||||
|
||||
local lines = Range.from_buf_text():lines()
|
||||
@@ -173,7 +173,7 @@ describe('Range', function()
|
||||
|
||||
it('delete multiple lines', function()
|
||||
withbuf({ 'pre line', 'the quick brown fox', 'jumps over a lazy dog', 'post line' }, function()
|
||||
local range = Range.from_lines(nil, 1, 2)
|
||||
local range = Range.from_lines(nil, 2, 3)
|
||||
range:replace(nil) -- delete lines
|
||||
|
||||
local lines = Range.from_buf_text():lines()
|
||||
@@ -187,53 +187,53 @@ describe('Range', function()
|
||||
it('text object: word', function()
|
||||
withbuf({ 'the quick brown fox' }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
assert.are.same('quick ', Range.from_text_object('aw'):text())
|
||||
assert.are.same('quick ', Range.from_motion('aw'):text())
|
||||
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
assert.are.same('quick', Range.from_text_object('iw'):text())
|
||||
assert.are.same('quick', Range.from_motion('iw'):text())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('text object: quote', function()
|
||||
withbuf({ [[the "quick" brown fox]] }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
assert.are.same('"quick"', Range.from_text_object('a"'):text())
|
||||
assert.are.same('"quick"', Range.from_motion('a"'):text())
|
||||
|
||||
vim.fn.setpos('.', { 0, 1, 6, 0 })
|
||||
assert.are.same('quick', Range.from_text_object('i"'):text())
|
||||
assert.are.same('quick', Range.from_motion('i"'):text())
|
||||
end)
|
||||
|
||||
withbuf({ [[the 'quick' brown fox]] }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
assert.are.same("'quick'", Range.from_text_object([[a']]):text())
|
||||
assert.are.same("'quick'", Range.from_motion([[a']]):text())
|
||||
|
||||
vim.fn.setpos('.', { 0, 1, 6, 0 })
|
||||
assert.are.same('quick', Range.from_text_object([[i']]):text())
|
||||
assert.are.same('quick', Range.from_motion([[i']]):text())
|
||||
end)
|
||||
|
||||
withbuf({ [[the `quick` brown fox]] }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
assert.are.same('`quick`', Range.from_text_object([[a`]]):text())
|
||||
assert.are.same('`quick`', Range.from_motion([[a`]]):text())
|
||||
|
||||
vim.fn.setpos('.', { 0, 1, 6, 0 })
|
||||
assert.are.same('quick', Range.from_text_object([[i`]]):text())
|
||||
assert.are.same('quick', Range.from_motion([[i`]]):text())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('text object: block', function()
|
||||
withbuf({ 'this is a {', 'block', '} here' }, function()
|
||||
vim.fn.setpos('.', { 0, 2, 1, 0 })
|
||||
assert.are.same('{\nblock\n}', Range.from_text_object('a{'):text())
|
||||
assert.are.same('{\nblock\n}', Range.from_motion('a{'):text())
|
||||
|
||||
vim.fn.setpos('.', { 0, 2, 1, 0 })
|
||||
assert.are.same('block', Range.from_text_object('i{'):text())
|
||||
assert.are.same('block', Range.from_motion('i{'):text())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('text object: restores cursor position', function()
|
||||
withbuf({ 'this is a {block} here' }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 13, 0 })
|
||||
assert.are.same('{block}', Range.from_text_object('a{'):text())
|
||||
assert.are.same('{block}', Range.from_motion('a{'):text())
|
||||
assert.are.same(vim.api.nvim_win_get_cursor(0), { 1, 12 })
|
||||
end)
|
||||
end)
|
||||
@@ -258,22 +258,18 @@ describe('Range', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
it('line0', function()
|
||||
it('line', function()
|
||||
withbuf({
|
||||
'this is a {',
|
||||
'block',
|
||||
'} here',
|
||||
}, function()
|
||||
local range = Range.new(Pos.new(0, 0, 5), Pos.new(0, 1, 4), 'v')
|
||||
local lfirst = range:line0(0)
|
||||
assert.are.same(5, lfirst.idx0.start)
|
||||
assert.are.same(10, lfirst.idx0.stop)
|
||||
assert.are.same(0, lfirst.lnum)
|
||||
assert.are.same('is a {', lfirst.text())
|
||||
assert.are.same('is a {', lfirst.range():text())
|
||||
assert.are.same(Pos.new(0, 0, 5), lfirst.range().start)
|
||||
assert.are.same(Pos.new(0, 0, 10), lfirst.range().stop)
|
||||
assert.are.same('block', range:line0(1).text())
|
||||
local range = Range.new(Pos.new(0, 1, 6), Pos.new(0, 2, 5), 'v')
|
||||
local lfirst = assert(range:line(1), 'lfirst null')
|
||||
assert.are.same('is a {', lfirst:text())
|
||||
assert.are.same(Pos.new(0, 1, 6), lfirst.start)
|
||||
assert.are.same(Pos.new(0, 1, 11), lfirst.stop)
|
||||
assert.are.same('block', range:line(2):text())
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -297,16 +293,16 @@ describe('Range', function()
|
||||
vim.cmd.normal 'v' -- enter visual mode
|
||||
vim.cmd.normal 'l' -- select one character to the right
|
||||
local range = Range.from_vtext()
|
||||
assert.are.same(range.start, Pos.new(nil, 0, 2))
|
||||
assert.are.same(range.stop, Pos.new(nil, 0, 3))
|
||||
assert.are.same(range.start, Pos.new(nil, 1, 3))
|
||||
assert.are.same(range.stop, Pos.new(nil, 1, 4))
|
||||
assert.are.same(range.mode, 'v')
|
||||
end)
|
||||
end)
|
||||
|
||||
it('from_op_func', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local a = Pos.new(nil, 0, 0)
|
||||
local b = Pos.new(nil, 1, 1)
|
||||
local a = Pos.new(nil, 1, 1)
|
||||
local b = Pos.new(nil, 2, 2)
|
||||
a:save_to_pos "'["
|
||||
b:save_to_pos "']"
|
||||
|
||||
@@ -317,7 +313,7 @@ describe('Range', function()
|
||||
|
||||
range = Range.from_op_func 'line'
|
||||
assert.are.same(range.start, a)
|
||||
assert.are.same(range.stop, Pos.new(nil, 1, Pos.MAX_COL))
|
||||
assert.are.same(range.stop, Pos.new(nil, 2, Pos.MAX_COL))
|
||||
assert.are.same(range.mode, 'V')
|
||||
end)
|
||||
end)
|
||||
@@ -325,8 +321,8 @@ describe('Range', function()
|
||||
it('from_cmd_args', function()
|
||||
local args = { range = 1 }
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local a = Pos.new(nil, 0, 0)
|
||||
local b = Pos.new(nil, 1, 1)
|
||||
local a = Pos.new(nil, 1, 1)
|
||||
local b = Pos.new(nil, 2, 2)
|
||||
a:save_to_pos "'<"
|
||||
b:save_to_pos "'>"
|
||||
|
||||
@@ -341,25 +337,25 @@ describe('Range', function()
|
||||
withbuf({ [[the "quick" brown fox]] }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
local range = Range.find_nearest_quotes()
|
||||
assert.are.same(range.start, Pos.new(nil, 0, 4))
|
||||
assert.are.same(range.stop, Pos.new(nil, 0, 10))
|
||||
assert.are.same(range.start, Pos.new(nil, 1, 5))
|
||||
assert.are.same(range.stop, Pos.new(nil, 1, 11))
|
||||
end)
|
||||
|
||||
withbuf({ [[the 'quick' brown fox]] }, function()
|
||||
vim.fn.setpos('.', { 0, 1, 5, 0 })
|
||||
local range = Range.find_nearest_quotes()
|
||||
assert.are.same(range.start, Pos.new(nil, 0, 4))
|
||||
assert.are.same(range.stop, Pos.new(nil, 0, 10))
|
||||
assert.are.same(range.start, Pos.new(nil, 1, 5))
|
||||
assert.are.same(range.stop, Pos.new(nil, 1, 11))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('smallest', function()
|
||||
local r1 = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 0, 3), 'v')
|
||||
local r2 = Range.new(Pos.new(nil, 0, 2), Pos.new(nil, 0, 4), 'v')
|
||||
local r3 = Range.new(Pos.new(nil, 0, 0), Pos.new(nil, 0, 5), 'v')
|
||||
local r1 = Range.new(Pos.new(nil, 1, 2), Pos.new(nil, 1, 4), 'v')
|
||||
local r2 = Range.new(Pos.new(nil, 1, 3), Pos.new(nil, 1, 5), 'v')
|
||||
local r3 = Range.new(Pos.new(nil, 1, 1), Pos.new(nil, 1, 6), 'v')
|
||||
local smallest = Range.smallest { r1, r2, r3 }
|
||||
assert.are.same(smallest.start, Pos.new(nil, 0, 1))
|
||||
assert.are.same(smallest.stop, Pos.new(nil, 0, 3))
|
||||
assert.are.same(smallest.start, Pos.new(nil, 1, 2))
|
||||
assert.are.same(smallest.stop, Pos.new(nil, 1, 4))
|
||||
end)
|
||||
|
||||
it('clone', function()
|
||||
@@ -381,9 +377,9 @@ describe('Range', function()
|
||||
|
||||
it('to_linewise()', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 1, 3), 'v')
|
||||
local range = Range.new(Pos.new(nil, 1, 2), Pos.new(nil, 2, 4), 'v')
|
||||
local linewise_range = range:to_linewise()
|
||||
assert.are.same(linewise_range.start.col, 0)
|
||||
assert.are.same(linewise_range.start.col, 1)
|
||||
assert.are.same(linewise_range.stop.col, Pos.MAX_COL)
|
||||
assert.are.same(linewise_range.mode, 'V')
|
||||
end)
|
||||
@@ -391,82 +387,133 @@ describe('Range', function()
|
||||
|
||||
it('is_empty', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 0), nil, 'v')
|
||||
local range = Range.new(Pos.new(nil, 1, 1), nil, 'v')
|
||||
assert.is_true(range:is_empty())
|
||||
|
||||
local range2 = Range.new(Pos.new(nil, 0, 0), Pos.new(nil, 0, 1), 'v')
|
||||
local range2 = Range.new(Pos.new(nil, 1, 1), Pos.new(nil, 1, 2), 'v')
|
||||
assert.is_false(range2:is_empty())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('trim_start', function()
|
||||
withbuf({ ' line one', 'line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 0), Pos.new(nil, 0, 9), 'v')
|
||||
local range = Range.new(Pos.new(nil, 1, 1), Pos.new(nil, 1, 10), 'v')
|
||||
local trimmed = range:trim_start()
|
||||
assert.are.same(trimmed.start, Pos.new(nil, 0, 3)) -- should be after the spaces
|
||||
assert.are.same(trimmed.start, Pos.new(nil, 1, 4)) -- should be after the spaces
|
||||
end)
|
||||
end)
|
||||
|
||||
it('trim_stop', function()
|
||||
withbuf({ 'line one ', 'line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 0), Pos.new(nil, 0, 9), 'v')
|
||||
local range = Range.new(Pos.new(nil, 1, 1), Pos.new(nil, 1, 10), 'v')
|
||||
local trimmed = range:trim_stop()
|
||||
assert.are.same(trimmed.stop, Pos.new(nil, 0, 7)) -- should be before the spaces
|
||||
assert.are.same(trimmed.stop, Pos.new(nil, 1, 8)) -- should be before the spaces
|
||||
end)
|
||||
end)
|
||||
|
||||
it('contains', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 0, 3), 'v')
|
||||
local pos = Pos.new(nil, 0, 2)
|
||||
local range = Range.new(Pos.new(nil, 1, 2), Pos.new(nil, 1, 4), 'v')
|
||||
local pos = Pos.new(nil, 1, 3)
|
||||
assert.is_true(range:contains(pos))
|
||||
|
||||
pos = Pos.new(nil, 0, 4) -- outside of range
|
||||
pos = Pos.new(nil, 1, 5) -- outside of range
|
||||
assert.is_false(range:contains(pos))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('difference', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range_outer = Range.new(Pos.new(nil, 2, 1), Pos.new(nil, 2, 12), 'v')
|
||||
local range_inner = Range.new(Pos.new(nil, 2, 5), Pos.new(nil, 2, 8), 'v')
|
||||
|
||||
assert.are.same(range_outer:text(), 'and line two')
|
||||
assert.are.same(range_inner:text(), 'line')
|
||||
|
||||
local left, right = range_outer:difference(range_inner)
|
||||
assert.are.same(left:text(), 'and ')
|
||||
assert.are.same(right:text(), ' two')
|
||||
|
||||
left, right = range_inner:difference(range_outer)
|
||||
assert.are.same(left:text(), 'and ')
|
||||
assert.are.same(right:text(), ' two')
|
||||
|
||||
left, right = range_outer:difference(range_outer)
|
||||
assert.are.same(left:is_empty(), true)
|
||||
assert.are.same(left:text(), '')
|
||||
assert.are.same(right:is_empty(), true)
|
||||
assert.are.same(right:text(), '')
|
||||
end)
|
||||
end)
|
||||
|
||||
it('length', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 2, 4), Pos.new(nil, 2, 9), 'v')
|
||||
assert.are.same(range:length(), #range:text())
|
||||
|
||||
range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 2, 9), 'v')
|
||||
assert.are.same(range:length(), #range:text())
|
||||
end)
|
||||
end)
|
||||
|
||||
it('sub', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 2, 4), Pos.new(nil, 2, 9), 'v')
|
||||
assert.are.same(range:text(), ' line ')
|
||||
assert.are.same(range:sub(1, -1):text(), ' line ')
|
||||
assert.are.same(range:sub(2, -2):text(), 'line')
|
||||
assert.are.same(range:sub(1, 5):text(), ' line')
|
||||
assert.are.same(range:sub(2, 5):text(), 'line')
|
||||
assert.are.same(range:sub(20, 25):text(), '')
|
||||
end)
|
||||
end)
|
||||
|
||||
it('shrink', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 1, 3), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 3), Pos.new(nil, 3, 5), 'v')
|
||||
local shrunk = range:shrink(1)
|
||||
assert.are.same(shrunk.start, Pos.new(nil, 0, 2))
|
||||
assert.are.same(shrunk.stop, Pos.new(nil, 1, 2))
|
||||
assert.are.same(shrunk.start, Pos.new(nil, 2, 4))
|
||||
assert.are.same(shrunk.stop, Pos.new(nil, 3, 4))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('must_shrink', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.new(Pos.new(nil, 0, 1), Pos.new(nil, 1, 3), 'v')
|
||||
local range = Range.new(Pos.new(nil, 2, 3), Pos.new(nil, 3, 5), 'v')
|
||||
local shrunk = range:must_shrink(1)
|
||||
assert.are.same(shrunk.start, Pos.new(nil, 0, 2))
|
||||
assert.are.same(shrunk.stop, Pos.new(nil, 1, 2))
|
||||
assert.are.same(shrunk.start, Pos.new(nil, 2, 4))
|
||||
assert.are.same(shrunk.stop, Pos.new(nil, 3, 4))
|
||||
|
||||
assert.has.error(function() range:must_shrink(100) end, 'error in Range:must_shrink: Range:shrink() returned nil')
|
||||
assert.has.error(
|
||||
function() range:must_shrink(100) end,
|
||||
'error in Range:must_shrink: Range:shrink() returned nil'
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('set_visual_selection', function()
|
||||
withbuf({ 'line one', 'and line two' }, function()
|
||||
local range = Range.from_lines(nil, 0, 1)
|
||||
local range = Range.from_lines(nil, 1, 2)
|
||||
range:set_visual_selection()
|
||||
|
||||
assert.are.same(Pos.from_pos 'v', Pos.new(nil, 0, 0))
|
||||
assert.are.same(Pos.from_pos '.', Pos.new(nil, 1, 11))
|
||||
assert.are.same(Pos.from_pos 'v', Pos.new(nil, 1, 1))
|
||||
-- Since the selection is 'V' (instead of 'v'), the end
|
||||
-- selects one character past the end:
|
||||
assert.are.same(Pos.from_pos '.', Pos.new(nil, 2, 13))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('selections set to past the EOL should not error', function()
|
||||
withbuf({ 'Rg SET NAMES' }, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 0, 3), Pos.new(b, 0, 12), 'v')
|
||||
local r = Range.new(Pos.new(b, 1, 4), Pos.new(b, 1, 13), 'v')
|
||||
r:replace 'bleh'
|
||||
assert.are.same({ 'Rg bleh' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
end)
|
||||
|
||||
withbuf({ 'Rg SET NAMES' }, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 0, 3), Pos.new(b, 0, 11), 'v')
|
||||
local r = Range.new(Pos.new(b, 1, 4), Pos.new(b, 1, 12), 'v')
|
||||
r:replace 'bleh'
|
||||
assert.are.same({ 'Rg bleh' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
end)
|
||||
@@ -475,13 +522,19 @@ describe('Range', function()
|
||||
it('replace updates Range.stop: same line', function()
|
||||
withbuf({ 'The quick brown fox jumps over the lazy dog' }, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 0, 4), Pos.new(b, 0, 8), 'v')
|
||||
local r = Range.new(Pos.new(b, 1, 5), Pos.new(b, 1, 9), 'v')
|
||||
|
||||
r:replace 'bleh1'
|
||||
assert.are.same({ 'The bleh1 brown fox jumps over the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
assert.are.same(
|
||||
{ 'The bleh1 brown fox jumps over the lazy dog' },
|
||||
vim.api.nvim_buf_get_lines(b, 0, -1, false)
|
||||
)
|
||||
|
||||
r:replace 'bleh2'
|
||||
assert.are.same({ 'The bleh2 brown fox jumps over the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
assert.are.same(
|
||||
{ 'The bleh2 brown fox jumps over the lazy dog' },
|
||||
vim.api.nvim_buf_get_lines(b, 0, -1, false)
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -491,14 +544,21 @@ describe('Range', function()
|
||||
'over the lazy dog',
|
||||
}, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 0, 20), Pos.new(b, 1, 3), 'v')
|
||||
local r = Range.new(Pos.new(b, 1, 21), Pos.new(b, 2, 4), 'v')
|
||||
assert.are.same({ 'jumps', 'over' }, r:lines())
|
||||
|
||||
r:replace 'bleh1'
|
||||
assert.are.same({ 'The quick brown fox bleh1 the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
assert.are.same(
|
||||
{ 'The quick brown fox bleh1 the lazy dog' },
|
||||
vim.api.nvim_buf_get_lines(b, 0, -1, false)
|
||||
)
|
||||
assert.are.same({ 'bleh1' }, r:lines())
|
||||
|
||||
r:replace 'blehGoo2'
|
||||
assert.are.same({ 'The quick brown fox blehGoo2 the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false))
|
||||
assert.are.same(
|
||||
{ 'The quick brown fox blehGoo2 the lazy dog' },
|
||||
vim.api.nvim_buf_get_lines(b, 0, -1, false)
|
||||
)
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -511,7 +571,7 @@ describe('Range', function()
|
||||
'the lazy dog',
|
||||
}, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 1, 0), Pos.new(b, 3, Pos.MAX_COL), 'V')
|
||||
local r = Range.new(Pos.new(b, 2, 1), Pos.new(b, 4, Pos.MAX_COL), 'V')
|
||||
assert.are.same({ 'fox', 'jumps', 'over' }, r:lines())
|
||||
|
||||
r:replace { 'bleh1', 'bleh2' }
|
||||
@@ -540,7 +600,7 @@ describe('Range', function()
|
||||
'the lazy dog',
|
||||
}, function()
|
||||
local b = vim.api.nvim_get_current_buf()
|
||||
local r = Range.new(Pos.new(b, 1, 0), Pos.new(b, 3, Pos.MAX_COL), 'V')
|
||||
local r = Range.new(Pos.new(b, 2, 1), Pos.new(b, 4, Pos.MAX_COL), 'V')
|
||||
assert.are.same({ 'fox', 'jumps', 'over' }, r:lines())
|
||||
|
||||
r:replace(nil)
|
||||
|
||||
135
spec/renderer_spec.lua
Normal file
135
spec/renderer_spec.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
local R = require 'u.renderer'
|
||||
local withbuf = loadfile './spec/withbuf.lua'()
|
||||
|
||||
local function getlines() return vim.api.nvim_buf_get_lines(0, 0, -1, true) end
|
||||
|
||||
describe('Renderer', function()
|
||||
it('should render text in an empty buffer', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render { 'hello', ' ', 'world' }
|
||||
assert.are.same(getlines(), { 'hello world' })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should result in the correct text after repeated renders', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render { 'hello', ' ', 'world' }
|
||||
assert.are.same(getlines(), { 'hello world' })
|
||||
|
||||
r:render { 'goodbye', ' ', 'world' }
|
||||
assert.are.same(getlines(), { 'goodbye world' })
|
||||
|
||||
r:render { 'hello', ' ', 'universe' }
|
||||
assert.are.same(getlines(), { 'hello universe' })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should handle tags correctly', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render {
|
||||
R.h('text', { hl = 'HighlightGroup' }, 'hello '),
|
||||
R.h('text', { hl = 'HighlightGroup' }, 'world'),
|
||||
}
|
||||
assert.are.same(getlines(), { 'hello world' })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should reconcile added lines', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render { 'line 1', '\n', 'line 2' }
|
||||
assert.are.same(getlines(), { 'line 1', 'line 2' })
|
||||
|
||||
-- Add a new line:
|
||||
r:render { 'line 1', '\n', 'line 2\n', 'line 3' }
|
||||
assert.are.same(getlines(), { 'line 1', 'line 2', 'line 3' })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should reconcile deleted lines', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render { 'line 1', '\nline 2', '\nline 3' }
|
||||
assert.are.same(getlines(), { 'line 1', 'line 2', 'line 3' })
|
||||
|
||||
-- Remove a line:
|
||||
r:render { 'line 1', '\nline 3' }
|
||||
assert.are.same(getlines(), { 'line 1', 'line 3' })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should handle multiple nested elements', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render {
|
||||
R.h('text', {}, {
|
||||
'first line',
|
||||
}),
|
||||
'\n',
|
||||
R.h('text', {}, 'second line'),
|
||||
}
|
||||
assert.are.same(getlines(), { 'first line', 'second line' })
|
||||
|
||||
r:render {
|
||||
R.h('text', {}, 'updated first line'),
|
||||
'\n',
|
||||
R.h('text', {}, 'third line'),
|
||||
}
|
||||
assert.are.same(getlines(), { 'updated first line', 'third line' })
|
||||
end)
|
||||
end)
|
||||
|
||||
--
|
||||
-- get_pos_infos
|
||||
--
|
||||
|
||||
it('should return no extmarks for an empty buffer', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
local pos_infos = r:get_pos_infos { 0, 0 }
|
||||
assert.are.same(pos_infos, {})
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should return correct extmark for a given position', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render {
|
||||
R.h('text', { hl = 'HighlightGroup1' }, 'Hello'),
|
||||
R.h('text', { hl = 'HighlightGroup2' }, ' World'),
|
||||
}
|
||||
|
||||
local pos_infos = r:get_pos_infos { 0, 2 }
|
||||
|
||||
assert.are.same(#pos_infos, 1)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup1')
|
||||
assert.are.same(pos_infos[1].extmark.start, { 0, 0 })
|
||||
assert.are.same(pos_infos[1].extmark.stop, { 0, 5 })
|
||||
end)
|
||||
end)
|
||||
|
||||
it('should return multiple extmarks for overlapping text', function()
|
||||
withbuf({}, function()
|
||||
local r = R.Renderer.new(0)
|
||||
r:render {
|
||||
R.h('text', { hl = 'HighlightGroup1' }, {
|
||||
'Hello',
|
||||
R.h(
|
||||
'text',
|
||||
{ hl = 'HighlightGroup2', extmark = { hl_group = 'HighlightGroup2' } },
|
||||
' World'
|
||||
),
|
||||
}),
|
||||
}
|
||||
|
||||
local pos_infos = r:get_pos_infos { 0, 5 }
|
||||
|
||||
assert.are.same(#pos_infos, 2)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup2')
|
||||
assert.are.same(pos_infos[2].tag.attributes.hl, 'HighlightGroup1')
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
206
spec/tracker_spec.lua
Normal file
206
spec/tracker_spec.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
local tracker = require 'u.tracker'
|
||||
local Signal = tracker.Signal
|
||||
local ExecutionContext = tracker.ExecutionContext
|
||||
|
||||
describe('Signal', function()
|
||||
local signal
|
||||
|
||||
before_each(function() signal = Signal:new(0, 'testSignal') end)
|
||||
|
||||
it('should initialize with correct parameters', function()
|
||||
assert.is.equal(signal.value, 0)
|
||||
assert.is.equal(signal.name, 'testSignal')
|
||||
assert.is.not_nil(signal.subscribers)
|
||||
assert.is.equal(#signal.subscribers, 0)
|
||||
assert.is.equal(signal.changing, false)
|
||||
end)
|
||||
|
||||
it('should set new value and notify subscribers', function()
|
||||
local called = false
|
||||
signal:subscribe(function(value)
|
||||
called = true
|
||||
assert.is.equal(value, 42)
|
||||
end)
|
||||
|
||||
signal:set(42)
|
||||
assert.is.equal(called, true)
|
||||
end)
|
||||
|
||||
it('should not notify subscribers during circular dependency', function()
|
||||
signal.changing = true
|
||||
local notified = false
|
||||
|
||||
signal:subscribe(function() notified = true end)
|
||||
|
||||
signal:set(42)
|
||||
assert.is.equal(notified, false) -- No notification should occur
|
||||
end)
|
||||
|
||||
it('should get current value', function()
|
||||
signal:set(100)
|
||||
assert.is.equal(signal:get(), 100)
|
||||
end)
|
||||
|
||||
it('should update value with function', function()
|
||||
signal:set(10)
|
||||
signal:update(function(value) return value * 2 end)
|
||||
assert.is.equal(signal:get(), 20)
|
||||
end)
|
||||
|
||||
it('should dispose subscribers', function()
|
||||
local called = false
|
||||
local unsubscribe = signal:subscribe(function() called = true end)
|
||||
|
||||
unsubscribe()
|
||||
signal:set(10)
|
||||
assert.is.equal(called, false) -- Should not be notified
|
||||
end)
|
||||
|
||||
describe('Signal:map', function()
|
||||
it('should transform the signal value', function()
|
||||
local test_signal = Signal:new(5)
|
||||
local mapped_signal = test_signal:map(function(value) return value * 2 end)
|
||||
|
||||
assert.is.equal(mapped_signal:get(), 10) -- Initial transformation
|
||||
test_signal:set(10)
|
||||
assert.is.equal(mapped_signal:get(), 20) -- Updated transformation
|
||||
end)
|
||||
|
||||
it('should handle empty transformations', function()
|
||||
local test_signal = Signal:new(nil)
|
||||
local mapped_signal = test_signal:map(function(value) return value or 'default' end)
|
||||
|
||||
assert.is.equal(mapped_signal:get(), 'default') -- Return default
|
||||
test_signal:set 'new value'
|
||||
assert.is.equal(mapped_signal:get(), 'new value') -- Return new value
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('Signal:filter', function()
|
||||
it('should only emit values that pass the filter', function()
|
||||
local test_signal = Signal:new(5)
|
||||
local filtered_signal = test_signal:filter(function(value) return value > 10 end)
|
||||
|
||||
assert.is.equal(filtered_signal:get(), nil) -- Initial value should not pass
|
||||
test_signal:set(15)
|
||||
assert.is.equal(filtered_signal:get(), 15) -- Now filtered
|
||||
test_signal:set(8)
|
||||
assert.is.equal(filtered_signal:get(), 15) -- Does not pass the filter
|
||||
end)
|
||||
|
||||
it('should handle empty initial values', function()
|
||||
local test_signal = Signal:new(nil)
|
||||
local filtered_signal = test_signal:filter(function(value) return value ~= nil end)
|
||||
|
||||
assert.is.equal(filtered_signal:get(), nil) -- Should be nil
|
||||
test_signal:set(10)
|
||||
assert.is.equal(filtered_signal:get(), 10) -- Should pass now
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('create_memo', function()
|
||||
it('should compute a derived value and update when dependencies change', function()
|
||||
local test_signal = Signal:new(2)
|
||||
local memoized_signal = tracker.create_memo(function() return test_signal:get() * 2 end)
|
||||
|
||||
assert.is.equal(memoized_signal:get(), 4) -- Initially compute 2 * 2
|
||||
|
||||
test_signal:set(3)
|
||||
assert.is.equal(memoized_signal:get(), 6) -- Update to 3 * 2 = 6
|
||||
|
||||
test_signal:set(5)
|
||||
assert.is.equal(memoized_signal:get(), 10) -- Update to 5 * 2 = 10
|
||||
end)
|
||||
|
||||
it('should not recompute if the dependencies do not change', function()
|
||||
local call_count = 0
|
||||
local test_signal = Signal:new(10)
|
||||
local memoized_signal = tracker.create_memo(function()
|
||||
call_count = call_count + 1
|
||||
return test_signal:get() + 1
|
||||
end)
|
||||
|
||||
assert.is.equal(memoized_signal:get(), 11) -- Compute first value
|
||||
assert.is.equal(call_count, 1) -- Should compute once
|
||||
|
||||
memoized_signal:get() -- Call again, should use memoized value
|
||||
assert.is.equal(call_count, 1) -- Still should only be one call
|
||||
|
||||
test_signal:set(10) -- Set the same value
|
||||
assert.is.equal(memoized_signal:get(), 11)
|
||||
assert.is.equal(call_count, 2)
|
||||
|
||||
test_signal:set(20)
|
||||
assert.is.equal(memoized_signal:get(), 21)
|
||||
assert.is.equal(call_count, 3)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('create_effect', function()
|
||||
it('should track changes and execute callback', function()
|
||||
local test_signal = Signal:new(5)
|
||||
local call_count = 0
|
||||
|
||||
tracker.create_effect(function()
|
||||
test_signal:get() -- track as a dependency
|
||||
call_count = call_count + 1
|
||||
end)
|
||||
|
||||
assert.is.equal(call_count, 1)
|
||||
test_signal:set(10)
|
||||
assert.is.equal(call_count, 2)
|
||||
end)
|
||||
|
||||
it('should clean up signals and not call after dispose', function()
|
||||
local test_signal = Signal:new(5)
|
||||
local call_count = 0
|
||||
|
||||
local unsubscribe = tracker.create_effect(function()
|
||||
call_count = call_count + 1
|
||||
return test_signal:get() * 2
|
||||
end)
|
||||
|
||||
assert.is.equal(call_count, 1) -- Initially calls
|
||||
unsubscribe() -- Unsubscribe the effect
|
||||
test_signal:set(10) -- Update signal value
|
||||
assert.is.equal(call_count, 1) -- Callback should not be called again
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ExecutionContext', function()
|
||||
local context
|
||||
|
||||
before_each(function() context = ExecutionContext:new() end)
|
||||
|
||||
it('should initialize a new context', function()
|
||||
assert.is.table(context.signals)
|
||||
assert.is.table(context.subscribers)
|
||||
end)
|
||||
|
||||
it('should track signals', function()
|
||||
local signal = Signal:new(0)
|
||||
context:track(signal)
|
||||
|
||||
assert.is.equal(next(context.signals), signal) -- Check if signal is tracked
|
||||
end)
|
||||
|
||||
it('should subscribe to signals', function()
|
||||
local signal = Signal:new(0)
|
||||
local callback_called = false
|
||||
|
||||
context:track(signal)
|
||||
context:subscribe(function() callback_called = true end)
|
||||
|
||||
signal:set(100)
|
||||
assert.is.equal(callback_called, true) -- Callback should be called
|
||||
end)
|
||||
|
||||
it('should dispose tracked signals', function()
|
||||
local signal = Signal:new(0)
|
||||
context:track(signal)
|
||||
|
||||
context:dispose()
|
||||
assert.is.falsy(next(context.signals)) -- Should not have any tracked signals
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user