"""Reader integration tests for the rewritten emulator suite.""" from __future__ import annotations import os import pytest from .support.reader_flow import ReaderSession, Session, app_name_matches _FRESH_READER_CASES = frozenset({ "test_reader_exit_returns_home_or_control_surface", }) def _restart_reader_emulator(emulator_reader) -> None: """Restart the shared emulator instance and wait for a ready reader baseline.""" emulator_reader.stop(force=True) emulator_reader.start(force=True) emulator_reader.wait_for_monitor(timeout=20.0) emulator_reader.wait_for_hwevent(timeout=20.0) emulator_reader.wait_for_informer_snapshot(timeout=20.0) emulator_reader.wait_for_active_task_info(timeout=20.0) Session(emulator_reader).wait_for_active_app( *ReaderSession.HOME_SURFACE_APPS, timeout=20.0, ) emulator_reader.wait_for_monitor_quiet(timeout=20.0, quiet_period=0.5) @pytest.fixture(scope="module", autouse=True) def _fresh_reader_module_session(emulator_reader): """Restart an externally managed emulator once for stable module isolation.""" if os.environ.get("PB_EMULATOR_EXTERNAL") != "1": yield return _restart_reader_emulator(emulator_reader) yield @pytest.fixture(autouse=True) def _fresh_reader_case_session(request, emulator_reader): """Restart before cases that cannot safely reuse a prior reader UI state.""" if request.node.name not in _FRESH_READER_CASES: yield return _restart_reader_emulator(emulator_reader) yield def test_reader_opens_real_book(emulator_reader): """The reader should open the staged real book from the home surface.""" rs = ReaderSession(Session(emulator_reader)) state = rs.ensure_open_from_home(timeout=15.0) assert app_name_matches(state.reader_task.appname, rs.READER_APP) assert state.opened_book_path.startswith("/mnt/ext1/") assert state.open_markers rs.session.assert_no_markers(rs.read_new_log(state), rs.CRASH_MARKERS) def test_reader_page_turn_changes_framebuffer(emulator_reader): """A reader page-turn gesture should change the framebuffer or log markers.""" rs = ReaderSession(Session(emulator_reader)) state = rs.ensure_open_from_home(timeout=15.0) result = rs.turn_page(state, timeout=10.0) assert result.after_hash != result.before_hash or result.matched_markers assert app_name_matches(result.reader_state.reader_task.appname, rs.READER_APP) rs.session.assert_no_markers(rs.read_new_log(result.reader_state), rs.CRASH_MARKERS) def test_reader_menu_exposes_exit_or_dialog(emulator_reader): """Opening the reader menu should show visible UI or log activity.""" rs = ReaderSession(Session(emulator_reader)) state = rs.ensure_open_from_home(timeout=15.0) menu = rs.open_menu(state, timeout=10.0) assert menu.matched_markers or menu.after_hash != menu.before_hash assert any( app_name_matches(menu.final_task.appname, app) for app in (rs.READER_APP, *rs.EXIT_CONTROL_APPS) ) rs.session.assert_no_markers(rs.read_new_log(state), rs.CRASH_MARKERS) def test_reader_exit_returns_home_or_control_surface(emulator_reader): """Leaving the reader should surface home UI or a control-surface task.""" rs = ReaderSession(Session(emulator_reader)) state = rs.ensure_open_from_home(timeout=15.0) result = rs.exit(timeout=12.0) assert result.control_surface_seen assert result.returned_home or result.new_control_tasks or result.matched_markers rs.session.assert_no_markers(rs.read_new_log(state), rs.CRASH_MARKERS)