170 lines
4.4 KiB
Python
170 lines
4.4 KiB
Python
|
import pytest
|
||
|
import gc
|
||
|
import weakref
|
||
|
import time
|
||
|
import os.path
|
||
|
|
||
|
__all__ = ('kivy_clock', 'kivy_metrics', 'kivy_exception_manager', 'kivy_app')
|
||
|
|
||
|
|
||
|
@pytest.fixture()
|
||
|
def kivy_clock():
|
||
|
from kivy.context import Context
|
||
|
from kivy.clock import ClockBase
|
||
|
|
||
|
context = Context(init=False)
|
||
|
context['Clock'] = ClockBase()
|
||
|
context.push()
|
||
|
|
||
|
from kivy.clock import Clock
|
||
|
Clock._max_fps = 0
|
||
|
|
||
|
try:
|
||
|
Clock.start_clock()
|
||
|
yield Clock
|
||
|
Clock.stop_clock()
|
||
|
finally:
|
||
|
context.pop()
|
||
|
|
||
|
|
||
|
@pytest.fixture()
|
||
|
def kivy_metrics():
|
||
|
from kivy.context import Context
|
||
|
from kivy.metrics import MetricsBase, Metrics
|
||
|
from kivy._metrics import dispatch_pixel_scale
|
||
|
|
||
|
context = Context(init=False)
|
||
|
context['Metrics'] = MetricsBase()
|
||
|
context.push()
|
||
|
# need to do it to reset the global value
|
||
|
dispatch_pixel_scale()
|
||
|
|
||
|
try:
|
||
|
yield Metrics
|
||
|
finally:
|
||
|
context.pop()
|
||
|
Metrics._set_cached_scaling()
|
||
|
|
||
|
|
||
|
@pytest.fixture()
|
||
|
def kivy_exception_manager():
|
||
|
from kivy.context import Context
|
||
|
from kivy.base import ExceptionManagerBase, ExceptionManager
|
||
|
|
||
|
context = Context(init=False)
|
||
|
context['ExceptionManager'] = ExceptionManagerBase()
|
||
|
context.push()
|
||
|
|
||
|
try:
|
||
|
yield ExceptionManager
|
||
|
finally:
|
||
|
context.pop()
|
||
|
|
||
|
|
||
|
# keep track of all the kivy app fixtures so that we can check that it
|
||
|
# properly dies
|
||
|
apps = []
|
||
|
|
||
|
|
||
|
@pytest.fixture()
|
||
|
async def kivy_app(request, nursery):
|
||
|
gc.collect()
|
||
|
if apps:
|
||
|
last_app, last_request = apps.pop()
|
||
|
assert last_app() is None, \
|
||
|
'Memory leak: failed to release app for test ' + repr(last_request)
|
||
|
|
||
|
from os import environ
|
||
|
environ['KIVY_USE_DEFAULTCONFIG'] = '1'
|
||
|
|
||
|
# force window size + remove all inputs
|
||
|
from kivy.config import Config
|
||
|
Config.set('graphics', 'width', '320')
|
||
|
Config.set('graphics', 'height', '240')
|
||
|
for items in Config.items('input'):
|
||
|
Config.remove_option('input', items[0])
|
||
|
|
||
|
from kivy.core.window import Window
|
||
|
from kivy.context import Context
|
||
|
from kivy.clock import ClockBase
|
||
|
from kivy.factory import FactoryBase, Factory
|
||
|
from kivy.app import App
|
||
|
from kivy.lang.builder import BuilderBase, Builder
|
||
|
from kivy.base import stopTouchApp
|
||
|
from kivy import kivy_data_dir
|
||
|
from kivy.logger import LoggerHistory
|
||
|
|
||
|
kivy_eventloop = environ.get('KIVY_EVENTLOOP', 'asyncio')
|
||
|
if kivy_eventloop == 'asyncio':
|
||
|
pytest.importorskip(
|
||
|
'pytest_asyncio',
|
||
|
reason='KIVY_EVENTLOOP == "asyncio" but '
|
||
|
'"pytest_asyncio" is not installed')
|
||
|
async_lib = 'asyncio'
|
||
|
elif kivy_eventloop == 'trio':
|
||
|
pytest.importorskip(
|
||
|
'pytest_trio',
|
||
|
reason='KIVY_EVENTLOOP == "trio" but '
|
||
|
'"pytest_trio" is not installed')
|
||
|
async_lib = 'trio'
|
||
|
else:
|
||
|
pytest.skip(
|
||
|
'KIVY_EVENTLOOP must be set to either of "asyncio" or '
|
||
|
'"trio" to run async tests')
|
||
|
|
||
|
context = Context(init=False)
|
||
|
context['Clock'] = ClockBase(async_lib=async_lib)
|
||
|
|
||
|
# have to make sure all global kv files are loaded before this because
|
||
|
# globally read kv files (e.g. on module import) will not be loaded again
|
||
|
# in the new builder, except if manually loaded, which we don't do
|
||
|
context['Factory'] = FactoryBase.create_from(Factory)
|
||
|
context['Builder'] = BuilderBase.create_from(Builder)
|
||
|
context.push()
|
||
|
|
||
|
Window.create_window()
|
||
|
Window.register()
|
||
|
Window.initialized = True
|
||
|
Window.canvas.clear()
|
||
|
|
||
|
app = request.param[0]()
|
||
|
app.set_async_lib(async_lib)
|
||
|
|
||
|
if async_lib == 'asyncio':
|
||
|
import asyncio
|
||
|
loop = asyncio.get_event_loop()
|
||
|
loop.create_task(app.async_run())
|
||
|
else:
|
||
|
nursery.start_soon(app.async_run)
|
||
|
from kivy.clock import Clock
|
||
|
Clock._max_fps = 0
|
||
|
|
||
|
ts = time.perf_counter()
|
||
|
while not app.app_has_started:
|
||
|
await app.async_sleep(.1)
|
||
|
if time.perf_counter() - ts >= 10:
|
||
|
raise TimeoutError()
|
||
|
|
||
|
await app.wait_clock_frames(5)
|
||
|
|
||
|
yield app
|
||
|
|
||
|
stopTouchApp()
|
||
|
|
||
|
ts = time.perf_counter()
|
||
|
while not app.app_has_stopped:
|
||
|
await app.async_sleep(.1)
|
||
|
if time.perf_counter() - ts >= 10:
|
||
|
raise TimeoutError()
|
||
|
|
||
|
for child in Window.children[:]:
|
||
|
Window.remove_widget(child)
|
||
|
context.pop()
|
||
|
|
||
|
# release all the resources
|
||
|
del context
|
||
|
LoggerHistory.clear_history()
|
||
|
apps.append((weakref.ref(app), request))
|
||
|
del app
|
||
|
gc.collect()
|