Skip to content

Commit

Permalink
Add unit tests for function renderer (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodmane authored Sep 24, 2023
1 parent 89e49e0 commit febf92f
Show file tree
Hide file tree
Showing 3 changed files with 278 additions and 3 deletions.
16 changes: 13 additions & 3 deletions sphinx_js/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,19 @@ def rst(
# Render to RST using Jinja:
env = Environment(loader=PackageLoader("sphinx_js", "templates"))
template = env.get_template(self._template)
return template.render(**self._template_vars(dotted_name, obj))
result = template.render(**self._template_vars(dotted_name, obj))
result = result.strip()
had_blank = False
lines = []
for line in result.splitlines():
if line.strip():
had_blank = False
lines.append(line.rstrip())
elif not had_blank:
lines.append("")
had_blank = True
result = "\n".join(lines) + "\n"
return result

def _formal_params(self, obj: Function | Class) -> str:
"""Return the JS function or class params, looking first to any
Expand Down Expand Up @@ -272,8 +284,6 @@ def _param_formatter(self, param: Param) -> tuple[list[str], str] | None:
# There's nothing worth saying about this param.
return None
heads = ["param"]
if param.type:
heads.append(self.format_type(param.type))
heads.append(param.name)

tail = param.description
Expand Down
1 change: 1 addition & 0 deletions sphinx_js/templates/common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
.. code-block:: js
{{ example|indent(3) }}
{% endfor %}
{%- endif %}
{% endmacro %}
Expand Down
264 changes: 264 additions & 0 deletions tests/test_renderers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
from textwrap import dedent, indent

import pytest

from sphinx_js.ir import Exc, Function, Param, Return, TypeParam, TypeXRefInternal
from sphinx_js.renderers import AutoFunctionRenderer


def setindent(txt):
return indent(dedent(txt), " " * 3)


@pytest.fixture()
def function_render() -> AutoFunctionRenderer:
renderer = AutoFunctionRenderer.__new__(AutoFunctionRenderer)
renderer._explicit_formal_params = None
renderer._content = []

def function_render(partial_path=None, use_short_name=False, **args):
if not partial_path:
partial_path = ["blah"]
return renderer.rst(partial_path, make_function(**args), use_short_name)

return function_render


def make_function(**args):
args = (
dict(
is_abstract=False,
is_optional=False,
is_static=False,
is_private=False,
name="",
path=[],
filename="",
deppath="",
description="",
line="",
deprecated="",
examples=[],
see_alsos=[],
properties=[],
exported_from=None,
params=[],
exceptions=[],
returns=[],
)
| args
)
return Function(**args)


# 'is_abstract', 'is_optional', 'is_static', 'is_private', 'name', 'path',
# 'filename', 'deppath', 'description', 'line', 'deprecated', 'examples',
# 'see_alsos', 'properties', 'exported_from', 'params', 'exceptions', and
# 'returns'


DEFAULT_RESULT = ".. js:function:: blah()\n"


def test_func_render_simple(function_render):
assert function_render() == DEFAULT_RESULT


def test_func_render_shortnames(function_render):
assert function_render(["a.", "b.", "c"]) == ".. js:function:: a.b.c()\n"
assert (
function_render(["a.", "b.", "c"], use_short_name=True)
== ".. js:function:: c()\n"
)


def test_func_render_flags(function_render):

# is_abstract is ignored? Maybe only makes sense if it is a class method??
# TODO: look into this.
assert function_render(is_abstract=True) == DEFAULT_RESULT
assert function_render(is_optional=True) == ".. js:function:: blah?()\n"
assert function_render(is_static=True) == ".. js:staticfunction:: blah()\n"
assert function_render(is_private=True) == DEFAULT_RESULT


def test_func_render_description(function_render):
assert function_render(
description="this is a description"
) == DEFAULT_RESULT + setindent(
"""
this is a description
""",
)


def test_func_render_params(function_render):
assert function_render(
description="this is a description",
params=[Param("a", description="a description")],
) == dedent(
"""\
.. js:function:: blah(a)
this is a description
:param a: a description
"""
)
assert function_render(
description="this is a description",
params=[Param("a", description="a description"), Param("b", "b description")],
) == dedent(
"""\
.. js:function:: blah(a, b)
this is a description
:param a: a description
:param b: b description
"""
)


def test_func_render_returns(function_render):
assert function_render(
params=[Param("a", description="a description"), Param("b", "b description")],
returns=[Return("number", "first thing"), Return("string", "second thing")],
) == dedent(
"""\
.. js:function:: blah(a, b)
:param a: a description
:param b: b description
:returns: **number** -- first thing
:returns: **string** -- second thing
"""
)


def test_func_render_type_params(function_render):
assert function_render(
params=[Param("a", type="T"), Param("b", type="S")],
type_params=[
TypeParam("T", "", "a type param"),
TypeParam("S", "", "second type param"),
],
) == dedent(
"""\
.. js:function:: blah(a, b)
:typeparam T: a type param
:typeparam S: second type param
:param a:
:param b:
:type a: **T**
:type b: **S**
"""
)


def test_func_render_param_type(function_render):
assert function_render(
description="this is a description",
params=[Param("a", description="a description", type="xxx")],
) == dedent(
"""\
.. js:function:: blah(a)
this is a description
:param a: a description
:type a: **xxx**
"""
)
assert function_render(
params=[
Param(
"a",
description="a description",
type=[TypeXRefInternal(name="A", path=["a.", "A"])],
)
],
) == dedent(
"""\
.. js:function:: blah(a)
:param a: a description
:type a: :js:class:`A`
"""
)


def test_func_render_param_options(function_render):
assert (
function_render(
params=[
Param(
"a",
has_default=True,
default="5",
)
],
)
== ".. js:function:: blah(a=5)\n"
)
assert function_render(
params=[
Param(
"a",
is_variadic=True,
)
],
) == dedent(".. js:function:: blah(...a)\n")


def test_func_render_param_exceptions(function_render):
assert function_render(
description="this is a description", exceptions=[Exc("TypeError", "")]
) == dedent(
"""\
.. js:function:: blah()
this is a description
:throws TypeError:
"""
)


def test_func_render_callouts(function_render):
assert function_render(deprecated=True) == DEFAULT_RESULT + setindent(
"""
.. note::
Deprecated.
""",
)
assert function_render(deprecated="v0.24") == DEFAULT_RESULT + setindent(
"""
.. note::
Deprecated: v0.24
""",
)
assert function_render(examples=["ex1", "ex2"]) == DEFAULT_RESULT + setindent(
"""
**Examples:**
.. code-block:: js
ex1
.. code-block:: js
ex2
""",
)
assert function_render(see_alsos=["see", "this too"]) == DEFAULT_RESULT + setindent(
"""
.. seealso::
- :any:`see`
- :any:`this too`
""",
)

0 comments on commit febf92f

Please sign in to comment.