diff options
Diffstat (limited to 'test/unit/marktree_spec.lua')
-rw-r--r-- | test/unit/marktree_spec.lua | 358 |
1 files changed, 231 insertions, 127 deletions
diff --git a/test/unit/marktree_spec.lua b/test/unit/marktree_spec.lua index 3f9dd4df12..b0a861727d 100644 --- a/test/unit/marktree_spec.lua +++ b/test/unit/marktree_spec.lua @@ -1,15 +1,17 @@ -local helpers = require("test.unit.helpers")(after_each) +local helpers = require('test.unit.helpers')(after_each) local itp = helpers.gen_itp(it) -local ffi = helpers.ffi -local eq = helpers.eq -local ok = helpers.ok +local ffi = helpers.ffi +local eq = helpers.eq +local ok = helpers.ok -local lib = helpers.cimport("./src/nvim/marktree.h") +local lib = helpers.cimport('./src/nvim/marktree.h') local function tablelength(t) local count = 0 - for _ in pairs(t) do count = count + 1 end + for _ in pairs(t) do + count = count + 1 + end return count end @@ -32,15 +34,14 @@ local function shadoworder(tree, shadow, iter, giveorder) local mark = lib.marktree_itr_current(iter) local id = tonumber(mark.id) local spos = shadow[id] - if (mark.pos.row ~= spos[1] or mark.pos.col ~= spos[2]) then - error("invalid pos for "..id..":("..mark.pos.row..", "..mark.pos.col..") instead of ("..spos[1]..", "..spos[2]..")") - end + eq(mark.pos.row, spos[1], mark.id) + eq(mark.pos.col, spos[2], mark.id) if lib.mt_right_test(mark) ~= spos[3] then - error("invalid gravity for "..id..":("..mark.pos.row..", "..mark.pos.col..")") + error('invalid gravity for ' .. id .. ':(' .. mark.pos.row .. ', ' .. mark.pos.col .. ')') end if count > 0 then if not pos_leq(last, spos) then - error("DISORDER") + error('DISORDER') end end count = count + 1 @@ -52,17 +53,21 @@ local function shadoworder(tree, shadow, iter, giveorder) until not lib.marktree_itr_next(tree, iter) local shadowlen = tablelength(shadow) if shadowlen ~= count then - error("missed some keys? (shadow "..shadowlen..", tree "..count..")") + error('missed some keys? (shadow ' .. shadowlen .. ', tree ' .. count .. ')') end return id2pos, pos2id end local function shadowsplice(shadow, start, old_extent, new_extent) - local old_end = {start[1] + old_extent[1], - (old_extent[1] == 0 and start[2] or 0) + old_extent[2]} - local new_end = {start[1] + new_extent[1], - (new_extent[1] == 0 and start[2] or 0) + new_extent[2]} - local delta = {new_end[1] - old_end[1], new_end[2] - old_end[2]} + local old_end = { + start[1] + old_extent[1], + (old_extent[1] == 0 and start[2] or 0) + old_extent[2], + } + local new_end = { + start[1] + new_extent[1], + (new_extent[1] == 0 and start[2] or 0) + new_extent[2], + } + local delta = { new_end[1] - old_end[1], new_end[2] - old_end[2] } for _, pos in pairs(shadow) do if pos_leq(start, pos) then if pos_leq(pos, old_end) then @@ -82,23 +87,31 @@ local function shadowsplice(shadow, start, old_extent, new_extent) end end -local function dosplice(tree, shadow, start, old_extent, new_extent) - lib.marktree_splice(tree, start[1], start[2], old_extent[1], old_extent[2], new_extent[1], new_extent[2]) - shadowsplice(shadow, start, old_extent, new_extent) +local function dosplice(tree, shadow, start, old, new) + lib.marktree_splice(tree, start[1], start[2], old[1], old[2], new[1], new[2]) + shadowsplice(shadow, start, old, new) end local ns = 10 local last_id = nil -local function put(tree, row, col, gravitate, end_row, end_col, end_gravitate) +local function put(tree, row, col, gravity, end_row, end_col, end_gravity) last_id = last_id + 1 local my_id = last_id end_row = end_row or -1 end_col = end_col or -1 - end_gravitate = end_gravitate or false + end_gravity = end_gravity or false + + lib.marktree_put_test(tree, ns, my_id, row, col, gravity, end_row, end_col, end_gravity, false) + return my_id +end - lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, end_row, end_col, end_gravitate); +local function put_meta(tree, row, col, gravitate, meta) + last_id = last_id + 1 + local my_id = last_id + + lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, -1, -1, false, meta) return my_id end @@ -108,18 +121,18 @@ describe('marktree', function() end) itp('works', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit local shadow = {} - local iter = ffi.new("MarkTreeIter[1]") - local iter2 = ffi.new("MarkTreeIter[1]") + local iter = ffi.new('MarkTreeIter[1]') + local iter2 = ffi.new('MarkTreeIter[1]') - for i = 1,100 do - for j = 1,100 do - local gravitate = (i%2) > 0 + for i = 1, 100 do + for j = 1, 100 do + local gravitate = (i % 2) > 0 local id = put(tree, j, i, gravitate) ok(id > 0) eq(nil, shadow[id]) - shadow[id] = {j,i,gravitate} + shadow[id] = { j, i, gravitate } end -- checking every insert is too slow, but this is ok lib.marktree_check(tree) @@ -133,7 +146,7 @@ describe('marktree', function() eq({}, pos2id) -- not set if not requested eq({}, id2pos) - for i,ipos in pairs(shadow) do + for i, ipos in pairs(shadow) do local p = lib.marktree_lookup_ns(tree, ns, i, false, iter) eq(ipos[1], p.pos.row) eq(ipos[2], p.pos.col) @@ -145,7 +158,7 @@ describe('marktree', function() -- local k2 = lib.marktree_itr_current(iter) end - for i,ipos in pairs(shadow) do + for i, ipos in pairs(shadow) do lib.marktree_itr_get(tree, ipos[1], ipos[2], iter) local k = lib.marktree_itr_current(iter) eq(i, tonumber(k.id)) @@ -160,9 +173,9 @@ describe('marktree', function() shadow[tonumber(del.id)] = nil shadoworder(tree, shadow, iter) - for _, ci in ipairs({0,-1,1,-2,2,-10,10}) do - for i = 1,100 do - lib.marktree_itr_get(tree, i, 50+ci, iter) + for _, ci in ipairs({ 0, -1, 1, -2, 2, -10, 10 }) do + for i = 1, 100 do + lib.marktree_itr_get(tree, i, 50 + ci, iter) local k = lib.marktree_itr_current(iter) local id = tonumber(k.id) eq(shadow[id][1], k.pos.row) @@ -177,14 +190,14 @@ describe('marktree', function() -- NB: this is quite rudimentary. We rely on -- functional tests exercising splicing quite a bit lib.marktree_check(tree) - dosplice(tree, shadow, {2,2}, {0,5}, {1, 2}) + dosplice(tree, shadow, { 2, 2 }, { 0, 5 }, { 1, 2 }) lib.marktree_check(tree) shadoworder(tree, shadow, iter) - dosplice(tree, shadow, {30,2}, {30,5}, {1, 2}) + dosplice(tree, shadow, { 30, 2 }, { 30, 5 }, { 1, 2 }) lib.marktree_check(tree) shadoworder(tree, shadow, iter) - dosplice(tree, shadow, {5,3}, {0,2}, {0, 5}) + dosplice(tree, shadow, { 5, 3 }, { 0, 2 }, { 0, 5 }) shadoworder(tree, shadow, iter) lib.marktree_check(tree) @@ -209,7 +222,7 @@ describe('marktree', function() -- Check iterator validity for 2 specific edge cases: -- https://github.com/neovim/neovim/pull/14719 lib.marktree_clear(tree) - for i = 1,20 do + for i = 1, 20 do put(tree, i, i, false) end @@ -224,45 +237,59 @@ describe('marktree', function() itp("'intersect_mov' function works correctly", function() local function mov(x, y, w) - local xa = ffi.new("uint64_t[?]", #x) - for i, xi in ipairs(x) do xa[i-1] = xi end - local ya = ffi.new("uint64_t[?]", #y) - for i, yi in ipairs(y) do ya[i-1] = yi end - local wa = ffi.new("uint64_t[?]", #w) - for i, wi in ipairs(w) do wa[i-1] = wi end + local xa = ffi.new('uint64_t[?]', #x) + for i, xi in ipairs(x) do + xa[i - 1] = xi + end + local ya = ffi.new('uint64_t[?]', #y) + for i, yi in ipairs(y) do + ya[i - 1] = yi + end + local wa = ffi.new('uint64_t[?]', #w) + for i, wi in ipairs(w) do + wa[i - 1] = wi + end local dummy_size = #x + #y + #w - local wouta = ffi.new("uint64_t[?]", dummy_size) - local douta = ffi.new("uint64_t[?]", dummy_size) - local wsize = ffi.new("size_t[1]") + local wouta = ffi.new('uint64_t[?]', dummy_size) + local douta = ffi.new('uint64_t[?]', dummy_size) + local wsize = ffi.new('size_t[1]') wsize[0] = dummy_size - local dsize = ffi.new("size_t[1]") + local dsize = ffi.new('size_t[1]') dsize[0] = dummy_size local status = lib.intersect_mov_test(xa, #x, ya, #y, wa, #w, wouta, wsize, douta, dsize) - if status == 0 then error'wowza' end + if status == 0 then + error 'wowza' + end local wout, dout = {}, {} - for i = 0,tonumber(wsize[0])-1 do table.insert(wout, tonumber(wouta[i])) end - for i = 0,tonumber(dsize[0])-1 do table.insert(dout, tonumber(douta[i])) end - return {wout, dout} - end - - eq({{}, {}}, mov({}, {2, 3}, {2, 3})) - eq({{2, 3}, {}}, mov({}, {}, {2, 3})) - eq({{2, 3}, {}}, mov({2, 3}, {}, {})) - eq({{}, {2,3}}, mov({}, {2,3}, {})) - - eq({{1, 5}, {}}, mov({1,2,5}, {2, 3}, {3})) - eq({{1, 2}, {}}, mov({1,2,5}, {5, 10}, {10})) - eq({{1, 2}, {5}}, mov({1,2}, {5, 10}, {10})) - eq({{1,3,5,7,9}, {2,4,6,8,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {})) - eq({{1,3,5,7,9}, {2,6,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {4, 8})) - eq({{1,4,7}, {2,5,8}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {})) - eq({{1,4,7}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {2,5,8})) - eq({{0,1,4,7,10}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {0,2,5,8,10})) - end) + for i = 0, tonumber(wsize[0]) - 1 do + table.insert(wout, tonumber(wouta[i])) + end + for i = 0, tonumber(dsize[0]) - 1 do + table.insert(dout, tonumber(douta[i])) + end + return { wout, dout } + end + eq({ {}, {} }, mov({}, { 2, 3 }, { 2, 3 })) + eq({ { 2, 3 }, {} }, mov({}, {}, { 2, 3 })) + eq({ { 2, 3 }, {} }, mov({ 2, 3 }, {}, {})) + eq({ {}, { 2, 3 } }, mov({}, { 2, 3 }, {})) + + eq({ { 1, 5 }, {} }, mov({ 1, 2, 5 }, { 2, 3 }, { 3 })) + eq({ { 1, 2 }, {} }, mov({ 1, 2, 5 }, { 5, 10 }, { 10 })) + eq({ { 1, 2 }, { 5 } }, mov({ 1, 2 }, { 5, 10 }, { 10 })) + eq({ { 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 } }, mov({ 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 }, {})) + eq({ { 1, 3, 5, 7, 9 }, { 2, 6, 10 } }, mov({ 1, 3, 5, 7, 9 }, { 2, 4, 6, 8, 10 }, { 4, 8 })) + eq({ { 1, 4, 7 }, { 2, 5, 8 } }, mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, {})) + eq({ { 1, 4, 7 }, {} }, mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, { 2, 5, 8 })) + eq( + { { 0, 1, 4, 7, 10 }, {} }, + mov({ 1, 3, 4, 6, 7, 9 }, { 2, 3, 5, 6, 8, 9 }, { 0, 2, 5, 8, 10 }) + ) + end) local function check_intersections(tree) lib.marktree_check(tree) @@ -279,13 +306,13 @@ describe('marktree', function() if not val then local str2 = lib.mt_inspect(tree, true, true) local dot2 = ffi.string(str2.data, str2.size) - print("actual:\n\n".."Xafile.dot".."\n\nexpected:\n\n".."Xefile.dot".."\n") - print("nivå", tree[0].root.level); + print('actual:\n\n' .. 'Xafile.dot' .. '\n\nexpected:\n\n' .. 'Xefile.dot' .. '\n') + print('nivå', tree[0].root.level) io.stdout:flush() - local afil = io.open("Xafile.dot", "wb") + local afil = io.open('Xafile.dot', 'wb') afil:write(dot1) afil:close() - local efil = io.open("Xefile.dot", "wb") + local efil = io.open('Xefile.dot', 'wb') efil:write(dot2) efil:close() ok(false) @@ -295,28 +322,28 @@ describe('marktree', function() end itp('works with intersections', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit local ids = {} - for i = 1,80 do - table.insert(ids, put(tree, 1, i, false, 2, 100-i, false)) + for i = 1, 80 do + table.insert(ids, put(tree, 1, i, false, 2, 100 - i, false)) check_intersections(tree) end - for i = 1,80 do + for i = 1, 80 do lib.marktree_del_pair_test(tree, ns, ids[i]) check_intersections(tree) end ids = {} - for i = 1,80 do - table.insert(ids, put(tree, 1, i, false, 2, 100-i, false)) + for i = 1, 80 do + table.insert(ids, put(tree, 1, i, false, 2, 100 - i, false)) check_intersections(tree) end - for i = 1,10 do - for j = 1,8 do - local ival = (j-1)*10+i + for i = 1, 10 do + for j = 1, 8 do + local ival = (j - 1) * 10 + i lib.marktree_del_pair_test(tree, ns, ids[ival]) check_intersections(tree) end @@ -324,12 +351,12 @@ describe('marktree', function() end) itp('works with intersections with a big tree', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit local ids = {} - for i = 1,1000 do - table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false)) + for i = 1, 1000 do + table.insert(ids, put(tree, 1, i, false, 2, 1000 - i, false)) if i % 10 == 1 then check_intersections(tree) end @@ -339,13 +366,13 @@ describe('marktree', function() eq(2000, tree[0].n_keys) ok(tree[0].root.level >= 2) - local iter = ffi.new("MarkTreeIter[1]") + local iter = ffi.new('MarkTreeIter[1]') local k = 0 - for i = 1,20 do - for j = 1,50 do + for i = 1, 20 do + for j = 1, 50 do k = k + 1 - local ival = (j-1)*20+i + local ival = (j - 1) * 20 + i if false == true then -- if there actually is a failure, this branch will fail out at the actual spot of the error lib.marktree_lookup_ns(tree, ns, ids[ival], false, iter) lib.marktree_del_itr(tree, iter, false) @@ -367,10 +394,10 @@ describe('marktree', function() end) itp('works with intersections and marktree_splice', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit - for i = 1,1000 do - put(tree, 1, i, false, 2, 1000-i, false) + for i = 1, 1000 do + put(tree, 1, i, false, 2, 1000 - i, false) if i % 10 == 1 then check_intersections(tree) end @@ -380,15 +407,15 @@ describe('marktree', function() eq(2000, tree[0].n_keys) ok(tree[0].root.level >= 2) - for _ = 1,10 do + for _ = 1, 10 do lib.marktree_splice(tree, 0, 0, 0, 100, 0, 0) check_intersections(tree) end end) itp('marktree_move should preserve key order', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit - local iter = ffi.new("MarkTreeIter[1]") + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit + local iter = ffi.new('MarkTreeIter[1]') local ids = {} -- new index and old index look the same, but still have to move because @@ -405,31 +432,30 @@ describe('marktree', function() end) itp('works with intersections and marktree_move', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit local ids = {} - for i = 1,1000 do - table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false)) + for i = 1, 1000 do + table.insert(ids, put(tree, 1, i, false, 2, 1000 - i, false)) if i % 10 == 1 then check_intersections(tree) end end - local iter = ffi.new("MarkTreeIter[1]") - for i = 1,1000 do - local which = i%2 + local iter = ffi.new('MarkTreeIter[1]') + for i = 1, 1000 do + local which = i % 2 lib.marktree_lookup_ns(tree, ns, ids[i], which, iter) - lib.marktree_move(tree, iter, 1+which, 500+i) + lib.marktree_move(tree, iter, 1 + which, 500 + i) if i % 10 == 1 then check_intersections(tree) end end - end) itp('works with intersections with a even bigger tree', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit local ids = {} @@ -441,21 +467,21 @@ describe('marktree', function() at_row[i] = {} end - local size = 1000*size_factor + local size = 1000 * size_factor local k = 1 while k <= size do - for row1 = 1,9 do - for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2 + for row1 = 1, 9 do + for row2 = row1, 10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2 if k > size then break end - local id = put(tree, row1, k, false, row2, size-k, false) + local id = put(tree, row1, k, false, row2, size - k, false) table.insert(ids, id) - for i = row1+1, row2 do + for i = row1 + 1, row2 do table.insert(at_row[i], id) end --if tree[0].root.level == 4 then error("kk"..k) end - if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then + if k % 100 * size_factor == 1 or (k < 2000 and k % 100 == 1) then check_intersections(tree) end k = k + 1 @@ -463,13 +489,13 @@ describe('marktree', function() end end - eq(2*size, tree[0].n_keys) + eq(2 * size, tree[0].n_keys) ok(tree[0].root.level >= 3) check_intersections(tree) - local iter = ffi.new("MarkTreeIter[1]") - local pair = ffi.new("MTPair[1]") - for i = 1,10 do + local iter = ffi.new('MarkTreeIter[1]') + local pair = ffi.new('MTPair[1]') + for i = 1, 10 do -- use array as set and not {[id]=true} map, to detect duplicates local set = {} eq(true, ffi.C.marktree_itr_get_overlap(tree, i, 0, iter)) @@ -482,14 +508,14 @@ describe('marktree', function() end k = 0 - for i = 1,100 do - for j = 1,(10*size_factor) do + for i = 1, 100 do + for j = 1, (10 * size_factor) do k = k + 1 - local ival = (j-1)*100+i + local ival = (j - 1) * 100 + i lib.marktree_del_pair_test(tree, ns, ids[ival]) -- just a few stickprov, if there is trouble we need to check -- everyone using the code in the "big tree" case above - if k % 100*size_factor == 0 or (k > 3000 and k % 200 == 0) then + if k % 100 * size_factor == 0 or (k > 3000 and k % 200 == 0) then check_intersections(tree) end end @@ -499,7 +525,7 @@ describe('marktree', function() end) itp('works with intersections with a even bigger tree and splice', function() - local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit -- too much overhead on ASAN local size_factor = helpers.is_asan() and 3 or 10 @@ -509,20 +535,20 @@ describe('marktree', function() at_row[i] = {} end - local size = 1000*size_factor + local size = 1000 * size_factor local k = 1 while k <= size do - for row1 = 1,9 do - for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2 + for row1 = 1, 9 do + for row2 = row1, 10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2 if k > size then break end - local id = put(tree, row1, k, false, row2, size-k, false) - for i = row1+1, row2 do + local id = put(tree, row1, k, false, row2, size - k, false) + for i = row1 + 1, row2 do table.insert(at_row[i], id) end --if tree[0].root.level == 4 then error("kk"..k) end - if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then + if k % 100 * size_factor == 1 or (k < 2000 and k % 100 == 1) then check_intersections(tree) end k = k + 1 @@ -530,15 +556,93 @@ describe('marktree', function() end end - eq(2*size, tree[0].n_keys) + eq(2 * size, tree[0].n_keys) ok(tree[0].root.level >= 3) check_intersections(tree) - for _ = 1,10 do + for _ = 1, 10 do for j = 3, 8 do lib.marktree_splice(tree, j, 0, 0, 200, 0, 0) check_intersections(tree) end end end) + + itp('works with meta counts', function() + local tree = ffi.new('MarkTree[1]') -- zero initialized by luajit + + -- add + local shadow = {} + for i = 1, 100 do + for j = 1, 100 do + local gravitate = (i % 2) > 0 + local inline = (j == 3 or j == 50 or j == 51 or j == 55) and i % 11 == 1 + inline = inline or ((j >= 80 and j < 85) and i % 3 == 1) + local id = put_meta(tree, j, i, gravitate, inline) + if inline then + shadow[id] = { j, i, gravitate } + end + end + -- checking every insert is too slow, but this is ok + lib.marktree_check(tree) + end + + lib.marktree_check(tree) + local iter = ffi.new('MarkTreeIter[1]') + local filter = ffi.new('uint32_t[4]') + filter[0] = -1 + ok(lib.marktree_itr_get_filter(tree, 0, 0, 101, 0, filter, iter)) + local seen = {} + repeat + local mark = lib.marktree_itr_current(iter) + eq(nil, seen[mark.id]) + seen[mark.id] = true + eq(mark.pos.row, shadow[mark.id][1]) + eq(mark.pos.col, shadow[mark.id][2]) + until not lib.marktree_itr_next_filter(tree, iter, 101, 0, filter) + eq(tablelength(seen), tablelength(shadow)) + + -- test skipping subtrees to find the filtered mark at line 50 + for i = 4, 50 do + ok(lib.marktree_itr_get_filter(tree, i, 0, 60, 0, filter, iter)) + local mark = lib.marktree_itr_current(iter) + eq({ 50, 50, 1 }, { mark.id, mark.pos.row, mark.pos.col }) + end + + -- delete + for id = 1, 10000, 2 do + lib.marktree_lookup_ns(tree, ns, id, false, iter) + if shadow[id] then + local mark = lib.marktree_itr_current(iter) + eq(mark.pos.row, shadow[id][1]) + eq(mark.pos.col, shadow[id][2]) + shadow[id] = nil + end + lib.marktree_del_itr(tree, iter, false) + if id % 100 == 1 then + lib.marktree_check(tree) + end + end + + -- Splice! + dosplice(tree, shadow, { 82, 0 }, { 0, 50 }, { 0, 0 }) + lib.marktree_check(tree) + + dosplice(tree, shadow, { 81, 50 }, { 2, 50 }, { 1, 0 }) + lib.marktree_check(tree) + + dosplice(tree, shadow, { 2, 50 }, { 1, 50 }, { 0, 10 }) + lib.marktree_check(tree) + + ok(lib.marktree_itr_get_filter(tree, 0, 0, 101, 0, filter, iter)) + seen = {} + repeat + local mark = lib.marktree_itr_current(iter) + eq(nil, seen[mark.id]) + seen[mark.id] = true + eq(mark.pos.row, shadow[mark.id][1]) + eq(mark.pos.col, shadow[mark.id][2]) + until not lib.marktree_itr_next_filter(tree, iter, 101, 0, filter) + eq(tablelength(seen), tablelength(shadow)) + end) end) |