summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/run.lua225
1 files changed, 224 insertions, 1 deletions
diff --git a/tests/run.lua b/tests/run.lua
index 7431de5..d24f3f0 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -2883,6 +2883,229 @@ test("Boundary-before-any outcomes preserve the original position", function()
same(empty_origin, empty_outcome.endpoint)
end)
+test("MotionPlanFactory samples live search scope into each plan", function()
+ local host = MemoryHost.new({
+ configuration = { search_current_line_only = false },
+ })
+ local service = policy.new(host)
+ local factory = motion_plan.new(service)
+ local target_match = target_plan.build(target("a"), matching_policy())
+
+ local buffer_plan = factory:build(target_match, "f")
+ same(domain.SearchScope.BUFFER, buffer_plan.search_scope)
+
+ host:set_configuration("search_current_line_only", true)
+ local line_plan = factory:build(target_match, "f")
+ same(domain.SearchScope.CURRENT_LINE, line_plan.search_scope)
+ same(domain.SearchScope.BUFFER, buffer_plan.search_scope)
+end)
+
+test("DestinationEngine matches the required basic TILL sequences", function()
+ local view = text_topology.new({ "poge huga hiyo poyo" }, "utf-8")
+ local engine = destination_engine.new()
+ local till_h = motion_plan.build(
+ target_plan.build(target("h"), matching_policy()),
+ "t"
+ )
+
+ local first_h = engine:calculate(
+ view,
+ domain.Position.new(1, 1),
+ till_h,
+ 1,
+ true
+ )
+ same(domain.Position.new(1, 5), first_h.endpoint)
+ local second_h = engine:calculate(view, first_h.endpoint, till_h, 1, false)
+ same(domain.Position.new(1, 10), second_h.endpoint)
+
+ local till_o = motion_plan.build(
+ target_plan.build(target("o"), matching_policy()),
+ "t"
+ )
+ local first_o = engine:calculate(
+ view,
+ domain.Position.new(1, 14),
+ till_o,
+ 1,
+ true
+ )
+ same(domain.Position.new(1, 16), first_o.endpoint)
+ local second_o = engine:calculate(view, first_o.endpoint, till_o, 1, false)
+ same(domain.Position.new(1, 18), second_o.endpoint)
+end)
+
+test("Buffer-wide destinations cross lines and ignore ambient wrapping", function()
+ local view = text_topology.new({
+ "foo bar baz",
+ "poge huga hiyo poyo",
+ }, "utf-8")
+ local target_match = target_plan.build(target("a"), matching_policy())
+ local engine = destination_engine.new()
+ local forward = motion_plan.build(target_match, "f", "buffer")
+ local backward = motion_plan.build(target_match, "F", "buffer")
+ local current = domain.Position.new(1, 1)
+ local expected = {
+ domain.Position.new(1, 6),
+ domain.Position.new(1, 10),
+ domain.Position.new(2, 9),
+ domain.Position.new(1, 10),
+ domain.Position.new(1, 6),
+ }
+ local plans = { forward, forward, forward, backward, backward }
+
+ for index, plan in ipairs(plans) do
+ local outcome = engine:calculate(view, current, plan, 1, index == 1)
+ same(domain.SearchStatus.COMPLETE, outcome.status)
+ same(expected[index], outcome.endpoint)
+ current = outcome.endpoint
+ end
+
+ local line_forward = motion_plan.build(target_match, "f", "current_line")
+ local line_last = engine:calculate(
+ view,
+ domain.Position.new(1, 6),
+ line_forward,
+ 1,
+ false
+ )
+ same(domain.Position.new(1, 10), line_last.endpoint)
+ local line_boundary = engine:calculate(
+ view,
+ line_last.endpoint,
+ line_forward,
+ 1,
+ false
+ )
+ same(domain.SearchStatus.BOUNDARY_BEFORE_ANY, line_boundary.status)
+ same(line_last.endpoint, line_boundary.endpoint)
+
+ local saved_wrapscan = vim.o.wrapscan
+ local outcomes = {}
+ for index, wrapscan in ipairs({ false, true }) do
+ vim.o.wrapscan = wrapscan
+ outcomes[index] = engine:calculate(
+ view,
+ domain.Position.new(2, 9),
+ forward,
+ 1,
+ false
+ )
+ end
+ vim.o.wrapscan = saved_wrapscan
+ for _, outcome in ipairs(outcomes) do
+ same(domain.SearchStatus.BOUNDARY_BEFORE_ANY, outcome.status)
+ same(domain.Position.new(2, 9), outcome.endpoint)
+ end
+end)
+
+test("Destination requests retain their initial match-start region", function()
+ local view = text_topology.new({ "ax", "ax" }, "utf-8")
+ local target_match = target_plan.build(target("x"), matching_policy())
+ local plan = motion_plan.build(
+ target_match,
+ "f",
+ "current_line",
+ domain.EndpointPolicy.VISUAL_EXCLUSIVE
+ )
+ local outcome = destination_engine.calculate(
+ view,
+ domain.Position.new(1, 1),
+ plan,
+ 2,
+ true
+ )
+
+ same(domain.SearchStatus.BOUNDARY_AFTER_PARTIAL, outcome.status)
+ same(domain.Position.new(2, 1), outcome.endpoint)
+ same(1, outcome.successful_steps)
+end)
+
+test("Multibyte destination sequences stay on valid byte starts", function()
+ local expected_columns = {
+ ["utf-8"] = 4,
+ ["cp932"] = 3,
+ ["euc-jp"] = 3,
+ }
+
+ for encoding, expected_column in pairs(expected_columns) do
+ local view = text_topology.new({
+ "a",
+ MIGEMO_HIRAGANA_A .. "a",
+ "a",
+ }, encoding)
+ local target_match = target_plan.build(target("a"), matching_policy())
+ local forward = motion_plan.build(target_match, "f", "buffer")
+ local backward = motion_plan.build(target_match, "F", "buffer")
+ local plans = { forward, forward, backward, backward }
+ local expected = {
+ domain.Position.new(2, expected_column),
+ domain.Position.new(3, 1),
+ domain.Position.new(2, expected_column),
+ domain.Position.new(1, 1),
+ }
+ local current = domain.Position.new(1, 1)
+
+ for index, plan in ipairs(plans) do
+ local outcome = destination_engine.calculate(
+ view,
+ current,
+ plan,
+ 1,
+ index == 1
+ )
+ same(domain.SearchStatus.COMPLETE, outcome.status, encoding)
+ same(expected[index], outcome.endpoint, encoding)
+ truthy(view:is_character_start(outcome.endpoint), encoding)
+ current = outcome.endpoint
+ end
+
+ local till = motion_plan.build(target_match, "t", "buffer")
+ local till_outcome = destination_engine.calculate(
+ view,
+ domain.Position.new(1, 1),
+ till,
+ 1,
+ true
+ )
+ same(domain.Position.new(2, 1), till_outcome.endpoint, encoding)
+ truthy(view:is_valid_cursor_position(till_outcome.endpoint), encoding)
+ end
+end)
+
+test("DestinationEngine leaves cursor and sequence state unchanged", function()
+ local state, transitions = fresh_sequence_state()
+ local target_value = target("a")
+ transitions:BeginAcquisition("n", "f")
+ transitions:CommitAcquiredTarget("n", target_value)
+ transitions:CommitCommandSuccess("n", domain.Position.new(1, 1), false)
+
+ local host = MemoryHost.new({
+ buffer_lines = { "abaca" },
+ cursor = { line = 1, byte_column = 1 },
+ effective_encoding = "utf-8",
+ })
+ local view = text_topology.from_host(host)
+ local origin = host:read_cursor()
+ host:clear_operations()
+ local state_before = state:to_table()
+ local plan = motion_plan.build(
+ target_plan.build(target_value, matching_policy()),
+ "f",
+ "buffer",
+ "regular"
+ )
+ local plan_before = plan:to_table()
+
+ local outcome = destination_engine.calculate(view, origin, plan, 2, true)
+ same(domain.SearchStatus.COMPLETE, outcome.status)
+ same(domain.Position.new(1, 5), outcome.endpoint)
+ same(0, #host:operations())
+ truthy(vim.deep_equal(state_before, state:to_table()))
+ truthy(vim.deep_equal(plan_before, plan:to_table()))
+ same(origin, host:read_cursor())
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then
@@ -2892,4 +3115,4 @@ for _, item in ipairs(tests) do
passed = passed + 1
end
-io.stdout:write(string.format("Phase 7: %d tests passed\n", passed))
+io.stdout:write(string.format("Phase 8: %d tests passed\n", passed))