249 lines
8.8 KiB
Python
249 lines
8.8 KiB
Python
"""
|
|
Unit tests for library interaction and tap detection.
|
|
|
|
These tests demonstrate the issue with interactive images in the library
|
|
and verify that tap detection works correctly.
|
|
"""
|
|
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
from dreader import LibraryManager
|
|
|
|
|
|
class TestLibraryInteraction(unittest.TestCase):
|
|
"""Test library browsing and tap interaction"""
|
|
|
|
def setUp(self):
|
|
"""Set up test library"""
|
|
self.library_path = Path(__file__).parent / 'data' / 'library-epub'
|
|
self.library = LibraryManager(
|
|
library_path=str(self.library_path),
|
|
page_size=(800, 1200)
|
|
)
|
|
|
|
def tearDown(self):
|
|
"""Clean up"""
|
|
self.library.cleanup()
|
|
|
|
def test_library_scan(self):
|
|
"""Test that library scanning finds books"""
|
|
books = self.library.scan_library()
|
|
|
|
# Should find at least one book
|
|
self.assertGreater(len(books), 0, "Library should contain at least one book")
|
|
|
|
# Each book should have required fields
|
|
for book in books:
|
|
self.assertIn('path', book)
|
|
self.assertIn('title', book)
|
|
self.assertIn('filename', book)
|
|
|
|
def test_library_table_creation(self):
|
|
"""Test that library table can be created"""
|
|
books = self.library.scan_library()
|
|
table = self.library.create_library_table()
|
|
|
|
# Table should exist
|
|
self.assertIsNotNone(table)
|
|
|
|
# Table should have body rows for 2-column grid layout
|
|
# Each pair of books gets 2 rows (cover row + detail row)
|
|
# So N books = ceil(N/2) * 2 rows
|
|
body_rows = list(table.body_rows())
|
|
expected_rows = ((len(books) + 1) // 2) * 2 # Round up to nearest even number, then double
|
|
self.assertEqual(len(body_rows), expected_rows)
|
|
|
|
def test_library_rendering(self):
|
|
"""Test that library can be rendered to image"""
|
|
self.library.scan_library()
|
|
self.library.create_library_table()
|
|
|
|
# Render library
|
|
image = self.library.render_library()
|
|
|
|
# Image should be created with correct size
|
|
self.assertIsNotNone(image)
|
|
self.assertEqual(image.size, self.library.page_size)
|
|
|
|
def test_tap_detection_first_book(self):
|
|
"""Test that tapping on first book row selects it
|
|
|
|
The entire row is interactive, so tapping anywhere in the row
|
|
(not just on the cover image) will select the book.
|
|
"""
|
|
books = self.library.scan_library()
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# Tap anywhere in the first book's row
|
|
# Based on layout: padding 30px, caption ~40px, first row starts at ~70px
|
|
selected_path = self.library.handle_library_tap(x=100, y=100)
|
|
|
|
# Should select the first book
|
|
self.assertIsNotNone(selected_path, "Tap should select a book")
|
|
self.assertEqual(selected_path, books[0]['path'], "Should select first book")
|
|
|
|
def test_tap_detection_second_book(self):
|
|
"""Test that tapping on second book selects it"""
|
|
books = self.library.scan_library()
|
|
|
|
if len(books) < 2:
|
|
self.skipTest("Need at least 2 books for this test")
|
|
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# Tap in the region of the second book
|
|
# Row height is ~180px, so second book is at ~70 + 180 = 250px
|
|
selected_path = self.library.handle_library_tap(x=400, y=250)
|
|
|
|
# Should select the second book
|
|
self.assertIsNotNone(selected_path, "Tap should select a book")
|
|
self.assertEqual(selected_path, books[1]['path'], "Should select second book")
|
|
|
|
def test_tap_outside_table(self):
|
|
"""Test that tapping outside table returns None"""
|
|
self.library.scan_library()
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# Tap outside the table area (far right)
|
|
selected_path = self.library.handle_library_tap(x=1000, y=100)
|
|
|
|
# Should not select anything
|
|
self.assertIsNone(selected_path, "Tap outside table should not select anything")
|
|
|
|
def test_tap_above_table(self):
|
|
"""Test that tapping in caption area returns None"""
|
|
self.library.scan_library()
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# Tap in caption area (above first row)
|
|
selected_path = self.library.handle_library_tap(x=400, y=40)
|
|
|
|
# Should not select anything
|
|
self.assertIsNone(selected_path, "Tap in caption should not select anything")
|
|
|
|
def test_tap_below_last_book(self):
|
|
"""Test that tapping below all books returns None"""
|
|
books = self.library.scan_library()
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# Tap way below the last book
|
|
# With 5 books and row height 180px: ~70 + (5 * 180) = 970px
|
|
selected_path = self.library.handle_library_tap(x=400, y=1100)
|
|
|
|
# Should not select anything
|
|
self.assertIsNone(selected_path, "Tap below last book should not select anything")
|
|
|
|
def test_multiple_taps(self):
|
|
"""Test that multiple taps work correctly with 2-column grid layout"""
|
|
books = self.library.scan_library()
|
|
|
|
if len(books) < 3:
|
|
self.skipTest("Need at least 3 books for this test")
|
|
|
|
self.library.create_library_table()
|
|
self.library.render_library()
|
|
|
|
# In 2-column layout:
|
|
# Books 0 and 1 are in the first pair (rows 0-1: cover and detail)
|
|
# Books 2 and 3 are in the second pair (rows 2-3: cover and detail)
|
|
|
|
# Tap first book (left column, first pair cover row)
|
|
path1 = self.library.handle_library_tap(x=100, y=100)
|
|
self.assertEqual(path1, books[0]['path'])
|
|
|
|
# Tap second book (right column, first pair cover row)
|
|
path2 = self.library.handle_library_tap(x=500, y=100)
|
|
self.assertEqual(path2, books[1]['path'])
|
|
|
|
# Tap third book (left column, second pair cover row)
|
|
path3 = self.library.handle_library_tap(x=100, y=360)
|
|
self.assertEqual(path3, books[2]['path'])
|
|
|
|
# All should be different
|
|
self.assertNotEqual(path1, path2)
|
|
self.assertNotEqual(path2, path3)
|
|
self.assertNotEqual(path1, path3)
|
|
|
|
def test_pagination(self):
|
|
"""Test library pagination with fake book data"""
|
|
# Create fake books (20 books to ensure multiple pages)
|
|
fake_books = []
|
|
for i in range(20):
|
|
fake_books.append({
|
|
'path': f'/fake/path/book_{i}.epub',
|
|
'title': f'Book Title {i}',
|
|
'author': f'Author {i}',
|
|
'filename': f'book_{i}.epub',
|
|
'cover_data': None,
|
|
'cover_path': None
|
|
})
|
|
|
|
# Create library with 6 books per page
|
|
library = LibraryManager(
|
|
library_path=str(self.library_path),
|
|
page_size=(800, 1200),
|
|
books_per_page=6
|
|
)
|
|
library.books = fake_books
|
|
|
|
# Test initial state
|
|
self.assertEqual(library.current_page, 0)
|
|
self.assertEqual(library.get_total_pages(), 4) # 20 books / 6 per page = 4 pages
|
|
|
|
# Test creating table for first page
|
|
table = library.create_library_table()
|
|
self.assertIsNotNone(table)
|
|
# 6 books = 3 pairs = 6 rows (3 cover rows + 3 detail rows)
|
|
body_rows = list(table.body_rows())
|
|
self.assertEqual(len(body_rows), 6)
|
|
|
|
# Test navigation to next page
|
|
self.assertTrue(library.next_page())
|
|
self.assertEqual(library.current_page, 1)
|
|
|
|
# Create table for second page
|
|
table = library.create_library_table()
|
|
body_rows = list(table.body_rows())
|
|
self.assertEqual(len(body_rows), 6) # Still 6 books on page 2
|
|
|
|
# Test navigation to last page
|
|
library.set_page(3)
|
|
self.assertEqual(library.current_page, 3)
|
|
table = library.create_library_table()
|
|
body_rows = list(table.body_rows())
|
|
# Page 4 has 2 books (20 - 18 = 2) = 1 pair = 2 rows
|
|
self.assertEqual(len(body_rows), 2)
|
|
|
|
# Test can't go beyond last page
|
|
self.assertFalse(library.next_page())
|
|
self.assertEqual(library.current_page, 3)
|
|
|
|
# Test navigation to previous page
|
|
self.assertTrue(library.previous_page())
|
|
self.assertEqual(library.current_page, 2)
|
|
|
|
# Test navigation to first page
|
|
library.set_page(0)
|
|
self.assertEqual(library.current_page, 0)
|
|
|
|
# Test can't go before first page
|
|
self.assertFalse(library.previous_page())
|
|
self.assertEqual(library.current_page, 0)
|
|
|
|
# Test invalid page number
|
|
self.assertFalse(library.set_page(-1))
|
|
self.assertFalse(library.set_page(100))
|
|
self.assertEqual(library.current_page, 0) # Should stay on current page
|
|
|
|
library.cleanup()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|