@@ -316,6 +316,183 @@ def test_handles_missing_files_gracefully(self, tmp_path):
316316 assert result .returncode == 0
317317 assert "SKIP" in result .stdout or "not found" in result .stdout .lower ()
318318
319+ def test_split_library_with_separate_paths (self , tmp_path ):
320+ """Test checksum generation with split library (separate metadata and books)."""
321+ # Create separate directories for metadata and books
322+ metadata_dir = tmp_path / "metadata"
323+ books_dir = tmp_path / "books"
324+
325+ metadata_dir .mkdir ()
326+ books_dir .mkdir ()
327+
328+ # Create metadata.db in metadata_dir
329+ create_minimal_calibre_library (metadata_dir )
330+
331+ # Add book to metadata.db
332+ db_path = metadata_dir / "metadata.db"
333+ conn = sqlite3 .connect (db_path )
334+ cur = conn .cursor ()
335+
336+ cur .execute ("""
337+ INSERT INTO books (title, sort, path, has_cover)
338+ VALUES ('Split Library Book', 'Split Library Book', 'split_book', 0)
339+ """ )
340+ book_id = cur .lastrowid
341+
342+ cur .execute ("""
343+ INSERT INTO data (book, format, name)
344+ VALUES (?, 'EPUB', 'split_book')
345+ """ , (book_id ,))
346+
347+ conn .commit ()
348+ conn .close ()
349+
350+ # Create actual book file in books_dir (NOT metadata_dir)
351+ book_folder = books_dir / "split_book"
352+ book_folder .mkdir ()
353+ (book_folder / "split_book.epub" ).write_bytes (b"Test EPUB content for split library testing" )
354+
355+ # Run script with separate books-path
356+ script_path = scripts_dir / "generate_book_checksums.py"
357+ result = subprocess .run (
358+ [sys .executable , str (script_path ),
359+ "--library-path" , str (metadata_dir ),
360+ "--books-path" , str (books_dir )],
361+ capture_output = True ,
362+ text = True ,
363+ timeout = 30
364+ )
365+
366+ assert result .returncode == 0
367+ assert "Split Library Book" in result .stdout
368+ assert "✓" in result .stdout
369+ assert "split library mode" in result .stdout .lower ()
370+
371+ # Verify checksum was stored in metadata.db
372+ conn = sqlite3 .connect (db_path )
373+ cur = conn .cursor ()
374+ checksum = cur .execute ("""
375+ SELECT checksum FROM book_format_checksums
376+ WHERE book = ? AND format = 'EPUB'
377+ """ , (book_id ,)).fetchone ()
378+ conn .close ()
379+
380+ assert checksum is not None
381+ assert len (checksum [0 ]) == 32 # Valid MD5
382+
383+ def test_books_path_falls_back_to_library_path (self , tmp_path ):
384+ """Test that invalid books-path falls back to library-path."""
385+ library_path = tmp_path / "library"
386+ create_minimal_calibre_library (library_path )
387+ add_book_to_library (library_path , "Fallback Test Book" , ["EPUB" ])
388+
389+ # Pass nonexistent books-path
390+ script_path = scripts_dir / "generate_book_checksums.py"
391+ result = subprocess .run (
392+ [sys .executable , str (script_path ),
393+ "--library-path" , str (library_path ),
394+ "--books-path" , "/nonexistent/path" ],
395+ capture_output = True ,
396+ text = True ,
397+ timeout = 30
398+ )
399+
400+ # Should succeed by falling back to library_path
401+ assert result .returncode == 0
402+ assert "Fallback Test Book" in result .stdout
403+ assert "✓" in result .stdout
404+
405+ def test_books_path_with_none_value (self , tmp_path ):
406+ """Test that None books-path uses library-path."""
407+ library_path = tmp_path / "library"
408+ create_minimal_calibre_library (library_path )
409+ add_book_to_library (library_path , "Normal Mode Book" , ["EPUB" ])
410+
411+ # Run without --books-path argument (default behavior)
412+ script_path = scripts_dir / "generate_book_checksums.py"
413+ result = subprocess .run (
414+ [sys .executable , str (script_path ),
415+ "--library-path" , str (library_path )],
416+ capture_output = True ,
417+ text = True ,
418+ timeout = 30
419+ )
420+
421+ # Should succeed using library_path for books
422+ assert result .returncode == 0
423+ assert "Normal Mode Book" in result .stdout
424+ assert "✓" in result .stdout
425+ # Should NOT show split library mode message
426+ assert "Books path: " in result .stdout
427+
428+ def test_split_library_with_multiple_formats (self , tmp_path ):
429+ """Test split library with book having multiple formats."""
430+ metadata_dir = tmp_path / "metadata"
431+ books_dir = tmp_path / "books"
432+
433+ metadata_dir .mkdir ()
434+ books_dir .mkdir ()
435+
436+ create_minimal_calibre_library (metadata_dir )
437+
438+ # Add book with multiple formats
439+ db_path = metadata_dir / "metadata.db"
440+ conn = sqlite3 .connect (db_path )
441+ cur = conn .cursor ()
442+
443+ cur .execute ("""
444+ INSERT INTO books (title, sort, path, has_cover)
445+ VALUES ('Multi Format Book', 'Multi Format Book', 'multi_format', 0)
446+ """ )
447+ book_id = cur .lastrowid
448+
449+ # Add multiple formats
450+ for fmt in ['EPUB' , 'MOBI' , 'PDF' ]:
451+ cur .execute ("""
452+ INSERT INTO data (book, format, name)
453+ VALUES (?, ?, 'multi_format')
454+ """ , (book_id , fmt ))
455+
456+ conn .commit ()
457+ conn .close ()
458+
459+ # Create actual book files in books_dir
460+ book_folder = books_dir / "multi_format"
461+ book_folder .mkdir ()
462+ (book_folder / "multi_format.epub" ).write_bytes (b"EPUB content" )
463+ (book_folder / "multi_format.mobi" ).write_bytes (b"MOBI content" )
464+ (book_folder / "multi_format.pdf" ).write_bytes (b"PDF content" )
465+
466+ # Run script
467+ script_path = scripts_dir / "generate_book_checksums.py"
468+ result = subprocess .run (
469+ [sys .executable , str (script_path ),
470+ "--library-path" , str (metadata_dir ),
471+ "--books-path" , str (books_dir )],
472+ capture_output = True ,
473+ text = True ,
474+ timeout = 30
475+ )
476+
477+ assert result .returncode == 0
478+
479+ # Verify all three formats got checksums
480+ conn = sqlite3 .connect (db_path )
481+ cur = conn .cursor ()
482+ checksums = cur .execute ("""
483+ SELECT format, checksum FROM book_format_checksums
484+ WHERE book = ?
485+ ORDER BY format
486+ """ , (book_id ,)).fetchall ()
487+ conn .close ()
488+
489+ assert len (checksums ) == 3
490+ assert all (len (checksum [1 ]) == 32 for checksum in checksums )
491+ formats = [c [0 ] for c in checksums ]
492+ assert 'EPUB' in formats
493+ assert 'MOBI' in formats
494+ assert 'PDF' in formats
495+
319496 def test_batch_size_parameter (self , tmp_path ):
320497 """Test that batch-size parameter is respected."""
321498 library_path = tmp_path / "test_library"
0 commit comments