Added unittest + basic python and lua unittests (#174)

---------

Co-authored-by: Danymat <d.danymat@gmail.com>
This commit is contained in:
Colin Kennedy
2024-07-23 12:18:14 -04:00
committed by GitHub
parent 6de0add480
commit fef1ab3932
9 changed files with 1027 additions and 2 deletions

View 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)

View 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)