feat: add --json

This commit is contained in:
2026-04-17 19:27:16 -04:00
parent 832312297c
commit 227484e975
4 changed files with 584 additions and 65 deletions
+290
View File
@@ -0,0 +1,290 @@
"""Tests for JSON output functionality."""
import json
import subprocess
from pathlib import Path
import pytest
from paperlib.models import PaperMetadata, SourceType
from paperlib.utils import JSONOutputMixin
class TestJSONOutputMixin:
"""Test JSONOutputMixin utility functions."""
def test_format_metadata_for_json(self):
"""Test formatting PaperMetadata for JSON output."""
metadata = PaperMetadata(
paper_id="test-paper-1",
source_type=SourceType.ARXIV,
source_id="2212.06340",
title="Test Paper",
authors=["Alice Smith", "Bob Jones"],
categories=["cs.AI"],
)
result = JSONOutputMixin.format_metadata_for_json(metadata)
assert result["paper_id"] == "test-paper-1"
assert result["source_type"] == "arxiv"
assert result["source_id"] == "2212.06340"
assert result["title"] == "Test Paper"
assert result["authors"] == ["Alice Smith", "Bob Jones"]
assert result["categories"] == ["cs.AI"]
def test_format_metadata_for_json_dict(self):
"""Test formatting dict metadata for JSON output."""
metadata_dict = {
"paper_id": "test-paper-1",
"title": "Test Paper",
"source_type": "local",
}
result = JSONOutputMixin.format_metadata_for_json(metadata_dict)
assert result == metadata_dict
def test_format_papers_list_for_json(self):
"""Test formatting a list of papers for JSON output."""
papers = [
PaperMetadata(
paper_id="paper-1",
source_type=SourceType.LOCAL,
title="Paper 1",
),
PaperMetadata(
paper_id="paper-2",
source_type=SourceType.ARXIV,
title="Paper 2",
),
]
result = JSONOutputMixin.format_papers_list_for_json(papers)
assert "papers" in result
assert "total" in result
assert result["total"] == 2
assert len(result["papers"]) == 2
assert result["papers"][0]["paper_id"] == "paper-1"
assert result["papers"][1]["paper_id"] == "paper-2"
class TestCLIJSONOutput:
"""Test CLI commands with JSON output."""
def run_paperlib_cmd(self, *args):
"""Helper to run paperlib commands and parse JSON output."""
cmd = ["uv", "run", "paperlib"] + list(args)
result = subprocess.run(cmd, capture_output=True, text=True, cwd=Path.cwd())
if "--json" in args:
try:
output_data = json.loads(result.stdout)
return result.returncode, output_data, result.stderr
except json.JSONDecodeError as e:
pytest.fail(f"Invalid JSON output: {e}\nOutput: {result.stdout}")
return result.returncode, result.stdout, result.stderr
def test_status_json_output(self):
"""Test status command with JSON output."""
# Create temporary library
temp_lib = Path("./.tmp") / f"test_status_json_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
try:
# Initialize library
self.run_paperlib_cmd("init", str(temp_lib))
# Test status with JSON
returncode, output_data, stderr = self.run_paperlib_cmd(
"status", "--library", str(temp_lib), "--json"
)
assert returncode == 0
assert isinstance(output_data, dict)
assert output_data["success"] is True
assert "timestamp" in output_data
assert "library_root" in output_data
assert "config_path" in output_data
assert "database_path" in output_data
assert str(temp_lib.resolve()) in output_data["library_root"]
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)
def test_list_json_output_empty(self):
"""Test list command with JSON output for empty library."""
temp_lib = Path("./.tmp") / f"test_list_json_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
try:
# Initialize library
self.run_paperlib_cmd("init", str(temp_lib))
# Test list with JSON
returncode, output_data, stderr = self.run_paperlib_cmd(
"list", "--library", str(temp_lib), "--json"
)
assert returncode == 0
assert isinstance(output_data, dict)
assert output_data["success"] is True
assert output_data["papers"] == []
assert output_data["total"] == 0
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)
def test_import_json_output(self):
"""Test import command with JSON output."""
temp_lib = Path("./.tmp") / f"test_import_json_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
# Create sample PDF
sample_pdf = Path("./.tmp") / f"test_import_json_{hash(self)}.pdf"
with sample_pdf.open("wb") as f:
f.write(b"%PDF-1.4\n%%EOF\n")
try:
# Initialize library
self.run_paperlib_cmd("init", str(temp_lib))
# Test import with JSON
returncode, output_data, stderr = self.run_paperlib_cmd(
"import",
"--pdf",
str(sample_pdf),
"--title",
"Test JSON Import",
"--library",
str(temp_lib),
"--json",
)
assert returncode == 0
assert isinstance(output_data, dict)
assert output_data["success"] is True
assert "paper_id" in output_data
assert output_data["title"] == "Test JSON Import"
assert output_data["source_type"] == "local"
assert "Successfully imported local PDF" in output_data["message"]
assert "paper" in output_data
assert isinstance(output_data["paper"], dict)
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)
if sample_pdf.exists():
sample_pdf.unlink()
def test_show_json_output(self):
"""Test show command with JSON output."""
temp_lib = Path("./.tmp") / f"test_show_json_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
# Create sample PDF
sample_pdf = Path("./.tmp") / f"test_show_json_{hash(self)}.pdf"
with sample_pdf.open("wb") as f:
f.write(b"%PDF-1.4\n%%EOF\n")
try:
# Initialize and import
self.run_paperlib_cmd("init", str(temp_lib))
import_returncode, import_data, _ = self.run_paperlib_cmd(
"import",
"--pdf",
str(sample_pdf),
"--title",
"Test JSON Show",
"--library",
str(temp_lib),
"--json",
)
assert import_returncode == 0
paper_id = import_data["paper_id"]
# Test show with JSON
returncode, output_data, stderr = self.run_paperlib_cmd(
"show", paper_id, "--library", str(temp_lib), "--json"
)
assert returncode == 0
assert isinstance(output_data, dict)
assert output_data["success"] is True
assert "paper" in output_data
assert output_data["paper"]["paper_id"] == paper_id
assert output_data["paper"]["title"] == "Test JSON Show"
assert "files_status" in output_data["paper"]
assert "pdf_exists" in output_data["paper"]["files_status"]
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)
if sample_pdf.exists():
sample_pdf.unlink()
def test_show_json_not_found(self):
"""Test show command with JSON output for non-existent paper."""
temp_lib = Path("./.tmp") / f"test_show_json_nf_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
try:
# Initialize library
self.run_paperlib_cmd("init", str(temp_lib))
# Test show non-existent paper
returncode, output_data, stderr = self.run_paperlib_cmd(
"show", "nonexistent", "--library", str(temp_lib), "--json"
)
assert returncode == 1
assert isinstance(output_data, dict)
assert output_data["success"] is False
assert "error" in output_data
assert "Paper not found" in output_data["error"]
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)
def test_convert_json_output(self):
"""Test convert command with JSON output."""
temp_lib = Path("./.tmp") / f"test_convert_json_{hash(self)}"
temp_lib.mkdir(parents=True, exist_ok=True)
try:
# Initialize library
self.run_paperlib_cmd("init", str(temp_lib))
# Test convert with no papers (JSON)
returncode, output_data, stderr = self.run_paperlib_cmd(
"convert", "--library", str(temp_lib), "--json"
)
assert returncode == 0
assert isinstance(output_data, dict)
assert output_data["success"] is True
assert output_data["action"] == "convert_pending"
assert output_data["success_count"] == 0
assert output_data["failure_count"] == 0
assert output_data["total_attempted"] == 0
finally:
if temp_lib.exists():
import shutil
shutil.rmtree(temp_lib)