# SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2025 Allaun """Final Coverage Completion Tests. Tests to achieve 100% coverage for all 11 target files. Note: Now uses pickle-safe test helpers for ProcessPoolExecutor testing. See: docs/PARALLEL_TESTING_SUSTAINABILITY.md """ import mmap import os import shutil import tarfile import tempfile import time import zipfile from pathlib import Path from unittest.mock import MagicMock, Mock, mock_open, patch import pytest # Loader Tests from nodupe.core.loader import ( CoreLoader, bootstrap, ) from nodupe.tools.hashing.autotune_logic import ( autotune_hash_algorithm, create_autotuned_hasher, ) from nodupe.tools.databases.connection import get_connection # Discovery Tests from nodupe.core.tool_system.discovery import ( ToolDiscovery, ToolDiscoveryError, ToolInfo, create_tool_discovery, ) # Archive Logic Tests from nodupe.tools.archive.archive_logic import ( ArchiveHandler, ArchiveHandlerError, create_archive_handler, ) # Leap Year Tests from nodupe.tools.leap_year.leap_year import LeapYearTool # MIME Logic Tests from nodupe.tools.mime.mime_logic import MIMEDetection, MIMEDetectionError # Import pickle-safe test helpers for process testing from tests.parallel.test_helpers import ( double_number, square_number, add_one, identity, maybe_raise, ) # MIME Tool Tests from nodupe.tools.mime.mime_tool import StandardMIMETool, register_tool # Filesystem Tests from nodupe.tools.os_filesystem.filesystem import Filesystem, FilesystemError # MMAP Handler Tests from nodupe.tools.os_filesystem.mmap_handler import MMAPHandler # Parallel Logic Tests from nodupe.tools.parallel.parallel_logic import Parallel, ParallelError, ParallelProgress # Security Logic Tests from nodupe.tools.security_audit.security_logic import Security, SecurityError # ============================================================================= # Archive Logic - Missing Lines: 97, 99, 101, 103, 105, 161-163, 216->214, 242->241, 243-268 # ============================================================================= class TestArchiveLogicMissingCoverage: """Test missing coverage in archive_logic.py.""" def test_detect_archive_format_nonexistent_file(self): """Test detect_archive_format with nonexistent file - line 97.""" handler = ArchiveHandler() result = handler.detect_archive_format('/nonexistent/file.zip') assert result is None def test_detect_archive_format_extension_fallback_zip(self): """Test extension fallback for zip - line 99.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f: f.write(b'not a real zip') f.flush() try: # Mock mime detection to return None with patch.object(handler._mime_detector, 'detect_mime_type', return_value=None): result = handler.detect_archive_format(f.name) assert result == 'zip' finally: os.unlink(f.name) def test_detect_archive_format_extension_fallback_tar(self): """Test extension fallback for tar - line 101.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.tar', delete=False) as f: f.write(b'not a real tar') f.flush() try: with patch.object(handler._mime_detector, 'detect_mime_type', return_value=None): result = handler.detect_archive_format(f.name) assert result == 'tar' finally: os.unlink(f.name) def test_detect_archive_format_extension_fallback_tgz(self): """Test extension fallback for tgz - line 103.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.tgz', delete=False) as f: f.write(b'not a real tgz') f.flush() try: with patch.object(handler._mime_detector, 'detect_mime_type', return_value=None): result = handler.detect_archive_format(f.name) assert result == 'tar.gz' finally: os.unlink(f.name) def test_detect_archive_format_extension_fallback_tbz2(self): """Test extension fallback for tbz2 - line 105.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.tbz2', delete=False) as f: f.write(b'not a real tbz2') f.flush() try: with patch.object(handler._mime_detector, 'detect_mime_type', return_value=None): result = handler.detect_archive_format(f.name) assert result == 'tar.bz2' finally: os.unlink(f.name) def test_extract_archive_unsupported_format_mime(self): """Test extract_archive with unsupported format - lines 161-163.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.xyz', delete=False) as f: f.write(b'unknown format') f.flush() try: with patch.object(handler._mime_detector, 'detect_mime_type', return_value='application/unknown'): with pytest.raises(ArchiveHandlerError) as exc_info: handler.extract_archive(f.name) assert 'Unsupported archive format' in str(exc_info.value) finally: os.unlink(f.name) def test_create_archive_tar_lzma_format(self): """Test create_archive with tar.lzma format - line 216->214.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.tar.lzma', delete=False) as f: archive_path = f.name with tempfile.NamedTemporaryFile(delete=False) as data_file: data_file.write(b'test data') data_file.flush() data_path = data_file.name try: # tar.lzma is not supported for creation - falls back to tar mode result = handler.create_archive(archive_path, [data_path], format='tar.lzma') # Should create a tar file (tar.lzma falls through to tar mode) assert result == archive_path assert os.path.exists(archive_path) finally: os.unlink(archive_path) os.unlink(data_path) def test_get_archive_contents_info_exception_path(self): """Test get_archive_contents_info exception path - lines 242->241, 243-268.""" handler = ArchiveHandler() # Create a valid zip file with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f: archive_path = f.name with zipfile.ZipFile(archive_path, 'w') as zf: zf.writestr('test.txt', 'test content') try: # Mock extract_archive to raise an exception with patch.object(handler, 'extract_archive', side_effect=Exception('Extraction failed')): result = handler.get_archive_contents_info(archive_path, '/base') assert result == [] finally: os.unlink(archive_path) def test_get_archive_contents_info_stat_error(self): """Test get_archive_contents_info with stat error.""" handler = ArchiveHandler() with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f: archive_path = f.name with zipfile.ZipFile(archive_path, 'w') as zf: zf.writestr('test.txt', 'test content') try: # Extract first extracted = handler.extract_archive(archive_path) # Now mock stat to raise exception with patch.object(Path, 'stat', side_effect=Exception('Stat failed')): result = handler.get_archive_contents_info(archive_path, '/base') # Should return empty list due to exception handling finally: handler.cleanup() os.unlink(archive_path) # ============================================================================= # MIME Tool - Missing Line: 72->78 # ============================================================================= class TestMIMEToolMissingCoverage: """Test missing coverage in mime_tool.py.""" def test_run_standalone_no_file_arg(self): """Test run_standalone with no file argument - line 72->78.""" tool = StandardMIMETool() # When no args, should print help and raise SystemExit(0) with pytest.raises(SystemExit) as exc_info: tool.run_standalone([]) assert exc_info.value.code == 0 # ============================================================================= # MIME Logic - Missing Lines: 179, 210-216, 247 # ============================================================================= class TestMIMELogicMissingCoverage: """Test missing coverage in mime_logic.py.""" def test_detect_by_magic_no_match(self): """Test _detect_by_magic with no matching magic number - line 179.""" from nodupe.tools.mime.mime_logic import MIMEDetection detector = MIMEDetection() with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b'unknown file content') f.flush() try: result = detector._detect_by_magic(Path(f.name)) assert result is None finally: os.unlink(f.name) def test_detect_by_magic_ogg(self): """Test _detect_by_magic for OGG format - line 210-216.""" from nodupe.tools.mime.mime_logic import MIMEDetection detector = MIMEDetection() with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b'OggS\x00\x00\x00\x00') f.flush() try: result = detector._detect_by_magic(Path(f.name)) assert result == 'audio/ogg' finally: os.unlink(f.name) def test_detect_by_magic_read_error(self): """Test _detect_by_magic with read error - line 247.""" from nodupe.tools.mime.mime_logic import MIMEDetection detector = MIMEDetection() mock_path = MagicMock() mock_path.open.side_effect = IOError('Cannot read') result = detector._detect_by_magic(mock_path) assert result is None # ============================================================================= # Loader - Missing Lines: 66->65, 162->165, 192->196, 253-257, 295->307, 296->295, 301, 303-304, 343-346, 374, 377, 414 # ============================================================================= class TestLoaderMissingCoverage: """Test missing coverage in loader.py.""" def test_initialize_double_init(self): """Test initialize when already initialized - line 66->65.""" loader = CoreLoader() loader.initialized = True # Should return immediately loader.initialize() assert loader.initialized is True def test_initialize_config_merge_nested_dict(self): """Test config merge with nested dicts - line 162->165.""" loader = CoreLoader() mock_config = MagicMock() mock_config.config = {'tools': {'existing': 'value'}} with patch('nodupe.core.loader.load_config', return_value=mock_config), \ patch.object(loader, '_apply_platform_autoconfig', return_value={'tools': {'new': 'value'}}), \ patch('nodupe.core.loader.ToolRegistry'), \ patch('nodupe.core.loader.create_tool_loader'), \ patch('nodupe.core.loader.create_tool_discovery'), \ patch('nodupe.core.loader.create_lifecycle_manager'), \ patch('nodupe.core.loader.ToolHotReload'), \ patch('nodupe.core.loader.ToolIPCServer'), \ patch('nodupe.core.loader.logging'): try: loader.initialize() except Exception: pass # Expected due to mocking # Both keys should exist assert 'existing' in mock_config.config['tools'] assert 'new' in mock_config.config['tools'] def test_discover_and_load_tools_disabled(self): """Test tool discovery when auto_load is disabled - line 192->196.""" loader = CoreLoader() loader.config = MagicMock() loader.config.config = {'tools': {'auto_load': False}} loader.tool_discovery = MagicMock() loader._discover_and_load_tools() # Should not call discover_tools_in_directory loader.tool_discovery.discover_tools_in_directory.assert_not_called() def test_perform_hash_autotuning_no_hasher_with_error(self): """Test hash autotuning with error - lines 253-257.""" loader = CoreLoader() loader.container = MagicMock() loader.container.get_service.return_value = None loader.logger = MagicMock() with patch('nodupe.core.loader.autotune_hash_algorithm', side_effect=Exception('Autotune failed')), \ patch('nodupe.core.loader.create_autotuned_hasher') as mock_create: mock_create.return_value = (MagicMock(), {}) loader._perform_hash_autotuning() # Should create fallback hasher assert loader.container.register_service.called def test_shutdown_not_initialized(self): """Test shutdown when not initialized - line 295->307.""" loader = CoreLoader() loader.initialized = False # Should return immediately loader.shutdown() def test_shutdown_exception_handling(self, caplog): """Test shutdown with exception - lines 296->295, 301, 303-304.""" loader = CoreLoader() loader.initialized = True loader.tool_lifecycle = MagicMock() loader.tool_lifecycle.shutdown_all_tools.side_effect = Exception('Shutdown failed') loader.logger = MagicMock() loader.shutdown() # Should log error but continue assert loader.logger.error.called def test_apply_platform_autoconfig_psutil_exception(self): """Test _apply_platform_autoconfig with psutil exception - lines 343-346.""" loader = CoreLoader() with patch('nodupe.core.loader.psutil') as mock_psutil: mock_psutil.virtual_memory.side_effect = Exception('psutil failed') mock_psutil.disk_partitions.return_value = [] result = loader._detect_system_resources() assert 'ram_gb' in result assert result['ram_gb'] == 8 # Default value def test_detect_thread_restrictions_kubernetes(self): """Test thread restriction detection for Kubernetes - line 374.""" loader = CoreLoader() system_info = {} with patch.dict(os.environ, {'KUBERNETES_SERVICE_HOST': 'localhost'}): loader._detect_thread_restrictions(system_info) assert system_info['thread_restrictions_detected'] is True assert 'kubernetes' in system_info['thread_restriction_reasons'] def test_detect_thread_restrictions_docker(self): """Test thread restriction detection for Docker - line 377.""" loader = CoreLoader() system_info = {} with patch.dict(os.environ, {'DOCKER_CONTAINER': 'true'}): loader._detect_thread_restrictions(system_info) assert system_info['thread_restrictions_detected'] is True assert 'container' in system_info['thread_restriction_reasons'] def test_detect_thread_restrictions_cgroup(self): """Test thread restriction detection for cgroups - line 414.""" loader = CoreLoader() system_info = {} # Create a mock cgroup file with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.cgroup') as f: f.write('50000') f.flush() cgroup_path = f.name try: with patch('nodupe.core.loader.os.path.exists', return_value=True), \ patch('nodupe.core.loader.open', mock_open(read_data='50000')): loader._detect_thread_restrictions(system_info) assert system_info['thread_restrictions_detected'] is True assert 'cgroup_cpu_limit' in system_info['thread_restriction_reasons'] finally: os.unlink(cgroup_path) def test_get_connection_existing(self): """Test get_connection with existing database.""" mock_db = MagicMock() with patch('nodupe.tools.databases.connection.global_container') as mock_container: mock_container.get_service.return_value = mock_db result = get_connection() # Should return the mock database assert result is not None def test_autotune_hash_algorithm(self): """Test autotune_hash_algorithm function.""" result = autotune_hash_algorithm() assert 'optimal_algorithm' in result assert result['optimal_algorithm'] == 'blake3' def test_create_autotuned_hasher(self): """Test create_autotuned_hasher function.""" hasher, config = create_autotuned_hasher() assert hasher is not None assert config['algorithm'] == 'blake3' # ============================================================================= # Discovery - Missing Lines: 148->129, 155-161, 165-167, 193->192, 235->234, 239-244, 273->272, 275, 312, 318, 335, 371->365, 383, 385, 400->365, 405-406, 411->365, 469-478 # ============================================================================= class TestDiscoveryMissingCoverage: """Test missing coverage in discovery.py.""" def test_discover_tools_in_directory_iterdir_exception(self): """Test discover_tools_in_directory with iterdir exception - line 148->129.""" discovery = ToolDiscovery() mock_dir = MagicMock() mock_dir.iterdir.side_effect = TypeError('Not a directory') result = discovery.discover_tools_in_directory(mock_dir) assert result == [] def test_discover_tools_in_directory_os_error(self): """Test discover_tools_in_directory with OSError - lines 155-161.""" discovery = ToolDiscovery() mock_dir = MagicMock() mock_dir.iterdir.side_effect = OSError('Directory not found') result = discovery.discover_tools_in_directory(mock_dir) assert result == [] def test_discover_tools_in_directory_item_exception(self): """Test discover_tools_in_directory with item exception - lines 165-167.""" discovery = ToolDiscovery() mock_item = MagicMock() mock_item.is_file.side_effect = Exception('Item check failed') mock_dir = MagicMock() mock_dir.iterdir.return_value = [mock_item] result = discovery.discover_tools_in_directory(mock_dir) assert result == [] def test_discover_tools_in_directories_exception(self): """Test discover_tools_in_directories with exception - line 193->192.""" discovery = ToolDiscovery() mock_dir = MagicMock() mock_dir.iterdir.side_effect = ToolDiscoveryError('Discovery failed') result = discovery.discover_tools_in_directories([mock_dir]) assert result == [] def test_find_tool_by_name_in_discovered(self): """Test find_tool_by_name in discovered tools - line 235->234.""" discovery = ToolDiscovery() tool_info = ToolInfo(name='test_tool', file_path=Path('/test.py')) discovery._discovered_tools.append(tool_info) result = discovery.find_tool_by_name('test_tool') assert result == tool_info def test_find_tool_by_name_not_found(self): """Test find_tool_by_name not found - lines 239-244.""" discovery = ToolDiscovery() result = discovery.find_tool_by_name('nonexistent_tool') assert result is None def test_find_tool_by_name_subdir_check(self): """Test find_tool_by_name with subdir check - line 273->272.""" discovery = ToolDiscovery() mock_dir = MagicMock() mock_dir.exists.return_value = False with patch('nodupe.core.tool_system.discovery.Path', return_value=mock_dir): result = discovery.find_tool_by_name('test_tool', search_directories=[MagicMock()]) assert result is None def test_find_tool_by_name_exception(self): """Test find_tool_by_name with exception - line 275.""" discovery = ToolDiscovery() mock_dir = MagicMock() mock_dir.iterdir.side_effect = ToolDiscoveryError('Failed') result = discovery.find_tool_by_name('test_tool', search_directories=[mock_dir]) assert result is None def test_refresh_discovery(self): """Test refresh_discovery - line 312.""" discovery = ToolDiscovery() discovery._discovered_tools.append(ToolInfo(name='test', file_path=Path('/test.py'))) discovery.refresh_discovery() assert len(discovery._discovered_tools) == 0 def test_get_discovered_tool_found(self): """Test get_discovered_tool found - line 318.""" discovery = ToolDiscovery() tool_info = ToolInfo(name='test_tool', file_path=Path('/test.py')) discovery._discovered_tools.append(tool_info) result = discovery.get_discovered_tool('test_tool') assert result == tool_info def test_get_discovered_tool_not_found(self): """Test get_discovered_tool not found - line 335.""" discovery = ToolDiscovery() result = discovery.get_discovered_tool('nonexistent') assert result is None def test_is_tool_discovered_true(self): """Test is_tool_discovered true - line 371->365.""" discovery = ToolDiscovery() discovery._discovered_tools.append(ToolInfo(name='test_tool', file_path=Path('/test.py'))) result = discovery.is_tool_discovered('test_tool') assert result is True def test_is_tool_discovered_false(self): """Test is_tool_discovered false - line 383.""" discovery = ToolDiscovery() result = discovery.is_tool_discovered('nonexistent') assert result is False def test_extract_tool_info_exception(self): """Test _extract_tool_info with exception - line 385.""" discovery = ToolDiscovery() mock_path = MagicMock() mock_path.open.side_effect = Exception('Read failed') result = discovery._extract_tool_info(mock_path) assert result is None def test_parse_metadata_capabilities_exception(self): """Test _parse_metadata with capabilities exception - line 400->365.""" discovery = ToolDiscovery() content = """ CAPABILITIES = "invalid syntax {{{" """ metadata = discovery._parse_metadata(content) # Should handle gracefully - may not have capabilities key assert metadata is not None def test_parse_metadata_dependencies_exception(self): """Test _parse_metadata with dependencies exception - lines 405-406.""" discovery = ToolDiscovery() content = """ DEPENDENCIES = "invalid syntax {{{" """ metadata = discovery._parse_metadata(content) # Should handle gracefully assert metadata.get('dependencies') is None or metadata.get('dependencies') == [] def test_parse_metadata_version_exception(self): """Test _parse_metadata with version exception - line 411->365.""" discovery = ToolDiscovery() content = """ __version__ = "invalid syntax {{{" """ metadata = discovery._parse_metadata(content) # Should handle gracefully assert 'version' in metadata def test_validate_tool_file_empty(self): """Test validate_tool_file with empty file - lines 469-478.""" discovery = ToolDiscovery() with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f: # Empty file temp_path = Path(f.name) try: result = discovery.validate_tool_file(temp_path) assert result is False finally: os.unlink(temp_path) # ============================================================================= # Parallel Logic - Missing Lines: 128-130, 132, 165, 195, 202-204, 264, 268-273, 280-282, 284, 291-322, 326-330, 340-341, 355-356, 367 # ============================================================================= class TestParallelLogicMissingCoverage: """Test missing coverage in parallel_logic.py. Note: Uses pickle-safe helpers from test_helpers for process testing. See: docs/PARALLEL_TESTING_SUSTAINABILITY.md """ def test_process_in_parallel_task_exception(self): """Test process_in_parallel with task exception - lines 128-130, 132.""" # Use pickle-safe maybe_raise for process testing with pytest.raises(ParallelError) as exc_info: Parallel.process_in_parallel( maybe_raise, # ✅ Pickle-safe [1, -1, 3], # -1 triggers error workers=2, use_processes=False # Threads for error testing ) assert 'Error for value -1' in str(exc_info.value) def test_map_parallel_unordered_batch_size_one(self): """Test map_parallel_unordered with batch_size=1 - line 165.""" items = [1, 2, 3] results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=True, prefer_batches=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_interpreter_exception(self): """Test map_parallel_unordered interpreter exception path - line 195.""" items = [1, 2, 3] with patch('nodupe.tools.parallel.parallel_logic.Parallel.supports_interpreter_pool', return_value=True): results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_interpreters=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_batch_exception(self): """Test map_parallel_unordered batch exception - lines 202-204.""" items = [1, 2, 3] with patch.object(os, 'getenv', return_value='invalid'): results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=True, prefer_batches=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_cpu_count_exception(self): """Test map_parallel_unordered cpu count exception - line 264.""" items = [1, 2, 3] with patch.object(Parallel, 'get_cpu_count', side_effect=Exception('CPU count failed')): results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_batch_logging(self): """Test map_parallel_unordered with batch logging - lines 268-273.""" items = [1, 2, 3] with patch.dict(os.environ, {'NODUPE_BATCH_LOG': '1'}): results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=True, prefer_batches=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_chunksize_exception(self): """Test map_parallel_unordered chunksize exception - lines 280-282, 284.""" items = [1, 2, 3] # Test with threads (not processes) to avoid multiprocessing issues with mocks # Use side_effect as a callable that returns default values for specific calls def getenv_side_effect(key, default=None): """Mock getenv that raises exception for specific environment variables.""" if key in ("NODUPE_BATCH_DIVISOR", "NODUPE_CHUNK_FACTOR"): raise Exception('Env failed') return default with patch.object(os, 'getenv', side_effect=getenv_side_effect): results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=False, prefer_batches=False, prefer_map=True )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_bounded_submission(self): """Test map_parallel_unordered bounded submission - lines 291-322.""" items = [1, 2, 3, 4, 5] results = list(Parallel.map_parallel_unordered( double_number, items, workers=2, use_processes=False )) assert sorted(results) == [2, 4, 6, 8, 10] def test_map_parallel_unordered_stopiteration(self): """Test map_parallel_unordered StopIteration handling - lines 326-330.""" items = [1] # Single item to trigger StopIteration early results = list(Parallel.map_parallel_unordered( double_number, items, workers=2 )) assert results == [2] def test_map_parallel_unordered_future_exception(self): """Test map_parallel_unordered future exception - line 340-341.""" # Use pickle-safe maybe_raise for process testing with pytest.raises(ParallelError) as exc_info: list(Parallel.map_parallel_unordered( maybe_raise, # ✅ Pickle-safe [-1], # -1 triggers error workers=1 )) assert 'Error for value -1' in str(exc_info.value) def test_map_parallel_unordered_timeout(self): """Test map_parallel_unordered with timeout - line 355-356.""" from tests.parallel.test_helpers import slow_square # Use pickle-safe slow_square for timeout testing with pytest.raises(ParallelError): list(Parallel.map_parallel_unordered( slow_square, # ✅ Pickle-safe with delay [1], timeout=0.01, use_processes=False # Threads for timeout testing )) def test_map_parallel_unordered_keyerror(self): """Test map_parallel_unordered KeyError handling - line 367.""" items = [1, 2, 3] # This should handle KeyError gracefully results = list(Parallel.map_parallel_unordered( double_number, items, workers=2 )) assert sorted(results) == [2, 4, 6] def test_map_parallel_unordered_with_processes(self): """Test map_parallel_unordered with ProcessPoolExecutor.""" items = [1, 2, 3, 4, 5] # Test with actual processes results = list(Parallel.map_parallel_unordered( double_number, # ✅ Pickle-safe items, workers=2, use_processes=True # ✅ Test processes )) assert sorted(results) == [2, 4, 6, 8, 10] def test_process_in_parallel_with_processes(self): """Test process_in_parallel with ProcessPoolExecutor.""" items = [1, 2, 3, 4, 5] # Test with actual processes results = Parallel.process_in_parallel( square_number, # ✅ Pickle-safe items, workers=2, use_processes=True # ✅ Test processes ) assert results == [1, 4, 9, 16, 25] def test_thread_vs_process_consistency(self): """Verify thread and process results are consistent.""" items = [1, 2, 3, 4, 5] # Thread result thread_result = Parallel.process_in_parallel( double_number, items, workers=2, use_processes=False ) # Process result process_result = Parallel.process_in_parallel( double_number, items, workers=2, use_processes=True ) # Both should produce same results assert thread_result == process_result == [2, 4, 6, 8, 10] # ============================================================================= # Security Logic - Missing Lines: 114, 154->157, 167, 176, 177->181, 183, 184->187, 342->344, 413-414, 442-444 # ============================================================================= class TestSecurityLogicMissingCoverage: """Test missing coverage in security_logic.py.""" def test_sanitize_path_null_bytes(self): """Test sanitize_path with null bytes - line 114.""" with pytest.raises(SecurityError) as exc_info: Security.sanitize_path('test\x00path') assert 'null bytes' in str(exc_info.value) def test_validate_path_allowed_parent_exception(self): """Test validate_path with allowed_parent exception - line 154->157.""" with pytest.raises(SecurityError) as exc_info: Security.validate_path('/test/path', allowed_parent='/nonexistent') assert 'Cannot resolve allowed parent' in str(exc_info.value) or 'outside allowed' in str(exc_info.value) def test_validate_path_must_exist(self): """Test validate_path with must_exist - line 167.""" with pytest.raises(SecurityError) as exc_info: Security.validate_path('/nonexistent/path', must_exist=True) assert 'does not exist' in str(exc_info.value) def test_validate_path_must_be_file(self): """Test validate_path with must_be_file - line 176.""" with tempfile.TemporaryDirectory() as tmpdir: with pytest.raises(SecurityError) as exc_info: Security.validate_path(tmpdir, must_be_file=True) assert 'not a file' in str(exc_info.value) def test_validate_path_must_be_dir(self): """Test validate_path with must_be_dir - line 177->181.""" with tempfile.NamedTemporaryFile(delete=False) as f: temp_file = f.name try: with pytest.raises(SecurityError) as exc_info: Security.validate_path(temp_file, must_be_dir=True) assert 'not a directory' in str(exc_info.value) finally: os.unlink(temp_file) def test_validate_path_resolve_exception(self): """Test validate_path with resolve exception - line 183.""" mock_path = MagicMock() mock_path.resolve.side_effect = RuntimeError('Resolve failed') with patch('nodupe.tools.security_audit.security_logic.Path', return_value=mock_path): with pytest.raises(SecurityError) as exc_info: Security.validate_path(mock_path) assert 'Cannot resolve' in str(exc_info.value) def test_validate_path_general_exception(self): """Test validate_path with general exception - line 184->187.""" with patch('nodupe.tools.security_audit.security_logic.Path') as mock_path_class: mock_path_class.side_effect = Exception('Path creation failed') with pytest.raises(SecurityError) as exc_info: Security.validate_path('/test') assert 'validation failed' in str(exc_info.value) def test_check_permissions_not_exists(self): """Test check_permissions with nonexistent path - line 342->344.""" with pytest.raises(SecurityError) as exc_info: Security.check_permissions('/nonexistent/path', readable=True) assert 'does not exist' in str(exc_info.value) def test_sanitize_filename_exception(self): """Test sanitize_filename with exception - lines 413-414.""" with patch('nodupe.tools.security_audit.security_logic.re.sub', side_effect=Exception('Regex failed')): with pytest.raises(SecurityError) as exc_info: Security.sanitize_filename('test.txt') assert 'sanitization failed' in str(exc_info.value) def test_generate_safe_filename_exception(self): """Test generate_safe_filename with exception - lines 442-444.""" with patch('nodupe.tools.security_audit.security_logic.Security.sanitize_filename', side_effect=Exception('Failed')): with pytest.raises(SecurityError) as exc_info: Security.generate_safe_filename('test') assert 'generation failed' in str(exc_info.value) # ============================================================================= # Filesystem - Missing Lines: 52, 74, 91, 110-116, 121-122, 141, 153, 170, 193, 201, 215, 219-220, 235, 256, 258, 273, 289, 291, 306 # ============================================================================= class TestFilesystemMissingCoverage: """Test missing coverage in filesystem.py.""" def test_safe_read_not_exists(self): """Test safe_read with nonexistent file - line 52.""" with pytest.raises(FilesystemError) as exc_info: Filesystem.safe_read('/nonexistent/file.txt') assert 'does not exist' in str(exc_info.value) def test_safe_read_not_file(self): """Test safe_read with directory - line 74.""" with tempfile.TemporaryDirectory() as tmpdir: with pytest.raises(FilesystemError) as exc_info: Filesystem.safe_read(tmpdir) assert 'not a file' in str(exc_info.value) def test_safe_read_exceeds_max_size(self): """Test safe_read with max_size exceeded - line 91.""" with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b'x' * 100) temp_file = f.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.safe_read(temp_file, max_size=50) assert 'exceeds limit' in str(exc_info.value) finally: os.unlink(temp_file) def test_safe_write_atomic_exception(self): """Test safe_write with atomic exception - lines 110-116.""" with tempfile.TemporaryDirectory() as tmpdir: target = Path(tmpdir) / 'test.txt' with patch('nodupe.tools.os_filesystem.filesystem.os.write', side_effect=OSError('Write failed')): with pytest.raises(FilesystemError) as exc_info: Filesystem.safe_write(target, b'test data', atomic=True) assert 'Failed to write' in str(exc_info.value) def test_safe_write_direct_exception(self): """Test safe_write with direct write exception - lines 121-122.""" with tempfile.TemporaryDirectory() as tmpdir: target = Path(tmpdir) / 'test.txt' with patch('nodupe.tools.os_filesystem.filesystem.Path.write_bytes', side_effect=OSError('Write failed')): with pytest.raises(FilesystemError) as exc_info: Filesystem.safe_write(target, b'test data', atomic=False) assert 'Failed to write' in str(exc_info.value) def test_validate_path_must_exist_fail(self): """Test validate_path with must_exist failure - line 141.""" with pytest.raises(FilesystemError) as exc_info: Filesystem.validate_path('/nonexistent/path', must_exist=True) assert 'does not exist' in str(exc_info.value) def test_validate_path_resolve_exception(self): """Test validate_path with resolve exception - line 153.""" mock_path = MagicMock() mock_path.resolve.side_effect = RuntimeError('Resolve failed') with patch('nodupe.tools.os_filesystem.filesystem.Path', return_value=mock_path): with pytest.raises(FilesystemError) as exc_info: Filesystem.validate_path(mock_path) assert 'Invalid path' in str(exc_info.value) def test_get_size_exception(self): """Test get_size with exception - line 170.""" mock_path = MagicMock() mock_path.stat.side_effect = OSError('Stat failed') with patch('nodupe.tools.os_filesystem.filesystem.Path', return_value=mock_path): with pytest.raises(FilesystemError) as exc_info: Filesystem.get_size(mock_path) assert 'Failed to get file size' in str(exc_info.value) def test_list_directory_not_dir(self): """Test list_directory with non-directory - line 193.""" with tempfile.NamedTemporaryFile(delete=False) as f: temp_file = f.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.list_directory(temp_file) assert 'not a directory' in str(exc_info.value) finally: os.unlink(temp_file) def test_list_directory_exception(self): """Test list_directory with exception - line 201.""" mock_path = MagicMock() mock_path.is_dir.return_value = True mock_path.glob.side_effect = OSError('Glob failed') with patch('nodupe.tools.os_filesystem.filesystem.Path', return_value=mock_path): with pytest.raises(FilesystemError) as exc_info: Filesystem.list_directory(mock_path) assert 'Failed to list directory' in str(exc_info.value) def test_ensure_directory_exception(self): """Test ensure_directory with exception - line 215.""" mock_path = MagicMock() mock_path.mkdir.side_effect = OSError('Mkdir failed') with patch('nodupe.tools.os_filesystem.filesystem.Path', return_value=mock_path): with pytest.raises(FilesystemError) as exc_info: Filesystem.ensure_directory(mock_path) assert 'Failed to create directory' in str(exc_info.value) def test_remove_file_exception(self): """Test remove_file with exception - lines 219-220.""" mock_path = MagicMock() mock_path.unlink.side_effect = OSError('Unlink failed') with patch('nodupe.tools.os_filesystem.filesystem.Path', return_value=mock_path): with pytest.raises(FilesystemError) as exc_info: Filesystem.remove_file(mock_path) assert 'Failed to remove' in str(exc_info.value) def test_copy_file_not_exists(self): """Test copy_file with nonexistent source - line 235.""" with pytest.raises(FilesystemError) as exc_info: Filesystem.copy_file('/nonexistent/src.txt', '/tmp/dst.txt') assert 'does not exist' in str(exc_info.value) def test_copy_file_exists_no_overwrite(self): """Test copy_file with existing destination - line 256.""" with tempfile.NamedTemporaryFile(delete=False) as src: src.write(b'source') src_path = src.name with tempfile.NamedTemporaryFile(delete=False) as dst: dst.write(b'dest') dst_path = dst.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.copy_file(src_path, dst_path, overwrite=False) assert 'Destination file exists' in str(exc_info.value) finally: os.unlink(src_path) os.unlink(dst_path) def test_copy_file_exception(self): """Test copy_file with exception - line 258.""" with patch('nodupe.tools.os_filesystem.filesystem.shutil.copy2', side_effect=OSError('Copy failed')): with tempfile.NamedTemporaryFile(delete=False) as src: src.write(b'source') src_path = src.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.copy_file(src_path, '/tmp/new_dst.txt', overwrite=True) assert 'Failed to copy' in str(exc_info.value) finally: os.unlink(src_path) def test_move_file_not_exists(self): """Test move_file with nonexistent source - line 273.""" with pytest.raises(FilesystemError) as exc_info: Filesystem.move_file('/nonexistent/src.txt', '/tmp/dst.txt') assert 'does not exist' in str(exc_info.value) def test_move_file_exists_no_overwrite(self): """Test move_file with existing destination - line 289.""" with tempfile.NamedTemporaryFile(delete=False) as src: src.write(b'source') src_path = src.name with tempfile.NamedTemporaryFile(delete=False) as dst: dst.write(b'dest') dst_path = dst.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.move_file(src_path, dst_path, overwrite=False) assert 'Destination file exists' in str(exc_info.value) finally: os.unlink(src_path) os.unlink(dst_path) def test_move_file_exception(self): """Test move_file with exception - line 291.""" with patch('nodupe.tools.os_filesystem.filesystem.shutil.move', side_effect=OSError('Move failed')): with tempfile.NamedTemporaryFile(delete=False) as src: src.write(b'source') src_path = src.name try: with pytest.raises(FilesystemError) as exc_info: Filesystem.move_file(src_path, '/tmp/new_dst.txt', overwrite=True) assert 'Failed to move' in str(exc_info.value) finally: os.unlink(src_path) def test_safe_read_string_path(self): """Test safe_read with string path - line 306.""" with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b'test data') temp_file = f.name try: result = Filesystem.safe_read(temp_file) assert result == b'test data' finally: os.unlink(temp_file) # ============================================================================= # MMAP Handler - Missing Line: 50->exit # ============================================================================= class TestMMAPHandlerMissingCoverage: """Test missing coverage in mmap_handler.py.""" def test_mmap_context_exception(self): """Test mmap_context with exception - line 50->exit.""" with tempfile.NamedTemporaryFile(delete=False) as f: f.write(b'test data') temp_file = f.name try: # Test that context manager properly closes on exception with pytest.raises(ValueError): with MMAPHandler.mmap_context(temp_file) as mapped: raise ValueError('Test exception') # File should be properly closed finally: os.unlink(temp_file) # ============================================================================= # Leap Year - Missing Lines: 128-130, 168->exit, 174->exit, 272, 560->562 # ============================================================================= class TestLeapYearMissingCoverage: """Test missing coverage in leap_year.py.""" def test_run_standalone_exception_handling(self): """Test run_standalone with exception - lines 128-130.""" tool = LeapYearTool() # Test with invalid argument that causes argparse to fail with patch('sys.argv', ['leap_year', 'invalid']): try: result = tool.run_standalone(['invalid']) except SystemExit: pass # Expected from argparse def test_shutdown_with_cache_stats(self): """Test shutdown with cache stats - line 168->exit.""" tool = LeapYearTool(enable_cache=True) tool.is_leap_year(2000) # Populate cache mock_container = MagicMock() tool.shutdown(mock_container) # Should log cache stats def test_shutdown_without_cache(self): """Test shutdown without cache - line 174->exit.""" tool = LeapYearTool(enable_cache=False) mock_container = MagicMock() tool.shutdown(mock_container) # Should not log cache stats def test_get_calendar_info(self): """Test get_calendar_info - line 272.""" tool = LeapYearTool() info = tool.get_calendar_info(2000) assert info['year'] == 2000 assert info['is_leap_year'] is True assert info['days_in_year'] == 366 def test_is_gregorian_leap_year(self): """Test is_gregorian_leap_year - line 560->562.""" tool = LeapYearTool() assert tool.is_gregorian_leap_year(2000) is True assert tool.is_gregorian_leap_year(1900) is False assert tool.is_gregorian_leap_year(2004) is True # ============================================================================= # Integration Tests # ============================================================================= class TestIntegration: """Integration tests for multiple modules.""" def test_archive_with_mime_detection(self): """Test archive handler with MIME detection.""" handler = ArchiveHandler() # Create a valid zip file with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f: archive_path = f.name with zipfile.ZipFile(archive_path, 'w') as zf: zf.writestr('test.txt', 'test content') try: # Test detection assert handler.is_archive_file(archive_path) is True assert handler.detect_archive_format(archive_path) == 'zip' # Test extraction result = handler.extract_archive(archive_path) assert len(result) > 0 finally: handler.cleanup() os.unlink(archive_path) def test_parallel_with_filesystem(self): """Test parallel processing with filesystem operations.""" with tempfile.TemporaryDirectory() as tmpdir: # Create test files test_files = [] for i in range(5): test_file = Path(tmpdir) / f'test_{i}.txt' test_file.write_bytes(f'data_{i}'.encode()) test_files.append(test_file) # Process in parallel def read_file(path): """Helper function to read file content.""" return Filesystem.safe_read(path) results = Parallel.process_in_parallel(read_file, test_files, workers=2) assert len(results) == 5 for i, result in enumerate(results): assert result == f'data_{i}'.encode() def test_security_with_filesystem(self): """Test security validation with filesystem operations.""" with tempfile.TemporaryDirectory() as tmpdir: test_file = Path(tmpdir) / 'test.txt' test_file.write_bytes(b'test data') # Validate path assert Security.validate_path(test_file, must_exist=True, must_be_file=True) # Check permissions assert Security.check_permissions(test_file, readable=True) if __name__ == '__main__': pytest.main([__file__, '-v'])