242 lines
8.0 KiB
Python
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
|