Skip to content

Commit da91c96

Browse files
Copilotbartlomieju
andcommitted
refactor: extract handle_expected_failure function and add clarifying comments
Co-authored-by: bartlomieju <13602871+bartlomieju@users.noreply.github.com>
1 parent a39644d commit da91c96

File tree

1 file changed

+112
-81
lines changed

1 file changed

+112
-81
lines changed

tests/node_compat/mod.rs

Lines changed: 112 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const TEST_ARGS: &[&str] = &[
4646

4747
/// Per-platform value: either a boolean (true = enabled, false = disabled)
4848
/// or an object describing an expected failure.
49+
///
50+
/// Uses `#[serde(untagged)]` so that config.jsonc can use both
51+
/// `"windows": false` (boolean) and `"windows": { "exitCode": 1 }` (object).
4952
#[derive(Debug, Clone, Deserialize)]
5053
#[serde(untagged)]
5154
enum PlatformExpectation {
@@ -826,85 +829,63 @@ fn run_test(
826829
let expected_failure = test_config.and_then(resolve_expected_failure);
827830

828831
if let Some(ef) = expected_failure {
829-
// Test has an expected-failure spec for this platform
830-
if success {
831-
// Test passed but was expected to fail
832-
results.lock().unwrap().insert(
833-
data.test_path.clone(),
834-
CollectedResult {
835-
passed: Some(false),
836-
error: Some(ErrorInfo {
837-
code: actual_exit_code,
838-
stderr: None,
839-
timeout: None,
840-
message: Some("expected test to fail but it passed".to_string()),
841-
}),
842-
uses_node_test,
843-
ignore_reason: None,
844-
},
845-
);
846-
return TestResult::Failed {
847-
duration: None,
848-
output: format!(
849-
"Test was expected to fail but passed\n{}",
850-
debugging_command_text
851-
)
852-
.into_bytes(),
853-
};
854-
}
855-
856-
let exit_code_matches =
857-
ef.exit_code.map_or(true, |ec| actual_exit_code == Some(ec));
858-
let output_matches = ef.output.as_ref().map_or(true, |pattern| {
859-
util::wildcard_match_detailed(pattern, &output_for_error).is_success()
860-
});
832+
return handle_expected_failure(
833+
&ef,
834+
success,
835+
actual_exit_code,
836+
uses_node_test,
837+
&output_for_error,
838+
&debugging_command_text,
839+
&data.test_path,
840+
results,
841+
);
842+
}
861843

862-
if exit_code_matches && output_matches {
863-
// Failed as expected — treat as a pass
864-
results.lock().unwrap().insert(
865-
data.test_path.clone(),
866-
CollectedResult {
867-
passed: Some(true),
868-
error: None,
869-
uses_node_test,
870-
ignore_reason: None,
871-
},
872-
);
873-
if *file_test_runner::NO_CAPTURE {
874-
test_util::eprintln!("{}", debugging_command_text);
875-
}
876-
return TestResult::Passed { duration: None };
877-
}
844+
results
845+
.lock()
846+
.unwrap()
847+
.insert(data.test_path.clone(), collected);
878848

879-
// Failed, but not in the expected way
880-
let mut mismatch_details = String::new();
881-
if !exit_code_matches {
882-
mismatch_details.push_str(&format!(
883-
"Exit code mismatch: expected {:?}, got {:?}\n",
884-
ef.exit_code, actual_exit_code
885-
));
849+
if success {
850+
if *file_test_runner::NO_CAPTURE {
851+
test_util::eprintln!("{}", debugging_command_text);
886852
}
887-
if !output_matches {
888-
let match_result = ef.output.as_ref().map(|pattern| {
889-
util::wildcard_match_detailed(pattern, &output_for_error)
890-
});
891-
if let Some(util::WildcardMatchResult::Fail(detail)) = match_result {
892-
mismatch_details
893-
.push_str(&format!("Output mismatch detail:\n{}\n", detail));
894-
} else {
895-
mismatch_details.push_str("Output did not match expected pattern\n");
896-
}
853+
TestResult::Passed { duration: None }
854+
} else {
855+
TestResult::Failed {
856+
duration: None,
857+
output: format!("{}\n{}", output_for_error, debugging_command_text)
858+
.into_bytes(),
897859
}
860+
}
861+
}
898862

863+
/// Handle a test that has an expected-failure configuration.
864+
///
865+
/// Returns `Passed` when the test fails in the expected way (matching exit code
866+
/// and/or output pattern), and `Failed` otherwise.
867+
#[allow(clippy::too_many_arguments)]
868+
fn handle_expected_failure(
869+
ef: &ExpectedFailure,
870+
success: bool,
871+
actual_exit_code: Option<i32>,
872+
uses_node_test: bool,
873+
output_for_error: &str,
874+
debugging_command_text: &str,
875+
test_path: &str,
876+
results: &Arc<Mutex<HashMap<String, CollectedResult>>>,
877+
) -> TestResult {
878+
if success {
879+
// Test passed but was expected to fail
899880
results.lock().unwrap().insert(
900-
data.test_path.clone(),
881+
test_path.to_string(),
901882
CollectedResult {
902883
passed: Some(false),
903884
error: Some(ErrorInfo {
904885
code: actual_exit_code,
905-
stderr: Some(truncate_output(&output_for_error, 2000)),
886+
stderr: None,
906887
timeout: None,
907-
message: Some(mismatch_details.clone()),
888+
message: Some("expected test to fail but it passed".to_string()),
908889
}),
909890
uses_node_test,
910891
ignore_reason: None,
@@ -913,30 +894,80 @@ fn run_test(
913894
return TestResult::Failed {
914895
duration: None,
915896
output: format!(
916-
"Test failed but not in the expected way:\n{}\nActual output:\n{}\n{}",
917-
mismatch_details, output_for_error, debugging_command_text
897+
"Test was expected to fail but passed\n{}",
898+
debugging_command_text
918899
)
919900
.into_bytes(),
920901
};
921902
}
922903

923-
results
924-
.lock()
925-
.unwrap()
926-
.insert(data.test_path.clone(), collected);
904+
// When exitCode/output are omitted, any value is accepted.
905+
let exit_code_matches =
906+
ef.exit_code.map_or(true, |ec| actual_exit_code == Some(ec));
907+
let output_matches = ef.output.as_ref().map_or(true, |pattern| {
908+
util::wildcard_match_detailed(pattern, output_for_error).is_success()
909+
});
927910

928-
if success {
911+
if exit_code_matches && output_matches {
912+
// Failed as expected — treat as a pass
913+
results.lock().unwrap().insert(
914+
test_path.to_string(),
915+
CollectedResult {
916+
passed: Some(true),
917+
error: None,
918+
uses_node_test,
919+
ignore_reason: None,
920+
},
921+
);
929922
if *file_test_runner::NO_CAPTURE {
930923
test_util::eprintln!("{}", debugging_command_text);
931924
}
932-
TestResult::Passed { duration: None }
933-
} else {
934-
TestResult::Failed {
935-
duration: None,
936-
output: format!("{}\n{}", output_for_error, debugging_command_text)
937-
.into_bytes(),
925+
return TestResult::Passed { duration: None };
926+
}
927+
928+
// Failed, but not in the expected way
929+
let mut mismatch_details = String::new();
930+
if !exit_code_matches {
931+
mismatch_details.push_str(&format!(
932+
"Exit code mismatch: expected {:?}, got {:?}\n",
933+
ef.exit_code, actual_exit_code
934+
));
935+
}
936+
if !output_matches {
937+
let match_result = ef
938+
.output
939+
.as_ref()
940+
.map(|pattern| util::wildcard_match_detailed(pattern, output_for_error));
941+
if let Some(util::WildcardMatchResult::Fail(detail)) = match_result {
942+
mismatch_details
943+
.push_str(&format!("Output mismatch detail:\n{}\n", detail));
944+
} else {
945+
mismatch_details.push_str("Output did not match expected pattern\n");
938946
}
939947
}
948+
949+
results.lock().unwrap().insert(
950+
test_path.to_string(),
951+
CollectedResult {
952+
passed: Some(false),
953+
error: Some(ErrorInfo {
954+
code: actual_exit_code,
955+
stderr: Some(truncate_output(output_for_error, 2000)),
956+
timeout: None,
957+
message: Some(mismatch_details.clone()),
958+
}),
959+
uses_node_test,
960+
ignore_reason: None,
961+
},
962+
);
963+
TestResult::Failed {
964+
duration: None,
965+
output: format!(
966+
"Test failed but not in the expected way:\n{}\nActual output:\n{}\n{}",
967+
mismatch_details, output_for_error, debugging_command_text
968+
)
969+
.into_bytes(),
970+
}
940971
}
941972

942973
fn generate_report(results: &HashMap<String, CollectedResult>) {

0 commit comments

Comments
 (0)