Added unittest + basic python and lua unittests (#174)
--------- Co-authored-by: Danymat <d.danymat@gmail.com>
This commit is contained in:
27
.github/workflows/test.yml
vendored
Normal file
27
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
on: [push, pull_request]
|
||||||
|
name: test
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
neovim: [v0.10.0, nightly]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
name: "OS: ${{ matrix.os }} - Neovim: ${{ matrix.neovim }}"
|
||||||
|
steps:
|
||||||
|
- name: Checkout neogen
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: danymat/neogen
|
||||||
|
path: neogen
|
||||||
|
- uses: rhysd/action-setup-vim@v1
|
||||||
|
with:
|
||||||
|
neovim: true
|
||||||
|
version: ${{ matrix.neovim }}
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: ./neogen
|
||||||
|
run: |
|
||||||
|
nvim --version
|
||||||
|
make test
|
||||||
12
Makefile
12
Makefile
@@ -1,5 +1,17 @@
|
|||||||
|
TESTS_INIT=tests/minimal_init.lua
|
||||||
|
TESTS_DIR=tests/
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
|
||||||
documentation:
|
documentation:
|
||||||
nvim --headless --noplugin -u ./scripts/minimal_init.vim -c "lua MiniDoc.generate()" -c "qa!"
|
nvim --headless --noplugin -u ./scripts/minimal_init.vim -c "lua MiniDoc.generate()" -c "qa!"
|
||||||
|
|
||||||
tag:
|
tag:
|
||||||
./scripts/generate_tag.sh
|
./scripts/generate_tag.sh
|
||||||
|
|
||||||
|
test:
|
||||||
|
@nvim \
|
||||||
|
--headless \
|
||||||
|
--noplugin \
|
||||||
|
-u ${TESTS_INIT} \
|
||||||
|
-c "PlenaryBustedDirectory ${TESTS_DIR} { minimal_init = '${TESTS_INIT}' }"
|
||||||
|
|||||||
@@ -183,12 +183,15 @@ Feel free to submit a PR, I will be happy to help you !
|
|||||||
We use semantic versioning ! (https://semver.org)
|
We use semantic versioning ! (https://semver.org)
|
||||||
Here is the current Neogen version:
|
Here is the current Neogen version:
|
||||||
>
|
>
|
||||||
neogen.version = "2.17.1"
|
neogen.version = "2.18.0"
|
||||||
<
|
<
|
||||||
# Changelog~
|
# Changelog~
|
||||||
|
|
||||||
Note: We will only document `major` and `minor` versions, not `patch` ones. (only X and Y in X.Y.z)
|
Note: We will only document `major` and `minor` versions, not `patch` ones. (only X and Y in X.Y.z)
|
||||||
|
|
||||||
|
## 2.18.0~
|
||||||
|
- Added plenary unittests to the repository
|
||||||
|
- Added Python + Google-style docstrings
|
||||||
## 2.17.1~
|
## 2.17.1~
|
||||||
- Python raises now supports `raise foo.Bar()` syntax
|
- Python raises now supports `raise foo.Bar()` syntax
|
||||||
## 2.17.0~
|
## 2.17.0~
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ end
|
|||||||
--- with multiple annotation conventions.
|
--- with multiple annotation conventions.
|
||||||
---@tag neogen-changelog
|
---@tag neogen-changelog
|
||||||
---@toc_entry Changes in neogen plugin
|
---@toc_entry Changes in neogen plugin
|
||||||
neogen.version = "2.17.1"
|
neogen.version = "2.18.0"
|
||||||
--minidoc_afterlines_end
|
--minidoc_afterlines_end
|
||||||
|
|
||||||
return neogen
|
return neogen
|
||||||
|
|||||||
27
tests/minimal_init.lua
Normal file
27
tests/minimal_init.lua
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
local plugins = {
|
||||||
|
["https://github.com/nvim-treesitter/nvim-treesitter"] = os.getenv("NVIM_TREESITTER_DIRECTORY")
|
||||||
|
or "/tmp/nvim_treesitter",
|
||||||
|
["https://github.com/nvim-lua/plenary.nvim"] = os.getenv("PLENARY_DIRECTORY") or "/tmp/plenary.nvim",
|
||||||
|
}
|
||||||
|
|
||||||
|
local tests_directory = vim.fn.fnamemodify(vim.fn.expand("<sfile>"), ":h")
|
||||||
|
local plugin_root = vim.fn.fnamemodify(tests_directory, ":h")
|
||||||
|
vim.opt.runtimepath:append(plugin_root)
|
||||||
|
|
||||||
|
for url, directory in pairs(plugins) do
|
||||||
|
if vim.fn.isdirectory(directory) == 0 then
|
||||||
|
vim.fn.system({ "git", "clone", url, directory })
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.opt.runtimepath:append(directory)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.cmd("runtime plugin/plenary.vim")
|
||||||
|
require("plenary.busted")
|
||||||
|
|
||||||
|
vim.cmd("runtime plugin/nvim-treesitter.lua")
|
||||||
|
|
||||||
|
-- Some tests require the Python parser
|
||||||
|
vim.cmd([[TSInstallSync! python]])
|
||||||
|
|
||||||
|
require("neogen").setup({ snippet_engine = "nvim" })
|
||||||
28
tests/neogen/lua_emmylua_spec.lua
Normal file
28
tests/neogen/lua_emmylua_spec.lua
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
--- Test cases for emmylua
|
||||||
|
---
|
||||||
|
--- @module 'tests.neogen.lua_spec'
|
||||||
|
|
||||||
|
local specs = require('tests.utils.specs')
|
||||||
|
|
||||||
|
local function make_emmylua(source)
|
||||||
|
return specs.make_docstring(source, 'lua', { annotation_convention = { lua = 'emmylua' } })
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("lua: emmylua", function()
|
||||||
|
describe("func", function()
|
||||||
|
it("works with an empty function", function()
|
||||||
|
local source = [[
|
||||||
|
function foo()|cursor|end
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
--- [TODO:description]
|
||||||
|
function foo()end
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_emmylua(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
816
tests/neogen/python_google_spec.lua
Normal file
816
tests/neogen/python_google_spec.lua
Normal file
@@ -0,0 +1,816 @@
|
|||||||
|
--- Make sure Python docstrings generate as expected.
|
||||||
|
---
|
||||||
|
--- @module 'tests.neogen.python_spec'
|
||||||
|
|
||||||
|
local specs = require('tests.utils.specs')
|
||||||
|
|
||||||
|
local function make_google_docstrings(source)
|
||||||
|
return specs.make_docstring(source, 'python', { annotation_convention = { python = 'google_docstrings' } })
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("python: google_docstrings", function()
|
||||||
|
describe("func", function()
|
||||||
|
it("works with an empty function", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with typed arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(bar: list[str], fizz: int, buzz: dict[str, int]):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(bar: list[str], fizz: int, buzz: dict[str, int]):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bar: [TODO:description]
|
||||||
|
fizz: [TODO:description]
|
||||||
|
buzz: [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("func - arguments", function()
|
||||||
|
it("works with class methods", function()
|
||||||
|
local source = [[
|
||||||
|
class Foo:
|
||||||
|
@classmethod
|
||||||
|
def no_arguments(cls):|cursor|
|
||||||
|
return 7
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def one_argument(cls, items):|cursor|
|
||||||
|
return 8
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def two_arguments(cls, items, another):|cursor|
|
||||||
|
return 9
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
class Foo:
|
||||||
|
@classmethod
|
||||||
|
def no_arguments(cls):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 7
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def one_argument(cls, items):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 8
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def two_arguments(cls, items, another):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
another ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 9
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with methods + nested functions", function()
|
||||||
|
local source = [[
|
||||||
|
# Reference: https://github.com/danymat/neogen/pull/151
|
||||||
|
class Thing(object):
|
||||||
|
def foo(self, bar, fizz, buzz):|cursor|
|
||||||
|
def another(inner, function):|cursor|
|
||||||
|
def inner_most(more, stuff):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
# Reference: https://github.com/danymat/neogen/pull/151
|
||||||
|
class Thing(object):
|
||||||
|
def foo(self, bar, fizz, buzz):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bar ([TODO:parameter]): [TODO:description]
|
||||||
|
fizz ([TODO:parameter]): [TODO:description]
|
||||||
|
buzz ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
def another(inner, function):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
inner ([TODO:parameter]): [TODO:description]
|
||||||
|
function ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
def inner_most(more, stuff):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
more ([TODO:parameter]): [TODO:description]
|
||||||
|
stuff ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with static methods", function()
|
||||||
|
local source = [[
|
||||||
|
class Foo:
|
||||||
|
@staticmethod
|
||||||
|
def no_arguments():|cursor|
|
||||||
|
return 7
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def one_argument(items):|cursor|
|
||||||
|
return 8
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def two_arguments(items, another):|cursor|
|
||||||
|
return 9
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
class Foo:
|
||||||
|
@staticmethod
|
||||||
|
def no_arguments():
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 7
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def one_argument(items):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 8
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def two_arguments(items, another):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
another ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 9
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("func - argument permutations", function()
|
||||||
|
it("works with named typed arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz: str=None, buzz: list[str]=None):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz: str=None, buzz: list[str]=None):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz: [TODO:description]
|
||||||
|
buzz: [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with named untyped arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz=None, buzz=8):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz=None, buzz=8):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz ([TODO:parameter]): [TODO:description]
|
||||||
|
buzz ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with positional typed arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz: str, buzz: list[str]):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz: str, buzz: list[str]):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz: [TODO:description]
|
||||||
|
buzz: [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with positional untyped arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz, buzz):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz, buzz):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz ([TODO:parameter]): [TODO:description]
|
||||||
|
buzz ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with required named typed arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz, *, buzz: int):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz, *, buzz: int):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz ([TODO:parameter]): [TODO:description]
|
||||||
|
buzz: [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with required named untyped arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(fizz, *, buzz):|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(fizz, *, buzz):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fizz ([TODO:parameter]): [TODO:description]
|
||||||
|
buzz ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO: These tests currently fail but should pass. Fix the bugs!
|
||||||
|
-- it("works with *args typed arguments", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(*args: list[str]):|cursor|
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(*args: list[str]):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- *args: [TODO:description]
|
||||||
|
-- """
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
--
|
||||||
|
-- it("works with *args untyped arguments", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(*args):|cursor|
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(*args):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- *args: [TODO:description]
|
||||||
|
-- """
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
-- TODO: These tests currently fail but should pass. Fix the bugs!
|
||||||
|
-- it("works with *kwargs typed arguments", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(**kwargs: dict[str, str]):|cursor|
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(**kwargs: dict[str, str]):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- **kwargs: [TODO:description]
|
||||||
|
-- """
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
--
|
||||||
|
-- it("works with *args untyped arguments", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(**kwargs):|cursor|
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(**kwargs):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- **kwargs: [TODO:description]
|
||||||
|
-- """
|
||||||
|
-- pass
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("func - raises", function()
|
||||||
|
it("does not show when implicitly re-raising an exception", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
try:
|
||||||
|
blah()
|
||||||
|
except:
|
||||||
|
print("Oh no!")
|
||||||
|
|
||||||
|
raise
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]"""
|
||||||
|
try:
|
||||||
|
blah()
|
||||||
|
except:
|
||||||
|
print("Oh no!")
|
||||||
|
|
||||||
|
raise
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO: This is broken. Fix it!
|
||||||
|
-- This used to work but broke later on, it seems - https://github.com/danymat/neogen/pull/142
|
||||||
|
-- it("lists only one entry per-raised type", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(bar):|cursor|
|
||||||
|
-- if bar:
|
||||||
|
-- raise TypeError("THING")
|
||||||
|
--
|
||||||
|
-- if GLOBAL:
|
||||||
|
-- raise ValueError("asdffsd")
|
||||||
|
--
|
||||||
|
-- raise TypeError("BLAH")
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(bar):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- bar ([TODO:parameter]): [TODO:description]
|
||||||
|
--
|
||||||
|
-- Raises:
|
||||||
|
-- TypeError: [TODO:throw]
|
||||||
|
-- ValueError: [TODO:throw]
|
||||||
|
-- """
|
||||||
|
-- if bar:
|
||||||
|
-- raise TypeError("THING")
|
||||||
|
--
|
||||||
|
-- raise ValueError("asdffsd")
|
||||||
|
--
|
||||||
|
-- raise TypeError("BLAH")
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
it("works with modules, even if they are nested", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
raise some_package.submodule.BlahError("asdffsd")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
some_package.submodule.BlahError: [TODO:throw]
|
||||||
|
"""
|
||||||
|
raise some_package.submodule.BlahError("asdffsd")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with 1 raise", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
raise ValueError("asdffsd")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: [TODO:throw]
|
||||||
|
"""
|
||||||
|
raise ValueError("asdffsd")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO: This is broken. Fix it!
|
||||||
|
-- This used to work but broke later on, it seems - https://github.com/danymat/neogen/pull/142
|
||||||
|
-- it("works with 2+ raises", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def foo(bar):|cursor|
|
||||||
|
-- if bar:
|
||||||
|
-- raise TypeError("THING")
|
||||||
|
--
|
||||||
|
-- if GLOBAL:
|
||||||
|
-- raise TypeError("asdffsd")
|
||||||
|
--
|
||||||
|
-- raise TypeError("BLAH")
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def foo(bar):
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- bar ([TODO:parameter]): [TODO:description]
|
||||||
|
--
|
||||||
|
-- Raises:
|
||||||
|
-- TypeError: [TODO:throw]
|
||||||
|
-- """
|
||||||
|
-- if bar:
|
||||||
|
-- raise TypeError("THING")
|
||||||
|
--
|
||||||
|
-- if GLOBAL:
|
||||||
|
-- raise TypeError("asdffsd")
|
||||||
|
--
|
||||||
|
-- raise TypeError("BLAH")
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("func - returns", function()
|
||||||
|
it("does not show if there are only implicit returns", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(bar):|cursor|
|
||||||
|
if bar:
|
||||||
|
return
|
||||||
|
|
||||||
|
return # Unneeded but good for the unittest
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(bar):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bar ([TODO:parameter]): [TODO:description]
|
||||||
|
"""
|
||||||
|
if bar:
|
||||||
|
return
|
||||||
|
|
||||||
|
return # Unneeded but good for the unittest
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO: This test is broken. Needs fixing
|
||||||
|
-- it("works with an inline comment", function()
|
||||||
|
-- local source = [[
|
||||||
|
-- def flags(self, index):|cursor| # pylint: disable=unused-argument
|
||||||
|
-- return (
|
||||||
|
-- QtCore.Qt.ItemIsEnabled
|
||||||
|
-- | QtCore.Qt.ItemIsSelectable
|
||||||
|
-- | QtCore.Qt.ItemIsUserCheckable
|
||||||
|
-- )
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local expected = [[
|
||||||
|
-- def flags(self, index): # pylint: disable=unused-argument
|
||||||
|
-- """[TODO:description]
|
||||||
|
--
|
||||||
|
-- Args:
|
||||||
|
-- self ([TODO:parameter]): [TODO:description]
|
||||||
|
-- index ([TODO:parameter]): [TODO:description]
|
||||||
|
--
|
||||||
|
-- Returns:
|
||||||
|
-- [TODO:return]
|
||||||
|
-- """
|
||||||
|
-- return (
|
||||||
|
-- QtCore.Qt.ItemIsEnabled
|
||||||
|
-- | QtCore.Qt.ItemIsSelectable
|
||||||
|
-- | QtCore.Qt.ItemIsUserCheckable
|
||||||
|
-- )
|
||||||
|
-- ]]
|
||||||
|
--
|
||||||
|
-- local result = _make_python_docstring(source)
|
||||||
|
--
|
||||||
|
-- assert.equal(expected, result)
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
it("works with no arguments", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
return 10
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
return 10
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with no return", function()
|
||||||
|
local source = [[
|
||||||
|
def foo():|cursor|
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo():
|
||||||
|
"""[TODO:description]"""
|
||||||
|
pass
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with various returns in one function", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(items):|cursor|
|
||||||
|
for item in items:
|
||||||
|
if item == "blah":
|
||||||
|
return "asdf"
|
||||||
|
|
||||||
|
return "something else"
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(items):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
[TODO:return]
|
||||||
|
"""
|
||||||
|
for item in items:
|
||||||
|
if item == "blah":
|
||||||
|
return "asdf"
|
||||||
|
|
||||||
|
return "something else"
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("func - yields", function()
|
||||||
|
it("works even with no explicit yield value", function()
|
||||||
|
local source = [[
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def foo(items):|cursor|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except:
|
||||||
|
print("bad thing happened")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def foo(items):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
[TODO:description]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except:
|
||||||
|
print("bad thing happened")
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works when doing yield + return at once", function()
|
||||||
|
local source = [[
|
||||||
|
def items(value):|cursor|
|
||||||
|
if value:
|
||||||
|
return
|
||||||
|
yield
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def items(value):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
[TODO:description]
|
||||||
|
"""
|
||||||
|
if value:
|
||||||
|
return
|
||||||
|
yield
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with 2+ yields in one function", function()
|
||||||
|
local source = [[
|
||||||
|
def foo(thing):|cursor|
|
||||||
|
if thing:
|
||||||
|
yield 10
|
||||||
|
yield 20
|
||||||
|
yield 30
|
||||||
|
else:
|
||||||
|
yield 0
|
||||||
|
|
||||||
|
for _ in range(10):
|
||||||
|
yield
|
||||||
|
]]
|
||||||
|
|
||||||
|
local expected = [[
|
||||||
|
def foo(thing):
|
||||||
|
"""[TODO:description]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
thing ([TODO:parameter]): [TODO:description]
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
[TODO:description]
|
||||||
|
"""
|
||||||
|
if thing:
|
||||||
|
yield 10
|
||||||
|
yield 20
|
||||||
|
yield 30
|
||||||
|
else:
|
||||||
|
yield 0
|
||||||
|
|
||||||
|
for _ in range(10):
|
||||||
|
yield
|
||||||
|
]]
|
||||||
|
|
||||||
|
local result = make_google_docstrings(source)
|
||||||
|
|
||||||
|
assert.equal(expected, result)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
47
tests/utils/specs.lua
Normal file
47
tests/utils/specs.lua
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
local textmate = require("tests.utils.textmate")
|
||||||
|
local neogen = require("neogen")
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
--- Make a docstring for given language and return the `neogen` result.
|
||||||
|
---@param source string Pseudo-source-code to call. It contains `"|cursor|"` which is the expected user position.
|
||||||
|
---@param filetype string Buffer filetype.
|
||||||
|
---@param neogen_opts table? Custom Neogen opts passed during generate command.
|
||||||
|
---@return string? # The same source code, after calling neogen.
|
||||||
|
function M.make_docstring(source, filetype, neogen_opts)
|
||||||
|
local result = textmate.extract_cursors(source)
|
||||||
|
|
||||||
|
if not result then
|
||||||
|
vim.notify(
|
||||||
|
string.format("Source\n\n%s\n\nwas not parsable. Does it have a |cursor| defined?", source),
|
||||||
|
vim.log.levels.ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local cursors, code = unpack(result)
|
||||||
|
|
||||||
|
local buffer = vim.api.nvim_create_buf(true, true)
|
||||||
|
vim.bo[buffer].filetype = filetype
|
||||||
|
vim.cmd.buffer(buffer)
|
||||||
|
local window = vim.fn.win_getid() -- We just created the buffer so the current window works
|
||||||
|
|
||||||
|
local strict_indexing = false
|
||||||
|
vim.api.nvim_buf_set_lines(buffer, 0, -1, strict_indexing, vim.fn.split(code, "\n"))
|
||||||
|
|
||||||
|
-- IMPORTANT: Because we are adding docstrings in the buffer, we must start
|
||||||
|
-- from the bottom docstring up. Otherwise the row/column positions of the
|
||||||
|
-- next `cursor` in `cursors` will be out of date.
|
||||||
|
for index = #cursors, 1, -1 do
|
||||||
|
local cursor = cursors[index]
|
||||||
|
vim.api.nvim_win_set_cursor(window, cursor)
|
||||||
|
|
||||||
|
neogen_opts = vim.tbl_deep_extend("force", { snippet_engine = "nvim" }, neogen_opts or {})
|
||||||
|
neogen.generate(neogen_opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(vim.api.nvim_buf_get_lines(buffer, 0, -1, strict_indexing), "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
65
tests/utils/textmate.lua
Normal file
65
tests/utils/textmate.lua
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
--- A file to make dealing with text in Lua a little easier.
|
||||||
|
---
|
||||||
|
--- @module 'tests.textmate'
|
||||||
|
|
||||||
|
local _CURSOR_MARKER = "|cursor|"
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
---@class Cursor
|
||||||
|
--- A fake position in-space where a user's cursor is meant to be.
|
||||||
|
---@field [1] number
|
||||||
|
--- A 1-or-more value indicating the buffer line value.
|
||||||
|
---@field [2] number
|
||||||
|
--- A 1-or-more value indicating the buffer column value.
|
||||||
|
|
||||||
|
--- Find all lines marked with `"|cursor|"` and return their row / column positions.
|
||||||
|
---
|
||||||
|
---@param source string Pseudo-Python source-code to call. It contains `"|cursor|"` which is the expected user position.
|
||||||
|
---@return Cursor[] # The row and column cursor position in `source`.
|
||||||
|
---@return string # The same source code but with `"|cursor|"` stripped out.
|
||||||
|
function M.extract_cursors(source)
|
||||||
|
local index = 1
|
||||||
|
local count = #source
|
||||||
|
local cursors = {}
|
||||||
|
local cursor_marker_offset = #_CURSOR_MARKER - 1
|
||||||
|
local code = ""
|
||||||
|
|
||||||
|
local current_row = 1
|
||||||
|
local current_column = 1
|
||||||
|
|
||||||
|
while index <= count do
|
||||||
|
local character = source:sub(index, index)
|
||||||
|
|
||||||
|
if character == "\n" then
|
||||||
|
current_row = current_row + 1
|
||||||
|
current_column = 1
|
||||||
|
else
|
||||||
|
current_column = current_column + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if character == "|" then
|
||||||
|
if source:sub(index, index + cursor_marker_offset) == _CURSOR_MARKER then
|
||||||
|
index = index + cursor_marker_offset
|
||||||
|
table.insert(cursors, { current_row, current_column })
|
||||||
|
else
|
||||||
|
code = code .. character
|
||||||
|
end
|
||||||
|
else
|
||||||
|
code = code .. character
|
||||||
|
end
|
||||||
|
|
||||||
|
index = index + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if index <= count then
|
||||||
|
-- If this happens, is because the while loop called `break` early
|
||||||
|
-- This is very likely so we add the last character(s) to the output
|
||||||
|
local remainder = source:sub(index, #source)
|
||||||
|
code = code .. remainder
|
||||||
|
end
|
||||||
|
|
||||||
|
return { cursors, code }
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
Reference in New Issue
Block a user