diff --git a/packages/hurl/src/cli/mod.rs b/packages/hurl/src/cli/mod.rs index e88ada9ca..fd85da280 100644 --- a/packages/hurl/src/cli/mod.rs +++ b/packages/hurl/src/cli/mod.rs @@ -16,6 +16,7 @@ * */ +use crate::report; use std::error::Error; use std::fmt; @@ -26,7 +27,7 @@ pub use self::options::parse_options; pub use self::options::{CliOptions, OutputType}; pub use self::variables::parse as parse_variable; pub use self::variables::parse_value as parse_variable_value; -pub use crate::util::logger::{error_string_no_color, Logger}; +pub use crate::util::logger::Logger; mod fs; pub mod interactive; @@ -57,9 +58,13 @@ impl From<&str> for CliError { impl From for CliError { fn from(e: String) -> Self { - Self { - message: format!("{e:?}"), - } + Self { message: e } + } +} + +impl From for CliError { + fn from(e: report::Error) -> Self { + Self { message: e.message } } } diff --git a/packages/hurl/src/json/result.rs b/packages/hurl/src/json/result.rs index 62cb0361e..946d3b215 100644 --- a/packages/hurl/src/json/result.rs +++ b/packages/hurl/src/json/result.rs @@ -15,12 +15,11 @@ * limitations under the License. * */ - -use crate::cli; use crate::http::{ Cookie, Header, Param, Request, RequestCookie, Response, ResponseCookie, Version, }; use crate::runner::{AssertResult, Call, CaptureResult, EntryResult, HurlResult}; +use crate::util::logger; impl HurlResult { /// Serializes an [`HurlResult`] to a JSON representation. @@ -258,7 +257,7 @@ impl AssertResult { map.insert("success".to_string(), serde_json::Value::Bool(success)); if let Some(err) = self.error() { - let message = cli::error_string_no_color(filename, content, &err); + let message = logger::error_string_no_color(filename, content, &err); map.insert("message".to_string(), serde_json::Value::String(message)); } map.insert( diff --git a/packages/hurl/src/main.rs b/packages/hurl/src/main.rs index 4cea3d87d..1f84cbf3c 100644 --- a/packages/hurl/src/main.rs +++ b/packages/hurl/src/main.rs @@ -32,11 +32,9 @@ use hurl::runner; use hurl::runner::HurlResult; use hurl::runner::RunnerOptions; use hurl::util::logger::{BaseLogger, LoggerBuilder}; -use hurl::util::path; use hurl::{cli, output}; use hurl_core::ast::HurlFile; use hurl_core::parser; -use junit::Testcase; use report::junit; const EXIT_OK: i32 = 0; @@ -285,21 +283,24 @@ fn create_junit_report(runs: &[Run], filename: &str) -> Result<(), CliError> { for run in runs.iter() { let hurl_result = &run.result; let content = &run.content; - let testcase = Testcase::from(hurl_result, content); + let testcase = junit::Testcase::from(hurl_result, content); testcases.push(testcase); } - junit::write_report(filename, &testcases) + junit::write_report(filename, &testcases)?; + Ok(()) } /// Create an HTML report for this run. fn create_html_report(runs: &[Run], dir_path: &Path) -> Result<(), CliError> { - let hurl_results = runs.iter().map(|it| &it.result).collect::>(); - html::write_report(dir_path, &hurl_results)?; - + let mut testcases = vec![]; for run in runs.iter() { - let filename = &run.result.filename; - format_html(filename, dir_path)?; + let hurl_result = &run.result; + let content = &run.content; + let testcase = html::Testcase::from(hurl_result); + testcase.write_html(content, dir_path)?; + testcases.push(testcase); } + html::write_report(dir_path, &testcases)?; Ok(()) } @@ -356,41 +357,6 @@ fn get_input_files( filenames } -fn format_html(input_file: &str, dir_path: &Path) -> Result<(), CliError> { - let relative_input_file = path::canonicalize_filename(input_file); - let absolute_input_file = dir_path.join(format!("{relative_input_file}.html")); - - let parent = absolute_input_file.parent().expect("a parent"); - std::fs::create_dir_all(parent).unwrap(); - let mut file = match std::fs::File::create(&absolute_input_file) { - Err(why) => { - return Err(CliError { - message: format!( - "Issue writing to {}: {:?}", - absolute_input_file.display(), - why - ), - }); - } - Ok(file) => file, - }; - let content = cli::read_to_string(input_file).expect("readable hurl file"); - let hurl_file = parser::parse_hurl_file(content.as_str()).expect("valid hurl file"); - - let s = hurl_core::format::format_html(hurl_file, true); - - if let Err(why) = file.write_all(s.as_bytes()) { - return Err(CliError { - message: format!( - "Issue writing to {}: {:?}", - absolute_input_file.display(), - why - ), - }); - } - Ok(()) -} - fn create_cookies_file(runs: &[Run], filename: &str) -> Result<(), CliError> { let mut file = match std::fs::File::create(filename) { Err(why) => { diff --git a/packages/hurl/src/report/html/mod.rs b/packages/hurl/src/report/html/mod.rs index 7c5cc8d06..798b666fc 100644 --- a/packages/hurl/src/report/html/mod.rs +++ b/packages/hurl/src/report/html/mod.rs @@ -18,12 +18,14 @@ //! HTML report -use crate::cli::CliError; -use crate::runner::HurlResult; +mod testcase; + +use crate::report::Error; use crate::util::path; use chrono::{DateTime, Local}; use std::io::Write; use std::path::Path; +pub use testcase::Testcase; /// The test result to be displayed in an HTML page /// @@ -36,17 +38,17 @@ struct HTMLResult { pub success: bool, } -/// Creates and HTML report for this list of [`HurlResult`] at `dir_path`/index.html. +/// Creates and HTML report for this list of [`Testcase`] at `dir_path`/index.html. /// /// If the report already exists, results are merged. -pub fn write_report(dir_path: &Path, hurl_results: &[&HurlResult]) -> Result<(), CliError> { +pub fn write_report(dir_path: &Path, testcases: &[Testcase]) -> Result<(), Error> { let index_path = dir_path.join("index.html"); let mut results = parse_html(&index_path)?; - for result in hurl_results.iter() { + for testcase in testcases { let html_result = HTMLResult { - filename: path::canonicalize_filename(&result.filename), - time_in_ms: result.time_in_ms, - success: result.success, + filename: path::canonicalize_filename(&testcase.filename), + time_in_ms: testcase.time_in_ms, + success: testcase.success, }; results.push(html_result); } @@ -56,14 +58,14 @@ pub fn write_report(dir_path: &Path, hurl_results: &[&HurlResult]) -> Result<(), let file_path = index_path; let mut file = match std::fs::File::create(&file_path) { Err(why) => { - return Err(CliError { + return Err(Error { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(file) => file, }; if let Err(why) = file.write_all(s.as_bytes()) { - return Err(CliError { + return Err(Error { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } @@ -71,26 +73,26 @@ pub fn write_report(dir_path: &Path, hurl_results: &[&HurlResult]) -> Result<(), let file_path = dir_path.join("report.css"); let mut file = match std::fs::File::create(&file_path) { Err(why) => { - return Err(CliError { + return Err(Error { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(file) => file, }; if let Err(why) = file.write_all(include_bytes!("../report.css")) { - return Err(CliError { + return Err(Error { message: format!("Issue writing to {}: {:?}", file_path.display(), why), }); } Ok(()) } -fn parse_html(path: &Path) -> Result, CliError> { +fn parse_html(path: &Path) -> Result, Error> { if path.exists() { let s = match std::fs::read_to_string(path) { Ok(s) => s, Err(why) => { - return Err(CliError { + return Err(Error { message: format!("Issue reading {} to string to {:?}", path.display(), why), }); } diff --git a/packages/hurl/src/report/html/testcase.rs b/packages/hurl/src/report/html/testcase.rs new file mode 100644 index 000000000..7fa2228b7 --- /dev/null +++ b/packages/hurl/src/report/html/testcase.rs @@ -0,0 +1,80 @@ +/* + * Hurl (https://hurl.dev) + * Copyright (C) 2023 Orange + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +use super::Error; +use crate::runner::HurlResult; +use crate::util::path; +use hurl_core::parser; +use std::io::Write; +use std::path::Path; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Testcase { + id: String, + pub filename: String, + pub success: bool, + pub time_in_ms: u128, +} + +impl Testcase { + /// Creates an HTML testcase. + pub fn from(hurl_result: &HurlResult) -> Testcase { + Testcase { + id: "to-be-defined".to_string(), + filename: hurl_result.filename.to_string(), + time_in_ms: hurl_result.time_in_ms, + success: hurl_result.success, + } + } + + /// Exports a [`Testcase`] to HTML. + /// + /// For the moment, it's just an export of this HTML file, with syntax colored. + pub fn write_html(&self, content: &str, dir_path: &Path) -> Result<(), Error> { + let relative_input_file = path::canonicalize_filename(&self.filename); + let absolute_input_file = dir_path.join(format!("{relative_input_file}.html")); + + let parent = absolute_input_file.parent().expect("a parent"); + std::fs::create_dir_all(parent).unwrap(); + let mut file = match std::fs::File::create(&absolute_input_file) { + Err(why) => { + return Err(Error { + message: format!( + "Issue writing to {}: {:?}", + absolute_input_file.display(), + why + ), + }); + } + Ok(file) => file, + }; + let hurl_file = parser::parse_hurl_file(content).expect("valid hurl file"); + + let s = hurl_core::format::format_html(hurl_file, true); + + if let Err(why) = file.write_all(s.as_bytes()) { + return Err(Error { + message: format!( + "Issue writing to {}: {:?}", + absolute_input_file.display(), + why + ), + }); + } + Ok(()) + } +} diff --git a/packages/hurl/src/report/junit/mod.rs b/packages/hurl/src/report/junit/mod.rs index 0610d412f..06b6d2e5f 100644 --- a/packages/hurl/src/report/junit/mod.rs +++ b/packages/hurl/src/report/junit/mod.rs @@ -54,16 +54,15 @@ //! //! ``` //! +mod testcase; -use crate::cli::CliError; +use crate::report::Error; use std::fs::File; pub use testcase::Testcase; use xmltree::{Element, XMLNode}; -mod testcase; - /// Creates a JUnit from a list of `testcases`. -pub fn write_report(filename: &str, testcases: &[Testcase]) -> Result<(), CliError> { +pub fn write_report(filename: &str, testcases: &[Testcase]) -> Result<(), Error> { let mut testsuites = vec![]; let path = std::path::Path::new(&filename); @@ -71,7 +70,7 @@ pub fn write_report(filename: &str, testcases: &[Testcase]) -> Result<(), CliErr let s = match std::fs::read_to_string(path) { Ok(s) => s, Err(why) => { - return Err(CliError { + return Err(Error { message: format!("Issue reading {} to string to {:?}", path.display(), why), }); } @@ -97,14 +96,14 @@ pub fn write_report(filename: &str, testcases: &[Testcase]) -> Result<(), CliErr let file = match File::create(filename) { Ok(f) => f, Err(e) => { - return Err(CliError { + return Err(Error { message: format!("Failed to produce junit report: {e:?}"), }); } }; match report.write(file) { Ok(_) => Ok(()), - Err(e) => Err(CliError { + Err(e) => Err(Error { message: format!("Failed to produce junit report: {e:?}"), }), } diff --git a/packages/hurl/src/report/junit/testcase.rs b/packages/hurl/src/report/junit/testcase.rs index fe69cb217..8dda5cb4b 100644 --- a/packages/hurl/src/report/junit/testcase.rs +++ b/packages/hurl/src/report/junit/testcase.rs @@ -15,10 +15,9 @@ * limitations under the License. * */ - -use crate::cli; use crate::runner::HurlResult; +use crate::util::logger; use xmltree::{Element, XMLNode}; #[derive(Clone, Debug, PartialEq, Eq)] @@ -40,7 +39,7 @@ impl Testcase { let mut errors = vec![]; for error in hurl_result.errors() { - let message = cli::error_string_no_color(&hurl_result.filename, content, error); + let message = logger::error_string_no_color(&hurl_result.filename, content, error); if error.assert { failures.push(message); } else { diff --git a/packages/hurl/src/report/mod.rs b/packages/hurl/src/report/mod.rs index a38144839..59e53d237 100644 --- a/packages/hurl/src/report/mod.rs +++ b/packages/hurl/src/report/mod.rs @@ -20,3 +20,8 @@ pub mod html; pub mod junit; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Error { + pub message: String, +}