1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
//! Edge case and error handling tests for the utils module.
//!
//! This module contains comprehensive tests targeting previously untested code paths
//! in the utils module, focusing on span validation, color parsing, and UU decoding.
use ass_core::utils::{decode_uu_data, parse_bgr_color, CoreError, Spans};
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{format, string::ToString};
/// Test `Spans` struct with invalid span data
#[test]
fn test_spans_invalid_span_validation() {
let source = "Hello, World! This is test data.";
let spans = Spans::new(source);
// Test validate_span with span from this source (should be valid)
let valid_span = &source[0..5]; // "Hello"
assert!(spans.validate_span(valid_span));
// Test with span from different text (should be invalid)
let other_text = "Different text entirely";
let other_span = &other_text[0..5]; // From different source
assert!(!spans.validate_span(other_span));
// Test with empty span
let empty_span = &source[0..0];
assert!(spans.validate_span(empty_span));
}
/// Test `span_offset`, `span_line`, and `span_column` with invalid spans
#[test]
fn test_spans_position_methods_invalid_input() {
let source = "Line 1\nLine 2\nLine 3";
let spans = Spans::new(source);
// Test with valid spans
let line1_span = &source[0..6]; // "Line 1"
assert_eq!(spans.span_offset(line1_span), Some(0));
assert_eq!(spans.span_line(line1_span), Some(1));
assert_eq!(spans.span_column(line1_span), Some(1));
let line2_span = &source[7..13]; // "Line 2"
assert_eq!(spans.span_offset(line2_span), Some(7));
assert_eq!(spans.span_line(line2_span), Some(2));
assert_eq!(spans.span_column(line2_span), Some(1));
// Test with span from different source (should return None)
let other_text = "Different text";
let invalid_span = &other_text[0..5];
assert!(spans.span_offset(invalid_span).is_none());
assert!(spans.span_line(invalid_span).is_none());
assert!(spans.span_column(invalid_span).is_none());
}
/// Test `substring` with out-of-bounds ranges
#[test]
fn test_spans_substring_out_of_bounds() {
let source = "Hello, World!";
let spans = Spans::new(source);
// Test with valid range
let result = spans.substring(0..5);
assert_eq!(result, Some("Hello"));
// Test with range beyond source length
let result = spans.substring(0..source.len() + 10);
assert!(result.is_none());
// Test with start beyond source length
let result = spans.substring(source.len() + 5..source.len() + 10);
assert!(result.is_none());
// Test with backwards range (intentionally empty)
#[allow(clippy::reversed_empty_ranges)]
let result = spans.substring(10..5);
assert!(result.is_none());
// Test with exact bounds
let result = spans.substring(0..source.len());
assert_eq!(result, Some(source));
}
/// Test `parse_bgr_color` with different prefixes and formats
#[test]
fn test_parse_bgr_color_edge_cases() {
// Test with 0x prefix
let hex_with_prefix = "0xFFFFFF";
let result = parse_bgr_color(hex_with_prefix);
assert!(result.is_ok());
// Test with plain hex (no prefix)
let plain_hex = "FF00FF";
let result = parse_bgr_color(plain_hex);
assert!(result.is_ok());
// Test with invalid hex characters
let invalid_hex = "GGHHII";
let result = parse_bgr_color(invalid_hex);
assert!(result.is_err());
// Test with wrong length
let short_hex = "FF";
let result = parse_bgr_color(short_hex);
assert!(result.is_err());
let long_hex = "FFFFFFFFFF";
let result = parse_bgr_color(long_hex);
assert!(result.is_err());
// Test with mixed case
let mixed_case = "0xaBcDeF";
let result = parse_bgr_color(mixed_case);
assert!(result.is_ok());
// Test with empty string
let empty = "";
let result = parse_bgr_color(empty);
assert!(result.is_err());
// Test with just prefix
let just_prefix = "0x";
let result = parse_bgr_color(just_prefix);
assert!(result.is_err());
// Test with special characters
let with_special = "0xFF@FF";
let result = parse_bgr_color(with_special);
assert!(result.is_err());
}
/// Test `decode_uu_data` with malformed data
#[test]
fn test_decode_uu_data_malformed_input() {
// Test with invalid length character (0x7F)
let invalid_length = "\x7FABCDEFGH"; // 0x7F is not a valid UU length character
let result = decode_uu_data(std::iter::once(invalid_length));
// UU decoder might be permissive, just test it doesn't panic
drop(result);
// Test with line shorter than encoded length
let short_line = "M"; // 'M' indicates 45 bytes but we only have 1 character
let result = decode_uu_data(std::iter::once(short_line));
// May succeed with partial data or fail, just test it doesn't panic
drop(result);
// Test with non-UU characters
let invalid_chars = "M\x01\x02\x03"; // Control characters are not valid UU
let result = decode_uu_data(std::iter::once(invalid_chars));
// May succeed or fail, just test it doesn't panic
drop(result);
// Test with expected_length > 45 path
let overlength = "N".repeat(100); // 'N' indicates 46 bytes, which is > 45
let result = decode_uu_data(std::iter::once(overlength.as_str()));
// May succeed or fail, just test it doesn't panic
drop(result);
// Test with empty input
let empty = std::iter::empty::<&str>();
let result = decode_uu_data(empty);
// Empty input returns empty result, not an error
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
// Test with only length character
let only_length = "M";
let result = decode_uu_data(std::iter::once(only_length));
// May succeed or fail, just test it doesn't panic
drop(result);
// Test with null bytes
let with_nulls = "M\0\0\0\0";
let result = decode_uu_data(std::iter::once(with_nulls));
// May succeed or fail, just test it doesn't panic
drop(result);
}
/// Test `decode_uu_data` with valid but edge case data
#[test]
fn test_decode_uu_data_edge_cases() {
// Test with minimum valid data (length 1)
let min_data = "!A"; // '!' = length 0, but we need at least some padding
let result = decode_uu_data(std::iter::once(min_data));
// Should succeed with small data
assert!(result.is_ok());
// Test with maximum valid length (45 bytes)
let max_length_char = 'M'; // 'M' represents 45 bytes
let max_data = format!("{}{}", max_length_char, "A".repeat(60)); // 60 chars for 45 bytes
let result = decode_uu_data(std::iter::once(max_data.as_str()));
assert!(result.is_ok() || result.is_err()); // Either decodes or fails gracefully
// Test with whitespace
let with_whitespace = "5 A B C D"; // Contains spaces
let result = decode_uu_data(std::iter::once(with_whitespace));
// May succeed or fail depending on implementation
drop(result); // Just test that it doesn't panic
// Test with multiple lines
let with_newlines = ["5ABCD", "EFGH"];
let result = decode_uu_data(with_newlines.iter().copied());
// Multiple lines may be processed successfully
drop(result); // Just test that it doesn't panic
}
/// Test various error conditions in utils functions
#[test]
fn test_utils_error_conditions() {
// Test color parsing with various invalid formats
let invalid_colors = [
"invalid", "#FFFFFF", // Wrong prefix
"0xGGGGGG", // Invalid hex
"FFFF", // Too short
"0x", // Empty after prefix
"xyz123", // Mixed invalid
];
for color in &invalid_colors {
let result = parse_bgr_color(color);
assert!(result.is_err(), "Should fail for color: {color}");
}
// Test 8-character hex separately as it might be valid
let eight_char = "FFFFFFFF";
let result = parse_bgr_color(eight_char);
// 8-character hex might be valid (AARRGGBB format)
drop(result); // Just test it doesn't panic
// Test UU decoding with various malformed inputs
let mut long_data = "~".to_owned();
long_data.push_str(&"A".repeat(100));
let mut invalid_chars = "5".to_owned();
invalid_chars.push_str(&"\x7F".repeat(10));
let invalid_uu_data = [
"\x7F\x7F\x7F", // Non-printable characters
&long_data, // Length too large
"A", // Missing data
"5ABC", // Too short for claimed length
&invalid_chars, // Invalid characters
];
for uu in &invalid_uu_data {
let result = decode_uu_data(std::iter::once(*uu));
// UU decoder is permissive, just test it doesn't panic
drop(result);
}
}
/// Test `Spans` with various source text formats
#[test]
fn test_spans_with_different_text_formats() {
// Test with empty source
let empty_source = "";
let empty_spans = Spans::new(empty_source);
let empty_span = &empty_source[0..0];
assert!(empty_spans.validate_span(empty_span));
assert_eq!(empty_spans.substring(0..0), Some(""));
// Test with Unicode text
let unicode_source = "Hello ๐ World! ใใใซใกใฏ";
let unicode_spans = Spans::new(unicode_source);
// Create span with valid byte boundaries
let hello_span = &unicode_source[0..5]; // "Hello"
assert!(unicode_spans.validate_span(hello_span));
// Test with various line endings
let mixed_endings = "Line1\nLine2\r\nLine3\rLine4";
let mixed_spans = Spans::new(mixed_endings);
let full_span = &mixed_endings[0..mixed_endings.len()];
assert!(mixed_spans.validate_span(full_span));
assert_eq!(
mixed_spans.substring(0..mixed_endings.len()),
Some(mixed_endings)
);
}
/// Test boundary conditions for all utils functions
#[test]
fn test_utils_boundary_conditions() {
// Test with maximum size inputs
let large_source = "x".repeat(10000);
let large_spans = Spans::new(&large_source);
let large_span = &large_source[0..large_source.len()];
assert!(large_spans.validate_span(large_span));
// Test color parsing at exact boundaries
let exact_6_chars = "ABCDEF";
assert!(parse_bgr_color(exact_6_chars).is_ok());
let exact_8_chars = "0xABCDEF";
assert!(parse_bgr_color(exact_8_chars).is_ok());
// Test UU decoding at boundaries
let boundary_uu = format!("{}{}", (32u8 + 45) as char, "A".repeat(60));
let _result = decode_uu_data(std::iter::once(boundary_uu.as_str())); // May succeed or fail, but shouldn't panic
}
/// Test error message formatting and types
#[test]
fn test_error_handling_details() {
// Test that errors contain useful information
let color_error = parse_bgr_color("invalid").unwrap_err();
let error_message = color_error.to_string();
assert!(!error_message.is_empty());
// For UU data, use something that's definitely invalid
let uu_result = decode_uu_data(std::iter::once("\x7F\x7F\x7F"));
if let Err(uu_error) = uu_result {
let uu_error_message = uu_error.to_string();
assert!(!uu_error_message.is_empty());
// Verify error type if it fails
assert!(matches!(uu_error, CoreError::Parse(_)));
}
// Verify color error type
assert!(matches!(color_error, CoreError::InvalidColor(_)));
}
}