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
118 changes: 118 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

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

# Testing
.pytest_cache/
.coverage
.coverage.*
htmlcov/
coverage.xml
*.cover
*.py,cover
.hypothesis/
.tox/
.nox/

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

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.project
.pydevproject
.settings/
.classpath

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

# Claude
.claude/*

# Project specific
*.log
*.sqlite
*.db

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# pipenv
Pipfile.lock

# Poetry
# Note: poetry.lock should be committed to version control
# poetry.lock

# PEP 582
__pypackages__/

# Celery
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.env.local
.env.*.local

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/
2 changes: 2 additions & 0 deletions coding_algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Coding algorithms package initialization
__version__ = "0.1.0"
282 changes: 282 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
[tool.poetry]
name = "coding-algorithms"
version = "0.1.0"
description = "A collection of coding algorithms and data structures"
authors = ["Your Name <you@example.com>"]
readme = "README.md"
packages = [{include = "coding_algorithms"}]

[tool.poetry.dependencies]
python = "^3.8"

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

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

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = [
"tests",
]
python_files = [
"test_*.py",
"*_test.py",
"tests.py",
]
python_classes = ["Test*", "*Tests"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=coding_algorithms",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=80",
]
markers = [
"unit: marks tests as unit tests (fast, isolated)",
"integration: marks tests as integration tests (slower, may have dependencies)",
"slow: marks tests as slow running",
]

[tool.coverage.run]
source = ["coding_algorithms"]
omit = [
"*/tests/*",
"*/__pycache__/*",
"*/venv/*",
"*/.venv/*",
"*/virtualenv/*",
"*/dist/*",
"*/build/*",
"*.pyx",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self\\.debug",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
precision = 2
show_missing = true
skip_covered = false
skip_empty = true

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

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

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Tests package initialization
170 changes: 170 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
"""Shared pytest fixtures and configuration for all tests."""

import os
import sys
import tempfile
from pathlib import Path
from typing import Generator

import pytest

# Add the project root to the Python path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Create a temporary directory for test files.

Yields:
Path: Path to the temporary directory.
"""
with tempfile.TemporaryDirectory() as temp_dir_str:
yield Path(temp_dir_str)


@pytest.fixture
def temp_file(temp_dir: Path) -> Generator[Path, None, None]:
"""Create a temporary file for testing.

Args:
temp_dir: Temporary directory fixture.

Yields:
Path: Path to the temporary file.
"""
temp_file = temp_dir / "test_file.txt"
temp_file.write_text("test content")
yield temp_file


@pytest.fixture
def mock_config() -> dict:
"""Provide a mock configuration dictionary.

Returns:
dict: Mock configuration for testing.
"""
return {
"debug": True,
"verbose": False,
"timeout": 30,
"max_retries": 3,
"features": {
"experimental": False,
"cache_enabled": True,
}
}


@pytest.fixture
def sample_data() -> dict:
"""Provide sample data for testing algorithms.

Returns:
dict: Sample data sets for different algorithm types.
"""
return {
"integers": [64, 34, 25, 12, 22, 11, 90],
"sorted_integers": [11, 12, 22, 25, 34, 64, 90],
"strings": ["apple", "banana", "cherry", "date", "elderberry"],
"graph_edges": [(0, 1), (0, 2), (1, 2), (2, 3), (3, 4)],
"matrix": [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
}


@pytest.fixture
def captured_output(monkeypatch):
"""Capture stdout and stderr for testing print statements.

Usage:
def test_print(captured_output):
print("Hello")
assert captured_output() == "Hello\\n"
"""
import io

captured = {"stdout": "", "stderr": ""}

def capture():
return captured["stdout"]

def mock_stdout_write(s):
captured["stdout"] += s

def mock_stderr_write(s):
captured["stderr"] += s

monkeypatch.setattr(sys.stdout, 'write', mock_stdout_write)
monkeypatch.setattr(sys.stderr, 'write', mock_stderr_write)

return capture


@pytest.fixture(autouse=True)
def reset_sys_modules():
"""Reset sys.modules to ensure clean imports between tests."""
modules_before = set(sys.modules.keys())
yield
modules_after = set(sys.modules.keys())
for module in modules_after - modules_before:
if module.startswith('coding_algorithms'):
del sys.modules[module]


@pytest.fixture
def mock_env_vars(monkeypatch) -> dict:
"""Set mock environment variables for testing.

Returns:
dict: Dictionary of environment variables set for testing.
"""
env_vars = {
"TEST_ENV": "true",
"DEBUG": "false",
"API_KEY": "test_key_12345",
"TIMEOUT": "60",
}

for key, value in env_vars.items():
monkeypatch.setenv(key, value)

return env_vars


def pytest_configure(config):
"""Configure pytest with custom settings."""
# Add custom markers documentation
config.addinivalue_line(
"markers", "unit: mark test as a unit test (fast, isolated)"
)
config.addinivalue_line(
"markers", "integration: mark test as an integration test (may have dependencies)"
)
config.addinivalue_line(
"markers", "slow: mark test as slow running (use --runslow to include)"
)


def pytest_addoption(parser):
"""Add custom command line options."""
parser.addoption(
"--runslow",
action="store_true",
default=False,
help="run slow tests"
)


def pytest_collection_modifyitems(config, items):
"""Modify test collection to handle custom markers."""
if not config.getoption("--runslow"):
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
for item in items:
if "slow" in item.keywords:
item.add_marker(skip_slow)
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 initialization
Loading