"""Tests for pdf2imos CLI interface.""" import json from pathlib import Path from typer.testing import CliRunner from pdf2imos import __version__ from pdf2imos.cli import app runner = CliRunner() INPUT_DIR = Path(__file__).parent / "fixtures" / "input" class TestVersion: def test_prints_version_string(self): result = runner.invoke(app, ["--version"]) assert result.exit_code == 0 assert __version__ in result.output def test_version_before_args(self): """--version is eager, works without positional args.""" result = runner.invoke(app, ["--version"]) assert result.exit_code == 0 class TestHelp: def test_help_exits_0(self): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 def test_help_mentions_input_dir(self): result = runner.invoke(app, ["--help"]) assert "INPUT_DIR" in result.output class TestBatchProcessing: def test_produces_dxf_and_json(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out)], ) assert result.exit_code in (0, 1) dxf_files = list(out.glob("*.dxf")) json_files = list(out.glob("*.json")) assert len(dxf_files) > 0 assert len(json_files) > 0 def test_output_names_match_pdfs(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out)], ) if result.exit_code == 0: for pdf in INPUT_DIR.glob("*.pdf"): assert (out / f"{pdf.stem}.dxf").exists() assert (out / f"{pdf.stem}.json").exists() def test_verbose_accepted(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out), "--verbose"], ) assert result.exit_code in (0, 1) class TestStageProcessing: def test_stage_extract_produces_json(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out), "--stage=extract"], ) assert result.exit_code == 0 intermediates = list(out.glob("*_extract.json")) assert len(intermediates) > 0 def test_stage_extract_json_content(self, tmp_path): out = tmp_path / "out" runner.invoke( app, [str(INPUT_DIR), str(out), "--stage=extract"], ) for f in out.glob("*_extract.json"): with open(f) as fh: data = json.load(fh) assert data["stage"] == "extract" assert "data" in data def test_stage_extract_no_dxf_output(self, tmp_path): out = tmp_path / "out" runner.invoke( app, [str(INPUT_DIR), str(out), "--stage=extract"], ) assert len(list(out.glob("*.dxf"))) == 0 def test_stage_segment(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out), "--stage=segment"], ) assert result.exit_code == 0 intermediates = list(out.glob("*_segment.json")) assert len(intermediates) > 0 class TestExitCodes: def test_exit_0_all_succeed(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out)], ) assert result.exit_code == 0 def test_exit_2_no_pdfs(self, tmp_path): empty = tmp_path / "empty" empty.mkdir() out = tmp_path / "out" result = runner.invoke( app, [str(empty), str(out)], ) assert result.exit_code == 2 def test_exit_2_nonexistent_input(self, tmp_path): result = runner.invoke( app, ["/nonexistent/path", str(tmp_path / "out")], ) assert result.exit_code == 2 def test_exit_2_invalid_stage(self, tmp_path): out = tmp_path / "out" result = runner.invoke( app, [str(INPUT_DIR), str(out), "--stage=bogus"], ) assert result.exit_code == 2 class TestNonPdfSkipped: def test_only_non_pdf_files_exit_2(self, tmp_path): input_dir = tmp_path / "input" input_dir.mkdir() (input_dir / "readme.txt").write_text("hello") (input_dir / "notes.md").write_text("# Notes") out = tmp_path / "out" result = runner.invoke( app, [str(input_dir), str(out)], ) assert result.exit_code == 2 def test_non_pdf_not_in_output(self, tmp_path): """Non-PDF files should not produce output.""" out = tmp_path / "out" runner.invoke( app, [str(INPUT_DIR), str(out)], ) # No output file named after a non-pdf for f in out.iterdir(): assert f.suffix in (".dxf", ".json", ".dwg")