local t = require('test.testutil')

local eq = t.eq
local pcall_err = t.pcall_err

describe('vim.text', function()
  describe('indent()', function()
    it('validation', function()
      t.matches('size%: expected number, got string', t.pcall_err(vim.text.indent, 'x', 'x'))
      t.matches('size%: expected number, got nil', t.pcall_err(vim.text.indent, nil, 'x'))
      t.matches('opts%: expected table, got string', t.pcall_err(vim.text.indent, 0, 'x', 'z'))
    end)

    it('basic cases', function()
      -- Basic cases.
      eq({ '', 0 }, { vim.text.indent(0, '') })
      eq({ '', 0 }, { vim.text.indent(2, '') })
      eq({ '  a', 4 }, { vim.text.indent(2, '    a') })
      eq({ '  a\n  b', 4 }, { vim.text.indent(2, '    a\n    b') })
      eq({ '\t\ta', 1 }, { vim.text.indent(2, '\ta') })
      eq({ ' a\n\n', 5 }, { vim.text.indent(1, '     a\n\n') })
      -- Indent 1 (tab) => 0. Starting with empty + blank lines.
      eq({ '\n\naa a aa', 1 }, { vim.text.indent(0, '\n	\n	aa a aa') })
      -- Indent 1 (tab) => 2 (tabs). Starting with empty + blank lines, 1-tab indent.
      eq({ '\n\t\t\n\t\taa a aa', 1 }, { vim.text.indent(2, '\n\t\n\taa a aa') })

      -- Indent 4 => 2, expandtab=false preserves tabs after the common indent.
      eq(
        { '  foo\n    bar\n  \tbaz\n', 4 },
        { vim.text.indent(2, '    foo\n      bar\n    \tbaz\n') }
      )
      -- Indent 9 => 3, expandtab=true.
      eq(
        { '    foo\n\n   bar \t baz\n', 9 },
        { vim.text.indent(3, '\t  foo\n\n         bar \t baz\n', { expandtab = 8 }) }
      )
      -- Indent 9 => 8, expandtab=true.
      eq(
        { '         foo\n\n        bar\n', 9 },
        { vim.text.indent(8, '\t  foo\n\n         bar\n', { expandtab = 8 }) }
      )
      -- Dedent: 5 => 0.
      eq({ '  foo\n\nbar\n', 5 }, { vim.text.indent(0, '       foo\n\n     bar\n') })
      -- Dedent: 1 => 0. Empty lines are ignored when deciding "common indent".
      eq(
        { ' \n  \nfoo\n\nbar\nbaz\n    \n', 1 },
        { vim.text.indent(0, '  \n   \n foo\n\n bar\n baz\n     \n') }
      )
    end)

    it('real-world cases', function()
      -- Dedent.
      eq({
        [[
bufs:
nvim args: 3
lua args: {
  [0] = "foo.lua"
}
]],
        10,
      }, {
        vim.text.indent(
          0,
          [[
          bufs:
          nvim args: 3
          lua args: {
            [0] = "foo.lua"
          }
          ]]
        ),
      })

      -- Indent 0 => 2.
      eq({
        [[
  # yay

  local function foo()
    if true then
      # yay
    end
  end

  return
]],
        0,
      }, {
        vim.text.indent(
          2,
          [[
# yay

local function foo()
  if true then
    # yay
  end
end

return
]]
        ),
      })

      -- 1-tab indent, last line spaces < tabsize.
      -- Preserves tab char immediately following the indent.
      eq({ 'text\n\tmatch\nmatch\ntext\n', 1 }, {
        vim.text.indent(0, (([[
	text
		match
	match
	text
]]):gsub('\n%s-([\n]?)$', '\n%1'))),
      })

      -- 1-tab indent, last line spaces=tabsize.
      eq({ 'text\n      match\nmatch\ntext\n', 6 }, {
        vim.text.indent(
          0,
          [[
	text
		match
	match
	text
      ]],
          { expandtab = 6 }
        ),
      })
    end)
  end)

  describe('hexencode(), hexdecode()', function()
    it('works', function()
      local cases = {
        { 'Hello world!', '48656C6C6F20776F726C6421' },
        { '😂', 'F09F9882' },
      }

      for _, v in ipairs(cases) do
        local input, output = unpack(v)
        eq(output, vim.text.hexencode(input))
        eq(input, vim.text.hexdecode(output))
      end
    end)

    it('with very large strings', function()
      local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16)
      eq(output, vim.text.hexencode(input))
      eq(input, vim.text.hexdecode(output))
    end)

    it('invalid input', function()
      -- Odd number of hex characters
      do
        local res, err = vim.text.hexdecode('ABC')
        eq(nil, res)
        eq('string must have an even number of hex characters', err)
      end

      -- Non-hexadecimal input
      do
        local res, err = vim.text.hexdecode('nothex')
        eq(nil, res)
        eq('string must contain only hex characters', err)
      end
    end)
  end)
end)
