123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- local t = require('test.testutil')
- local eq = t.eq
- local matches = t.matches
- local pcall_err = t.pcall_err
- describe('vim.iter', function()
- it('new() on iterable class instance', function()
- local rb = vim.ringbuf(3)
- rb:push('a')
- rb:push('b')
- local it = vim.iter(rb)
- eq({ 'a', 'b' }, it:totable())
- end)
- it('filter()', function()
- local function odd(v)
- return v % 2 ~= 0
- end
- local q = { 1, 2, 3, 4, 5 }
- eq({ 1, 3, 5 }, vim.iter(q):filter(odd):totable())
- eq(
- { 2, 4 },
- vim
- .iter(q)
- :filter(function(v)
- return not odd(v)
- end)
- :totable()
- )
- eq(
- {},
- vim
- .iter(q)
- :filter(function(v)
- return v > 5
- end)
- :totable()
- )
- do
- local it = vim.iter(ipairs(q))
- it:filter(function(i, v)
- return i > 1 and v < 5
- end)
- it:map(function(_, v)
- return v * 2
- end)
- eq({ 4, 6, 8 }, it:totable())
- end
- local it = vim.iter(string.gmatch('the quick brown fox', '%w+'))
- eq(
- { 'the', 'fox' },
- it:filter(function(s)
- return #s <= 3
- end):totable()
- )
- end)
- it('map()', function()
- local q = { 1, 2, 3, 4, 5 }
- eq(
- { 2, 4, 6, 8, 10 },
- vim
- .iter(q)
- :map(function(v)
- return 2 * v
- end)
- :totable()
- )
- local it = vim.gsplit(
- [[
- Line 1
- Line 2
- Line 3
- Line 4
- ]],
- '\n'
- )
- eq(
- { 'Lion 2', 'Lion 4' },
- vim
- .iter(it)
- :map(function(s)
- local lnum = s:match('(%d+)')
- if lnum and tonumber(lnum) % 2 == 0 then
- return vim.trim(s:gsub('Line', 'Lion'))
- end
- end)
- :totable()
- )
- end)
- it('for loops', function()
- local q = { 1, 2, 3, 4, 5 }
- local acc = 0
- for v in
- vim.iter(q):map(function(v)
- return v * 3
- end)
- do
- acc = acc + v
- end
- eq(45, acc)
- end)
- it('totable()', function()
- do
- local it = vim.iter({ 1, 2, 3 }):map(function(v)
- return v, v * v
- end)
- eq({ { 1, 1 }, { 2, 4 }, { 3, 9 } }, it:totable())
- end
- -- Holes in array-like tables are removed
- eq({ 1, 2, 3 }, vim.iter({ 1, nil, 2, nil, 3 }):totable())
- do
- local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber)
- eq({ 1, 4, 17, 2, 9, 3 }, it:totable())
- end
- end)
- it('join()', function()
- eq('1, 2, 3', vim.iter({ 1, 2, 3 }):join(', '))
- eq('a|b|c|d', vim.iter(vim.gsplit('a|b|c|d', '|')):join('|'))
- end)
- it('next()', function()
- local it = vim.iter({ 1, 2, 3 }):map(function(v)
- return 2 * v
- end)
- eq(2, it:next())
- eq(4, it:next())
- eq(6, it:next())
- eq(nil, it:next())
- end)
- it('rev()', function()
- eq({ 3, 2, 1 }, vim.iter({ 1, 2, 3 }):rev():totable())
- local it = vim.iter(string.gmatch('abc', '%w'))
- matches('rev%(%) requires an array%-like table', pcall_err(it.rev, it))
- end)
- it('skip()', function()
- do
- local q = { 4, 3, 2, 1 }
- eq(q, vim.iter(q):skip(0):totable())
- eq({ 3, 2, 1 }, vim.iter(q):skip(1):totable())
- eq({ 2, 1 }, vim.iter(q):skip(2):totable())
- eq({ 1 }, vim.iter(q):skip(#q - 1):totable())
- eq({}, vim.iter(q):skip(#q):totable())
- eq({}, vim.iter(q):skip(#q + 1):totable())
- end
- do
- local function skip(n)
- return vim.iter(vim.gsplit('a|b|c|d', '|')):skip(n):totable()
- end
- eq({ 'a', 'b', 'c', 'd' }, skip(0))
- eq({ 'b', 'c', 'd' }, skip(1))
- eq({ 'c', 'd' }, skip(2))
- eq({ 'd' }, skip(3))
- eq({}, skip(4))
- eq({}, skip(5))
- end
- end)
- it('rskip()', function()
- do
- local q = { 4, 3, 2, 1 }
- eq(q, vim.iter(q):rskip(0):totable())
- eq({ 4, 3, 2 }, vim.iter(q):rskip(1):totable())
- eq({ 4, 3 }, vim.iter(q):rskip(2):totable())
- eq({ 4 }, vim.iter(q):rskip(#q - 1):totable())
- eq({}, vim.iter(q):rskip(#q):totable())
- eq({}, vim.iter(q):rskip(#q + 1):totable())
- end
- local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
- matches('rskip%(%) requires an array%-like table', pcall_err(it.rskip, it, 0))
- end)
- it('slice()', function()
- local q = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
- eq({ 3, 4, 5, 6, 7 }, vim.iter(q):slice(3, 7):totable())
- eq({}, vim.iter(q):slice(6, 5):totable())
- eq({}, vim.iter(q):slice(0, 0):totable())
- eq({ 1 }, vim.iter(q):slice(1, 1):totable())
- eq({ 1, 2 }, vim.iter(q):slice(1, 2):totable())
- eq({ 10 }, vim.iter(q):slice(10, 10):totable())
- eq({ 8, 9, 10 }, vim.iter(q):slice(8, 11):totable())
- local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
- matches('slice%(%) requires an array%-like table', pcall_err(it.slice, it, 1, 3))
- end)
- it('nth()', function()
- do
- local q = { 4, 3, 2, 1 }
- eq(nil, vim.iter(q):nth(0))
- eq(4, vim.iter(q):nth(1))
- eq(3, vim.iter(q):nth(2))
- eq(2, vim.iter(q):nth(3))
- eq(1, vim.iter(q):nth(4))
- eq(nil, vim.iter(q):nth(5))
- end
- do
- local function nth(n)
- return vim.iter(vim.gsplit('a|b|c|d', '|')):nth(n)
- end
- eq(nil, nth(0))
- eq('a', nth(1))
- eq('b', nth(2))
- eq('c', nth(3))
- eq('d', nth(4))
- eq(nil, nth(5))
- end
- end)
- it('nth(-x) advances in reverse order starting from end', function()
- do
- local q = { 4, 3, 2, 1 }
- eq(nil, vim.iter(q):nth(0))
- eq(1, vim.iter(q):nth(-1))
- eq(2, vim.iter(q):nth(-2))
- eq(3, vim.iter(q):nth(-3))
- eq(4, vim.iter(q):nth(-4))
- eq(nil, vim.iter(q):nth(-5))
- end
- local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
- matches('rskip%(%) requires an array%-like table', pcall_err(it.nth, it, -1))
- end)
- it('take()', function()
- do
- local q = { 4, 3, 2, 1 }
- eq({}, vim.iter(q):take(0):totable())
- eq({ 4 }, vim.iter(q):take(1):totable())
- eq({ 4, 3 }, vim.iter(q):take(2):totable())
- eq({ 4, 3, 2 }, vim.iter(q):take(3):totable())
- eq({ 4, 3, 2, 1 }, vim.iter(q):take(4):totable())
- eq({ 4, 3, 2, 1 }, vim.iter(q):take(5):totable())
- end
- do
- local q = { 4, 3, 2, 1 }
- eq({ 1, 2, 3 }, vim.iter(q):rev():take(3):totable())
- eq({ 2, 3, 4 }, vim.iter(q):take(3):rev():totable())
- end
- do
- local q = { 4, 3, 2, 1 }
- local it = vim.iter(q)
- eq({ 4, 3 }, it:take(2):totable())
- -- tail is already set from the previous take()
- eq({ 4, 3 }, it:take(3):totable())
- end
- do
- local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
- eq({ 'a', 'b' }, it:take(2):totable())
- -- non-array iterators are consumed by take()
- eq({}, it:take(2):totable())
- end
- end)
- it('any()', function()
- local function odd(v)
- return v % 2 ~= 0
- end
- do
- local q = { 4, 8, 9, 10 }
- eq(true, vim.iter(q):any(odd))
- end
- do
- local q = { 4, 8, 10 }
- eq(false, vim.iter(q):any(odd))
- end
- do
- eq(
- true,
- vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s)
- return s == 'd'
- end)
- )
- eq(
- false,
- vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s)
- return s == 'e'
- end)
- )
- end
- end)
- it('all()', function()
- local function odd(v)
- return v % 2 ~= 0
- end
- do
- local q = { 3, 5, 7, 9 }
- eq(true, vim.iter(q):all(odd))
- end
- do
- local q = { 3, 5, 7, 10 }
- eq(false, vim.iter(q):all(odd))
- end
- do
- eq(
- true,
- vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s)
- return s == 'a'
- end)
- )
- eq(
- false,
- vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s)
- return s == 'a'
- end)
- )
- end
- end)
- it('last()', function()
- local s = 'abcdefghijklmnopqrstuvwxyz'
- eq('z', vim.iter(vim.split(s, '')):last())
- eq('z', vim.iter(vim.gsplit(s, '')):last())
- end)
- it('enumerate()', function()
- local it = vim.iter(vim.gsplit('abc', '')):enumerate()
- eq({ 1, 'a' }, { it:next() })
- eq({ 2, 'b' }, { it:next() })
- eq({ 3, 'c' }, { it:next() })
- eq({}, { it:next() })
- end)
- it('peek()', function()
- do
- local it = vim.iter({ 3, 6, 9, 12 })
- eq(3, it:peek())
- eq(3, it:peek())
- eq(3, it:next())
- end
- do
- local it = vim.iter(vim.gsplit('hi', ''))
- matches('peek%(%) requires an array%-like table', pcall_err(it.peek, it))
- end
- end)
- it('find()', function()
- local q = { 3, 6, 9, 12 }
- eq(12, vim.iter(q):find(12))
- eq(nil, vim.iter(q):find(15))
- eq(
- 12,
- vim.iter(q):find(function(v)
- return v % 4 == 0
- end)
- )
- do
- local it = vim.iter(q)
- local pred = function(v)
- return v % 3 == 0
- end
- eq(3, it:find(pred))
- eq(6, it:find(pred))
- eq(9, it:find(pred))
- eq(12, it:find(pred))
- eq(nil, it:find(pred))
- end
- do
- local it = vim.iter(vim.gsplit('AbCdE', ''))
- local pred = function(s)
- return s:match('[A-Z]')
- end
- eq('A', it:find(pred))
- eq('C', it:find(pred))
- eq('E', it:find(pred))
- eq(nil, it:find(pred))
- end
- end)
- it('rfind()', function()
- local q = { 1, 2, 3, 2, 1 }
- do
- local it = vim.iter(q)
- eq(1, it:rfind(1))
- eq(1, it:rfind(1))
- eq(nil, it:rfind(1))
- end
- do
- local it = vim.iter(q):enumerate()
- local pred = function(i)
- return i % 2 ~= 0
- end
- eq({ 5, 1 }, { it:rfind(pred) })
- eq({ 3, 3 }, { it:rfind(pred) })
- eq({ 1, 1 }, { it:rfind(pred) })
- eq(nil, it:rfind(pred))
- end
- do
- local it = vim.iter(vim.gsplit('AbCdE', ''))
- matches('rfind%(%) requires an array%-like table', pcall_err(it.rfind, it, 'E'))
- end
- end)
- it('pop()', function()
- do
- local it = vim.iter({ 1, 2, 3, 4 })
- eq(4, it:pop())
- eq(3, it:pop())
- eq(2, it:pop())
- eq(1, it:pop())
- eq(nil, it:pop())
- eq(nil, it:pop())
- end
- do
- local it = vim.iter(vim.gsplit('hi', ''))
- matches('pop%(%) requires an array%-like table', pcall_err(it.pop, it))
- end
- end)
- it('rpeek()', function()
- do
- local it = vim.iter({ 1, 2, 3, 4 })
- eq(4, it:rpeek())
- eq(4, it:rpeek())
- eq(4, it:pop())
- end
- do
- local it = vim.iter(vim.gsplit('hi', ''))
- matches('rpeek%(%) requires an array%-like table', pcall_err(it.rpeek, it))
- end
- end)
- it('fold()', function()
- local q = { 1, 2, 3, 4, 5 }
- eq(
- 115,
- vim.iter(q):fold(100, function(acc, v)
- return acc + v
- end)
- )
- eq(
- { 5, 4, 3, 2, 1 },
- vim.iter(q):fold({}, function(acc, v)
- table.insert(acc, 1, v)
- return acc
- end)
- )
- end)
- it('flatten()', function()
- local q = { { 1, { 2 } }, { { { { 3 } } }, { 4 } }, { 5 } }
- eq(q, vim.iter(q):flatten(-1):totable())
- eq(q, vim.iter(q):flatten(0):totable())
- eq({ 1, { 2 }, { { { 3 } } }, { 4 }, 5 }, vim.iter(q):flatten():totable())
- eq({ 1, 2, { { 3 } }, 4, 5 }, vim.iter(q):flatten(2):totable())
- eq({ 1, 2, { 3 }, 4, 5 }, vim.iter(q):flatten(3):totable())
- eq({ 1, 2, 3, 4, 5 }, vim.iter(q):flatten(4):totable())
- local m = { a = 1, b = { 2, 3 }, d = { 4 } }
- local it = vim.iter(m)
- local flat_err = 'flatten%(%) requires an array%-like table'
- matches(flat_err, pcall_err(it.flatten, it))
- -- cases from the documentation
- local simple_example = { 1, { 2 }, { { 3 } } }
- eq({ 1, 2, { 3 } }, vim.iter(simple_example):flatten():totable())
- local not_list_like = { [2] = 2 }
- eq({ 2 }, vim.iter(not_list_like):flatten():totable())
- local also_not_list_like = { nil, 2 }
- eq({ 2 }, vim.iter(also_not_list_like):flatten():totable())
- eq({ 1, 2, 3 }, vim.iter({ nil, { 1, nil, 2 }, 3 }):flatten():totable())
- local nested_non_lists = vim.iter({ 1, { { a = 2 } }, { { nil } }, { 3 } })
- eq({ 1, { a = 2 }, { nil }, 3 }, nested_non_lists:flatten():totable())
- -- only error if we're going deep enough to flatten a dict-like table
- matches(flat_err, pcall_err(nested_non_lists.flatten, nested_non_lists, math.huge))
- end)
- it('handles map-like tables', function()
- local it = vim.iter({ a = 1, b = 2, c = 3 }):map(function(k, v)
- if v % 2 ~= 0 then
- return k:upper(), v * 2
- end
- end)
- local q = it:fold({}, function(q, k, v)
- q[k] = v
- return q
- end)
- eq({ A = 2, C = 6 }, q)
- end)
- it('handles table values mid-pipeline', function()
- local map = {
- item = {
- file = 'test',
- },
- item_2 = {
- file = 'test',
- },
- item_3 = {
- file = 'test',
- },
- }
- local output = vim
- .iter(map)
- :map(function(key, value)
- return { [key] = value.file }
- end)
- :totable()
- table.sort(output, function(a, b)
- return next(a) < next(b)
- end)
- eq({
- { item = 'test' },
- { item_2 = 'test' },
- { item_3 = 'test' },
- }, output)
- end)
- end)
|