Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,68 @@
__pycache__
# Python cache and bytecode
__pycache__/
*.py[cod]
*$py.class
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Testing and coverage
.pytest_cache/
.coverage
htmlcov/
coverage.xml
.tox/
.nox/
.coverage.*

# Claude Code settings
.claude/*

# Project specific
patches/patcherex
*.mp4

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

453 changes: 453 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[tool.poetry]
name = "dnn-decompiler"
version = "0.1.0"
description = "A DNN decompiler and patcher for binary analysis"
authors = ["DNN Decompiler Team"]
readme = "README.md"
packages = [{include = "src"}]

[tool.poetry.dependencies]
python = "^3.8"
numpy = "^1.21.0"
onnx = "^1.12.0"
capstone = "^5.0.0"
# Note: angr and patcherex2 may need system dependencies or manual installation

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.11.0"

# Poetry scripts will be configured via command line usage:
# poetry run pytest (or poetry run python -m pytest)

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=src",
"--cov-report=term-missing",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=80"
]
markers = [
"unit: marks tests as unit tests",
"integration: marks tests as integration tests",
"slow: marks tests as slow (deselect with '-m \"not slow\"')"
]

[tool.coverage.run]
source = ["src"]
omit = [
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/venv/*",
"*/.venv/*"
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:"
]
show_missing = true
precision = 2

[tool.coverage.html]
directory = "htmlcov"
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test package marker
127 changes: 127 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
Shared pytest fixtures for the DNN decompiler test suite.
"""
import pytest
import tempfile
import os
import shutil
from pathlib import Path
from unittest.mock import Mock, MagicMock
import numpy as np


@pytest.fixture
def temp_dir():
"""Create a temporary directory for tests."""
temp_path = tempfile.mkdtemp()
yield Path(temp_path)
shutil.rmtree(temp_path, ignore_errors=True)


@pytest.fixture
def sample_binary_path(temp_dir):
"""Create a sample binary file for testing."""
binary_path = temp_dir / "test_binary.bin"
with open(binary_path, "wb") as f:
f.write(b"\x00" * 1024) # Simple 1KB binary
return binary_path


@pytest.fixture
def mock_angr_project():
"""Mock angr project for testing."""
project = Mock()
project.arch = Mock()
project.arch.name = "ARM"
project.loader = Mock()
project.loader.main_object = Mock()
project.funcs = {}
project.outer_loops = {}
project.func_calling_regs = {}
return project


@pytest.fixture
def mock_capstone():
"""Mock capstone disassembler."""
mock_cs = Mock()
mock_cs.disasm = Mock(return_value=[])
return mock_cs


@pytest.fixture
def sample_numpy_array():
"""Sample numpy array for testing."""
return np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)


@pytest.fixture
def mock_onnx_model():
"""Mock ONNX model for testing."""
model = Mock()
model.graph = Mock()
model.graph.node = []
model.graph.input = []
model.graph.output = []
return model


@pytest.fixture
def test_config():
"""Test configuration dictionary."""
return {
"timeout": 10,
"debug": True,
"arch": "ARM",
"endian": "little"
}


@pytest.fixture
def mock_memory_record():
"""Mock memory record for testing."""
record = Mock()
record.addr = 0x1000
record.size = 4
record.data = b"\x01\x02\x03\x04"
return record


@pytest.fixture
def sample_lifted_ast():
"""Sample lifted AST for testing."""
from src.lifted_ast import LiftedAST, AST_OP
ast = LiftedAST(None, None, None, None)
ast.op_type = AST_OP.CONV
return ast


@pytest.fixture(autouse=True)
def cleanup_temp_files():
"""Auto-cleanup fixture to remove temporary files after each test."""
yield
# Clean up any .tmp files or test artifacts
for tmp_file in Path("/tmp").glob("test_*"):
try:
if tmp_file.is_file():
tmp_file.unlink()
elif tmp_file.is_dir():
shutil.rmtree(tmp_file)
except (OSError, PermissionError):
pass


@pytest.fixture
def capture_logs(caplog):
"""Fixture to capture and provide access to log messages."""
import logging
caplog.set_level(logging.DEBUG)
return caplog


# Custom markers
def pytest_configure(config):
"""Register custom markers."""
config.addinivalue_line("markers", "unit: mark test as a unit test")
config.addinivalue_line("markers", "integration: mark test as an integration test")
config.addinivalue_line("markers", "slow: mark test as slow running")
1 change: 1 addition & 0 deletions tests/integration/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration tests package marker
117 changes: 117 additions & 0 deletions tests/test_infrastructure_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""
Validation tests to ensure the testing infrastructure is properly configured.
"""
import pytest
import sys
import os
from pathlib import Path
import numpy as np


class TestInfrastructureValidation:
"""Test class to validate testing infrastructure setup."""

def test_pytest_working(self):
"""Test that pytest is working correctly."""
assert True

def test_numpy_import(self):
"""Test that numpy can be imported and used."""
arr = np.array([1, 2, 3])
assert arr.shape == (3,)
assert arr.dtype == np.int64 or arr.dtype == np.int32

@pytest.mark.unit
def test_unit_marker(self):
"""Test that unit test marker works."""
assert True

@pytest.mark.integration
def test_integration_marker(self):
"""Test that integration test marker works."""
assert True

@pytest.mark.slow
def test_slow_marker(self):
"""Test that slow test marker works."""
import time
time.sleep(0.01) # Minimal delay
assert True

def test_fixtures_available(self, temp_dir, test_config):
"""Test that custom fixtures are available."""
assert temp_dir.exists()
assert isinstance(test_config, dict)
assert "timeout" in test_config

def test_mock_fixtures(self, mock_angr_project, mock_capstone):
"""Test that mock fixtures work."""
assert mock_angr_project is not None
assert mock_capstone is not None
assert hasattr(mock_angr_project, "arch")

def test_sample_data_fixtures(self, sample_numpy_array, sample_binary_path):
"""Test that sample data fixtures work."""
assert sample_numpy_array.shape == (2, 3)
assert sample_binary_path.exists()
assert sample_binary_path.stat().st_size == 1024

def test_src_module_accessible(self):
"""Test that src module is accessible for imports."""
# Test that we can import from src without errors
# This validates the package structure is correct
try:
import src.utils
except ImportError as e:
# If specific modules don't exist, that's fine for infrastructure test
# Just ensure we can attempt the import
pass

# Just test that src is in the path
src_path = Path(__file__).parent.parent / "src"
assert src_path.exists()

def test_project_structure(self):
"""Test that the project structure is correct."""
project_root = Path(__file__).parent.parent

# Check key directories exist
assert (project_root / "src").exists()
assert (project_root / "tests").exists()
assert (project_root / "tests" / "unit").exists()
assert (project_root / "tests" / "integration").exists()

# Check key files exist
assert (project_root / "pyproject.toml").exists()
assert (project_root / "tests" / "conftest.py").exists()

def test_coverage_will_run(self):
"""Test a simple function to ensure coverage tracking works."""
def simple_function(x):
if x > 0:
return x * 2
else:
return 0

assert simple_function(5) == 10
assert simple_function(-1) == 0
assert simple_function(0) == 0

def test_pytest_mock_available(self, mocker):
"""Test that pytest-mock is available."""
mock_func = mocker.Mock(return_value=42)
assert mock_func() == 42
mock_func.assert_called_once()

def test_environment_variables(self):
"""Test that we can work with environment variables."""
os.environ["TEST_VAR"] = "test_value"
assert os.environ.get("TEST_VAR") == "test_value"
del os.environ["TEST_VAR"]

def test_temp_file_cleanup(self, temp_dir):
"""Test that temporary files are properly cleaned up."""
test_file = temp_dir / "test_cleanup.txt"
test_file.write_text("test content")
assert test_file.exists()
# The cleanup fixture should handle removal after test
Loading