148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
# tests/test_analysis.py
|
|
from pathlib import Path
|
|
import pytest
|
|
from click.testing import CliRunner
|
|
from ctf.analysis import run_analysis, RouteResult
|
|
|
|
TEST_ENV = Path("tests/env")
|
|
|
|
def test_run_analysis_no_file():
|
|
"""
|
|
Verifies that run_analysis returns non-executed metadata route when file_path is None.
|
|
"""
|
|
result = run_analysis(None)
|
|
assert not result.success
|
|
assert len(result.routes) == 1
|
|
assert not result.routes[0].executed
|
|
assert "No file attached" in result.routes[0].message
|
|
|
|
def test_run_analysis_file_not_found():
|
|
"""
|
|
Verifies that run_analysis returns a failed metadata route when path does not exist.
|
|
"""
|
|
result = run_analysis(Path("non_existent_file_xyz.jpg"))
|
|
assert not result.success
|
|
assert len(result.routes) == 1
|
|
assert result.routes[0].executed
|
|
assert not result.routes[0].success
|
|
assert "File not found" in result.routes[0].message
|
|
|
|
def test_run_analysis_success_with_flag():
|
|
"""
|
|
Verifies that run_analysis successfully extracts flag from file comment.
|
|
"""
|
|
import struct
|
|
comment_text = b"flag{metadata_analyse_success}"
|
|
comment_len = len(comment_text) + 2
|
|
mock_jpeg = b"\xff\xd8\xff\xfe" + struct.pack(">H", comment_len) + comment_text + b"\xff\xd9"
|
|
|
|
test_file = TEST_ENV / "mock_analyse_flag.jpg"
|
|
with open(test_file, "wb") as f:
|
|
f.write(mock_jpeg)
|
|
|
|
result = run_analysis(test_file)
|
|
assert result.success
|
|
assert len(result.routes) == 1
|
|
assert result.routes[0].success
|
|
assert "flag{metadata_analyse_success}" in result.routes[0].extracted_flags
|
|
|
|
def test_cli_analyse_success():
|
|
"""
|
|
Verifies that 'ctf analyse' CLI successfully runs and outputs the extracted flags.
|
|
"""
|
|
from ctf.main import cli
|
|
runner = CliRunner()
|
|
|
|
import struct
|
|
comment_text = b"flag{cli_analyse_success}"
|
|
comment_len = len(comment_text) + 2
|
|
mock_jpeg = b"\xff\xd8\xff\xfe" + struct.pack(">H", comment_len) + comment_text + b"\xff\xd9"
|
|
|
|
test_file = TEST_ENV / "mock_cli_analyse_flag.jpg"
|
|
with open(test_file, "wb") as f:
|
|
f.write(mock_jpeg)
|
|
|
|
result = runner.invoke(cli, ["analyse", "-f", str(test_file)])
|
|
assert result.exit_code == 0
|
|
assert "Starting dynamic challenge analysis" in result.output
|
|
assert "Route: File Metadata Extraction" in result.output
|
|
assert "flag{cli_analyse_success}" in result.output
|
|
assert "Challenge solved successfully!" in result.output
|
|
|
|
def test_cli_analyse_no_file():
|
|
"""
|
|
Verifies that 'ctf analyse' CLI displays warnings when run without -f option.
|
|
"""
|
|
from ctf.main import cli
|
|
runner = CliRunner()
|
|
|
|
result = runner.invoke(cli, ["analyse"])
|
|
assert result.exit_code == 0
|
|
assert "No file attached to analyze" in result.output
|
|
assert "No clear flag found yet" in result.output
|
|
# }}}
|
|
|
|
# {{{ test_metadata_route_direct_execute
|
|
def test_metadata_route_direct_execute():
|
|
"""
|
|
Verifies that MetadataRoute can be instantiated and executed directly.
|
|
"""
|
|
from ctf.analysis import MetadataRoute, RouteResult
|
|
|
|
route = MetadataRoute()
|
|
assert route.route_name == "File Metadata Extraction"
|
|
assert route.is_applicable(Path("dummy.txt"))
|
|
|
|
# Executing on non-existent file
|
|
res = route.execute(Path("non_existent_file_xyz.bin"))
|
|
assert isinstance(res, RouteResult)
|
|
assert res.executed
|
|
assert not res.success
|
|
assert "File not found" in res.message
|
|
# }}}
|
|
|
|
# {{{ test_routing_engine_register_and_run
|
|
def test_routing_engine_register_and_run():
|
|
"""
|
|
Verifies that RoutingEngine successfully registers and runs applicable routes.
|
|
"""
|
|
from ctf.analysis import RoutingEngine, BaseRoute, RouteResult
|
|
|
|
class MockRoute(BaseRoute):
|
|
def __init__(self):
|
|
super().__init__("Mock Route")
|
|
def is_applicable(self, file_path: Path) -> bool:
|
|
return file_path.name.endswith(".mock")
|
|
def execute(self, file_path: Path) -> RouteResult:
|
|
return RouteResult(
|
|
route_name=self.route_name,
|
|
executed=True,
|
|
success=True,
|
|
message="Mock success",
|
|
extracted_flags=["flag{mock_success}"]
|
|
)
|
|
|
|
engine = RoutingEngine()
|
|
route = MockRoute()
|
|
engine.register_route(route)
|
|
|
|
# Run with no file path
|
|
res_no_path = engine.run_all(None)
|
|
assert not res_no_path.success
|
|
assert len(res_no_path.routes) == 1
|
|
assert not res_no_path.routes[0].executed
|
|
|
|
# Run with non-applicable file path
|
|
res_non_app = engine.run_all(Path("test.txt"))
|
|
assert not res_non_app.success
|
|
assert len(res_non_app.routes) == 0
|
|
|
|
# Run with applicable file path
|
|
res_app = engine.run_all(Path("test.mock"))
|
|
assert res_app.success
|
|
assert len(res_app.routes) == 1
|
|
assert res_app.routes[0].success
|
|
assert "flag{mock_success}" in res_app.routes[0].extracted_flags
|
|
# }}}
|
|
|