""" Test backward navigation after resuming from a saved position. This test specifically checks if backward navigation works correctly after opening an epub, navigating forward, closing it, then resuming and attempting to navigate backward. This may reveal issues with pyWebLayout's backward navigation handling. """ import unittest import tempfile import shutil from pathlib import Path import numpy as np from PIL import Image from dreader.application import EbookReader class TestBackwardNavigationAfterResume(unittest.TestCase): """Test backward navigation behavior after resume""" 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 compare_images(self, img1: Image.Image, img2: Image.Image) -> bool: """ Check if two PIL Images are pixel-perfect identical. """ if img1 is None or img2 is None: return False if img1.size != img2.size: return False arr1 = np.array(img1) arr2 = np.array(img2) return np.array_equal(arr1, arr2) def test_backward_navigation_after_resume(self): """ Test that backward navigation works after closing and resuming. Steps: 1. Open EPUB 2. Navigate forward 3 pages 3. Save positions and pages 4. Close reader 5. Open new reader (resume) 6. Try to navigate backward 7. Verify we can reach previous pages """ # Phase 1: Initial session - navigate forward reader1 = EbookReader( page_size=(800, 1000), bookmarks_dir=self.temp_dir, buffer_size=0 # Disable buffering for consistent testing ) success = reader1.load_epub(self.epub_path) self.assertTrue(success, "Failed to load test EPUB") # Capture initial page page0 = reader1.get_current_page() self.assertIsNotNone(page0, "Initial page should not be None") pos0 = reader1.manager.current_position.copy() print(f"\nInitial position: {pos0}") # Navigate forward 3 pages, capturing each page pages = [page0] positions = [pos0] for i in range(3): page = reader1.next_page() self.assertIsNotNone(page, f"Page {i+1} should not be None") pages.append(page) positions.append(reader1.manager.current_position.copy()) print(f"Forward page {i+1} position: {positions[-1]}") # We should now be at page 3 (0-indexed) self.assertEqual(len(pages), 4, "Should have 4 pages total (0-3)") # Save the current position before closing final_position = reader1.manager.current_position.copy() print(f"Final position before close: {final_position}") # Close reader (this should save the position) reader1.close() # Phase 2: Resume session - navigate backward reader2 = EbookReader( page_size=(800, 1000), bookmarks_dir=self.temp_dir, buffer_size=0 ) success = reader2.load_epub(self.epub_path) self.assertTrue(success, "Failed to load test EPUB on resume") # Verify we resumed at the correct position resumed_position = reader2.manager.current_position.copy() print(f"Resumed at position: {resumed_position}") self.assertEqual( resumed_position, final_position, "Should resume at the last saved position" ) # Get the current page (should match page 3) resumed_page = reader2.get_current_page() self.assertIsNotNone(resumed_page, "Resumed page should not be None") # Now try to navigate backward print("\nAttempting backward navigation...") backward_pages = [] backward_positions = [] # Try to go back 3 times for i in range(3): prev_page = reader2.previous_page() print(f"Backward step {i+1}: page={'Not None' if prev_page else 'None'}") if prev_page is None: print(f"WARNING: previous_page() returned None at step {i+1}") # This is the bug we're testing for! self.fail(f"Backward navigation failed at step {i+1}: previous_page() returned None") backward_pages.append(prev_page) backward_positions.append(reader2.manager.current_position.copy()) print(f" Position after backward: {backward_positions[-1]}") # We should have successfully gone back 3 pages self.assertEqual(len(backward_pages), 3, "Should have navigated back 3 pages") # Verify final position matches original position final_backward_position = reader2.manager.current_position.copy() print(f"\nFinal position after backward navigation: {final_backward_position}") print(f"Original position (page 0): {pos0}") self.assertEqual( final_backward_position, pos0, "After going forward 3 and back 3, should be at initial position" ) # Verify the page content matches final_page = reader2.get_current_page() self.assertTrue( self.compare_images(page0, final_page), "Final page should match initial page after forward/backward navigation" ) reader2.close() print("\n✓ Test passed: Backward navigation works correctly after resume") def test_backward_navigation_single_step(self): """ Simplified test: Open, go forward 1 page, close, resume, go back 1 page. This is a minimal reproduction case. """ # Session 1: Navigate forward one page reader1 = EbookReader( page_size=(800, 1000), bookmarks_dir=self.temp_dir, buffer_size=0 ) reader1.load_epub(self.epub_path) page0 = reader1.get_current_page() pos0 = reader1.manager.current_position.copy() page1 = reader1.next_page() self.assertIsNotNone(page1, "Should be able to navigate forward") pos1 = reader1.manager.current_position.copy() reader1.close() # Session 2: Resume and navigate backward reader2 = EbookReader( page_size=(800, 1000), bookmarks_dir=self.temp_dir, buffer_size=0 ) reader2.load_epub(self.epub_path) # Verify we're at page 1 self.assertEqual( reader2.manager.current_position, pos1, "Should resume at page 1" ) # Try to go back prev_page = reader2.previous_page() # This is the critical assertion - if this fails, backward nav is broken self.assertIsNotNone( prev_page, "CRITICAL: previous_page() returned None after resume - this indicates a pyWebLayout bug" ) # Verify we're back at page 0 final_pos = reader2.manager.current_position.copy() self.assertEqual( final_pos, pos0, "Should be back at initial position" ) reader2.close() if __name__ == '__main__': unittest.main()