-
Notifications
You must be signed in to change notification settings - Fork 366
Expand file tree
/
Copy pathtest_examples.py
More file actions
98 lines (81 loc) · 2.87 KB
/
test_examples.py
File metadata and controls
98 lines (81 loc) · 2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""
Import and run all examples one frame
"""
import contextlib
import io
import inspect
import os
from importlib.machinery import SourceFileLoader
from pathlib import Path
import arcade
import pytest
import arcade.clock
# File path, module path
EXAMPLE_LOCATIONS = [
(Path(arcade.__file__).parent / "examples", "arcade.examples"),
(
Path(arcade.__file__).parent / "examples" / "platform_tutorial",
"arcade.examples.platform_tutorial",
),
(Path(arcade.__file__).parent / "examples" / "gl", "arcade.examples.gl"),
]
# These examples are allowed to print to stdout
ALLOW_STDOUT = set(
[
"arcade.examples.dual_stick_shooter",
"transform_multi",
]
)
IGNORE_PATTERNS = [
"net_process_animal_facts", # Starts network process
"transform_emit", # Broken
"compute", # Compute shader stuff we can't run in unit test
"multisample", # Anything requiring multisampling we can't run in unit test
"indirect", # Indirect rendering cannot be run in unit test
"bindless", # Bindless textures cannot be run in unit test
"spritelist_interaction", # Currently only works for spritelist buffer backend. Not textures.
"numpy_sprite", # Needs numpy installed as a dependency
]
def list_examples():
for path, module_path in EXAMPLE_LOCATIONS:
for example in path.glob("*.py"):
if example.stem.startswith("_"):
continue
def is_ignored(example):
for pattern in IGNORE_PATTERNS:
if pattern in example.stem:
return True
return False
if is_ignored(example):
continue
yield f"{module_path}.{example.stem}", example, True
def find_class_inheriting_from_window(module):
for name, obj in module.__dict__.items():
match = inspect.isclass(obj) and issubclass(obj, arcade.Window)
if match:
return obj
return None
def find_main_function(module):
if "main" in module.__dict__:
return module.__dict__["main"]
return None
@pytest.mark.parametrize(
"module_path, file_path, allow_stdout",
list_examples(),
)
def test_examples(window_proxy, module_path, file_path, allow_stdout):
"""Run all examples"""
os.environ["ARCADE_TEST"] = "TRUE"
print(f"Running {module_path}...")
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
# Manually load the module as __main__ so it runs on import
loader = SourceFileLoader("__main__", str(file_path))
loader.exec_module(loader.load_module())
# Reset the global clock's tick speed
# is this a good argument against a global scope clock?
# yes.
arcade.clock.GLOBAL_CLOCK.set_tick_speed(1.0)
if not allow_stdout:
output = stdout.getvalue()
assert not output, f"Example {module_path} printed to stdout: {output}"