diff --git a/fixtures/TEST_DETAILED_JSON_OUTPUT_ERROR.md b/fixtures/TEST_DETAILED_JSON_OUTPUT_ERROR.md new file mode 100644 index 0000000000..81e0535c5d --- /dev/null +++ b/fixtures/TEST_DETAILED_JSON_OUTPUT_ERROR.md @@ -0,0 +1,8 @@ +# Test detailed JSON output error + +This file is used to test if the error details are parsed properly in the json +format. + +[The website](https://expired.badssl.com/) produce SSL expired certificate +error. Such network error has no status code but it can be identified by error +status details. diff --git a/lychee-bin/tests/cli.rs b/lychee-bin/tests/cli.rs index e31a1561be..616e2388a4 100644 --- a/lychee-bin/tests/cli.rs +++ b/lychee-bin/tests/cli.rs @@ -133,6 +133,36 @@ mod cli { Ok(()) } + #[test] + fn test_detailed_json_output_on_error() -> Result<()> { + let test_path = fixtures_path().join("TEST_DETAILED_JSON_OUTPUT_ERROR.md"); + + let mut cmd = main_command(); + cmd.arg("--format") + .arg("json") + .arg(&test_path) + .assert() + .failure() + .code(2); + + let output = cmd.output()?; + + // Check that the output is valid JSON + assert!(serde_json::from_slice::(&output.stdout).is_ok()); + + // Parse site error status from the fail_map + let output_json = serde_json::from_slice::(&output.stdout).unwrap(); + let site_error_status = &output_json["fail_map"][&test_path.to_str().unwrap()][0]["status"]; + + assert_eq!( + "error:0A000086:SSL routines:tls_post_process_server_certificate:\ + certificate verify failed:../ssl/statem/statem_clnt.c:1883: \ + (certificate has expired)", + site_error_status["details"] + ); + Ok(()) + } + #[test] fn test_exclude_all_private() -> Result<()> { test_json_output!( diff --git a/lychee-lib/src/types/status.rs b/lychee-lib/src/types/status.rs index 7360128e88..a4a9a01fb5 100644 --- a/lychee-lib/src/types/status.rs +++ b/lychee-lib/src/types/status.rs @@ -68,6 +68,10 @@ impl Serialize for Status { s = serializer.serialize_struct("Status", 2)?; s.serialize_field("text", &self.to_string())?; s.serialize_field("code", &code.as_u16())?; + } else if let Some(details) = self.details() { + s = serializer.serialize_struct("Status", 2)?; + s.serialize_field("text", &self.to_string())?; + s.serialize_field("details", &details.to_string())?; } else { s = serializer.serialize_struct("Status", 1)?; s.serialize_field("text", &self.to_string())?;