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
46 changes: 46 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
*~
*.swp
build

# Testing
.pytest_cache/
.coverage
htmlcov/
coverage.xml
*.py[cod]
__pycache__/

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

# IDE files
.vscode/
.idea/
*.sublime-*

# Claude settings
.claude/*

# Build artifacts
dist/
*.egg-info/
.eggs/

# OS files
.DS_Store
Thumbs.db

# Tensorflow/Model files
*.pb
*.h5
checkpoint
*.ckpt*

# Data files
*.h5
*.hdf5

# Logs
logs/
*.log
3,044 changes: 3,044 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

88 changes: 88 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
[tool.poetry]
name = "depthmotionnet"
version = "0.1.0"
description = "DeMoN - Depth Motion Network: Learning Depth and Camera Motion from Images"
authors = ["DeMoN Team"]
readme = "README.md"
packages = [{include = "depthmotionnet", from = "python"}]

[tool.poetry.dependencies]
python = "^3.8"
tensorflow = "^2.13.0"
numpy = "^1.24.0"
pillow = "^10.0.0"
matplotlib = "^3.7.0"

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

[tool.poetry.scripts]
test = "pytest:main"
tests = "pytest:main"

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = [
"tests",
]
python_files = [
"test_*.py",
"*_test.py",
]
python_classes = [
"Test*",
]
python_functions = [
"test_*",
]
addopts = [
"-ra",
"--strict-markers",
"--cov=python/depthmotionnet",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=0",
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Tests that take a long time to run",
]

[tool.coverage.run]
source = ["python/depthmotionnet"]
omit = [
"*/tests/*",
"*/__init__.py",
"*/setup.py",
"*/conf.py",
"*/.venv/*",
"*/venv/*",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"@abstractmethod",
]
show_missing = true
fail_under = 80

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
140 changes: 140 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""
Shared pytest fixtures and configuration for the DeMoN test suite.
"""
import pytest
import tempfile
import shutil
import os
import numpy as np
from pathlib import Path
from unittest.mock import Mock


@pytest.fixture
def temp_dir():
"""Create a temporary directory for test files."""
temp_path = tempfile.mkdtemp()
yield Path(temp_path)
shutil.rmtree(temp_path)


@pytest.fixture
def mock_config():
"""Provide a mock configuration object for testing."""
config = Mock()
config.batch_size = 32
config.learning_rate = 0.001
config.epochs = 10
config.data_format = 'channels_last'
config.image_height = 192
config.image_width = 256
return config


@pytest.fixture
def sample_image_pair(temp_dir):
"""Create a pair of sample images for testing."""
from PIL import Image

# Create two simple RGB images
img1 = Image.new('RGB', (256, 192), color='red')
img2 = Image.new('RGB', (256, 192), color='blue')

img1_path = temp_dir / 'image1.png'
img2_path = temp_dir / 'image2.png'

img1.save(img1_path)
img2.save(img2_path)

return img1_path, img2_path


@pytest.fixture
def sample_depth_map():
"""Create a sample depth map for testing."""
# Create a simple gradient depth map
depth = np.linspace(0.1, 10.0, 192*256).reshape(192, 256).astype(np.float32)
return depth


@pytest.fixture
def sample_camera_matrix():
"""Create a sample camera intrinsic matrix."""
K = np.array([
[500.0, 0.0, 128.0],
[0.0, 500.0, 96.0],
[0.0, 0.0, 1.0]
], dtype=np.float32)
return K


@pytest.fixture
def sample_rotation_translation():
"""Create sample rotation and translation matrices."""
# Identity rotation
R = np.eye(3, dtype=np.float32)

# Small translation
t = np.array([0.1, 0.0, 0.0], dtype=np.float32)

return R, t


@pytest.fixture(autouse=True)
def reset_tensorflow():
"""Reset TensorFlow graph before each test."""
import tensorflow as tf
tf.keras.backend.clear_session()
yield
tf.keras.backend.clear_session()


@pytest.fixture
def mock_dataset(temp_dir):
"""Create a mock dataset structure for testing."""
dataset_dir = temp_dir / 'test_dataset'
dataset_dir.mkdir()

# Create mock dataset structure
(dataset_dir / 'train').mkdir()
(dataset_dir / 'test').mkdir()
(dataset_dir / 'val').mkdir()

# Create a mock metadata file
metadata = {
'num_train': 100,
'num_test': 20,
'num_val': 10,
'image_height': 192,
'image_width': 256
}

import json
with open(dataset_dir / 'metadata.json', 'w') as f:
json.dump(metadata, f)

return dataset_dir


@pytest.fixture
def capture_stdout(monkeypatch):
"""Capture stdout for testing print statements."""
import io
captured_output = io.StringIO()

def mock_print(*args, **kwargs):
print(*args, file=captured_output, **kwargs)

monkeypatch.setattr('builtins.print', mock_print)
return captured_output


# Test environment markers
def pytest_configure(config):
"""Configure custom pytest markers."""
config.addinivalue_line(
"markers", "gpu: marks tests that require GPU (deselect with '-m \"not gpu\"')"
)
config.addinivalue_line(
"markers", "large_memory: marks tests that require large amounts of memory"
)
Empty file added tests/integration/__init__.py
Empty file.
116 changes: 116 additions & 0 deletions tests/test_setup_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
Validation tests to ensure the testing infrastructure is properly set up.
"""
import pytest
import sys
import os
from pathlib import Path


