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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
"""
Base classes for test cases using the normal pyglet application event loop.
"""
import pytest
import pyglet
from pyglet import clock
from pyglet import gl
from pyglet.graphics import Batch
from pyglet.text.document import FormattedDocument
from pyglet.text.layout import TextLayout
from pyglet.window import Window, key
from .interactive import InteractiveFixture
@pytest.fixture
def event_loop(request):
return EventLoopFixture(request)
class EventLoopFixture(InteractiveFixture):
question = '\n\n(P)ass/(F)ail/(S)kip/(Q)uit?'
key_pass = key.P
key_fail = key.F
key_skip = key.S
key_quit = key.Q
clear_color = 1, 1, 1, 1
base_options = {
'width': 300,
'height': 300,
}
def __init__(self, request):
super().__init__(request)
self._request = request
self.window = None
self.text_batch = None
self.text_document = None
self.answer = None
request.addfinalizer(self.tear_down)
def tear_down(self):
if self.window:
self.window.close()
self.window = None
def create_window(self, **kwargs):
combined_kwargs = {}
combined_kwargs.update(self.base_options)
combined_kwargs.update(kwargs)
self.window = Window(**combined_kwargs)
self.window.push_handlers(self)
return self.window
def get_document(self):
if self.text_document is None:
self._create_text()
return self.text_document
def _create_text(self):
assert self.window is not None
self.text_batch = Batch()
self.text_document = FormattedDocument()
layout = TextLayout(self.text_document, self.window.width, self.window.height,
multiline=True, wrap_lines=True, batch=self.text_batch)
layout.content_valign = 'bottom'
def add_text(self, text):
self.get_document()
self.text_document.insert_text(len(self.text_document.text), text)
def ask_question(self, description=None, screenshot=True):
"""Ask a question inside the test window. By default takes a screenshot and validates
that too."""
if self.window is None:
self.create_window()
self.add_text('\n\n')
if description:
self.add_text(description)
self.add_text(self.question)
self.answer = None
caught_exception = None
try:
if self.interactive:
self.run_event_loop()
self.handle_answer()
else:
self.run_event_loop(0.1)
except Exception as ex:
import traceback
traceback.print_exc()
caught_exception = ex
finally:
if screenshot:
try:
screenshot_name = self._take_screenshot(self.window)
if caught_exception is None and not self.interactive:
self._check_screenshot(screenshot_name)
except:
if not caught_exception:
raise
if caught_exception:
raise caught_exception
def handle_answer(self):
if self.answer is None:
raise Exception('Did not receive valid input in question window')
elif self.answer == self.key_fail:
# TODO: Ask input
pytest.fail('Tester marked test failed')
elif self.answer == self.key_skip:
pytest.skip('Tester marked test skipped')
elif self.answer == self.key_quit:
pytest.exit('Tester requested to quit')
def ask_question_no_window(self, description=None):
"""Ask a question to verify the current test result. Uses the console or an external gui
as no window is available."""
super().ask_question(description)
def run_event_loop(self, duration=None):
if duration:
clock.schedule_once(self.interrupt_event_loop, duration)
pyglet.app.run()
def interrupt_event_loop(self, *args, **kwargs):
pyglet.app.exit()
@staticmethod
def schedule_once(callback, dt=.1):
clock.schedule_once(callback, dt)
def on_draw(self):
self.clear()
self.draw_text()
def clear(self):
gl.glClearColor(*self.clear_color)
self.window.clear()
def draw_text(self):
if self.text_batch is not None:
self.text_batch.draw()
def on_key_press(self, symbol, modifiers):
if symbol in (self.key_pass, self.key_fail, self.key_skip, self.key_quit):
self.answer = symbol
self.interrupt_event_loop()
# Prevent handling of Escape to close the window
return True
def test_question_pass(event_loop):
event_loop.create_window()
event_loop.ask_question('If you read this text, you should let the test pass.')
def test_question_fail(event_loop):
event_loop.create_window()
with pytest.raises(pytest.fail.Exception):
event_loop.ask_question('Please press F to fail this test.')
def test_question_skip(event_loop):
event_loop.create_window()
event_loop.ask_question('Please press S to skip the rest of this test.')
pytest.fail('You should have pressed S')
|