Generalize config prefix stripping and refactor improve CSV output
- Replace hardcoded v2c_/v1c_ prefix stripping with generic rsplit_once('_')
approach that handles any prefix (v2b_, v3a_, etc.) while validating
the suffix is exactly 3 ASCII digits
- Refactor write_improve_csv to emit one row per normalized config per car
instead of a single aggregated row, giving visibility into all viable
upgrade paths
- Add 4 new tests covering prefix stripping and improve CSV behavior
This commit is contained in:
parent
2b0602d564
commit
fc9f637c60
2 changed files with 218 additions and 40 deletions
|
|
@ -97,15 +97,17 @@ pub fn parse_car_times(
|
|||
// Process each configuration variant (111, 233, 323, etc.)
|
||||
if let Some(configurations) = json_data["data"].as_object() {
|
||||
for (raw_config, entry) in configurations {
|
||||
// Strip version prefix (e.g., "v2c_" from "v2c_233") at read time.
|
||||
// Downstream code only ever sees bare digit strings.
|
||||
// Use explicit prefix matching to avoid mis-stripping keys that
|
||||
// naturally contain underscores.
|
||||
// Strip version prefix (e.g., "v2c_" from "v2c_233", "v2b_" from "v2b_111")
|
||||
// at read time. Downstream code only ever sees bare digit strings.
|
||||
// Generic approach: find the last '_' and take what follows it,
|
||||
// but only if the remainder is exactly 3 ASCII digits. Otherwise
|
||||
// keep the key unchanged (handles bare configs like "233" and
|
||||
// unexpected formats gracefully).
|
||||
let config = raw_config
|
||||
.strip_prefix("v2c_")
|
||||
.or_else(|| raw_config.strip_prefix("v1c_"))
|
||||
.unwrap_or(raw_config)
|
||||
.to_string();
|
||||
.rsplit_once('_')
|
||||
.filter(|(_, suffix)| suffix.len() == 3 && suffix.bytes().all(|b| b.is_ascii_digit()))
|
||||
.map(|(_, suffix)| suffix.to_string())
|
||||
.unwrap_or_else(|| raw_config.clone());
|
||||
// Process timing data for each track
|
||||
if let Some(times) = entry["times"].as_object() {
|
||||
for (track_id, details) in times {
|
||||
|
|
@ -636,6 +638,100 @@ mod tests {
|
|||
assert_eq!(translate_track_type("99"), "99");
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// Prefix stripping tests
|
||||
// =======================================================================
|
||||
|
||||
#[test]
|
||||
fn test_parse_car_times_strips_v2b_prefix() {
|
||||
let ctx = AnalysisContext::new();
|
||||
let car = Car {
|
||||
rid: "TestCar_2020".to_string(),
|
||||
brand: "TestBrand".to_string(),
|
||||
only_name: "TestModel".to_string(),
|
||||
year: 2020,
|
||||
rq: 85,
|
||||
prize: false,
|
||||
guid: "guid_test".to_string(),
|
||||
};
|
||||
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let times_dir = dir.path().to_str().unwrap();
|
||||
let file_path = dir.path().join("TestCar_2020.json");
|
||||
|
||||
// Use "v2b_233" prefix — previously not stripped
|
||||
let json_content = r#"{
|
||||
"data": {
|
||||
"v2b_233": {
|
||||
"times": {
|
||||
"laguna_a00": { "t": 100.0, "u": "Player1" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
fs::write(&file_path, json_content).unwrap();
|
||||
|
||||
let my_cars: HashSet<String> = HashSet::new();
|
||||
parse_car_times(car, &my_cars, &ctx.best_cars, times_dir).unwrap();
|
||||
|
||||
// Verify the config was stripped to "233" (not "v2b_233")
|
||||
let records = ctx.best_cars.get(&("Laguna Seca".to_string(), 85, "Dry".to_string())).unwrap();
|
||||
assert_eq!(records[0].config, "233", "v2b_ prefix should be stripped");
|
||||
assert_eq!(records[0].normalized_config, "233", "233 is already a final build");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_car_times_strips_various_prefixes() {
|
||||
let ctx = AnalysisContext::new();
|
||||
let car = Car {
|
||||
rid: "TestCar_2021".to_string(),
|
||||
brand: "TestBrand".to_string(),
|
||||
only_name: "TestModel".to_string(),
|
||||
year: 2021,
|
||||
rq: 90,
|
||||
prize: false,
|
||||
guid: "guid_test2".to_string(),
|
||||
};
|
||||
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let times_dir = dir.path().to_str().unwrap();
|
||||
let file_path = dir.path().join("TestCar_2021.json");
|
||||
|
||||
// Mix of prefix styles: v2c_, v1c_, v3a_, and bare
|
||||
let json_content = r#"{
|
||||
"data": {
|
||||
"v2c_111": {
|
||||
"times": {
|
||||
"laguna_a00": { "t": 110.0, "u": "P1" }
|
||||
}
|
||||
},
|
||||
"v3a_233": {
|
||||
"times": {
|
||||
"laguna_a00": { "t": 95.0, "u": "P2" }
|
||||
}
|
||||
},
|
||||
"323": {
|
||||
"times": {
|
||||
"mnCity_a01": { "t": 88.0, "u": "P3" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
fs::write(&file_path, json_content).unwrap();
|
||||
|
||||
let my_cars: HashSet<String> = HashSet::new();
|
||||
parse_car_times(car, &my_cars, &ctx.best_cars, times_dir).unwrap();
|
||||
|
||||
// Best on Laguna Seca should be the v3a_233 entry (95.0 beats 110.0)
|
||||
let records = ctx.best_cars.get(&("Laguna Seca".to_string(), 90, "Dry".to_string())).unwrap();
|
||||
assert_eq!(records[0].config, "233", "v3a_ prefix should be stripped");
|
||||
assert_eq!(records[0].time, 95.0);
|
||||
|
||||
// Monaco Streets from bare "323"
|
||||
let records = ctx.best_cars.get(&("Monaco Streets".to_string(), 90, "Wet".to_string())).unwrap();
|
||||
assert_eq!(records[0].config, "323", "bare config should pass through");
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// Constants tests
|
||||
// =======================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue