provide-testkit 0.0.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- provide/__init__.py +3 -0
- provide/testkit/__init__.py +248 -0
- provide/testkit/archive/__init__.py +24 -0
- provide/testkit/archive/fixtures.py +217 -0
- provide/testkit/cli.py +229 -0
- provide/testkit/common/__init__.py +32 -0
- provide/testkit/common/fixtures.py +234 -0
- provide/testkit/crypto.py +163 -0
- provide/testkit/environment.py +79 -0
- provide/testkit/file/__init__.py +40 -0
- provide/testkit/file/content_fixtures.py +275 -0
- provide/testkit/file/directory_fixtures.py +105 -0
- provide/testkit/file/fixtures.py +49 -0
- provide/testkit/file/special_fixtures.py +141 -0
- provide/testkit/fixtures.py +52 -0
- provide/testkit/harness.py +122 -0
- provide/testkit/hub.py +22 -0
- provide/testkit/logger/__init__.py +39 -0
- provide/testkit/logger/hooks.py +100 -0
- provide/testkit/logger/reset.py +230 -0
- provide/testkit/main.py +22 -0
- provide/testkit/mocking/__init__.py +46 -0
- provide/testkit/mocking/fixtures.py +340 -0
- provide/testkit/process/__init__.py +48 -0
- provide/testkit/process/async_fixtures.py +410 -0
- provide/testkit/process/fixtures.py +54 -0
- provide/testkit/process/subprocess_fixtures.py +208 -0
- provide/testkit/quality/__init__.py +101 -0
- provide/testkit/quality/artifacts.py +360 -0
- provide/testkit/quality/base.py +158 -0
- provide/testkit/quality/cli.py +394 -0
- provide/testkit/quality/complexity/__init__.py +30 -0
- provide/testkit/quality/complexity/analyzer.py +392 -0
- provide/testkit/quality/complexity/fixture.py +196 -0
- provide/testkit/quality/coverage/__init__.py +36 -0
- provide/testkit/quality/coverage/fixture.py +236 -0
- provide/testkit/quality/coverage/reporter.py +150 -0
- provide/testkit/quality/coverage/tracker.py +313 -0
- provide/testkit/quality/decorators.py +380 -0
- provide/testkit/quality/documentation/__init__.py +29 -0
- provide/testkit/quality/documentation/checker.py +361 -0
- provide/testkit/quality/documentation/fixture.py +187 -0
- provide/testkit/quality/profiling/__init__.py +30 -0
- provide/testkit/quality/profiling/fixture.py +332 -0
- provide/testkit/quality/profiling/profiler.py +428 -0
- provide/testkit/quality/report.py +266 -0
- provide/testkit/quality/runner.py +319 -0
- provide/testkit/quality/security/__init__.py +29 -0
- provide/testkit/quality/security/fixture.py +196 -0
- provide/testkit/quality/security/scanner.py +338 -0
- provide/testkit/streams.py +54 -0
- provide/testkit/threading/__init__.py +38 -0
- provide/testkit/threading/basic_fixtures.py +103 -0
- provide/testkit/threading/data_fixtures.py +101 -0
- provide/testkit/threading/execution_fixtures.py +268 -0
- provide/testkit/threading/fixtures.py +50 -0
- provide/testkit/threading/sync_fixtures.py +98 -0
- provide/testkit/time/__init__.py +32 -0
- provide/testkit/time/fixtures.py +416 -0
- provide/testkit/transport/__init__.py +30 -0
- provide/testkit/transport/fixtures.py +278 -0
- provide_testkit-0.0.0.dev0.dist-info/METADATA +145 -0
- provide_testkit-0.0.0.dev0.dist-info/RECORD +66 -0
- provide_testkit-0.0.0.dev0.dist-info/WHEEL +5 -0
- provide_testkit-0.0.0.dev0.dist-info/entry_points.txt +2 -0
- provide_testkit-0.0.0.dev0.dist-info/top_level.txt +1 -0
provide/__init__.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#
|
|
2
|
+
# __init__.py
|
|
3
|
+
#
|
|
4
|
+
"""
|
|
5
|
+
Provide TestKit.
|
|
6
|
+
|
|
7
|
+
Unified testing utilities for the provide ecosystem with automatic context detection.
|
|
8
|
+
Comprehensive fixtures and utilities for testing Foundation-based applications.
|
|
9
|
+
|
|
10
|
+
Note: Testing information is displayed via pytest hooks in conftest.py
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Lazy imports to avoid importing testing utilities in production
|
|
17
|
+
def __getattr__(name: str) -> Any:
|
|
18
|
+
"""Lazy import testing utilities only when accessed."""
|
|
19
|
+
|
|
20
|
+
# CLI testing utilities
|
|
21
|
+
if name in [
|
|
22
|
+
"MockContext",
|
|
23
|
+
"isolated_cli_runner",
|
|
24
|
+
"temp_config_file",
|
|
25
|
+
"create_test_cli",
|
|
26
|
+
"CliTestCase",
|
|
27
|
+
"click_testing_mode",
|
|
28
|
+
]:
|
|
29
|
+
import provide.testkit.cli as cli_module
|
|
30
|
+
|
|
31
|
+
return getattr(cli_module, name)
|
|
32
|
+
|
|
33
|
+
# Logger testing utilities
|
|
34
|
+
elif name in [
|
|
35
|
+
"reset_foundation_setup_for_testing",
|
|
36
|
+
"reset_foundation_state",
|
|
37
|
+
"mock_logger",
|
|
38
|
+
"mock_logger_factory",
|
|
39
|
+
# New hook utilities
|
|
40
|
+
"DEFAULT_NOISY_LOGGERS",
|
|
41
|
+
"get_noisy_loggers",
|
|
42
|
+
"get_log_level_for_noisy_loggers",
|
|
43
|
+
"pytest_runtest_setup",
|
|
44
|
+
"suppress_loggers",
|
|
45
|
+
]:
|
|
46
|
+
import provide.testkit.logger as logger_module
|
|
47
|
+
|
|
48
|
+
return getattr(logger_module, name)
|
|
49
|
+
|
|
50
|
+
# Stream testing utilities
|
|
51
|
+
elif name in ["set_log_stream_for_testing"]:
|
|
52
|
+
import provide.testkit.streams as streams_module
|
|
53
|
+
|
|
54
|
+
return getattr(streams_module, name)
|
|
55
|
+
|
|
56
|
+
# Fixture utilities
|
|
57
|
+
elif name in [
|
|
58
|
+
"captured_stderr_for_foundation",
|
|
59
|
+
"setup_foundation_telemetry_for_test",
|
|
60
|
+
]:
|
|
61
|
+
import provide.testkit.fixtures as fixtures_module
|
|
62
|
+
|
|
63
|
+
return getattr(fixtures_module, name)
|
|
64
|
+
|
|
65
|
+
# Import submodules directly
|
|
66
|
+
elif name in [
|
|
67
|
+
"archive",
|
|
68
|
+
"common",
|
|
69
|
+
"file",
|
|
70
|
+
"process",
|
|
71
|
+
"transport",
|
|
72
|
+
"mocking",
|
|
73
|
+
"time",
|
|
74
|
+
"threading",
|
|
75
|
+
]:
|
|
76
|
+
import importlib
|
|
77
|
+
|
|
78
|
+
return importlib.import_module(f"provide.testkit.{name}")
|
|
79
|
+
|
|
80
|
+
# File testing utilities (backward compatibility)
|
|
81
|
+
elif name in [
|
|
82
|
+
"temp_directory",
|
|
83
|
+
"test_files_structure",
|
|
84
|
+
"temp_file",
|
|
85
|
+
"binary_file",
|
|
86
|
+
"nested_directory_structure",
|
|
87
|
+
"empty_directory",
|
|
88
|
+
"readonly_file",
|
|
89
|
+
]:
|
|
90
|
+
import provide.testkit.file.fixtures as file_module
|
|
91
|
+
|
|
92
|
+
return getattr(file_module, name)
|
|
93
|
+
|
|
94
|
+
# Process/async testing utilities (backward compatibility)
|
|
95
|
+
elif name in [
|
|
96
|
+
"clean_event_loop",
|
|
97
|
+
"async_timeout",
|
|
98
|
+
"mock_async_process",
|
|
99
|
+
"async_stream_reader",
|
|
100
|
+
"event_loop_policy",
|
|
101
|
+
"async_context_manager",
|
|
102
|
+
"async_iterator",
|
|
103
|
+
"async_queue",
|
|
104
|
+
"async_lock",
|
|
105
|
+
"mock_async_sleep",
|
|
106
|
+
]:
|
|
107
|
+
import provide.testkit.process.fixtures as process_module
|
|
108
|
+
|
|
109
|
+
return getattr(process_module, name)
|
|
110
|
+
|
|
111
|
+
# Common mock utilities (backward compatibility)
|
|
112
|
+
elif name in [
|
|
113
|
+
"mock_http_config",
|
|
114
|
+
"mock_telemetry_config",
|
|
115
|
+
"mock_config_source",
|
|
116
|
+
"mock_event_emitter",
|
|
117
|
+
"mock_transport",
|
|
118
|
+
"mock_metrics_collector",
|
|
119
|
+
"mock_cache",
|
|
120
|
+
"mock_database",
|
|
121
|
+
"mock_file_system",
|
|
122
|
+
"mock_subprocess",
|
|
123
|
+
]:
|
|
124
|
+
import provide.testkit.common.fixtures as common_module
|
|
125
|
+
|
|
126
|
+
return getattr(common_module, name)
|
|
127
|
+
|
|
128
|
+
# Transport/network testing utilities (backward compatibility)
|
|
129
|
+
elif name in [
|
|
130
|
+
"free_port",
|
|
131
|
+
"mock_server",
|
|
132
|
+
"httpx_mock_responses",
|
|
133
|
+
"mock_websocket",
|
|
134
|
+
"mock_dns_resolver",
|
|
135
|
+
"tcp_client_server",
|
|
136
|
+
"mock_ssl_context",
|
|
137
|
+
"network_timeout",
|
|
138
|
+
"mock_http_headers",
|
|
139
|
+
]:
|
|
140
|
+
import provide.testkit.transport.fixtures as transport_module
|
|
141
|
+
|
|
142
|
+
return getattr(transport_module, name)
|
|
143
|
+
|
|
144
|
+
# Archive testing utilities
|
|
145
|
+
elif name in [
|
|
146
|
+
"archive_test_content",
|
|
147
|
+
"large_file_for_compression",
|
|
148
|
+
"multi_format_archives",
|
|
149
|
+
"archive_with_permissions",
|
|
150
|
+
"corrupted_archives",
|
|
151
|
+
"archive_stress_test_files",
|
|
152
|
+
]:
|
|
153
|
+
import provide.testkit.archive.fixtures as archive_module
|
|
154
|
+
|
|
155
|
+
return getattr(archive_module, name)
|
|
156
|
+
|
|
157
|
+
# Crypto fixtures (many fixtures)
|
|
158
|
+
elif name in [
|
|
159
|
+
"client_cert",
|
|
160
|
+
"server_cert",
|
|
161
|
+
"ca_cert",
|
|
162
|
+
"valid_cert_pem",
|
|
163
|
+
"valid_key_pem",
|
|
164
|
+
"invalid_cert_pem",
|
|
165
|
+
"invalid_key_pem",
|
|
166
|
+
"malformed_cert_pem",
|
|
167
|
+
"empty_cert",
|
|
168
|
+
"temporary_cert_file",
|
|
169
|
+
"temporary_key_file",
|
|
170
|
+
"cert_with_windows_line_endings",
|
|
171
|
+
"cert_with_utf8_bom",
|
|
172
|
+
"cert_with_extra_whitespace",
|
|
173
|
+
"external_ca_pem",
|
|
174
|
+
]:
|
|
175
|
+
import provide.testkit.crypto as crypto_module
|
|
176
|
+
|
|
177
|
+
return getattr(crypto_module, name)
|
|
178
|
+
|
|
179
|
+
# Hub fixtures
|
|
180
|
+
elif name in ["default_container_directory"]:
|
|
181
|
+
import provide.testkit.hub as hub_module
|
|
182
|
+
|
|
183
|
+
return getattr(hub_module, name)
|
|
184
|
+
|
|
185
|
+
# Environment utilities
|
|
186
|
+
elif name in [
|
|
187
|
+
"TestEnvironment",
|
|
188
|
+
"get_example_dir",
|
|
189
|
+
"add_src_to_path",
|
|
190
|
+
"reset_test_environment",
|
|
191
|
+
]:
|
|
192
|
+
import provide.testkit.environment as environment_module
|
|
193
|
+
|
|
194
|
+
return getattr(environment_module, name)
|
|
195
|
+
|
|
196
|
+
else:
|
|
197
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# Public API - these will be available for import but loaded lazily
|
|
201
|
+
__all__ = [
|
|
202
|
+
# Context detection
|
|
203
|
+
"_is_testing_context",
|
|
204
|
+
# CLI testing
|
|
205
|
+
"MockContext",
|
|
206
|
+
"isolated_cli_runner",
|
|
207
|
+
"temp_config_file",
|
|
208
|
+
"create_test_cli",
|
|
209
|
+
"mock_logger",
|
|
210
|
+
"CliTestCase",
|
|
211
|
+
# Logger testing
|
|
212
|
+
"reset_foundation_setup_for_testing",
|
|
213
|
+
"reset_foundation_state",
|
|
214
|
+
# Logger hook utilities
|
|
215
|
+
"DEFAULT_NOISY_LOGGERS",
|
|
216
|
+
"get_noisy_loggers",
|
|
217
|
+
"get_log_level_for_noisy_loggers",
|
|
218
|
+
"pytest_runtest_setup",
|
|
219
|
+
"suppress_loggers",
|
|
220
|
+
# Stream testing
|
|
221
|
+
"set_log_stream_for_testing",
|
|
222
|
+
# Common fixtures
|
|
223
|
+
"captured_stderr_for_foundation",
|
|
224
|
+
"setup_foundation_telemetry_for_test",
|
|
225
|
+
# Crypto fixtures
|
|
226
|
+
"client_cert",
|
|
227
|
+
"server_cert",
|
|
228
|
+
"ca_cert",
|
|
229
|
+
"valid_cert_pem",
|
|
230
|
+
"valid_key_pem",
|
|
231
|
+
"invalid_cert_pem",
|
|
232
|
+
"invalid_key_pem",
|
|
233
|
+
"malformed_cert_pem",
|
|
234
|
+
"empty_cert",
|
|
235
|
+
"temporary_cert_file",
|
|
236
|
+
"temporary_key_file",
|
|
237
|
+
"cert_with_windows_line_endings",
|
|
238
|
+
"cert_with_utf8_bom",
|
|
239
|
+
"cert_with_extra_whitespace",
|
|
240
|
+
"external_ca_pem",
|
|
241
|
+
# Hub fixtures
|
|
242
|
+
"default_container_directory",
|
|
243
|
+
# Environment utilities
|
|
244
|
+
"TestEnvironment",
|
|
245
|
+
"get_example_dir",
|
|
246
|
+
"add_src_to_path",
|
|
247
|
+
"reset_test_environment",
|
|
248
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Archive testing fixtures for the provide-io ecosystem.
|
|
3
|
+
|
|
4
|
+
Standard fixtures for testing archive operations (tar, zip, gzip, bzip2)
|
|
5
|
+
across any project that depends on provide.foundation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from provide.testkit.archive.fixtures import (
|
|
9
|
+
archive_stress_test_files,
|
|
10
|
+
archive_test_content,
|
|
11
|
+
archive_with_permissions,
|
|
12
|
+
corrupted_archives,
|
|
13
|
+
large_file_for_compression,
|
|
14
|
+
multi_format_archives,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"archive_stress_test_files",
|
|
19
|
+
"archive_test_content",
|
|
20
|
+
"archive_with_permissions",
|
|
21
|
+
"corrupted_archives",
|
|
22
|
+
"large_file_for_compression",
|
|
23
|
+
"multi_format_archives",
|
|
24
|
+
]
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Archive Testing Fixtures.
|
|
3
|
+
|
|
4
|
+
Fixtures specific to testing archive operations like tar, zip, gzip, bzip2.
|
|
5
|
+
Builds on top of file fixtures for archive-specific test scenarios.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from collections.abc import Generator
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from provide.testkit.file.fixtures import temp_directory
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
def archive_test_content() -> Generator[tuple[Path, dict[str, str]], None, None]:
|
|
18
|
+
"""
|
|
19
|
+
Create a standard set of files for archive testing.
|
|
20
|
+
|
|
21
|
+
Creates multiple files with different types of content to ensure
|
|
22
|
+
proper compression and extraction testing.
|
|
23
|
+
|
|
24
|
+
Yields:
|
|
25
|
+
Tuple of (source_dir, content_map) where content_map maps
|
|
26
|
+
relative paths to their expected content.
|
|
27
|
+
"""
|
|
28
|
+
with temp_directory() as temp_dir:
|
|
29
|
+
source = temp_dir / "archive_source"
|
|
30
|
+
source.mkdir()
|
|
31
|
+
|
|
32
|
+
content_map = {
|
|
33
|
+
"text_file.txt": "This is a text file for archive testing.\n" * 10,
|
|
34
|
+
"data.json": '{"test": "data", "array": [1, 2, 3]}',
|
|
35
|
+
"script.py": "#!/usr/bin/env python\nprint('Hello from archive')\n",
|
|
36
|
+
"nested/dir/file.md": "# Nested File\nContent in nested directory",
|
|
37
|
+
"binary.dat": "Binary\x00\x01\x02\x03\xff\xfe data",
|
|
38
|
+
"empty.txt": "",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Create all files
|
|
42
|
+
for rel_path, content in content_map.items():
|
|
43
|
+
file_path = source / rel_path
|
|
44
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
if isinstance(content, str):
|
|
47
|
+
file_path.write_text(content)
|
|
48
|
+
else:
|
|
49
|
+
file_path.write_bytes(content.encode() if isinstance(content, str) else content)
|
|
50
|
+
|
|
51
|
+
yield source, content_map
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
def large_file_for_compression() -> Generator[Path, None, None]:
|
|
56
|
+
"""
|
|
57
|
+
Create a large file suitable for compression testing.
|
|
58
|
+
|
|
59
|
+
The file contains repetitive content that compresses well.
|
|
60
|
+
|
|
61
|
+
Yields:
|
|
62
|
+
Path to a large file with compressible content.
|
|
63
|
+
"""
|
|
64
|
+
with temp_directory() as temp_dir:
|
|
65
|
+
large_file = temp_dir / "large_compressible.txt"
|
|
66
|
+
|
|
67
|
+
# Create 10MB of highly compressible content
|
|
68
|
+
content = "This is a line of text that will be repeated many times.\n" * 100
|
|
69
|
+
large_content = content * 1000 # ~6MB of repetitive text
|
|
70
|
+
|
|
71
|
+
large_file.write_text(large_content)
|
|
72
|
+
yield large_file
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@pytest.fixture
|
|
76
|
+
def multi_format_archives() -> Generator[dict[str, Path], None, None]:
|
|
77
|
+
"""
|
|
78
|
+
Create sample archives in different formats for format detection testing.
|
|
79
|
+
|
|
80
|
+
Yields:
|
|
81
|
+
Dict mapping format names to paths of sample archives.
|
|
82
|
+
"""
|
|
83
|
+
with temp_directory() as temp_dir:
|
|
84
|
+
archives = {}
|
|
85
|
+
|
|
86
|
+
# Create minimal valid archives in different formats
|
|
87
|
+
# Note: These are minimal headers, not full valid archives
|
|
88
|
+
|
|
89
|
+
# GZIP file (magic: 1f 8b)
|
|
90
|
+
gzip_file = temp_dir / "sample.gz"
|
|
91
|
+
gzip_file.write_bytes(b"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03" + b"compressed data")
|
|
92
|
+
archives["gzip"] = gzip_file
|
|
93
|
+
|
|
94
|
+
# BZIP2 file (magic: BZh)
|
|
95
|
+
bzip2_file = temp_dir / "sample.bz2"
|
|
96
|
+
bzip2_file.write_bytes(b"BZh91AY&SY" + b"compressed data")
|
|
97
|
+
archives["bzip2"] = bzip2_file
|
|
98
|
+
|
|
99
|
+
# ZIP file (magic: PK\x03\x04)
|
|
100
|
+
zip_file = temp_dir / "sample.zip"
|
|
101
|
+
zip_file.write_bytes(b"PK\x03\x04" + b"\x00" * 16 + b"zipfile")
|
|
102
|
+
archives["zip"] = zip_file
|
|
103
|
+
|
|
104
|
+
# TAR file (has specific header structure)
|
|
105
|
+
tar_file = temp_dir / "sample.tar"
|
|
106
|
+
# Minimal tar header (512 bytes)
|
|
107
|
+
tar_header = b"testfile.txt" + b"\x00" * 88 # name
|
|
108
|
+
tar_header += b"0000644\x00" # mode
|
|
109
|
+
tar_header += b"0000000\x00" # uid
|
|
110
|
+
tar_header += b"0000000\x00" # gid
|
|
111
|
+
tar_header += b"00000000000\x00" # size
|
|
112
|
+
tar_header += b"00000000000\x00" # mtime
|
|
113
|
+
tar_header += b" " # checksum placeholder
|
|
114
|
+
tar_header += b"0" # typeflag
|
|
115
|
+
tar_header += b"\x00" * 355 # padding to 512 bytes
|
|
116
|
+
tar_file.write_bytes(tar_header[:512])
|
|
117
|
+
archives["tar"] = tar_file
|
|
118
|
+
|
|
119
|
+
yield archives
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@pytest.fixture
|
|
123
|
+
def archive_with_permissions() -> Generator[Path, None, None]:
|
|
124
|
+
"""
|
|
125
|
+
Create files with specific permissions for archive permission testing.
|
|
126
|
+
|
|
127
|
+
Yields:
|
|
128
|
+
Path to directory containing files with various permission modes.
|
|
129
|
+
"""
|
|
130
|
+
with temp_directory() as temp_dir:
|
|
131
|
+
source = temp_dir / "permissions_test"
|
|
132
|
+
source.mkdir()
|
|
133
|
+
|
|
134
|
+
# Regular file
|
|
135
|
+
regular = source / "regular.txt"
|
|
136
|
+
regular.write_text("Regular file")
|
|
137
|
+
regular.chmod(0o644)
|
|
138
|
+
|
|
139
|
+
# Executable file
|
|
140
|
+
executable = source / "script.sh"
|
|
141
|
+
executable.write_text("#!/bin/bash\necho 'Hello'")
|
|
142
|
+
executable.chmod(0o755)
|
|
143
|
+
|
|
144
|
+
# Read-only file
|
|
145
|
+
readonly = source / "readonly.txt"
|
|
146
|
+
readonly.write_text("Read only content")
|
|
147
|
+
readonly.chmod(0o444)
|
|
148
|
+
|
|
149
|
+
# Directory with specific permissions
|
|
150
|
+
special_dir = source / "special"
|
|
151
|
+
special_dir.mkdir()
|
|
152
|
+
special_dir.chmod(0o700)
|
|
153
|
+
|
|
154
|
+
yield source
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@pytest.fixture
|
|
158
|
+
def corrupted_archives() -> Generator[dict[str, Path], None, None]:
|
|
159
|
+
"""
|
|
160
|
+
Create corrupted archive files for error handling testing.
|
|
161
|
+
|
|
162
|
+
Yields:
|
|
163
|
+
Dict mapping format names to paths of corrupted archives.
|
|
164
|
+
"""
|
|
165
|
+
with temp_directory() as temp_dir:
|
|
166
|
+
corrupted = {}
|
|
167
|
+
|
|
168
|
+
# Corrupted GZIP (invalid header)
|
|
169
|
+
bad_gzip = temp_dir / "corrupted.gz"
|
|
170
|
+
bad_gzip.write_bytes(b"\x1f\x8c" + b"not really gzip data")
|
|
171
|
+
corrupted["gzip"] = bad_gzip
|
|
172
|
+
|
|
173
|
+
# Corrupted ZIP (incomplete header)
|
|
174
|
+
bad_zip = temp_dir / "corrupted.zip"
|
|
175
|
+
bad_zip.write_bytes(b"PK\x03") # Incomplete magic
|
|
176
|
+
corrupted["zip"] = bad_zip
|
|
177
|
+
|
|
178
|
+
# Corrupted BZIP2 (wrong magic)
|
|
179
|
+
bad_bzip2 = temp_dir / "corrupted.bz2"
|
|
180
|
+
bad_bzip2.write_bytes(b"BZX" + b"not bzip2")
|
|
181
|
+
corrupted["bzip2"] = bad_bzip2
|
|
182
|
+
|
|
183
|
+
# Empty file claiming to be archive
|
|
184
|
+
empty_archive = temp_dir / "empty.tar.gz"
|
|
185
|
+
empty_archive.write_bytes(b"")
|
|
186
|
+
corrupted["empty"] = empty_archive
|
|
187
|
+
|
|
188
|
+
yield corrupted
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@pytest.fixture
|
|
192
|
+
def archive_stress_test_files() -> Generator[Path, None, None]:
|
|
193
|
+
"""
|
|
194
|
+
Create a large number of files for stress testing archive operations.
|
|
195
|
+
|
|
196
|
+
Yields:
|
|
197
|
+
Path to directory with many files for stress testing.
|
|
198
|
+
"""
|
|
199
|
+
with temp_directory() as temp_dir:
|
|
200
|
+
stress_dir = temp_dir / "stress_test"
|
|
201
|
+
stress_dir.mkdir()
|
|
202
|
+
|
|
203
|
+
# Create 100 files in various subdirectories
|
|
204
|
+
for i in range(10):
|
|
205
|
+
subdir = stress_dir / f"subdir_{i}"
|
|
206
|
+
subdir.mkdir()
|
|
207
|
+
|
|
208
|
+
for j in range(10):
|
|
209
|
+
file_path = subdir / f"file_{j}.txt"
|
|
210
|
+
file_path.write_text(f"Content of file {i}_{j}\n" * 10)
|
|
211
|
+
|
|
212
|
+
# Add some binary files
|
|
213
|
+
for i in range(5):
|
|
214
|
+
bin_file = stress_dir / f"binary_{i}.dat"
|
|
215
|
+
bin_file.write_bytes(bytes(range(256)) * 10)
|
|
216
|
+
|
|
217
|
+
yield stress_dir
|