Skip to content

Commit 9fe8507

Browse files
hyperpolymathclaude
andcommitted
test: convert remaining integration tests to panic-free Result style
Fixes compilation (missing schema_version / safe_unwrap_calls fields added in a prior session) and converts all .unwrap() calls to ? propagation across five test files: panll_tests.rs (7 tests) — TempDir + file I/O + JSON value access via ? and .ok_or("..."). Adds schema_version / safe_unwrap_calls to struct initializers. Replaces .as_array().unwrap() with .ok_or("...")?. report_tests.rs (10 tests) — generate_assault_report() / serialize() calls all become ?. Adds schema_version / safe_unwrap_calls to fixtures. sarif_tests.rs (8 tests) — Adds schema_version to fixtures. Converts JSON value access to .ok_or(). Unifies mixed .unwrap()/.expect() into consistent ?. readiness.rs (20 tests) — Largest file (83 bare unwraps removed). All 17 tests that used TempDir / fs::write / fs::read_to_string now return Result<(), Box<dyn Error>> with ? throughout. Path-to-str uses .ok_or("path not valid UTF-8")?. The binary() helper uses .expect() with an invariant-documenting message (structurally infallible in cargo test). property_tests.rs — Adds missing safe_unwrap_calls: 0 field that was blocking compilation. Full test suite: 0 failures across all 17 test files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2053fd9 commit 9fe8507

5 files changed

Lines changed: 366 additions & 410 deletions

File tree

tests/panll_tests.rs

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// SPDX-License-Identifier: PMPL-1.0-or-later
22

