webdrop-bridge/tests/unit/test_validator.py
claudi dbf8f2b92f Enhance test coverage and refactor code in various modules
- Achieved 85% overall test coverage with detailed results for individual components.
- Added unit tests for DragInterceptor and MainWindow components.
- Refactored imports and removed unused code in multiple files.
- Updated test configurations and ensured compliance with coverage standards.
2026-01-28 11:51:59 +01:00

180 lines
5.9 KiB
Python

"""Unit tests for path validator."""
from pathlib import Path
import pytest
from webdrop_bridge.core.validator import PathValidator, ValidationError
class TestPathValidator:
"""Test path validation."""
def test_validator_initialization(self, tmp_path):
"""Test creating a validator with valid roots."""
dir1 = tmp_path / "dir1"
dir2 = tmp_path / "dir2"
dir1.mkdir()
dir2.mkdir()
validator = PathValidator([dir1, dir2])
assert len(validator.allowed_roots) == 2
def test_validator_nonexistent_root(self, tmp_path):
"""Test that nonexistent root raises ValidationError."""
nonexistent = tmp_path / "nonexistent"
with pytest.raises(ValidationError, match="does not exist"):
PathValidator([nonexistent])
def test_validator_non_directory_root(self, tmp_path):
"""Test that non-directory root raises ValidationError."""
file_path = tmp_path / "file.txt"
file_path.write_text("test")
with pytest.raises(ValidationError, match="not a directory"):
PathValidator([file_path])
def test_validate_valid_file(self, tmp_path):
"""Test validating a file within allowed root."""
file_path = tmp_path / "test.txt"
file_path.write_text("test content")
validator = PathValidator([tmp_path])
assert validator.validate(file_path) is True
assert validator.is_valid(file_path) is True
def test_validate_nonexistent_file(self, tmp_path):
"""Test that nonexistent file raises ValidationError."""
validator = PathValidator([tmp_path])
nonexistent = tmp_path / "nonexistent.txt"
with pytest.raises(ValidationError, match="does not exist"):
validator.validate(nonexistent)
def test_validate_directory_path(self, tmp_path):
"""Test that directory path raises ValidationError."""
subdir = tmp_path / "subdir"
subdir.mkdir()
validator = PathValidator([tmp_path])
with pytest.raises(ValidationError, match="not a regular file"):
validator.validate(subdir)
def test_validate_file_outside_roots(self, tmp_path):
"""Test that file outside allowed roots raises ValidationError."""
allowed_dir = tmp_path / "allowed"
other_dir = tmp_path / "other"
allowed_dir.mkdir()
other_dir.mkdir()
file_in_other = other_dir / "test.txt"
file_in_other.write_text("test")
validator = PathValidator([allowed_dir])
with pytest.raises(ValidationError, match="not within allowed roots"):
validator.validate(file_in_other)
def test_validate_multiple_roots(self, tmp_path):
"""Test validating files in multiple allowed roots."""
dir1 = tmp_path / "dir1"
dir2 = tmp_path / "dir2"
dir1.mkdir()
dir2.mkdir()
file1 = dir1 / "file1.txt"
file2 = dir2 / "file2.txt"
file1.write_text("content1")
file2.write_text("content2")
validator = PathValidator([dir1, dir2])
assert validator.validate(file1) is True
assert validator.validate(file2) is True
def test_validate_with_relative_path(self, tmp_path):
"""Test validating with relative path (gets resolved)."""
import os
file_path = tmp_path / "test.txt"
file_path.write_text("test")
validator = PathValidator([tmp_path])
# Change to tmp_path directory
original_cwd = os.getcwd()
try:
os.chdir(tmp_path)
# Use relative path
assert validator.validate(Path("test.txt")) is True
finally:
os.chdir(original_cwd)
def test_validate_with_path_traversal(self, tmp_path):
"""Test that path traversal attacks are blocked."""
allowed_dir = tmp_path / "allowed"
other_dir = tmp_path / "other"
allowed_dir.mkdir()
other_dir.mkdir()
file_in_other = other_dir / "secret.txt"
file_in_other.write_text("secret")
validator = PathValidator([allowed_dir])
# Try to access file outside root using ..
traversal_path = allowed_dir / ".." / "other" / "secret.txt"
with pytest.raises(ValidationError, match="not within allowed roots"):
validator.validate(traversal_path)
def test_is_valid_doesnt_raise(self, tmp_path):
"""Test that is_valid() never raises exceptions."""
validator = PathValidator([tmp_path])
# These should all return False, not raise
assert validator.is_valid(Path("/nonexistent")) is False
assert validator.is_valid(tmp_path) is False # Directory, not file
# Valid file should return True
file_path = tmp_path / "test.txt"
file_path.write_text("test")
assert validator.is_valid(file_path) is True
class TestPathValidatorEdgeCases:
"""Test edge cases in path validation."""
def test_symlink_to_valid_file(self, tmp_path):
"""Test validating a symlink to a valid file."""
# Skip on Windows if symlink creation fails
actual_file = tmp_path / "actual.txt"
actual_file.write_text("content")
try:
symlink = tmp_path / "link.txt"
symlink.symlink_to(actual_file)
validator = PathValidator([tmp_path])
# Symlinks resolve to their target, should validate
assert validator.validate(symlink) is True
except (OSError, NotImplementedError):
# Skip if symlinks not supported
pytest.skip("Symlinks not supported on this platform")
def test_nested_files_in_allowed_root(self, tmp_path):
"""Test validating files in nested subdirectories."""
nested_dir = tmp_path / "a" / "b" / "c"
nested_dir.mkdir(parents=True)
nested_file = nested_dir / "file.txt"
nested_file.write_text("content")
validator = PathValidator([tmp_path])
assert validator.validate(nested_file) is True