Add WIP testing framework to repo. Ruby spec is partly done.

This commit is contained in:
Cameron 2023-02-13 10:24:36 +01:00
parent 5e718a76ab
commit e9f1557edd
5 changed files with 355 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
spec/support/**/*

View file

@ -43,6 +43,10 @@ local function toggle_block(node)
end
local function inline_conditional(structure)
if structure.consequence:match("\n") then
return
end
local replacement = {
structure.consequence,
structure["if"] or structure["unless"],

14
run_spec Executable file
View file

@ -0,0 +1,14 @@
#!/usr/bin/env bash
PLENARY="$(pwd)/spec/support/plenary/"
TREESITTER="$(pwd)/spec/support/treesitter/"
[ ! -d $PLENARY ] && git clone git@github.com:nvim-lua/plenary.nvim.git --branch=master $PLENARY
[ ! -d $TREESITTER ] && git clone git@github.com:nvim-treesitter/nvim-treesitter.git --branch=master $TREESITTER
SET_PLENARY="vim.opt.rtp:prepend('$PLENARY');"
SET_TREESITTER="vim.opt.rtp:prepend('$TREESITTER');"
SET_PLUGIN="vim.opt.rtp:prepend('.');"
CMD="require('plenary.test_harness').test_directory_command(vim.loop.cwd() .. '/spec/filetypes', { sequential = true })"
nvim -u NONE --clean --headless -c "lua $SET_PLENARY $SET_TREESITTER $SET_PLUGIN $CMD"

View file

@ -0,0 +1,221 @@
dofile("./spec/spec_helper.lua")
local Helper = SpecHelper:new("ruby")
describe("integer", function()
it("adds underscores to long int", function()
assert.are.same({ "1_000_000" }, Helper:call("1000000"))
end)
it("removes underscores from long int", function()
assert.are.same({ "1000000" }, Helper:call("1_000_000"))
end)
it("doesn't change ints less than four places", function()
assert.are.same({ "100" }, Helper:call("100"))
end)
end)
describe("if", function()
pending("expands ternary to multiline expression", function()
assert.are.same(
{
[[if greet?]],
[[ puts("hello")]],
[[else]],
[[ puts("booooo")]],
[[end]],
},
Helper:call({ [[greet? ? puts("hello") : puts("booooo")]] }, { 1, 7 })
)
end)
pending("inlines to ternary statement", function()
assert.are.same(
{ [[greet? ? puts("hello") : puts("booooo")]] },
Helper:call({
[[if greet?]],
[[ puts "hello"]],
[[else]],
[[ puts "booooo"]],
[[end]],
})
)
end)
end)
describe("if_modifier", function()
it("expands from one line to three", function()
assert.are.same(
{
[[if greet?]],
[[ puts "hello"]],
[[end]],
},
Helper:call({ [[puts "hello" if greet?]], }, { 1, 13 })
)
end)
it("collapses from three lines to one", function()
assert.are.same(
{ [[puts "hello" if greet?]] },
Helper:call({
[[if greet?]],
[[ puts "hello"]],
[[end]],
})
)
end)
it("can handle more complex conditions", function()
assert.are.same(
{
[[if greet? && 1 == 2 || something * 3 <= 10]],
[[ puts "hello"]],
[[end]],
},
Helper:call({ [[puts "hello" if greet? && 1 == 2 || something * 3 <= 10]], }, { 1, 13 })
)
end)
it("doesn't change conditionals with multi-line bodies", function()
local text = {
[[if greet?]],
[[ puts "hello"]],
[[ puts "hello"]],
[[ puts "hello"]],
[[end]],
}
assert.are.same(text, Helper:call(text))
end)
end)
describe("unless_modifier", function()
it("expands from one line to three", function()
assert.are.same(
{
[[unless rude?]],
[[ puts "hello"]],
[[end]],
},
Helper:call({ [[puts "hello" unless rude?]] }, { 1, 13 })
)
end)
it("collapses from three lines to one", function()
assert.are.same(
{ [[puts "hello" unless rude?]] },
Helper:call({
[[unless rude?]],
[[ puts "hello"]],
[[end]],
})
)
end)
it("can handle more complex conditions", function()
assert.are.same(
{
[[unless rude? && 1 == 2 || something * 3 <= 10]],
[[ puts "hello"]],
[[end]],
},
Helper:call({ [[puts "hello" unless rude? && 1 == 2 || something * 3 <= 10]], }, { 1, 13 })
)
end)
end)
describe("binary", function()
it("flips == into !=", function()
assert.are.same({ "1 != 1" }, Helper:call({ "1 == 1" }, { 1, 3 }))
end)
it("flips != into ==", function()
assert.are.same({ "1 == 1" }, Helper:call({ "1 != 1" }, { 1, 3 }))
end)
it("flips > into <", function()
assert.are.same({ "1 < 1" }, Helper:call({ "1 > 1" }, { 1, 3 }))
end)
it("flips < into >", function()
assert.are.same({ "1 > 1" }, Helper:call({ "1 < 1" }, { 1, 3 }))
end)
it("flips >= into <=", function()
assert.are.same({ "1 <= 1" }, Helper:call({ "1 >= 1" }, { 1, 3 }))
end)
it("flips <= into >=", function()
assert.are.same({ "1 >= 1" }, Helper:call({ "1 <= 1" }, { 1, 3 }))
end)
end)
describe("boolean", function()
it("turns 'true' into 'false'", function()
assert.are.same({ "false" }, Helper:call({ "true" }))
end)
it("turns 'false' into 'true'", function()
assert.are.same({ "true" }, Helper:call({ "false" }))
end)
end)
describe("array", function()
it("expands single line array to multiple lines", function()
assert.are.same(
{
"[",
" 1,",
" 2,",
" 3",
"]"
},
Helper:call({ "[1, 2, 3]" })
)
end)
it("doesn't expand child arrays", function()
assert.are.same(
{
"[",
" 1,",
" 2,",
" [3, 4, 5]",
"]"
},
Helper:call({ "[1, 2, [3, 4, 5]]" })
)
end)
it("collapses multi-line array to single line", function()
assert.are.same(
{ "[1, 2, 3]" },
Helper:call({
"[",
" 1,",
" 2,",
" 3",
"]"
})
)
end)
it("collapses child arrays", function()
assert.are.same(
{ "[1, 2, [3, 4, 5]]" },
Helper:call({
"[",
" 1,",
" 2,",
" [",
" 3,",
" 4,",
" 5",
" ]",
"]"
})
)
end)
end)

115
spec/spec_helper.lua Normal file
View file

@ -0,0 +1,115 @@
local Buffer = {}
Buffer.__index = Buffer
-- Creates a new Buffer object for testing. Custom buf options can be passed into constructor.
-- @param lang string
-- @param user_opts table
-- @return Buffer
function Buffer:new(lang, buf_opts)
local buffer = {}
buffer.lang = lang
buffer.opts = vim.tbl_extend(
"keep",
{ filetype = lang, indentexpr = "nvim_treesitter#indent()" },
buf_opts or {}
)
return setmetatable(buffer, self)
end
-- @return Buffer
function Buffer:setup()
self.handle = vim.api.nvim_create_buf(false, true)
vim.treesitter.start(self.handle, self.lang)
for key, value in pairs(self.opts) do
vim.api.nvim_buf_set_option(self.handle, key, value)
end
return self
end
-- Fakes cursor location by just returning the node at where the cursor should be
-- 1-indexed { row, col }, like vim.fn.getpos(".")
--
-- @param pos table
-- @return Buffer
function Buffer:set_cursor(pos)
local row = pos[1] - 1
local col = pos[2] - 1
local fake_get_node_at_cursor = function()
return vim.treesitter.get_parser(self.handle, self.lang)
:parse()[1]
:root()
:named_descendant_for_range(row, col, row, col)
end
require("nvim-treesitter.ts_utils").get_node_at_cursor = fake_get_node_at_cursor
return self
end
-- @param text string|table
-- @return Buffer
function Buffer:write(text)
if type(text) ~= "table" then
text = { text }
end
vim.api.nvim_buf_set_lines(self.handle, 0, -1, false, text)
return self
end
-- @return table
function Buffer:read()
return vim.api.nvim_buf_get_lines(self.handle, 0, -1, false)
end
-- @return nil
function Buffer:teardown()
vim.api.nvim_buf_delete(self.handle, { force = true })
end
-- @return Buffer
function Buffer:run_action()
vim.api.nvim_buf_call(self.handle, require("ts-node-action").node_action)
return self
end
-- SpecHelper - A general wrapper, available in the global scope, for test related helpers
local SpecHelper = {}
SpecHelper.__index = SpecHelper
_G.SpecHelper = SpecHelper
-- Builds language helper. Custom buffer opts can also be set on a per-filetype basis.
-- @param lang string
-- @param buf_opts table|nil
-- @return SpecHelper
function SpecHelper:new(lang, buf_opts)
local language = {}
language.lang = lang
language.buf_opts = buf_opts or {}
return setmetatable(language, self)
end
-- Runs full integration test for text
-- Cursor (pos) is 0-indexed, { row, col }. Defaults to first line, first col if empty
-- Returns full buffer text as a table, one string per line.
--
-- @param text string|table
-- @param pos table|nil
-- @return table
function SpecHelper:call(text, pos)
local buffer = Buffer:new(self.lang, self.buf_opts)
local result = buffer:setup()
:set_cursor(pos or { 1, 1 })
:write(text)
:run_action()
:read()
buffer:teardown()
return result
end