Spaces:
Sleeping
Sleeping
File size: 13,769 Bytes
bff1348 e224609 bff1348 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | """Tests Sprint 9 — Documentation, packaging et intégration finale.
Classes de tests
----------------
TestVersion (4 tests) — version cohérente dans tous les fichiers
TestMainModule (3 tests) — python -m picarones fonctionne
TestMakefile (5 tests) — Makefile syntaxe et cibles
TestDockerfile (6 tests) — Dockerfile structure et commandes
TestDockerCompose (5 tests) — docker-compose.yml structure
TestCIWorkflow (6 tests) — .github/workflows/ci.yml structure
TestPyInstallerSpec (4 tests) — picarones.spec structure
TestCLIDemoEndToEnd (6 tests) — picarones demo bout en bout
TestReadme (5 tests) — README.md complet et bilingue
TestInstallMd (4 tests) — INSTALL.md contenu
TestChangelog (5 tests) — CHANGELOG.md contenu et structure
TestContributing (4 tests) — CONTRIBUTING.md contenu
"""
from __future__ import annotations
import re
from pathlib import Path
import pytest
ROOT = Path(__file__).parent.parent
# ===========================================================================
# TestVersion
# ===========================================================================
class TestVersion:
def test_version_in_init(self):
from picarones import __version__
assert __version__ == "1.0.0"
def test_version_in_pyproject(self):
pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
assert 'version = "1.0.0"' in pyproject
def test_version_cli(self):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
result = runner.invoke(cli, ["--version"])
assert result.exit_code == 0
assert "1.0.0" in result.output
def test_version_consistent(self):
"""La version dans __init__.py et pyproject.toml doit être identique."""
from picarones import __version__
pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
m = re.search(r'version\s*=\s*"([^"]+)"', pyproject)
assert m is not None
pyproject_version = m.group(1)
assert __version__ == pyproject_version, (
f"Version incohérente : __init__.py={__version__} vs pyproject.toml={pyproject_version}"
)
# ===========================================================================
# TestMainModule
# ===========================================================================
class TestMainModule:
def test_main_module_exists(self):
main_path = ROOT / "picarones" / "__main__.py"
assert main_path.exists(), "picarones/__main__.py est manquant"
def test_main_imports_cli(self):
content = (ROOT / "picarones" / "__main__.py").read_text(encoding="utf-8")
assert "from picarones.cli import cli" in content
def test_main_importable(self):
import importlib
mod = importlib.import_module("picarones.__main__")
assert hasattr(mod, "cli")
# ===========================================================================
# TestMakefile
# ===========================================================================
class TestMakefile:
@pytest.fixture
def makefile(self):
path = ROOT / "Makefile"
assert path.exists(), "Makefile est manquant"
return path.read_text(encoding="utf-8")
def test_makefile_exists(self):
assert (ROOT / "Makefile").exists()
def test_has_install_target(self, makefile):
assert "install:" in makefile
def test_has_test_target(self, makefile):
assert "test:" in makefile
def test_has_demo_target(self, makefile):
assert "demo:" in makefile
def test_has_docker_build_target(self, makefile):
assert "docker-build:" in makefile
def test_has_help_target(self, makefile):
assert "help:" in makefile
# ===========================================================================
# TestDockerfile
# ===========================================================================
class TestDockerfile:
@pytest.fixture
def dockerfile(self):
path = ROOT / "Dockerfile"
assert path.exists(), "Dockerfile est manquant"
return path.read_text(encoding="utf-8")
def test_dockerfile_exists(self):
assert (ROOT / "Dockerfile").exists()
def test_has_python_base(self, dockerfile):
assert "python:3.11" in dockerfile
def test_has_tesseract_install(self, dockerfile):
assert "tesseract-ocr" in dockerfile
def test_has_picarones_serve_cmd(self, dockerfile):
assert "picarones" in dockerfile
assert "serve" in dockerfile
assert "0.0.0.0" in dockerfile
def test_has_workdir(self, dockerfile):
assert "WORKDIR" in dockerfile
def test_has_healthcheck(self, dockerfile):
assert "HEALTHCHECK" in dockerfile
# ===========================================================================
# TestDockerCompose
# ===========================================================================
class TestDockerCompose:
@pytest.fixture
def compose(self):
path = ROOT / "docker-compose.yml"
assert path.exists(), "docker-compose.yml est manquant"
return path.read_text(encoding="utf-8")
def test_compose_exists(self):
assert (ROOT / "docker-compose.yml").exists()
def test_has_picarones_service(self, compose):
assert "picarones:" in compose
def test_has_ollama_service(self, compose):
assert "ollama" in compose
def test_has_port_mapping(self, compose):
assert "7860" in compose
def test_has_volume_for_history(self, compose):
assert "picarones_history" in compose
# ===========================================================================
# TestCIWorkflow
# ===========================================================================
class TestCIWorkflow:
@pytest.fixture
def ci(self):
path = ROOT / ".github" / "workflows" / "ci.yml"
assert path.exists(), ".github/workflows/ci.yml est manquant"
return path.read_text(encoding="utf-8")
def test_ci_exists(self):
assert (ROOT / ".github" / "workflows" / "ci.yml").exists()
def test_has_python_311(self, ci):
assert "3.11" in ci
def test_has_python_312(self, ci):
assert "3.12" in ci
def test_has_linux_macos_windows(self, ci):
assert "ubuntu-latest" in ci
assert "macos-latest" in ci
assert "windows-latest" in ci
def test_has_pytest_step(self, ci):
assert "pytest" in ci
def test_has_demo_job(self, ci):
assert "demo" in ci
# ===========================================================================
# TestPyInstallerSpec
# ===========================================================================
class TestPyInstallerSpec:
@pytest.fixture
def spec(self):
path = ROOT / "picarones.spec"
assert path.exists(), "picarones.spec est manquant"
return path.read_text(encoding="utf-8")
def test_spec_exists(self):
assert (ROOT / "picarones.spec").exists()
def test_spec_has_analysis(self, spec):
assert "Analysis(" in spec
def test_spec_has_picarones_cli(self, spec):
assert "picarones.cli" in spec
def test_spec_has_exe(self, spec):
assert "EXE(" in spec
# ===========================================================================
# TestCLIDemoEndToEnd
# ===========================================================================
class TestCLIDemoEndToEnd:
def test_demo_runs_without_error(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
result = runner.invoke(cli, [
"demo", "--docs", "3",
"--output", str(tmp_path / "test.html"),
])
assert result.exit_code == 0, f"demo a échoué : {result.output}"
def test_demo_generates_html_file(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
output = tmp_path / "rapport.html"
runner.invoke(cli, ["demo", "--docs", "3", "--output", str(output)])
assert output.exists()
def test_demo_html_contains_expected_content(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
output = tmp_path / "rapport.html"
runner.invoke(cli, ["demo", "--docs", "3", "--output", str(output)])
content = output.read_text(encoding="utf-8")
assert "Picarones" in content
assert "CER" in content
assert len(content) > 50_000, f"Rapport trop petit : {len(content):,} octets"
def test_demo_with_history_flag(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
result = runner.invoke(cli, [
"demo", "--docs", "3",
"--output", str(tmp_path / "test.html"),
"--with-history",
])
assert result.exit_code == 0
assert "CER" in result.output
def test_demo_with_robustness_flag(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
runner = CliRunner()
result = runner.invoke(cli, [
"demo", "--docs", "3",
"--output", str(tmp_path / "test.html"),
"--with-robustness",
])
assert result.exit_code == 0
def test_demo_with_json_output(self, tmp_path):
from click.testing import CliRunner
from picarones.cli import cli
import json
runner = CliRunner()
json_out = tmp_path / "results.json"
result = runner.invoke(cli, [
"demo", "--docs", "3",
"--output", str(tmp_path / "test.html"),
"--json-output", str(json_out),
])
assert result.exit_code == 0
assert json_out.exists()
data = json.loads(json_out.read_text())
assert "engine_reports" in data
# ===========================================================================
# TestReadme
# ===========================================================================
class TestReadme:
@pytest.fixture
def readme(self):
path = ROOT / "README.md"
assert path.exists()
return path.read_text(encoding="utf-8")
def test_readme_has_french_section(self, readme):
assert "Fonctionnalités" in readme or "Picarones" in readme
def test_readme_has_english_section(self, readme):
assert "English" in readme or "Quick Start" in readme
def test_readme_has_installation(self, readme):
assert "Installation" in readme
assert "pip install" in readme
def test_readme_has_cli_examples(self, readme):
assert "picarones demo" in readme
assert "picarones run" in readme
def test_readme_has_engines_table(self, readme):
assert "Tesseract" in readme
assert "Pero OCR" in readme
# ===========================================================================
# TestInstallMd
# ===========================================================================
class TestInstallMd:
@pytest.fixture
def install(self):
path = ROOT / "INSTALL.md"
assert path.exists(), "INSTALL.md est manquant"
return path.read_text(encoding="utf-8")
def test_has_linux_section(self, install):
assert "Linux" in install or "Ubuntu" in install
def test_has_macos_section(self, install):
assert "macOS" in install
def test_has_windows_section(self, install):
assert "Windows" in install
def test_has_docker_section(self, install):
assert "Docker" in install
# ===========================================================================
# TestChangelog
# ===========================================================================
class TestChangelog:
@pytest.fixture
def changelog(self):
path = ROOT / "CHANGELOG.md"
assert path.exists(), "CHANGELOG.md est manquant"
return path.read_text(encoding="utf-8")
def test_has_sprint1(self, changelog):
assert "Sprint 1" in changelog or "0.1.0" in changelog
def test_has_sprint8(self, changelog):
assert "Sprint 8" in changelog or "0.8.0" in changelog
def test_has_sprint9(self, changelog):
assert "Sprint 9" in changelog or "1.0.0" in changelog
def test_has_versions(self, changelog):
# Au moins 2 versions documentées
versions = re.findall(r"\[[\d.]+\]", changelog)
assert len(versions) >= 2
def test_has_date(self, changelog):
assert "2025" in changelog
# ===========================================================================
# TestContributing
# ===========================================================================
class TestContributing:
@pytest.fixture
def contrib(self):
path = ROOT / "CONTRIBUTING.md"
assert path.exists(), "CONTRIBUTING.md est manquant"
return path.read_text(encoding="utf-8")
def test_has_how_to_add_engine(self, contrib):
assert "moteur" in contrib.lower() or "engine" in contrib.lower()
def test_has_tests_section(self, contrib):
assert "test" in contrib.lower()
def test_has_pull_request_section(self, contrib):
assert "pull request" in contrib.lower() or "PR" in contrib
def test_has_code_style(self, contrib):
assert "Google" in contrib or "docstring" in contrib.lower() or "style" in contrib.lower()
|