tarn 0.6.2

CLI-first API testing tool
Documentation
pub mod curl;
pub mod html;
pub mod human;
pub mod json;
pub mod junit;
pub mod progress;
pub mod redaction;
pub mod tap;

use crate::assert::types::RunResult;
use std::path::PathBuf;
use std::str::FromStr;

/// Options that tweak how test results are rendered.
#[derive(Debug, Clone, Copy, Default)]
pub struct RenderOptions {
    /// Show only failed tests/steps in the output. Summary counts stay accurate.
    pub only_failed: bool,
}

/// Output format for test results.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutputFormat {
    Human,
    Json,
    Junit,
    Tap,
    Html,
    Curl,
    CurlAll,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutputTarget {
    pub format: OutputFormat,
    pub path: Option<PathBuf>,
}

impl FromStr for OutputFormat {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "human" => Ok(OutputFormat::Human),
            "json" => Ok(OutputFormat::Json),
            "junit" => Ok(OutputFormat::Junit),
            "tap" => Ok(OutputFormat::Tap),
            "html" => Ok(OutputFormat::Html),
            "curl" => Ok(OutputFormat::Curl),
            "curl-all" => Ok(OutputFormat::CurlAll),
            other => Err(format!("Unknown output format: '{}'", other)),
        }
    }
}

impl FromStr for OutputTarget {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (format_raw, path) = match s.split_once('=') {
            Some((format, path)) => (format, Some(PathBuf::from(path))),
            None => (s, None),
        };

        let format = format_raw.parse::<OutputFormat>()?;
        Ok(Self { format, path })
    }
}

impl OutputTarget {
    pub fn writes_to_stdout(&self) -> bool {
        self.path.is_none() && self.format != OutputFormat::Html
    }
}

/// Render test results in the specified format.
pub fn render(result: &RunResult, format: OutputFormat) -> String {
    render_with_options(result, format, RenderOptions::default())
}

/// Render test results in the specified format with rendering options.
pub fn render_with_options(
    result: &RunResult,
    format: OutputFormat,
    opts: RenderOptions,
) -> String {
    match format {
        OutputFormat::Human => human::render_with_options(result, opts),
        OutputFormat::Json => {
            json::render_with_options(result, json::JsonOutputMode::Verbose, opts)
        }
        OutputFormat::Junit => junit::render(result),
        OutputFormat::Tap => tap::render(result),
        OutputFormat::Html => html::render(result),
        OutputFormat::Curl => curl::render_failures(result),
        OutputFormat::CurlAll => curl::render_all(result),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn output_format_from_str() {
        assert_eq!("human".parse::<OutputFormat>(), Ok(OutputFormat::Human));
        assert_eq!("json".parse::<OutputFormat>(), Ok(OutputFormat::Json));
        assert_eq!("junit".parse::<OutputFormat>(), Ok(OutputFormat::Junit));
        assert_eq!("tap".parse::<OutputFormat>(), Ok(OutputFormat::Tap));
        assert_eq!("html".parse::<OutputFormat>(), Ok(OutputFormat::Html));
        assert_eq!("curl".parse::<OutputFormat>(), Ok(OutputFormat::Curl));
        assert_eq!(
            "curl-all".parse::<OutputFormat>(),
            Ok(OutputFormat::CurlAll)
        );
        assert_eq!("JSON".parse::<OutputFormat>(), Ok(OutputFormat::Json));
        assert_eq!("HTML".parse::<OutputFormat>(), Ok(OutputFormat::Html));
        assert!("unknown".parse::<OutputFormat>().is_err());
    }

    #[test]
    fn output_target_from_format_only() {
        assert_eq!(
            "json".parse::<OutputTarget>(),
            Ok(OutputTarget {
                format: OutputFormat::Json,
                path: None,
            })
        );
    }

    #[test]
    fn output_target_from_format_and_path() {
        assert_eq!(
            "junit=reports/junit.xml".parse::<OutputTarget>(),
            Ok(OutputTarget {
                format: OutputFormat::Junit,
                path: Some(PathBuf::from("reports/junit.xml")),
            })
        );
    }

    #[test]
    fn html_without_path_does_not_write_to_stdout() {
        let target = "html".parse::<OutputTarget>().unwrap();
        assert!(!target.writes_to_stdout());
    }
}