| """ |
| Test cases for CLI and app.py functionality. |
| """ |
|
|
| import os |
| import sys |
| import tempfile |
| import subprocess |
| from pathlib import Path |
| import pytest |
| import yaml |
| from loguru import logger |
|
|
| |
| ROOT = Path(__file__).parent.parent |
| sys.path.insert(0, str(ROOT)) |
|
|
| TIMEOUT = 10 |
|
|
|
|
| @pytest.mark.skip(reason="Skipping due to occasional CI timeouts") |
| def test_cli_help(): |
| """Test that CLI help command works.""" |
| result = subprocess.run( |
| [sys.executable, "-m", "imcui.cli.main", "--help"], |
| capture_output=True, |
| text=True, |
| cwd=ROOT, |
| ) |
| assert result.returncode == 0 |
| assert "Launch the Image Matching WebUI application" in result.stdout |
| assert "--server-port" in result.stdout |
| assert "--config" in result.stdout |
| logger.info("CLI help command works as expected.") |
|
|
|
|
| def test_cli_version(): |
| """Test that CLI version command works.""" |
| result = subprocess.run( |
| [sys.executable, "-m", "imcui.cli.main", "--version"], |
| capture_output=True, |
| text=True, |
| cwd=ROOT, |
| ) |
| assert result.returncode == 0 |
| assert "Image Matching WebUI Version" in result.stdout |
| logger.info("CLI version command works as expected.") |
|
|
|
|
| def test_cli_default_config_loading(): |
| """Test that CLI can load default configuration.""" |
| from imcui import get_default_config_path |
|
|
| config_path = get_default_config_path() |
| assert config_path.exists(), f"Config file not found: {config_path}" |
|
|
| |
| with open(config_path, "r") as f: |
| config = yaml.safe_load(f) |
|
|
| assert "server" in config |
| assert "defaults" in config |
| logger.info("CLI default configuration loaded and validated successfully.") |
|
|
|
|
| @pytest.mark.skip(reason="Skipping due to occasional CI timeouts") |
| def test_app_py_default_config(): |
| """Test that app.py can load default configuration.""" |
| |
| import argparse |
|
|
| |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--config", type=str, default=str(ROOT / "imcui/config/app.yaml") |
| ) |
| args = parser.parse_args([]) |
|
|
| config_path = Path(args.config) |
| assert config_path.exists(), f"Config file not found: {config_path}" |
| logger.info(f"Default config path: {config_path}") |
|
|
| |
| with open(config_path, "r") as f: |
| config = yaml.safe_load(f) |
|
|
| assert "server" in config |
| |
|
|
| with tempfile.TemporaryDirectory() as temp_dir: |
| temp_path = Path(temp_dir) |
| log_path = temp_path / "experiments" / "all" |
| log_path.mkdir(parents=True, exist_ok=True) |
|
|
| |
| config["log_path"] = str(log_path) |
|
|
| |
| temp_config = temp_path / "temp_config.yaml" |
| with open(temp_config, "w") as f: |
| yaml.dump(config, f) |
|
|
| |
| result = subprocess.run( |
| [sys.executable, "app.py", "--config", str(temp_config)], |
| capture_output=True, |
| text=True, |
| cwd=ROOT, |
| timeout=TIMEOUT, |
| ) |
|
|
| |
| assert result.returncode != 0 or "Running on" in result.stdout |
| logger.info("app.py ran successfully with temporary config.") |
|
|
|
|
| def test_cli_with_custom_config(): |
| """Test CLI with custom configuration file.""" |
| with tempfile.TemporaryDirectory() as temp_dir: |
| temp_path = Path(temp_dir) |
| custom_config = temp_path / "test_config.yaml" |
|
|
| |
| config_data = { |
| "server": {"name": "127.0.0.1", "port": 9999}, |
| "defaults": {"max_keypoints": 1000, "match_threshold": 0.1}, |
| "matcher_zoo": { |
| "sift": { |
| "enable": True, |
| "matcher": "NN-mutual", |
| "feature": "sift", |
| "dense": False, |
| "info": {"name": "SIFT", "source": "IJCV 2004", "display": True}, |
| } |
| }, |
| } |
|
|
| with open(custom_config, "w") as f: |
| yaml.dump(config_data, f) |
|
|
| |
| from click.testing import CliRunner |
| from imcui.cli.main import main as cli_main |
|
|
| runner = CliRunner() |
| result = runner.invoke( |
| cli_main, |
| ["--config", str(custom_config), "--verbose"], |
| env={"IMCUI_CLI_TEST": "1"}, |
| ) |
|
|
| |
| assert "Config file:" in result.output |
| logger.info("CLI successfully loaded and parsed custom config.") |
|
|
|
|
| def test_package_entry_point(): |
| """Test that the package entry point works.""" |
| |
| try: |
| import imcui |
| from imcui.cli import main as cli_main |
| from imcui.ui import ImageMatchingApp |
|
|
| |
| assert hasattr(imcui, "__version__") or hasattr(imcui, "__name__") |
| assert callable(cli_main.main) |
| assert hasattr(ImageMatchingApp, "run") |
|
|
| except ImportError as e: |
| pytest.fail(f"Failed to import package components: {e}") |
| logger.info("Package entry point and components are valid.") |
|
|
|
|
| @pytest.mark.skipif( |
| os.name == "nt", reason="Skip on Windows due to signal handling issues" |
| ) |
| def test_cli_quick_exit(): |
| """Test that CLI exits quickly when interrupted.""" |
| import signal |
| import time |
|
|
| |
| process = subprocess.Popen( |
| [sys.executable, "-m", "imcui.cli.main", "--server-port", "0"], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE, |
| cwd=ROOT, |
| ) |
|
|
| |
| time.sleep(1) |
|
|
| |
| process.send_signal(signal.SIGINT) |
|
|
| |
| try: |
| stdout, stderr = process.communicate(timeout=5) |
| assert ( |
| process.returncode != 0 |
| ) |
| except subprocess.TimeoutExpired: |
| process.kill() |
| pytest.fail("CLI process did not exit promptly after interrupt") |
| logger.info("CLI process exited promptly after interrupt.") |
|
|
|
|
| if __name__ == "__main__": |
| |
| test_cli_help() |
| test_cli_version() |
| test_cli_default_config_loading() |
| |
| logger.info( |
| "Skipping test_app_py_default_config when running directly (use pytest)" |
| ) |
| test_package_entry_point() |
| logger.success("All tests passed!") |
|
|