Files
paperlib/tests/test_cli.py
T
2026-04-17 16:54:30 -04:00

242 lines
8.0 KiB
Python

"""Tests for paperlib CLI functionality."""
import shutil
import subprocess
from pathlib import Path
import pytest
class TestCLI:
"""Test CLI functionality."""
@pytest.fixture
def temp_library(self):
"""Create a temporary library for testing."""
temp_dir = Path("./.tmp") / f"test_cli_{hash(self)}"
temp_dir.mkdir(parents=True, exist_ok=True)
yield temp_dir
# Cleanup
if temp_dir.exists():
shutil.rmtree(temp_dir)
@pytest.fixture
def sample_pdf(self):
"""Create a sample PDF file for testing."""
pdf_file = Path("./.tmp") / f"cli_test_{hash(self)}.pdf"
with pdf_file.open("wb") as f:
# Minimal PDF content
f.write(b"%PDF-1.4\n")
f.write(b"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n")
f.write(b"%%EOF\n")
yield pdf_file
# Cleanup
if pdf_file.exists():
pdf_file.unlink()
def run_paperlib_cmd(self, *args):
"""Helper to run paperlib commands."""
cmd = ["uv", "run", "paperlib"] + list(args)
result = subprocess.run(cmd, capture_output=True, text=True, cwd=Path.cwd())
return result
def test_cli_help(self):
"""Test CLI help output."""
result = self.run_paperlib_cmd("--help")
assert result.returncode == 0
assert "paperlib" in result.stdout
assert "Local-first paper library engine" in result.stdout
assert "init" in result.stdout
assert "import" in result.stdout
assert "convert" in result.stdout
def test_cli_version(self):
"""Test CLI version output."""
result = self.run_paperlib_cmd("--version")
assert result.returncode == 0
assert "paperlib" in result.stdout
assert "0.1.0" in result.stdout
def test_init_command(self, temp_library):
"""Test library initialization command."""
result = self.run_paperlib_cmd("init", str(temp_library))
assert result.returncode == 0
assert "Initialized paper library" in result.stdout
# Check directory structure was created
assert (temp_library / "config").exists()
assert (temp_library / "papers").exists()
assert (temp_library / "inbox").exists()
assert (temp_library / "db").exists()
assert (temp_library / "cache").exists()
def test_status_command(self, temp_library):
"""Test status command."""
# Initialize library first
self.run_paperlib_cmd("init", str(temp_library))
result = self.run_paperlib_cmd("status", "--library", str(temp_library))
assert result.returncode == 0
# Check for absolute path since that's what we get
assert str(temp_library.resolve()) in result.stdout
assert "config:" in result.stdout
assert "database:" in result.stdout
assert "papers:" in result.stdout
def test_import_local_pdf_command(self, temp_library, sample_pdf):
"""Test importing local PDF via CLI."""
# Initialize library
self.run_paperlib_cmd("init", str(temp_library))
# Import PDF
result = self.run_paperlib_cmd(
"import",
"--pdf",
str(sample_pdf),
"--title",
"Test CLI Paper",
"--tags",
"test",
"cli",
"--library",
str(temp_library),
)
assert result.returncode == 0
assert "Successfully imported local PDF" in result.stdout
assert "Test CLI Paper" in result.stdout
def test_list_command_empty(self, temp_library):
"""Test list command with empty library."""
self.run_paperlib_cmd("init", str(temp_library))
result = self.run_paperlib_cmd("list", "--library", str(temp_library))
assert result.returncode == 0
assert "No papers found" in result.stdout
def test_list_command_with_papers(self, temp_library, sample_pdf):
"""Test list command with papers."""
# Initialize and import
self.run_paperlib_cmd("init", str(temp_library))
self.run_paperlib_cmd(
"import",
"--pdf",
str(sample_pdf),
"--title",
"Test Paper for List",
"--library",
str(temp_library),
)
result = self.run_paperlib_cmd("list", "--library", str(temp_library))
assert result.returncode == 0
assert "Found 1 papers" in result.stdout
assert "Test Paper for List" in result.stdout
def test_show_command(self, temp_library, sample_pdf):
"""Test show command."""
# Initialize and import
self.run_paperlib_cmd("init", str(temp_library))
import_result = self.run_paperlib_cmd(
"import",
"--pdf",
str(sample_pdf),
"--title",
"Test Paper for Show",
"--library",
str(temp_library),
)
# Extract paper ID from import output
paper_id = None
for line in import_result.stdout.split("\n"):
if "Successfully imported local PDF:" in line:
paper_id = line.split(":")[-1].strip()
break
assert paper_id is not None
# Show paper details
result = self.run_paperlib_cmd("show", paper_id, "--library", str(temp_library))
assert result.returncode == 0
assert f"Paper ID: {paper_id}" in result.stdout
assert "Test Paper for Show" in result.stdout
assert "Source: local" in result.stdout
def test_show_nonexistent_paper(self, temp_library):
"""Test show command with nonexistent paper."""
self.run_paperlib_cmd("init", str(temp_library))
result = self.run_paperlib_cmd(
"show", "nonexistent", "--library", str(temp_library)
)
assert result.returncode == 1
assert "Paper not found" in result.stdout
def test_reindex_command(self, temp_library, sample_pdf):
"""Test reindex command."""
# Initialize and import
self.run_paperlib_cmd("init", str(temp_library))
self.run_paperlib_cmd(
"import", "--pdf", str(sample_pdf), "--library", str(temp_library)
)
# Reindex
result = self.run_paperlib_cmd("reindex", "--library", str(temp_library))
assert result.returncode == 0
assert "Rebuilding search index" in result.stdout
assert "papers indexed" in result.stdout
assert "Total papers: 1" in result.stdout
def test_convert_command_no_papers(self, temp_library):
"""Test convert command with no papers."""
self.run_paperlib_cmd("init", str(temp_library))
result = self.run_paperlib_cmd("convert", "--library", str(temp_library))
assert result.returncode == 0
assert "Complete: 0 successful, 0 failed" in result.stdout
def test_convert_command_with_papers_no_mineru(self, temp_library, sample_pdf):
"""Test convert command with papers when MinerU is not available."""
# Initialize and import
self.run_paperlib_cmd("init", str(temp_library))
self.run_paperlib_cmd(
"import", "--pdf", str(sample_pdf), "--library", str(temp_library)
)
# Convert (will fail because MinerU command may not be properly set up)
result = self.run_paperlib_cmd("convert", "--library", str(temp_library))
# Should complete but may have failures due to MinerU setup
assert "Complete:" in result.stdout
def test_invalid_command(self):
"""Test invalid command."""
result = self.run_paperlib_cmd("invalid-command")
assert result.returncode != 0
def test_missing_required_arguments(self):
"""Test commands with missing required arguments."""
# Import without PDF or arXiv
result = self.run_paperlib_cmd("import")
assert result.returncode != 0
# Show without paper ID
result = self.run_paperlib_cmd("show")
assert result.returncode != 0