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