Work on run api.

This commit is contained in:
jcamiel 2023-02-24 18:29:34 +01:00
parent e825e3dd5f
commit 704aebc6b4
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
16 changed files with 158 additions and 218 deletions

View File

@ -27,16 +27,16 @@ impl HurlResult {
/// Note: `content` is passed to this method to save asserts and
/// errors messages (with lines and columns). This parameter will be removed
/// soon and the original content will be accessible through the [`HurlResult`] instance.
pub fn to_json(&self, content: &str) -> serde_json::Value {
pub fn to_json(&self, content: &str, filename: &str) -> serde_json::Value {
let mut map = serde_json::Map::new();
map.insert(
"filename".to_string(),
serde_json::Value::String(self.filename.clone()),
serde_json::Value::String(filename.to_string()),
);
let entries = self
.entries
.iter()
.map(|e| e.to_json(&self.filename, content))
.map(|e| e.to_json(filename, content))
.collect();
map.insert("entries".to_string(), serde_json::Value::Array(entries));
map.insert("success".to_string(), serde_json::Value::Bool(self.success));

View File

@ -43,11 +43,15 @@ const EXIT_ERROR_RUNTIME: i32 = 3;
const EXIT_ERROR_ASSERT: i32 = 4;
const EXIT_ERROR_UNDEFINED: i32 = 127;
/// Structure that stores teh result of an Hurl file execution, and the content of the file.
/// This structure is temporary, as we want to move the `content` into [`HurlResult`].
struct Run {
content: String,
result: HurlResult,
/// Structure that stores the result of an Hurl file execution, and the content of the file.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HurlRun {
/// Source string for this [`HurlFile`]
pub content: String,
/// Filename of the content
pub filename: String,
pub hurl_file: HurlFile,
pub hurl_result: HurlResult,
}
/// Executes Hurl entry point.
@ -108,35 +112,36 @@ fn main() {
let content = cli::read_to_string(filename);
let content = unwrap_or_exit(content, EXIT_ERROR_PARSING, &base_logger);
// Our rich logger is using the Hurl filename and content to be able to report error
// with file content (line number, etc...)
let mut builder = LoggerBuilder::new();
let logger = builder
let logger = LoggerBuilder::new()
.color(color)
.verbose(verbose)
.test(cli_options.test)
.progress_bar(progress_bar)
.filename(filename)
.content(&content)
.build()
.unwrap();
.build();
let total = filenames.len();
logger.test_running(current + 1, total);
logger.test_running(filename, current + 1, total);
// We try to parse the text file to an HurlFile instance.
let hurl_file = parser::parse_hurl_file(&content);
if let Err(e) = hurl_file {
logger.error_rich(&e);
logger.error_rich(filename, &content, &e);
std::process::exit(EXIT_ERROR_PARSING);
}
// Now, we have a syntactically correct HurlFile instance, we can run it.
let hurl_file = hurl_file.unwrap();
let hurl_result = execute(&hurl_file, filename, current_dir, &cli_options, &logger);
let hurl_result = execute(
&hurl_file,
&content,
filename,
current_dir,
&cli_options,
&logger,
);
let success = hurl_result.success;
logger.test_completed(&hurl_result);
logger.test_completed(&hurl_result, filename);
// We can output the result, either the raw body or a structured JSON representation.
let output_body = success
@ -146,6 +151,7 @@ fn main() {
let include_headers = cli_options.include;
let result = output::write_body(
&hurl_result,
filename,
include_headers,
color,
&cli_options.output,
@ -155,13 +161,15 @@ fn main() {
}
if matches!(cli_options.output_type, cli::OutputType::Json) {
let result = output::write_json(&hurl_result, &content, &cli_options.output);
let result = output::write_json(&hurl_result, &content, filename, &cli_options.output);
unwrap_or_exit(result, EXIT_ERROR_RUNTIME, &base_logger);
}
let run = Run {
let run = HurlRun {
content,
result: hurl_result,
filename: filename.to_string(),
hurl_file,
hurl_result,
};
runs.push(run);
}
@ -186,16 +194,20 @@ fn main() {
if cli_options.test {
let duration = start.elapsed().as_millis();
let summary = get_summary(duration, &runs);
let summary = get_summary(&runs, duration);
base_logger.info(summary.as_str());
}
std::process::exit(exit_code(&runs));
}
/// Runs a Hurl format `content` originated form the file `filename` and returns a result.
/// Runs a Hurl file `hurl_file` and returns a result.
///
/// Original file `content` and `filename` are used to log rich asserts and errors
/// (including annotated source, line and column).
fn execute(
hurl_file: &HurlFile,
content: &str,
filename: &str,
current_dir: &Path,
cli_options: &cli::CliOptions,
@ -210,6 +222,7 @@ fn execute(
runner::run(
hurl_file,
content,
filename,
&mut client,
&runner_options,
@ -277,26 +290,21 @@ fn exit_with_error(message: &str, code: i32, logger: &BaseLogger) -> ! {
}
/// Create a JUnit report for this run.
fn create_junit_report(runs: &[Run], filename: &str) -> Result<(), cli::CliError> {
let mut testcases = vec![];
for run in runs.iter() {
let hurl_result = &run.result;
let content = &run.content;
let testcase = junit::Testcase::from(hurl_result, content);
testcases.push(testcase);
}
fn create_junit_report(runs: &[HurlRun], filename: &str) -> Result<(), cli::CliError> {
let testcases: Vec<junit::Testcase> = runs
.iter()
.map(|r| junit::Testcase::from(&r.hurl_result, &r.content, &r.filename))
.collect();
junit::write_report(filename, &testcases)?;
Ok(())
}
/// Create an HTML report for this run.
fn create_html_report(runs: &[Run], dir_path: &Path) -> Result<(), cli::CliError> {
fn create_html_report(runs: &[HurlRun], dir_path: &Path) -> Result<(), cli::CliError> {
let mut testcases = vec![];
for run in runs.iter() {
let hurl_result = &run.result;
let content = &run.content;
let testcase = html::Testcase::from(hurl_result);
testcase.write_html(content, dir_path)?;
let testcase = html::Testcase::from(&run.hurl_result, &run.filename);
testcase.write_html(&run.hurl_file, dir_path)?;
testcases.push(testcase);
}
html::write_report(dir_path, &testcases)?;
@ -304,11 +312,11 @@ fn create_html_report(runs: &[Run], dir_path: &Path) -> Result<(), cli::CliError
}
/// Returns an exit code for a list of HurlResult.
fn exit_code(runs: &[Run]) -> i32 {
fn exit_code(runs: &[HurlRun]) -> i32 {
let mut count_errors_runner = 0;
let mut count_errors_assert = 0;
for run in runs.iter() {
let errors = run.result.errors();
let errors = run.hurl_result.errors();
if errors.is_empty() {
} else if errors.iter().filter(|e| !e.assert).count() == 0 {
count_errors_assert += 1;
@ -356,7 +364,7 @@ fn get_input_files(
filenames
}
fn create_cookies_file(runs: &[Run], filename: &str) -> Result<(), cli::CliError> {
fn create_cookies_file(runs: &[HurlRun], filename: &str) -> Result<(), cli::CliError> {
let mut file = match std::fs::File::create(filename) {
Err(why) => {
return Err(cli::CliError {
@ -377,7 +385,7 @@ fn create_cookies_file(runs: &[Run], filename: &str) -> Result<(), cli::CliError
});
}
Some(run) => {
for cookie in run.result.cookies.clone() {
for cookie in run.hurl_result.cookies.clone() {
s.push_str(cookie.to_string().as_str());
s.push('\n');
}
@ -392,9 +400,9 @@ fn create_cookies_file(runs: &[Run], filename: &str) -> Result<(), cli::CliError
Ok(())
}
fn get_summary(duration: u128, runs: &[Run]) -> String {
fn get_summary(runs: &[HurlRun], duration: u128) -> String {
let total = runs.len();
let success = runs.iter().filter(|r| r.result.success).count();
let success = runs.iter().filter(|r| r.hurl_result.success).count();
let failed = total - success;
let mut s =
"--------------------------------------------------------------------------------\n"

View File

@ -19,18 +19,19 @@ use crate::output;
use crate::output::Error;
use crate::runner::HurlResult;
/// Writes the `hurl_result` JSON representation to the file `filename`.
/// Writes the `hurl_result` JSON representation to the file `filename_out`.
///
/// If `filename` is `None`, stdout is used. The original content of the Hurl
/// If `filename_out` is `None`, stdout is used. The original content of the Hurl
/// file is necessary in order to construct error fields with column, line number etc... when
/// processing failed asserts and captures.
pub fn write_json(
hurl_result: &HurlResult,
content: &str,
filename: &Option<String>,
filename_in: &str,
filename_out: &Option<String>,
) -> Result<(), Error> {
let json_result = hurl_result.to_json(content);
let json_result = hurl_result.to_json(content, filename_in);
let serialized = serde_json::to_string(&json_result).unwrap();
let s = format!("{serialized}\n");
output::write_output(&s.into_bytes(), filename)
output::write_output(&s.into_bytes(), filename_out)
}

View File

@ -24,15 +24,16 @@ use colored::Colorize;
use hurl_core::ast::SourceInfo;
use hurl_core::error::Error;
/// Writes the `hurl_result` last body response to the file `filename`.
/// Writes the `hurl_result` last body response to the file `filename_out`.
///
/// If `filename` is `None`, stdout is used. If `include_headers` is true, the last HTTP
/// response headers are written before the body response.
pub fn write_body(
hurl_result: &HurlResult,
filename_in: &str,
include_headers: bool,
color: bool,
filename: &Option<String>,
filename_out: &Option<String>,
logger: &Logger,
) -> Result<(), output::Error> {
// By default, we output the body response bytes of the last entry
@ -67,7 +68,7 @@ pub fn write_body(
response.body.clone()
};
output.append(&mut body);
let result = output::write_output(&output, filename);
let result = output::write_output(&output, filename_out);
if result.is_err() {
return Err(output::Error {
message: "Undefined error".to_string(),
@ -77,11 +78,10 @@ pub fn write_body(
logger.info("No response has been received");
}
} else {
let filename = &hurl_result.filename;
let source = if filename == "-" {
let source = if filename_in == "-" {
"".to_string()
} else {
format!("for file {filename}")
format!("for file {filename_in}")
};
logger.warning(format!("No entry have been executed {source}").as_str());
}

View File

@ -17,7 +17,7 @@
*/
use super::Error;
use crate::runner::HurlResult;
use hurl_core::parser;
use hurl_core::ast::HurlFile;
use std::io::Write;
use std::path::Path;
use uuid::Uuid;
@ -32,11 +32,11 @@ pub struct Testcase {
impl Testcase {
/// Creates an HTML testcase.
pub fn from(hurl_result: &HurlResult) -> Testcase {
pub fn from(hurl_result: &HurlResult, filename: &str) -> Testcase {
let id = Uuid::new_v4();
Testcase {
id: id.to_string(),
filename: hurl_result.filename.to_string(),
filename: filename.to_string(),
time_in_ms: hurl_result.time_in_ms,
success: hurl_result.success,
}
@ -45,7 +45,7 @@ impl Testcase {
/// 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> {
pub fn write_html(&self, hurl_file: &HurlFile, dir_path: &Path) -> Result<(), Error> {
let output_file = dir_path.join("store").join(format!("{}.html", self.id));
let parent = output_file.parent().expect("a parent");
@ -58,8 +58,6 @@ impl Testcase {
}
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()) {

View File

@ -16,7 +16,6 @@
*
*/
use crate::runner::HurlResult;
use crate::util::logger;
use xmltree::{Element, XMLNode};
@ -30,16 +29,16 @@ pub struct Testcase {
}
impl Testcase {
/// Creates an XML Junit &lt;testcase&gt; from an Hurl result.
pub fn from(hurl_result: &HurlResult, content: &str) -> Testcase {
let id = hurl_result.filename.clone();
let name = hurl_result.filename.clone();
/// Creates an XML Junit &lt;testcase&gt; from an [`HurlResult`].
pub fn from(hurl_result: &HurlResult, content: &str, filename: &str) -> Testcase {
let id = filename.to_string();
let name = filename.to_string();
let time_in_ms = hurl_result.time_in_ms;
let mut failures = vec![];
let mut errors = vec![];
for error in hurl_result.errors() {
let message = logger::error_string_no_color(&hurl_result.filename, content, error);
let message = logger::error_string_no_color(filename, content, error);
if error.assert {
failures.push(message);
} else {
@ -107,7 +106,6 @@ mod test {
#[test]
fn test_create_testcase_success() {
let hurl_result = HurlResult {
filename: "test.hurl".to_string(),
entries: vec![],
time_in_ms: 230,
success: true,
@ -116,7 +114,8 @@ mod test {
let mut buffer = Vec::new();
let content = "";
Testcase::from(&hurl_result, content)
let filename = "test.hurl";
Testcase::from(&hurl_result, content, filename)
.to_xml()
.write(&mut buffer)
.unwrap();
@ -131,8 +130,8 @@ mod test {
let content = r#"GET http://localhost:8000/not_found
HTTP/1.0 200
"#;
let filename = "test.hurl";
let hurl_result = HurlResult {
filename: "test.hurl".to_string(),
entries: vec![EntryResult {
entry_index: 1,
calls: vec![],
@ -153,7 +152,7 @@ HTTP/1.0 200
cookies: vec![],
};
let mut buffer = Vec::new();
Testcase::from(&hurl_result, content)
Testcase::from(&hurl_result, content, filename)
.to_xml()
.write(&mut buffer)
.unwrap();
@ -171,8 +170,8 @@ HTTP/1.0 200
#[test]
fn test_create_testcase_error() {
let content = "GET http://unknown";
let filename = "test.hurl";
let hurl_result = HurlResult {
filename: "test.hurl".to_string(),
entries: vec![EntryResult {
entry_index: 1,
calls: vec![],
@ -194,7 +193,7 @@ HTTP/1.0 200
cookies: vec![],
};
let mut buffer = Vec::new();
Testcase::from(&hurl_result, content)
Testcase::from(&hurl_result, content, filename)
.to_xml()
.write(&mut buffer)
.unwrap();

View File

@ -30,7 +30,6 @@ pub enum Verbosity {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HurlResult {
pub filename: String,
pub entries: Vec<EntryResult>,
pub time_in_ms: u128,
pub success: bool,

View File

@ -29,10 +29,10 @@ use crate::util::logger::LoggerBuilder;
use hurl_core::ast::VersionValue::VersionAnyLegacy;
use hurl_core::ast::*;
/// Runs a `hurl_file`, issue from the given `filename`, with
/// Runs a `hurl_file`, issue from the given `content`and `filename`, with
/// an `http_client`. Returns a [`HurlResult`] upon completion.
///
/// `filename` and `content` are used to display line base logs (for parsing error or asserts
/// `filename` and `content` are used to display rich logs (for parsing error or asserts
/// failures).
///
/// # Example
@ -45,20 +45,19 @@ use hurl_core::ast::*;
/// use hurl::http::ContextDir;
/// use hurl::runner;
/// use hurl::runner::{Value, RunnerOptionsBuilder, Verbosity};
/// use hurl::util::logger::{Logger, LoggerBuilder};
/// use hurl::util::logger::LoggerBuilder;
///
/// // Parse Hurl file
/// let filename = "sample.hurl";
/// let s = r#"
/// let content = r#"
/// GET http://localhost:8000/hello
/// HTTP/1.1 200
/// "#;
/// let hurl_file = parser::parse_hurl_file(s).unwrap();
/// let hurl_file = parser::parse_hurl_file(content).unwrap();
///
/// // Create an HTTP client
/// let mut client = http::Client::new(None);
/// let mut builder = LoggerBuilder::new();
/// let logger = builder.filename(filename).content(s).build().unwrap();
/// let logger = LoggerBuilder::new().build();
///
/// // Define runner options
/// let runner_options = RunnerOptionsBuilder::new()
@ -73,6 +72,7 @@ use hurl_core::ast::*;
/// // Run the hurl file
/// let hurl_results = runner::run(
/// &hurl_file,
/// content,
/// filename,
/// &mut client,
/// &runner_options,
@ -83,6 +83,7 @@ use hurl_core::ast::*;
/// ```
pub fn run(
hurl_file: &HurlFile,
content: &str,
filename: &str,
http_client: &mut http::Client,
runner_options: &RunnerOptions,
@ -110,16 +111,12 @@ pub fn run(
// function because entry options can modify the logger and we want the preamble
// "Executing entry..." to be displayed based on the entry level verbosity.
let entry_verbosity = entry::get_entry_verbosity(entry, &runner_options.verbosity);
let mut builder = LoggerBuilder::new();
let logger = builder
let logger = LoggerBuilder::new()
.color(logger.color)
.verbose(entry_verbosity.is_some())
.test(logger.test)
.progress_bar(entry_verbosity.is_none() && logger.progress_bar)
.filename(logger.filename)
.content(logger.content)
.build()
.unwrap();
.build();
if let Some(pre_entry) = runner_options.pre_entry {
let exit = pre_entry(entry.clone());
@ -133,7 +130,7 @@ pub fn run(
);
logger.debug_important(format!("Executing entry {entry_index}").as_str());
warn_deprecated(entry, &logger);
warn_deprecated(entry, filename, &logger);
logger.test_progress(entry_index, n);
@ -188,9 +185,9 @@ pub fn run(
for e in &entry_result.errors {
logger.test_erase_line();
if retry {
logger.debug_error(e);
logger.debug_error(filename, content, e);
} else {
logger.error_rich(e);
logger.error_rich(filename, content, e);
}
}
entries.push(entry_result);
@ -225,10 +222,8 @@ pub fn run(
let time_in_ms = start.elapsed().as_millis();
let cookies = http_client.get_cookie_storage();
let filename = filename.to_string();
let success = is_success(&entries);
HurlResult {
filename,
entries,
time_in_ms,
success,
@ -258,7 +253,7 @@ fn is_success(entries: &[EntryResult]) -> bool {
}
/// Logs deprecated syntax and provides alternatives.
fn warn_deprecated(entry: &Entry, logger: &Logger) {
fn warn_deprecated(entry: &Entry, filename: &str, logger: &Logger) {
// HTTP/* is used instead of HTTP.
if let Some(response) = &entry.response {
let version = &response.version;
@ -268,8 +263,7 @@ fn warn_deprecated(entry: &Entry, logger: &Logger) {
if version.value == VersionAnyLegacy {
logger.warning(
format!(
"{}:{}:{} 'HTTP/*' keyword is deprecated, please use 'HTTP' instead",
logger.filename, line, column
"{filename}:{line}:{column} 'HTTP/*' keyword is deprecated, please use 'HTTP' instead"
)
.as_str(),
);
@ -292,8 +286,7 @@ fn warn_deprecated(entry: &Entry, logger: &Logger) {
let template = template.to_string();
logger.warning(
format!(
"{}:{}:{} '```{}```' request body is deprecated, please use '`{}`' instead",
logger.filename, line, column, template, template
"{filename}:{line}:{column} '```{template}```' request body is deprecated, please use '`{template}`' instead"
)
.as_str(),
);
@ -314,8 +307,7 @@ fn warn_deprecated(entry: &Entry, logger: &Logger) {
let template = template.to_string();
logger.warning(
format!(
"{}:{}:{} '```{}```' response body is deprecated, please use '`{}`' instead",
logger.filename, line, column, template, template
"{filename}:{line}:{column} '```{template}```' response body is deprecated, please use '`{template}`' instead"
)
.as_str(),
);

View File

@ -66,28 +66,23 @@ impl BaseLogger {
}
/// A Hurl dedicated logger for an Hurl file. Contrary to [`BaseLogger`], this logger can display
/// rich error for parsing and runtime errors. As the rich errors can display user content,
/// this logger should have access to the content of the file being run.
pub struct Logger<'a> {
/// rich error for parsing and runtime errors.
pub struct Logger {
pub(crate) color: bool,
pub(crate) verbose: bool,
pub(crate) progress_bar: bool,
pub(crate) test: bool,
pub(crate) filename: &'a str,
pub(crate) content: &'a str,
}
#[derive(Default)]
pub struct LoggerBuilder<'a> {
pub struct LoggerBuilder {
color: bool,
verbose: bool,
progress_bar: bool,
test: bool,
filename: Option<&'a str>,
content: Option<&'a str>,
}
impl<'a> LoggerBuilder<'a> {
impl LoggerBuilder {
/// Returns a new Logger builder with a default values.
pub fn new() -> Self {
LoggerBuilder::default()
@ -105,18 +100,6 @@ impl<'a> LoggerBuilder<'a> {
self
}
/// Sets the filename used to display error, warning etc...
pub fn filename(&mut self, filename: &'a str) -> &mut Self {
self.filename = Some(filename);
self
}
/// Sets the content used to display error, warning etc...
pub fn content(&mut self, content: &'a str) -> &mut Self {
self.content = Some(content);
self
}
/// Sets progress bar.
pub fn progress_bar(&mut self, progress_bar: bool) -> &mut Self {
self.progress_bar = progress_bar;
@ -130,26 +113,17 @@ impl<'a> LoggerBuilder<'a> {
}
/// Creates a new logger.
pub fn build(&self) -> Result<Logger, &'static str> {
if self.filename.is_none() {
return Err("filename is not set");
}
if self.content.is_none() {
return Err("content is not set");
}
Ok(Logger {
pub fn build(&self) -> Logger {
Logger {
color: self.color,
verbose: self.verbose,
progress_bar: self.progress_bar,
test: self.test,
filename: self.filename.unwrap(),
content: self.content.unwrap(),
})
}
}
}
impl<'a> Logger<'a> {
impl Logger {
pub fn info(&self, message: &str) {
log_info(message)
}
@ -176,14 +150,14 @@ impl<'a> Logger<'a> {
}
}
pub fn debug_error(&self, error: &dyn Error) {
pub fn debug_error(&self, filename: &str, content: &str, error: &dyn Error) {
if !self.verbose {
return;
}
if self.color {
log_debug_error(self.filename, self.content, error)
log_debug_error(filename, content, error)
} else {
log_debug_error_no_color(self.filename, self.content, error)
log_debug_error_no_color(filename, content, error)
}
}
@ -247,11 +221,11 @@ impl<'a> Logger<'a> {
}
}
pub fn error_rich(&self, error: &dyn Error) {
pub fn error_rich(&self, filename: &str, content: &str, error: &dyn Error) {
if self.color {
log_error_rich(self.filename, self.content, error)
log_error_rich(filename, content, error)
} else {
log_error_rich_no_color(self.filename, self.content, error)
log_error_rich_no_color(filename, content, error)
}
}
@ -277,14 +251,14 @@ impl<'a> Logger<'a> {
}
}
pub fn test_running(&self, current: usize, total: usize) {
pub fn test_running(&self, filename: &str, current: usize, total: usize) {
if !self.test {
return;
}
if self.color {
log_test_running(self.filename, current, total)
log_test_running(filename, current, total)
} else {
log_test_running_no_color(self.filename, current, total)
log_test_running_no_color(filename, current, total)
}
}
@ -295,14 +269,14 @@ impl<'a> Logger<'a> {
log_test_progress(entry_index, count)
}
pub fn test_completed(&self, result: &HurlResult) {
pub fn test_completed(&self, result: &HurlResult, filename: &str) {
if !self.test {
return;
}
if self.color {
log_test_completed(result)
log_test_completed(result, filename)
} else {
log_test_completed_no_color(result)
log_test_completed_no_color(result, filename)
}
}
@ -473,7 +447,7 @@ fn progress_string(entry_index: usize, count: usize) -> String {
format!("[{completed}>{void}] {entry_index}/{count}")
}
fn log_test_completed(result: &HurlResult) {
fn log_test_completed(result: &HurlResult, filename: &str) {
let state = if result.success {
"Success".green().bold()
} else {
@ -482,19 +456,19 @@ fn log_test_completed(result: &HurlResult) {
let count = result.entries.iter().flat_map(|r| &r.calls).count();
eprintln!(
"{}: {} ({} request(s) in {} ms)",
result.filename.bold(),
filename.bold(),
state,
count,
result.time_in_ms
)
}
fn log_test_completed_no_color(result: &HurlResult) {
fn log_test_completed_no_color(result: &HurlResult, filename: &str) {
let state = if result.success { "Success" } else { "Failure" };
let count = result.entries.iter().flat_map(|r| &r.calls).count();
eprintln!(
"{}: {} ({} request(s) in {} ms)",
result.filename, state, count, result.time_in_ms
filename, state, count, result.time_in_ms
)
}

View File

@ -42,8 +42,7 @@ fn test_hello() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/hello");
assert_eq!(
@ -85,8 +84,7 @@ fn test_put() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Put,
url: "http://localhost:8000/put".to_string(),
@ -118,8 +116,7 @@ fn test_patch() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Patch,
url: "http://localhost:8000/patch/file.txt".to_string(),
@ -168,8 +165,7 @@ fn test_custom_headers() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Get,
@ -208,8 +204,7 @@ fn test_querystring_params() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Get,
@ -256,8 +251,7 @@ fn test_form_params() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Post,
@ -320,8 +314,7 @@ fn test_form_params() {
#[test]
fn test_redirect() {
let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let options = ClientOptions::default();
let mut client = Client::new(None);
@ -347,8 +340,7 @@ fn test_redirect() {
#[test]
fn test_follow_location() {
let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let options = ClientOptions {
follow_location: true,
@ -413,8 +405,7 @@ fn test_max_redirect() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/redirect/15");
assert_eq!(
@ -446,8 +437,7 @@ fn test_multipart_form_data() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Post,
@ -505,8 +495,7 @@ fn test_post_bytes() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Post,
@ -538,8 +527,7 @@ fn test_expect() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Post,
@ -578,8 +566,7 @@ fn test_basic_authentication() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/basic-authentication");
assert_eq!(
@ -621,8 +608,7 @@ fn test_cacert() {
..Default::default()
};
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("https://localhost:8001/hello");
let (_, response) = client.execute(&request_spec, &options, &logger).unwrap();
@ -633,8 +619,7 @@ fn test_cacert() {
fn test_error_could_not_resolve_host() {
let options = ClientOptions::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://unknown");
let error = client
@ -658,8 +643,7 @@ fn test_error_could_not_resolve_host() {
fn test_error_fail_to_connect() {
let options = ClientOptions::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:9999");
let error = client
@ -706,8 +690,7 @@ fn test_error_could_not_resolve_proxy_name() {
..Default::default()
};
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/hello");
let error = client
@ -731,8 +714,7 @@ fn test_error_could_not_resolve_proxy_name() {
fn test_error_ssl() {
let options = ClientOptions::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("https://localhost:8001/hello");
let error = client
@ -775,8 +757,7 @@ fn test_timeout() {
..Default::default()
};
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/timeout");
let error = client
@ -803,8 +784,7 @@ fn test_accept_encoding() {
..Default::default()
};
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/compressed/gzip");
let (request, response) = client.execute(&request_spec, &options, &logger).unwrap();
assert!(request.headers.contains(&Header {
@ -826,8 +806,7 @@ fn test_connect_timeout() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://10.0.0.0");
assert_eq!(
@ -870,8 +849,7 @@ fn test_cookie() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Get,
@ -909,8 +887,7 @@ fn test_multiple_request_cookies() {
let options = ClientOptions::default();
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Get,
@ -949,8 +926,7 @@ fn test_multiple_request_cookies() {
fn test_cookie_storage() {
let options = ClientOptions::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec =
default_get_request("http://localhost:8000/cookies/set-session-cookie2-valueA");
@ -996,8 +972,7 @@ fn test_cookie_file() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(Some("tests/cookies.txt".to_string()));
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec =
default_get_request("http://localhost:8000/cookies/assert-that-cookie2-is-valueA");
@ -1029,8 +1004,7 @@ fn test_proxy() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = default_get_request("http://localhost:8000/proxy");
assert_eq!(
@ -1050,8 +1024,7 @@ fn test_insecure() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
assert_eq!(options.curl_args(), vec!["--insecure".to_string()]);
let request_spec = default_get_request("https://localhost:8001/hello");
assert_eq!(
@ -1071,8 +1044,7 @@ fn test_head() {
};
let context_dir = ContextDir::default();
let mut client = Client::new(None);
let mut builder = LoggerBuilder::new();
let logger = builder.filename("").content("").build().unwrap();
let logger = LoggerBuilder::new().build();
let request_spec = RequestSpec {
method: Method::Head,

View File

@ -94,8 +94,7 @@ fn test_hello() {
// been built from a text content.
let content = "";
let filename = "filename";
let mut builder = LoggerBuilder::new();
let logger = builder.filename(filename).content(content).build().unwrap();
let logger = LoggerBuilder::new().build();
let source_info = SourceInfo {
start: Pos { line: 1, column: 1 },
@ -138,7 +137,8 @@ fn test_hello() {
let runner_options = RunnerOptions::default();
runner::run(
&hurl_file,
"filename",
content,
filename,
&mut client,
&runner_options,
&variables,

View File

@ -25,7 +25,7 @@ trait Htmlable {
///
/// If `standalone` is true, a complete HTML body with inline styling is returned.
/// Otherwise, a `<pre>` HTML tag is returned, without styling.
pub fn format(hurl_file: HurlFile, standalone: bool) -> String {
pub fn format(hurl_file: &HurlFile, standalone: bool) -> String {
if standalone {
format_standalone(hurl_file)
} else {
@ -33,7 +33,7 @@ pub fn format(hurl_file: HurlFile, standalone: bool) -> String {
}
}
fn format_standalone(hurl_file: HurlFile) -> String {
fn format_standalone(hurl_file: &HurlFile) -> String {
let css = include_str!("hurl.css");
let body = hurl_file.to_html();

View File

@ -15,8 +15,6 @@
* limitations under the License.
*
*/
use crate::ast::HurlFile;
pub type ParseResult<'a, T> = Result<T, Error>;
pub type ParseFunc<'a, T> = fn(&mut Reader) -> ParseResult<'a, T>;
@ -32,6 +30,7 @@ pub use self::json::number_value as parse_json_number;
pub use self::json::parse as parse_json;
pub use self::reader::Reader;
pub use self::template::templatize;
use crate::ast::HurlFile;
mod base64;
mod bytes;

View File

@ -266,7 +266,6 @@ mod tests {
#[test]
fn test_entry() {
let mut reader = Reader::init("GET http://google.fr");
//println!("{:?}", entry(&mut reader));
let e = entry(&mut reader).unwrap();
assert_eq!(e.request.method, Method::Get);
assert_eq!(reader.state.cursor, 20);
@ -277,7 +276,6 @@ mod tests {
let mut reader = Reader::init("GET http://google.fr\nGET http://google.fr");
let e = entry(&mut reader).unwrap();
//println!("{:?}", e);
assert_eq!(e.request.method, Method::Get);
assert_eq!(reader.state.cursor, 21);
assert_eq!(reader.state.pos.line, 2);

View File

@ -23,7 +23,7 @@ use hurl_core::ast::*;
use super::serialize_json::*;
pub fn format(hurl_file: HurlFile) -> String {
pub fn format(hurl_file: &HurlFile) -> String {
hurl_file.to_json().format()
}

View File

@ -206,7 +206,7 @@ fn main() {
let log_parser_error =
cli::make_logger_parser_error(lines.clone(), output_color, optional_filename.clone());
let log_linter_error = cli::make_logger_linter_error(lines, output_color, optional_filename);
match parser::parse_hurl_file(contents.as_str()) {
match parser::parse_hurl_file(&contents) {
Err(e) => {
log_parser_error(&e, false);
process::exit(2);
@ -227,10 +227,10 @@ fn main() {
};
format::format_text(hurl_file, output_color)
}
"json" => format::format_json(hurl_file),
"json" => format::format_json(&hurl_file),
"html" => {
let standalone = cli::has_flag(&matches, "standalone");
hurl_core::format::format_html(hurl_file, standalone)
hurl_core::format::format_html(&hurl_file, standalone)
}
"ast" => format!("{hurl_file:#?}"),
_ => {