3-
//! Tests for the PanLL event-chain export module
3+
//! Tests for the PanLL event-chain export module.
4+
//!
5+
//! All tests are panic-free: they return `Result` and propagate errors with
6+
//! `?`. JSON value access uses `.ok_or(...)` rather than `.as_array().unwrap()`.
47
58
use panic_attack::panll;
69
use panic_attack::types::*;
@@ -12,17 +15,15 @@ fn make_assault_report(
1215
weak_points: Vec<WeakPoint>,
1316
attack_results: Vec<AttackResult>,
1417
) -> AssaultReport {
15-
let _critical_count = weak_points
16-
.iter()
17-
.filter(|wp| wp.severity == Severity::Critical)
18-
.count();
1918
let unsafe_count = weak_points
2019
.iter()
2120
.filter(|wp| wp.category == WeakPointCategory::UnsafeCode)
2221
.count();
2322

2423
AssaultReport {
24+
schema_version: "2.5".to_string(),
2525
assail_report: AssailReport {
26+
schema_version: "2.5".to_string(),
2627
program_path: PathBuf::from("/tmp/test-target"),
2728
language: Language::Rust,
2829
frameworks: vec![],
@@ -32,6 +33,7 @@ fn make_assault_report(
3233
unsafe_blocks: unsafe_count,
3334
panic_sites: 0,
3435
unwrap_calls: 3,
36+
safe_unwrap_calls: 0,
3537
allocation_sites: 5,
3638
io_operations: 1,
3739
threading_constructs: 0,
@@ -56,21 +58,22 @@ fn make_assault_report(
5658
}
5759

5860
#[test]
59-
fn test_panll_export_writes_valid_json() {
61+
fn test_panll_export_writes_valid_json() -> Result<(), Box<dyn std::error::Error>> {
6062
let report = make_assault_report(vec![], vec![]);
61-
let dir = TempDir::new().unwrap();
63+
let dir = TempDir::new()?;
6264
let output = dir.path().join("panll-out.json");
6365

64-
panll::write_export(&report, None, &output).unwrap();
66+
panll::write_export(&report, None, &output)?;
6567

66-
let content = std::fs::read_to_string(&output).unwrap();
67-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
68+
let content = std::fs::read_to_string(&output)?;
69+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
6870
assert_eq!(parsed["format"], "panll.event-chain.v0");
6971
assert_eq!(parsed["source"]["tool"], "panic-attack");
72+
Ok(())
7073
}
7174

7275
#[test]
73-
fn test_panll_export_summary_reflects_report() {
76+
fn test_panll_export_summary_reflects_report() -> Result<(), Box<dyn std::error::Error>> {
7477
let report = make_assault_report(
7578
vec![WeakPoint {
7679
category: WeakPointCategory::UnsafeCode,
@@ -84,20 +87,21 @@ fn test_panll_export_summary_reflects_report() {
8487
}],
8588
vec![],
8689
);
87-
let dir = TempDir::new().unwrap();
90+
let dir = TempDir::new()?;
8891
let output = dir.path().join("panll-out.json");
8992

90-
panll::write_export(&report, None, &output).unwrap();
93+
panll::write_export(&report, None, &output)?;
9194

92-
let content = std::fs::read_to_string(&output).unwrap();
93-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
95+
let content = std::fs::read_to_string(&output)?;
96+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
9497
assert_eq!(parsed["summary"]["weak_points"], 1);
9598
assert_eq!(parsed["summary"]["critical_weak_points"], 1);
9699
assert_eq!(parsed["summary"]["robustness_score"], 75.0);
100+
Ok(())
97101
}
98102

99103
#[test]
100-
fn test_panll_export_constraints_from_critical_wp() {
104+
fn test_panll_export_constraints_from_critical_wp() -> Result<(), Box<dyn std::error::Error>> {
101105
let report = make_assault_report(
102106
vec![
103107
WeakPoint {
@@ -123,29 +127,37 @@ fn test_panll_export_constraints_from_critical_wp() {
123127
],
124128
vec![],
125129
);
126-
let dir = TempDir::new().unwrap();
130+
let dir = TempDir::new()?;
127131
let output = dir.path().join("panll-out.json");
128132

129-
panll::write_export(&report, None, &output).unwrap();
133+
panll::write_export(&report, None, &output)?;
130134

131-
let content = std::fs::read_to_string(&output).unwrap();
132-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
133-
let constraints = parsed["constraints"].as_array().unwrap();
135+
let content = std::fs::read_to_string(&output)?;
136+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
137+
let constraints = parsed["constraints"]
138+
.as_array()
139+
.ok_or("constraints must be an array")?;
134140

135-
// Only the critical WP should generate a constraint, not the medium one
136141
assert_eq!(constraints.len(), 1, "only critical WPs become constraints");
137-
assert!(constraints[0]["id"]
138-
.as_str()
139-
.unwrap()
140-
.starts_with("wp-crit-"));
141-
assert!(constraints[0]["description"]
142-
.as_str()
143-
.unwrap()
144-
.contains("transmute"));
142+
assert!(
143+
constraints[0]["id"]
144+
.as_str()
145+
.ok_or("constraint id must be a string")?
146+
.starts_with("wp-crit-"),
147+
"constraint id should start with wp-crit-"
148+
);
149+
assert!(
150+
constraints[0]["description"]
151+
.as_str()
152+
.ok_or("constraint description must be a string")?
153+
.contains("transmute"),
154+
"constraint should mention the detected issue"
155+
);
156+
Ok(())
145157
}
146158

147159
#[test]
148-
fn test_panll_export_event_chain_from_attacks() {
160+
fn test_panll_export_event_chain_from_attacks() -> Result<(), Box<dyn std::error::Error>> {
149161
let report = make_assault_report(
150162
vec![],
151163
vec![
@@ -175,24 +187,27 @@ fn test_panll_export_event_chain_from_attacks() {
175187
},
176188
],
177189
);
178-
let dir = TempDir::new().unwrap();
190+
let dir = TempDir::new()?;
179191
let output = dir.path().join("panll-out.json");
180192

181-
panll::write_export(&report, None, &output).unwrap();
193+
panll::write_export(&report, None, &output)?;
182194

183-
let content = std::fs::read_to_string(&output).unwrap();
184-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
185-
let events = parsed["event_chain"].as_array().unwrap();
195+
let content = std::fs::read_to_string(&output)?;
196+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
197+
let events = parsed["event_chain"]
198+
.as_array()
199+
.ok_or("event_chain must be an array")?;
186200

187201
assert_eq!(events.len(), 2);
188202
assert_eq!(events[0]["axis"], "cpu");
189203
assert_eq!(events[0]["status"], "passed");
190204
assert_eq!(events[1]["axis"], "memory");
191205
assert_eq!(events[1]["status"], "failed");
206+
Ok(())
192207
}
193208

194209
#[test]
195-
fn test_panll_export_constraints_from_failed_attacks() {
210+
fn test_panll_export_constraints_from_failed_attacks() -> Result<(), Box<dyn std::error::Error>> {
196211
let mut report = make_assault_report(
197212
vec![],
198213
vec![AttackResult {
@@ -216,25 +231,28 @@ fn test_panll_export_constraints_from_failed_attacks() {
216231
);
217232
report.total_crashes = 1;
218233

219-
let dir = TempDir::new().unwrap();
234+
let dir = TempDir::new()?;
220235
let output = dir.path().join("panll-out.json");
221236

222-
panll::write_export(&report, None, &output).unwrap();
237+
panll::write_export(&report, None, &output)?;
223238

224-
let content = std::fs::read_to_string(&output).unwrap();
225-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
226-
let constraints = parsed["constraints"].as_array().unwrap();
239+
let content = std::fs::read_to_string(&output)?;
240+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
241+
let constraints = parsed["constraints"]
242+
.as_array()
243+
.ok_or("constraints must be an array")?;
227244

228245
assert!(
229246
constraints
230247
.iter()
231-
.any(|c| c["id"].as_str().unwrap().starts_with("attack-fail-")),
248+
.any(|c| c["id"].as_str().map_or(false, |id| id.starts_with("attack-fail-"))),
232249
"failed attack should generate a constraint"
233250
);
251+
Ok(())
234252
}
235253

236254
#[test]
237-
fn test_panll_export_skipped_attacks_not_in_constraints() {
255+
fn test_panll_export_skipped_attacks_not_in_constraints() -> Result<(), Box<dyn std::error::Error>> {
238256
let report = make_assault_report(
239257
vec![],
240258
vec![AttackResult {
@@ -251,34 +269,40 @@ fn test_panll_export_skipped_attacks_not_in_constraints() {
251269
}],
252270
);
253271

254-
let dir = TempDir::new().unwrap();
272+
let dir = TempDir::new()?;
255273
let output = dir.path().join("panll-out.json");
256274

257-
panll::write_export(&report, None, &output).unwrap();
275+
panll::write_export(&report, None, &output)?;
258276

259-
let content = std::fs::read_to_string(&output).unwrap();
260-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
261-
let constraints = parsed["constraints"].as_array().unwrap();
277+
let content = std::fs::read_to_string(&output)?;
278+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
279+
let constraints = parsed["constraints"]
280+
.as_array()
281+
.ok_or("constraints must be an array")?;
262282

263283
assert!(
264284
constraints.is_empty(),
265285
"skipped attacks should not generate constraints"
266286
);
267287

268-
let events = parsed["event_chain"].as_array().unwrap();
288+
let events = parsed["event_chain"]
289+
.as_array()
290+
.ok_or("event_chain must be an array")?;
269291
assert_eq!(events[0]["status"], "skipped");
292+
Ok(())
270293
}
271294

272295
#[test]
273-
fn test_panll_export_report_path_recorded() {
296+
fn test_panll_export_report_path_recorded() -> Result<(), Box<dyn std::error::Error>> {
274297
let report = make_assault_report(vec![], vec![]);
275-
let dir = TempDir::new().unwrap();
298+
let dir = TempDir::new()?;
276299
let output = dir.path().join("panll-out.json");
277300
let source_path = std::path::Path::new("/tmp/my-report.json");
278301

279-
panll::write_export(&report, Some(source_path), &output).unwrap();
302+
panll::write_export(&report, Some(source_path), &output)?;
280303

281-
let content = std::fs::read_to_string(&output).unwrap();
282-
let parsed: serde_json::Value = serde_json::from_str(&content).unwrap();
304+
let content = std::fs::read_to_string(&output)?;
305+
let parsed: serde_json::Value = serde_json::from_str(&content)?;
283306
assert_eq!(parsed["source"]["report_path"], "/tmp/my-report.json");
307+
Ok(())
284308
}

tests/property_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ fn prop_report_statistics_consistency() {
247247
threading_constructs: 0,
248248
allocation_sites: 3,
249249
io_operations: 2,
250+
safe_unwrap_calls: 0,
250251
};
251252

252253
// Unwrap + panic sites should not exceed total lines

0 commit comments

Comments
 (0)