- 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.
180 lines
5.9 KiB
Python
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
|