Root had grown to 30 entries, most of it generated output and one-off scripts. It now holds 12. Docs: - Merge HARDWARE_SETUP, HARDWARE_PINOUT, GPIO_BUTTONS and ACCELEROMETER_PAGE_FLIP into a single docs/HARDWARE.md - Move ARCHITECTURE, REQUIREMENTS and HAL_IMPLEMENTATION_SPEC to docs/, leaving only README.md in the root - Update cross-references in README, setup_rpi.py and install_hardware_drivers.sh, and re-base ARCHITECTURE's source links Merging surfaced three errors, reconciled against hardware_config.json: - The power button was documented as GPIO 21 to GND with a pull-up. It is active high (pull_up: false); wiring it as documented reads as permanently pressed. - GPIO_BUTTONS used GPIO 23 for next-page; it is GPIO 27. - The FT5316 INT pin was routed to GPIO 27, which collides with the next-page button. Now documented as a conflict. Scripts: - Move debug_overlay_links.py and debug_previous_page.py to scripts/debug/ - Rename test_pagination_visual.py to scripts/debug/visualize_pagination.py; it renders output and asserts nothing, so the test_ prefix was misleading - Fix the __file__-relative paths these three relied on - Track update_pyweblayout.sh under scripts/ Tests: - Reword the backward-navigation tests, which described a pyWebLayout bug that is now fixed, as regression tests Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
"""
|
|
Regression test for backward navigation onto the cover page.
|
|
|
|
Going forward off the cover and then back again must return to block_index=0.
|
|
|
|
Previously it left current_position at the first content block (1) while flagging
|
|
the cover as displayed, so the cover had two different internal representations.
|
|
Since current_position is what gets persisted, saving while on the cover reopened
|
|
the book past it. Fixed in pyWebLayout's EreaderLayoutManager.previous_page().
|
|
"""
|
|
|
|
import unittest
|
|
import tempfile
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from dreader.application import EbookReader
|
|
|
|
|
|
class TestBackwardNavigationBug(unittest.TestCase):
|
|
"""Minimal reproduction of backward navigation bug"""
|
|
|
|
def setUp(self):
|
|
"""Set up test environment"""
|
|
self.temp_dir = tempfile.mkdtemp()
|
|
self.epub_path = "tests/data/test.epub"
|
|
|
|
if not Path(self.epub_path).exists():
|
|
self.skipTest(f"Test EPUB not found at {self.epub_path}")
|
|
|
|
def tearDown(self):
|
|
"""Clean up test environment"""
|
|
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
|
|
|
def test_minimal_backward_navigation_bug(self):
|
|
"""
|
|
MINIMAL CASE:
|
|
|
|
1. Start at block_index=0
|
|
2. Go forward once (to block_index=1)
|
|
3. Go backward once
|
|
4. Should land back at block_index=0
|
|
"""
|
|
reader = EbookReader(
|
|
page_size=(800, 1000),
|
|
bookmarks_dir=self.temp_dir,
|
|
buffer_size=0
|
|
)
|
|
|
|
reader.load_epub(self.epub_path)
|
|
|
|
# Starting position
|
|
pos_start = reader.manager.current_position.copy()
|
|
print(f"\n1. Starting at block_index={pos_start.block_index}")
|
|
self.assertEqual(pos_start.block_index, 0, "Should start at block 0")
|
|
|
|
# Go forward
|
|
reader.next_page()
|
|
pos_forward = reader.manager.current_position.copy()
|
|
print(f"2. After next_page(): block_index={pos_forward.block_index}")
|
|
self.assertEqual(pos_forward.block_index, 1, "Should be at block 1")
|
|
|
|
# Go backward
|
|
reader.previous_page()
|
|
pos_final = reader.manager.current_position.copy()
|
|
print(f"3. After previous_page(): block_index={pos_final.block_index}")
|
|
|
|
print(f"\nEXPECTED: block_index=0")
|
|
print(f"ACTUAL: block_index={pos_final.block_index}")
|
|
|
|
self.assertEqual(
|
|
pos_final.block_index,
|
|
0,
|
|
"Backward navigation from block 1 should return to block 0"
|
|
)
|
|
|
|
reader.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|