class TestSetupValidation:
"""Validate that the testing infrastructure is properly configured."""

def test_pytest_installed(self):
"""Test that pytest is available."""
assert pytest.__version__

def test_python_path_includes_project(self):
"""Test that the project module can be imported."""
project_root = Path(__file__).parent.parent
python_path = project_root / 'python'

# Ensure python directory is in path
assert any(str(python_path) in p for p in sys.path), \
f"Python path should include {python_path}"

def test_can_import_depthmotionnet(self):
"""Test that the main package can be imported."""
# Add python directory to path if not already there
project_root = Path(__file__).parent.parent
python_path = project_root / 'python'
if str(python_path) not in sys.path:
sys.path.insert(0, str(python_path))

import depthmotionnet
assert depthmotionnet is not None

@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."""
assert True

def test_fixtures_available(self, temp_dir, mock_config):
"""Test that custom fixtures are available."""
assert temp_dir.exists()
assert temp_dir.is_dir()
assert mock_config.batch_size == 32

def test_coverage_configured(self):
"""Test that coverage is properly configured."""
# This test will pass if coverage is running
# The actual validation happens when running with coverage
assert True

def test_test_directories_exist(self):
"""Test that all test directories exist."""
test_root = Path(__file__).parent
assert test_root.exists()
assert (test_root / 'unit').exists()
assert (test_root / 'integration').exists()
assert (test_root / 'conftest.py').exists()


class TestSampleFixtures:
"""Test that the sample fixtures work correctly."""

def test_sample_image_pair_fixture(self, sample_image_pair):
"""Test the sample image pair fixture."""
img1_path, img2_path = sample_image_pair
assert img1_path.exists()
assert img2_path.exists()
assert img1_path.suffix == '.png'
assert img2_path.suffix == '.png'

def test_sample_depth_map_fixture(self, sample_depth_map):
"""Test the sample depth map fixture."""
import numpy as np
assert isinstance(sample_depth_map, np.ndarray)
assert sample_depth_map.shape == (192, 256)
assert sample_depth_map.dtype == np.float32

def test_sample_camera_matrix_fixture(self, sample_camera_matrix):
"""Test the sample camera matrix fixture."""
import numpy as np
assert isinstance(sample_camera_matrix, np.ndarray)
assert sample_camera_matrix.shape == (3, 3)
assert sample_camera_matrix[2, 2] == 1.0

def test_mock_dataset_fixture(self, mock_dataset):
"""Test the mock dataset fixture."""
assert mock_dataset.exists()
assert (mock_dataset / 'train').exists()
assert (mock_dataset / 'test').exists()
assert (mock_dataset / 'val').exists()
assert (mock_dataset / 'metadata.json').exists()


def test_running_specific_markers():
"""
Document how to run tests with specific markers.
This test itself always passes but serves as documentation.
"""
# Run only unit tests: pytest -m unit
# Run only integration tests: pytest -m integration
# Run all except slow tests: pytest -m "not slow"
# Run unit and integration but not slow: pytest -m "unit or integration and not slow"
assert True
Empty file added tests/unit/__init__.py
Empty file.