mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
autodoc crashed when a decorator in mocked module takes arguments because mock system returns the first argument for the decorator as a decorated object. This changes the approach for mocking decorators that remembers arguments for each decoration, and fetch the latest argument on generating document.
153 lines
3.9 KiB
Python
153 lines
3.9 KiB
Python
"""
|
|
test_ext_autodoc_mock
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Test the autodoc extension.
|
|
|
|
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
|
:license: BSD, see LICENSE for details.
|
|
"""
|
|
|
|
import abc
|
|
import sys
|
|
from importlib import import_module
|
|
from typing import TypeVar
|
|
|
|
import pytest
|
|
|
|
from sphinx.ext.autodoc.mock import _MockModule, _MockObject, ismock, mock, undecorate
|
|
|
|
|
|
def test_MockModule():
|
|
mock = _MockModule('mocked_module')
|
|
assert isinstance(mock.some_attr, _MockObject)
|
|
assert isinstance(mock.some_method, _MockObject)
|
|
assert isinstance(mock.attr1.attr2, _MockObject)
|
|
assert isinstance(mock.attr1.attr2.meth(), _MockObject)
|
|
|
|
assert repr(mock.some_attr) == 'mocked_module.some_attr'
|
|
assert repr(mock.some_method) == 'mocked_module.some_method'
|
|
assert repr(mock.attr1.attr2) == 'mocked_module.attr1.attr2'
|
|
assert repr(mock.attr1.attr2.meth) == 'mocked_module.attr1.attr2.meth'
|
|
|
|
assert repr(mock) == 'mocked_module'
|
|
|
|
|
|
def test_MockObject():
|
|
mock = _MockObject()
|
|
assert isinstance(mock.some_attr, _MockObject)
|
|
assert isinstance(mock.some_method, _MockObject)
|
|
assert isinstance(mock.attr1.attr2, _MockObject)
|
|
assert isinstance(mock.attr1.attr2.meth(), _MockObject)
|
|
|
|
# subclassing
|
|
class SubClass(mock.SomeClass):
|
|
"""docstring of SubClass"""
|
|
|
|
def method(self):
|
|
return "string"
|
|
|
|
obj = SubClass()
|
|
assert SubClass.__doc__ == "docstring of SubClass"
|
|
assert isinstance(obj, SubClass)
|
|
assert obj.method() == "string"
|
|
assert isinstance(obj.other_method(), SubClass)
|
|
|
|
# parametrized type
|
|
T = TypeVar('T')
|
|
|
|
class SubClass2(mock.SomeClass[T]):
|
|
"""docstring of SubClass"""
|
|
|
|
obj2 = SubClass2()
|
|
assert SubClass2.__doc__ == "docstring of SubClass"
|
|
assert isinstance(obj2, SubClass2)
|
|
|
|
|
|
def test_mock():
|
|
modname = 'sphinx.unknown'
|
|
submodule = modname + '.submodule'
|
|
assert modname not in sys.modules
|
|
with pytest.raises(ImportError):
|
|
import_module(modname)
|
|
|
|
with mock([modname]):
|
|
import_module(modname)
|
|
assert modname in sys.modules
|
|
assert isinstance(sys.modules[modname], _MockModule)
|
|
|
|
# submodules are also mocked
|
|
import_module(submodule)
|
|
assert submodule in sys.modules
|
|
assert isinstance(sys.modules[submodule], _MockModule)
|
|
|
|
assert modname not in sys.modules
|
|
with pytest.raises(ImportError):
|
|
import_module(modname)
|
|
|
|
|
|
def test_mock_does_not_follow_upper_modules():
|
|
with mock(['sphinx.unknown.module']):
|
|
with pytest.raises(ImportError):
|
|
import_module('sphinx.unknown')
|
|
|
|
|
|
@pytest.mark.skipif(sys.version_info < (3, 7), reason='Only for py37 or above')
|
|
def test_abc_MockObject():
|
|
mock = _MockObject()
|
|
|
|
class Base:
|
|
@abc.abstractmethod
|
|
def __init__(self):
|
|
pass
|
|
|
|
class Derived(Base, mock.SubClass):
|
|
pass
|
|
|
|
obj = Derived()
|
|
assert isinstance(obj, Base)
|
|
assert isinstance(obj, _MockObject)
|
|
assert isinstance(obj.some_method(), Derived)
|
|
|
|
|
|
def test_mock_decorator():
|
|
mock = _MockObject()
|
|
|
|
@mock.function_deco
|
|
def func():
|
|
pass
|
|
|
|
class Foo:
|
|
@mock.method_deco
|
|
def meth(self):
|
|
pass
|
|
|
|
@mock.class_deco
|
|
class Bar:
|
|
pass
|
|
|
|
@mock.funcion_deco(Foo)
|
|
class Baz:
|
|
pass
|
|
|
|
assert undecorate(func).__name__ == "func"
|
|
assert undecorate(Foo.meth).__name__ == "meth"
|
|
assert undecorate(Bar).__name__ == "Bar"
|
|
assert undecorate(Baz).__name__ == "Baz"
|
|
|
|
|
|
def test_ismock():
|
|
with mock(['sphinx.unknown']):
|
|
mod1 = import_module('sphinx.unknown')
|
|
mod2 = import_module('sphinx.application')
|
|
|
|
class Inherited(mod1.Class):
|
|
pass
|
|
|
|
assert ismock(mod1) is True
|
|
assert ismock(mod1.Class) is True
|
|
assert ismock(Inherited) is False
|
|
|
|
assert ismock(mod2) is False
|
|
assert ismock(mod2.Sphinx) is False
|