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
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
.idea/
venv/

# Python testing
.pytest_cache/
.coverage
htmlcov/
coverage.xml
*.cover
.hypothesis/
.tox/

# Poetry
dist/
.venv/

# Claude
.claude/*

# exclude everything
output/*
# exception to the rule
Expand Down
570 changes: 570 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
[tool.poetry]
name = "sharpyshell"
version = "0.1.0"
description = "A Python-based shell tool"
authors = ["Your Name <[email protected]>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.8"
urllib3 = "*"
PySocks = "*"
pycryptodome = "*"
pyopenssl = "*"
pefile = "*"
prettytable = "*"

[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=core",
"--cov=modules",
"--cov=utils",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html",
"--cov-report=xml",
"--cov-fail-under=80",
"-vv"
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow tests"
]
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning"
]

[tool.coverage.run]
source = ["core", "modules", "utils"]
branch = true
omit = [
"*/tests/*",
"*/__init__.py",
"*/conftest.py",
"setup.py"
]

[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if __name__ == '__main__':",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if False:",
"class .*\\(Protocol\\):"
]

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

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

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
147 changes: 147 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import os
import sys
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, patch
import pytest

# Add the project root to the Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))


@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."""
config = Mock()
config.debug = False
config.verbose = False
config.timeout = 30
config.max_retries = 3
return config


@pytest.fixture
def sample_data():
"""Provide sample test data."""
return {
'test_string': 'Hello, World!',
'test_bytes': b'Hello, World!',
'test_list': [1, 2, 3, 4, 5],
'test_dict': {'key1': 'value1', 'key2': 'value2'},
'test_int': 42,
'test_float': 3.14159
}


@pytest.fixture
def mock_file_system(temp_dir):
"""Create a mock file system structure."""
# Create directories
(temp_dir / 'modules').mkdir()
(temp_dir / 'core').mkdir()
(temp_dir / 'utils').mkdir()

# Create some mock files
(temp_dir / 'test_file.txt').write_text('Test content')
(temp_dir / 'modules' / 'module1.py').write_text('# Module 1')
(temp_dir / 'core' / 'core1.py').write_text('# Core 1')

return temp_dir


@pytest.fixture
def mock_network():
"""Mock network-related functions."""
with patch('socket.socket') as mock_socket:
mock_instance = Mock()
mock_socket.return_value = mock_instance
mock_instance.connect.return_value = None
mock_instance.send.return_value = 10
mock_instance.recv.return_value = b'response'
yield mock_instance


@pytest.fixture
def mock_subprocess():
"""Mock subprocess calls."""
with patch('subprocess.run') as mock_run:
mock_run.return_value = Mock(
stdout='Success',
stderr='',
returncode=0
)
yield mock_run


@pytest.fixture(autouse=True)
def reset_environment():
"""Reset environment variables before each test."""
original_env = os.environ.copy()
yield
os.environ.clear()
os.environ.update(original_env)


@pytest.fixture
def capture_logs():
"""Capture log messages during tests."""
import logging
from io import StringIO

log_capture = StringIO()
handler = logging.StreamHandler(log_capture)
handler.setLevel(logging.DEBUG)

logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

yield log_capture

logger.removeHandler(handler)


@pytest.fixture
def mock_crypto():
"""Mock cryptographic operations."""
with patch('Crypto.Cipher.AES.new') as mock_aes:
mock_cipher = Mock()
mock_aes.return_value = mock_cipher
mock_cipher.encrypt.return_value = b'encrypted_data'
mock_cipher.decrypt.return_value = b'decrypted_data'
yield mock_cipher


@pytest.fixture(scope="session")
def test_resources():
"""Provide paths to test resource files."""
resources_dir = Path(__file__).parent / 'resources'
return {
'base_dir': resources_dir,
'sample_dll': resources_dir / 'sample.dll',
'sample_exe': resources_dir / 'sample.exe',
'sample_config': resources_dir / 'config.json'
}


# Markers for different test types
def pytest_configure(config):
"""Configure pytest with 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"
)
Empty file added tests/integration/__init__.py
Empty file.
113 changes: 113 additions & 0 deletions tests/test_infrastructure_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import pytest
import sys
import os
from pathlib import Path


class TestInfrastructureValidation:
"""Validation tests to ensure the testing infrastructure is properly set up."""

@pytest.mark.unit
def test_pytest_is_working(self):
"""Verify that pytest is installed and working."""
assert True

@pytest.mark.unit
def test_project_imports(self):
"""Verify that project modules can be imported."""
# Test that the project root is in the Python path
project_root = Path(__file__).parent.parent
assert str(project_root) in sys.path

# Try importing main modules
try:
import core
import modules
import utils
except ImportError as e:
pytest.fail(f"Failed to import project modules: {e}")

@pytest.mark.unit
def test_fixtures_available(self, temp_dir, mock_config, sample_data):
"""Verify that pytest fixtures are available and working."""
# Test temp_dir fixture
assert temp_dir.exists()
assert temp_dir.is_dir()

# Test mock_config fixture
assert hasattr(mock_config, 'debug')
assert hasattr(mock_config, 'timeout')

# Test sample_data fixture
assert 'test_string' in sample_data
assert sample_data['test_int'] == 42

@pytest.mark.unit
def test_mock_fixtures(self, mock_network, mock_subprocess):
"""Verify that mock fixtures are working."""
# Test mock_network
assert hasattr(mock_network, 'connect')
assert hasattr(mock_network, 'send')

# Test mock_subprocess
result = mock_subprocess()
assert result.returncode == 0

@pytest.mark.unit
def test_file_operations(self, temp_dir):
"""Test file operations with temporary directory."""
test_file = temp_dir / 'test.txt'
test_file.write_text('Hello, Testing!')

assert test_file.exists()
assert test_file.read_text() == 'Hello, Testing!'

@pytest.mark.unit
def test_markers_defined(self, request):
"""Verify that custom markers are defined."""
markers = request.config.getini('markers')
marker_names = [m.split(':')[0].strip() for m in markers]

assert 'unit' in marker_names
assert 'integration' in marker_names
assert 'slow' in marker_names

@pytest.mark.integration
def test_mock_file_system(self, mock_file_system):
"""Test the mock file system fixture."""
assert (mock_file_system / 'modules').exists()
assert (mock_file_system / 'core').exists()
assert (mock_file_system / 'utils').exists()
assert (mock_file_system / 'test_file.txt').read_text() == 'Test content'

@pytest.mark.unit
def test_coverage_configured(self):
"""Verify that coverage is properly configured."""
# This test will pass if coverage is running (which it should be
# based on our pytest configuration)
import coverage
assert hasattr(coverage, 'Coverage')

@pytest.mark.slow
def test_slow_marker(self):
"""Test that the slow marker works."""
import time
time.sleep(0.1) # Simulate a slow test
assert True


@pytest.mark.unit
def test_standalone_function():
"""Test that standalone test functions work too."""
assert 1 + 1 == 2


@pytest.mark.parametrize("input_val,expected", [
(1, 2),
(2, 4),
(3, 6),
(4, 8)
])
def test_parametrized(input_val, expected):
"""Test that parametrized tests work."""
assert input_val * 2 == expected
Empty file added tests/unit/__init__.py
Empty file.