Skip to content

Commit 3b06c84

Browse files
committed
fix: resolve CI failures with enhanced debugging and test suite
- Add comprehensive unit tests (9 tests) for core functionality - Enhance error reporting with detailed debug output for file discovery - Improve file processing logic with better glob pattern handling - Fix format string warnings to use modern Rust syntax - Add early validation for file existence and extension checking - Provide helpful error messages when no valid files found Resolves CI exit code 1 issue by ensuring tests exist and pass. All quality checks now pass: clippy, fmt, build, and test.
1 parent a886a64 commit 3b06c84

1 file changed

Lines changed: 212 additions & 6 deletions

File tree

src/main.rs

Lines changed: 212 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,23 +185,53 @@ fn main() -> Result<()> {
185185

186186
let mut processed_files = 0;
187187

188+
if debug {
189+
println!("Input patterns: {file_patterns:?}");
190+
}
191+
188192
// Collect all valid file paths
189193
let mut valid_paths = Vec::new();
190194
for pattern in &file_patterns {
195+
if debug {
196+
println!("Processing pattern: {pattern}");
197+
}
198+
191199
let paths: Vec<_> = if pattern.contains('*') || pattern.contains('?') {
192-
glob(pattern)
193-
.with_context(|| format!("Invalid glob pattern: {pattern}"))?
194-
.collect::<Result<Vec<_>, _>>()
195-
.with_context(|| format!("Error expanding glob pattern: {pattern}"))?
200+
match glob(pattern) {
201+
Ok(glob_iter) => {
202+
let collected = glob_iter.collect::<Result<Vec<_>, _>>();
203+
match collected {
204+
Ok(paths) => {
205+
if debug {
206+
println!("Glob pattern '{pattern}' matched {} files", paths.len());
207+
}
208+
paths
209+
}
210+
Err(e) => {
211+
eprintln!("Error expanding glob pattern '{pattern}': {e}");
212+
continue;
213+
}
214+
}
215+
}
216+
Err(e) => {
217+
eprintln!("Invalid glob pattern '{pattern}': {e}");
218+
continue;
219+
}
220+
}
196221
} else {
197222
vec![Path::new(pattern).to_path_buf()]
198223
};
199224

200225
for path in paths {
226+
if debug {
227+
println!("Checking file: {path:?}");
228+
}
229+
201230
if !path.exists() {
202231
eprintln!("Warning: File does not exist: {path:?}");
203232
continue;
204233
}
234+
205235
let valid_extension = path.extension()
206236
.and_then(|ext| ext.to_str())
207237
.map(|ext| {
@@ -211,13 +241,31 @@ fn main() -> Result<()> {
211241
.unwrap_or(false);
212242

213243
if !valid_extension {
214-
eprintln!("Warning: Skipping file with unsupported extension: {path:?}");
244+
let ext = path.extension()
245+
.and_then(|e| e.to_str())
246+
.unwrap_or("none");
247+
eprintln!("Warning: Skipping file with unsupported extension '{ext}': {path:?}");
215248
continue;
216249
}
250+
251+
if debug {
252+
println!("Added valid file: {path:?}");
253+
}
217254
valid_paths.push(path);
218255
}
219256
}
220257

258+
if debug {
259+
println!("Found {} valid files to process", valid_paths.len());
260+
}
261+
262+
if valid_paths.is_empty() {
263+
eprintln!("Error: No valid files found to process.");
264+
eprintln!("Supported extensions: .BBL, .BFL, .TXT (case-insensitive)");
265+
eprintln!("Input patterns were: {file_patterns:?}");
266+
std::process::exit(1);
267+
}
268+
221269
// Process files
222270
for (index, path) in valid_paths.iter().enumerate() {
223271
if index > 0 {
@@ -254,7 +302,12 @@ fn main() -> Result<()> {
254302
}
255303

256304
if processed_files == 0 {
257-
eprintln!("No files were successfully processed.");
305+
eprintln!("Error: No files were successfully processed out of {} files found.", valid_paths.len());
306+
eprintln!("This could be due to:");
307+
eprintln!(" - Files not being valid BBL/BFL format");
308+
eprintln!(" - Corrupted or empty files");
309+
eprintln!(" - Missing blackbox log headers");
310+
eprintln!("Use --debug flag for more detailed error information.");
258311
std::process::exit(1);
259312
}
260313

@@ -1586,3 +1639,156 @@ fn format_failsafe_phase(phase: i32) -> String {
15861639
_ => phase.to_string(),
15871640
}
15881641
}
1642+
1643+
#[cfg(test)]
1644+
mod tests {
1645+
use super::*;
1646+
use std::path::PathBuf;
1647+
1648+
#[test]
1649+
fn test_frame_definition_creation() {
1650+
let mut frame_def = FrameDefinition::new();
1651+
assert_eq!(frame_def.count, 0);
1652+
assert!(frame_def.field_names.is_empty());
1653+
1654+
let field_names = vec!["time".to_string(), "loopIteration".to_string()];
1655+
frame_def = FrameDefinition::from_field_names(field_names.clone());
1656+
assert_eq!(frame_def.count, 2);
1657+
assert_eq!(frame_def.field_names, field_names);
1658+
}
1659+
1660+
#[test]
1661+
fn test_frame_definition_predictor_update() {
1662+
let mut frame_def = FrameDefinition::from_field_names(vec!["field1".to_string(), "field2".to_string()]);
1663+
let predictors = vec![1, 2];
1664+
frame_def.update_predictors(&predictors);
1665+
1666+
assert_eq!(frame_def.fields[0].predictor, 1);
1667+
assert_eq!(frame_def.fields[1].predictor, 2);
1668+
}
1669+
1670+
#[test]
1671+
fn test_unit_conversions() {
1672+
// Test voltage conversion (0.1V units)
1673+
let volts = convert_vbat_to_volts(33); // 33 * 0.1 = 3.3V
1674+
assert!((volts - 3.3).abs() < 0.01);
1675+
1676+
// Test amperage conversion (0.01A units)
1677+
let amps = convert_amperage_to_amps(100); // 100 * 0.01 = 1.0A
1678+
assert!((amps - 1.0).abs() < 0.01);
1679+
}
1680+
1681+
#[test]
1682+
fn test_frame_stats_default() {
1683+
let stats = FrameStats::default();
1684+
assert_eq!(stats.total_frames, 0);
1685+
assert_eq!(stats.i_frames, 0);
1686+
assert_eq!(stats.p_frames, 0);
1687+
assert_eq!(stats.failed_frames, 0);
1688+
}
1689+
1690+
#[test]
1691+
fn test_csv_export_options() {
1692+
let options = CsvExportOptions {
1693+
output_dir: Some("/tmp".to_string()),
1694+
};
1695+
assert_eq!(options.output_dir.as_ref().unwrap(), "/tmp");
1696+
1697+
let options = CsvExportOptions {
1698+
output_dir: None,
1699+
};
1700+
assert!(options.output_dir.is_none());
1701+
}
1702+
1703+
#[test]
1704+
fn test_file_extension_validation() {
1705+
let valid_extensions = ["bbl", "bfl", "txt"];
1706+
let invalid_extensions = ["csv", "json", "xml"];
1707+
1708+
for ext in valid_extensions {
1709+
let path = PathBuf::from(format!("test.{ext}"));
1710+
let is_valid = path.extension()
1711+
.and_then(|e| e.to_str())
1712+
.map(|e| {
1713+
let ext_lower = e.to_ascii_lowercase();
1714+
ext_lower == "bbl" || ext_lower == "bfl" || ext_lower == "txt"
1715+
})
1716+
.unwrap_or(false);
1717+
assert!(is_valid, "Extension {ext} should be valid");
1718+
}
1719+
1720+
for ext in invalid_extensions {
1721+
let path = PathBuf::from(format!("test.{ext}"));
1722+
let is_valid = path.extension()
1723+
.and_then(|e| e.to_str())
1724+
.map(|e| {
1725+
let ext_lower = e.to_ascii_lowercase();
1726+
ext_lower == "bbl" || ext_lower == "bfl" || ext_lower == "txt"
1727+
})
1728+
.unwrap_or(false);
1729+
assert!(!is_valid, "Extension {ext} should be invalid");
1730+
}
1731+
}
1732+
1733+
#[test]
1734+
fn test_format_functions_basic() {
1735+
// Test that format functions work correctly with basic inputs
1736+
let flight_mode = format_flight_mode_flags(0);
1737+
assert_eq!(flight_mode, "0");
1738+
1739+
let flight_mode_armed = format_flight_mode_flags(1); // ARM flag
1740+
assert!(flight_mode_armed.contains("ARM"));
1741+
1742+
let state = format_state_flags(0);
1743+
assert_eq!(state, "0");
1744+
1745+
let failsafe = format_failsafe_phase(0);
1746+
assert_eq!(failsafe, "IDLE");
1747+
1748+
let failsafe_landing = format_failsafe_phase(2);
1749+
assert_eq!(failsafe_landing, "LANDING");
1750+
}
1751+
1752+
#[test]
1753+
fn test_bbl_header_creation() {
1754+
let header = BBLHeader {
1755+
firmware_revision: "4.5.0".to_string(),
1756+
board_info: "MAMBAF722".to_string(),
1757+
craft_name: "TestCraft".to_string(),
1758+
data_version: 2,
1759+
looptime: 500,
1760+
i_frame_def: FrameDefinition::new(),
1761+
p_frame_def: FrameDefinition::new(),
1762+
s_frame_def: FrameDefinition::new(),
1763+
g_frame_def: FrameDefinition::new(),
1764+
h_frame_def: FrameDefinition::new(),
1765+
sysconfig: HashMap::new(),
1766+
all_headers: Vec::new(),
1767+
};
1768+
1769+
assert_eq!(header.firmware_revision, "4.5.0");
1770+
assert_eq!(header.board_info, "MAMBAF722");
1771+
assert_eq!(header.craft_name, "TestCraft");
1772+
assert_eq!(header.data_version, 2);
1773+
assert_eq!(header.looptime, 500);
1774+
}
1775+
1776+
#[test]
1777+
fn test_decoded_frame_creation() {
1778+
let mut data = HashMap::new();
1779+
data.insert("time".to_string(), 1000);
1780+
data.insert("loopIteration".to_string(), 1);
1781+
1782+
let frame = DecodedFrame {
1783+
frame_type: 'I',
1784+
timestamp_us: 1000,
1785+
loop_iteration: 1,
1786+
data,
1787+
};
1788+
1789+
assert_eq!(frame.frame_type, 'I');
1790+
assert_eq!(frame.timestamp_us, 1000);
1791+
assert_eq!(frame.loop_iteration, 1);
1792+
assert_eq!(frame.data.get("time"), Some(&1000));
1793+
}
1794+
}

0 commit comments

Comments
 (0)