Skip to content

Commit d7ee7e0

Browse files
committed
Revive and rewrite docs tests
1 parent 634775e commit d7ee7e0

File tree

3 files changed

+58
-59
lines changed

3 files changed

+58
-59
lines changed

.vscode/launch.json

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@
1414
"runeffect",
1515
"examples.cubes",
1616
],
17+
},
18+
{
19+
"name": "Python: demosys-py test",
20+
"type": "python",
21+
"request": "launch",
22+
"console": "none",
23+
"program": "${workspaceFolder}/manage.py",
24+
"args": [
25+
"test",
26+
"tests/test_docs.py",
27+
],
1728
}
1829
]
1930
}

demosys/test/testcase.py

+16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import sys
12
from unittest import TestCase
3+
from unittest.mock import MagicMock
24

35
from demosys import context, resources
46
from demosys import project
@@ -9,6 +11,18 @@
911
DataDescription,
1012
)
1113

14+
MOCK_MODULES = ['glfw', 'pyglet', 'pyglet.window']
15+
16+
17+
def apply_mocks():
18+
# Mock modules
19+
class Mock(MagicMock):
20+
@classmethod
21+
def __getattr__(cls, name):
22+
return MagicMock()
23+
24+
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
25+
1226

1327
class DemosysTestCase(TestCase):
1428

@@ -17,6 +31,8 @@ class DemosysTestCase(TestCase):
1731
project = project.instance
1832
timeline = None
1933

34+
apply_mocks()
35+
2036
def load_program(self, path):
2137
return resources.programs.load(ProgramDescription(label=path, path=path))
2238

tests/test_docs.py

+31-59
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,51 @@
11
"""
22
Documentation testing
33
4-
Based on:
4+
Inspired by:
55
https://github.com/cprogrammer1994/ModernGL/blob/master/tests/test_documentation.py
66
by Szabolcs Dombi
7+
8+
This version is simplified:
9+
* Only test if the attribute or method is present in the class. Function parameters are not inspected.
10+
* Include ignore pattern in the implemented set
711
"""
8-
import inspect
912
import os
1013
import re
11-
import unittest
12-
13-
os.environ['DEMOSYS_SETTINGS_MODULE'] = 'tests.settings' # noqa
1414

15-
import demosys
16-
from demosys import effects, opengl
15+
from demosys.test import DemosysTestCase
16+
from demosys.utils import module_loading
1717

18-
# Modules we want to remove from types
19-
MODULES = [
20-
'demosys.',
21-
'opengl.',
22-
'texture.',
23-
'shader.',
24-
'resources.',
25-
'data.',
26-
'moderngl.',
27-
'buffer.',
28-
'rocket.',
29-
'tracks.',
30-
'scene.',
31-
'buffer.',
32-
'depth.',
33-
'texture_array.',
34-
'program.',
35-
'vertex_array.',
36-
'array.',
37-
]
18+
os.environ['DEMOSYS_SETTINGS_MODULE'] = 'tests.settings' # noqa
3819

39-
class TestCase(unittest.TestCase):
4020

21+
class TestCase(DemosysTestCase):
22+
"""
23+
Test reference docs
24+
"""
4125
def validate(self, filename, module, classname, ignore):
42-
root = os.path.dirname(os.path.dirname(__file__))
43-
with open(os.path.normpath(os.path.join(root, 'docs', 'source', filename))) as f:
26+
"""
27+
Finds all automethod and autoattribute statements in an rst file
28+
comparing them to the attributes found in the actual class
29+
"""
30+
with open(os.path.normpath(os.path.join('docs', 'reference', filename))) as f:
4431
docs = f.read()
45-
methods = re.findall(r'^\.\. automethod:: ([^\(\n]+)([^\n]+)', docs, flags=re.M)
46-
attributes = re.findall(r'^\.\. autoattribute:: ([^\n]+)', docs, flags=re.M)
47-
documented = set(filter(lambda x: x.startswith(classname), [a for a, b in methods] + attributes))
48-
implemented = set(classname + '.' + x for x in dir(getattr(module, classname)) if not x.startswith('_'))
49-
ignored = set(classname + '.' + x for x in ignore)
50-
self.assertSetEqual(implemented - documented - ignored, set(), msg='Implemented but not Documented')
51-
self.assertSetEqual(documented - implemented, set(), msg='Documented but not Implemented')
52-
53-
for method, docsig in methods:
54-
classname, methodname = method.split('.')
55-
sig = str(inspect.signature(getattr(getattr(module, classname), methodname)))
56-
print(sig)
57-
sig = sig.replace('self, ', '').replace('typing.', '').replace(' -> None', '')
5832

59-
for m in MODULES:
60-
sig = sig.replace(m, '')
33+
module = module_loading.import_module(module)
6134

62-
sig = sig.replace('(self)', '()').replace(', *,', ',').replace('(*, ', '(')
63-
sig = re.sub(r'-> \'(\w+)\'', r'-> \1', sig)
35+
methods = re.findall(r'^\.\. automethod:: ([^\(\n]+)', docs, flags=re.M)
36+
attributes = re.findall(r'^\.\. autoattribute:: ([^\n]+)', docs, flags=re.M)
6437

65-
self.assertEqual(docsig, sig, msg=filename + '::' + method)
38+
documented = set(filter(lambda x: x.startswith(classname), [a for a in methods] + attributes))
39+
implemented = set(classname + '.' + x for x in dir(getattr(module, classname))
40+
if not x.startswith('_') or x == '__init__')
41+
print(implemented)
42+
ignored = set(classname + '.' + x for x in ignore)
6643

67-
# def test_effect_docs(self):
68-
# self.validate(
69-
# os.path.join('reference', 'effect.rst'),
70-
# effects, 'Effect', [])
44+
self.assertSetEqual(implemented - documented - ignored, set(), msg='Implemented but not Documented')
45+
self.assertSetEqual(documented - implemented - ignored, set(), msg='Documented but not Implemented')
7146

72-
# def test_vao_docs(self):
73-
# self.validate(
74-
# os.path.join('reference', 'vao.rst'),
75-
# opengl, 'VAO', []
76-
# )
47+
def test_demosys_contex_base(self):
48+
self.validate('demosys.context.base.rst', 'demosys.context.base', 'BaseWindow', [])
7749

78-
if __name__ == '__main__':
79-
unittest.main()
50+
def test_demosys_context_glfw(self):
51+
self.validate('demosys.context.glfw.rst', 'demosys.context.glfw', 'Window', [])

0 commit comments

Comments
 (0)