this repo has no description
1use crate::utils::ExtractedTarget;
2use std::fs;
3use std::io;
4use std::path::Path;
5use tempfile::tempdir;
6
7use crate::utils::{CmprssInput, CmprssOutput, CompressionLevelValidator, Compressor};
8
9/// Test basic trait functionality that should be common across all compressors
10pub fn test_compressor_interface<T: Compressor>(
11 compressor: &T,
12 expected_name: &str,
13 expected_extension: Option<&str>,
14) {
15 let ext = expected_extension.unwrap_or(expected_name);
16
17 // Test name() returns expected value
18 assert_eq!(compressor.name(), expected_name);
19
20 // Test extension() returns expected value
21 assert_eq!(compressor.extension(), ext);
22
23 // Test is_archive() detection logic
24 let temp_dir = tempdir().expect("Failed to create temp dir");
25
26 // Test with matching extension
27 let archive_path = temp_dir.path().join(format!("test.{}", ext));
28 fs::File::create(&archive_path).expect("Failed to create test file");
29 assert!(compressor.is_archive(&archive_path));
30
31 // Test with non-matching extension
32 let non_archive_path = temp_dir.path().join("test.txt");
33 fs::File::create(&non_archive_path).expect("Failed to create test file");
34 assert!(!compressor.is_archive(&non_archive_path));
35
36 // Test default_compressed_filename
37 let test_path = Path::new("test.txt");
38 let expected = format!("test.txt.{}", ext);
39 assert_eq!(compressor.default_compressed_filename(test_path), expected);
40
41 // Test default_extracted_filename
42 let formatted_name = format!("test.{}", ext);
43 let archive_path = Path::new(&formatted_name);
44 match compressor.default_extracted_target() {
45 ExtractedTarget::FILE => {
46 assert_eq!(compressor.default_extracted_filename(archive_path), "test");
47 }
48 ExtractedTarget::DIRECTORY => {
49 assert_eq!(compressor.default_extracted_filename(archive_path), ".");
50 }
51 }
52
53 // Test default_extracted_filename with non-matching extension
54 let non_archive_path = Path::new("test.txt");
55 match compressor.default_extracted_target() {
56 ExtractedTarget::FILE => {
57 assert_eq!(
58 compressor.default_extracted_filename(non_archive_path),
59 "archive"
60 );
61 }
62 ExtractedTarget::DIRECTORY => {
63 assert_eq!(compressor.default_extracted_filename(non_archive_path), ".");
64 }
65 }
66}
67
68/// Test compression and extraction functionality with a simple string
69pub fn test_compressor_roundtrip<T: Compressor>(
70 compressor: &T,
71 test_data: &str,
72) -> Result<(), io::Error> {
73 let temp_dir = tempdir().expect("Failed to create temp dir");
74
75 // Create test file
76 let input_path = temp_dir.path().join("input.txt");
77 fs::write(&input_path, test_data)?;
78
79 // Compress
80 let archive_path = temp_dir
81 .path()
82 .join(format!("archive.{}", compressor.extension()));
83 compressor.compress(
84 CmprssInput::Path(vec![input_path.clone()]),
85 CmprssOutput::Path(archive_path.clone()),
86 )?;
87
88 // Extract
89 let output_path = match compressor.default_extracted_target() {
90 ExtractedTarget::FILE => temp_dir.path().join("output.txt"),
91 ExtractedTarget::DIRECTORY => temp_dir.path().join("output"),
92 };
93 compressor.extract(
94 CmprssInput::Path(vec![archive_path]),
95 CmprssOutput::Path(output_path.clone()),
96 )?;
97
98 // Verify
99 let input_filename = "input.txt";
100 let output_data = match compressor.default_extracted_target() {
101 ExtractedTarget::FILE => fs::read_to_string(output_path)?,
102 ExtractedTarget::DIRECTORY => fs::read_to_string(output_path.join(input_filename))?,
103 };
104 assert_eq!(output_data, test_data);
105
106 Ok(())
107}
108
109/// Test compression and extraction with different content sizes
110pub fn test_compression<T: Compressor>(compressor: &T) -> Result<(), io::Error> {
111 // Test with empty content
112 test_compressor_roundtrip(compressor, "")?;
113
114 // Test with small content
115 test_compressor_roundtrip(compressor, "Small test content")?;
116
117 // Test with medium content (generate a 10KB string)
118 let medium_content = "0123456789".repeat(1024);
119 test_compressor_roundtrip(compressor, &medium_content)?;
120
121 Ok(())
122}
123
124/// Run a full suite of tests on a compressor implementation
125pub fn run_compressor_tests<T: Compressor>(
126 compressor: &T,
127 expected_name: &str,
128 expected_extension: Option<&str>,
129) -> Result<(), io::Error> {
130 // Test interface methods
131 test_compressor_interface(compressor, expected_name, expected_extension);
132
133 // Test compression/extraction functionality
134 test_compression(compressor)?;
135
136 Ok(())
137}
138
139/// Helper function to test CompressionValidator implementations
140/// This avoids duplicating the same test pattern across multiple backends
141pub fn test_compression_validator_helper<V: CompressionLevelValidator>(
142 validator: &V,
143 min_level: i32,
144 max_level: i32,
145 default_level: i32,
146 fast_name_level: Option<i32>,
147 best_name_level: Option<i32>,
148 none_name_level: Option<i32>,
149) {
150 // Test range
151 assert_eq!(validator.min_level(), min_level);
152 assert_eq!(validator.max_level(), max_level);
153 assert_eq!(validator.default_level(), default_level);
154
155 // Test validation
156 assert!(validator.is_valid_level(min_level));
157 assert!(validator.is_valid_level(max_level));
158 assert!(!validator.is_valid_level(min_level - 1));
159 assert!(!validator.is_valid_level(max_level + 1));
160
161 // Test middle level if range is big enough
162 if max_level - min_level >= 2 {
163 let mid_level = (min_level + max_level) / 2;
164 assert!(validator.is_valid_level(mid_level));
165 }
166
167 // Test clamping
168 assert_eq!(validator.validate_and_clamp_level(min_level - 1), min_level);
169 assert_eq!(validator.validate_and_clamp_level(min_level), min_level);
170 assert_eq!(validator.validate_and_clamp_level(max_level), max_level);
171 assert_eq!(validator.validate_and_clamp_level(max_level + 1), max_level);
172
173 // Test special names
174 if let Some(level) = fast_name_level {
175 assert_eq!(validator.name_to_level("fast"), Some(level));
176 } else {
177 assert_eq!(validator.name_to_level("fast"), None);
178 }
179
180 if let Some(level) = best_name_level {
181 assert_eq!(validator.name_to_level("best"), Some(level));
182 } else {
183 assert_eq!(validator.name_to_level("best"), None);
184 }
185
186 if let Some(level) = none_name_level {
187 assert_eq!(validator.name_to_level("none"), Some(level));
188 } else {
189 assert_eq!(validator.name_to_level("none"), None);
190 }
191
192 // Test invalid name
193 assert_eq!(validator.name_to_level("invalid"), None);
194}