[go: up one dir, main page]

toml-test 0.3.2

Verify Rust TOML parsers
Documentation
use std::io::Write;

pub trait Encoder {
    fn encode(&self, data: crate::decoded::Decoded) -> Result<String, crate::Error>;

    fn verify_valid_case(&self, decoded: &[u8], fixture: &dyn Decoder) -> Result<(), crate::Error> {
        let decoded_expected = crate::decoded::Decoded::from_slice(decoded)?;
        let actual = self.encode(decoded_expected.clone())?;
        let decoded_actual = fixture.decode(actual.as_bytes()).map_err(|err| {
            crate::Error::new(format!(
                "Could not parse encoded TOML: {}\n```\n{}\n```",
                err, actual
            ))
        })?;

        if decoded_actual == decoded_expected {
            Ok(())
        } else {
            Err(crate::Error::new(format!(
                "Unexpected decoding.\nExpected\n{}\nActual\n{}",
                decoded_expected.to_string_pretty().unwrap(),
                decoded_actual.to_string_pretty().unwrap()
            )))
        }
    }

    fn name(&self) -> &str;
}

pub trait Decoder {
    fn decode(&self, data: &[u8]) -> Result<crate::decoded::Decoded, crate::Error>;

    fn verify_valid_case(&self, fixture: &[u8], expected: &[u8]) -> Result<(), crate::Error> {
        let actual = self.decode(fixture)?;
        let expected = crate::decoded::Decoded::from_slice(expected)?;
        if actual == expected {
            Ok(())
        } else {
            Err(crate::Error::new(format!(
                "Unexpected decoding.\nExpected\n{}\nActual\n{}",
                expected.to_string_pretty().unwrap(),
                actual.to_string_pretty().unwrap()
            )))
        }
    }

    fn verify_invalid_case(&self, fixture: &[u8]) -> Result<crate::Error, crate::Error> {
        match self.decode(fixture) {
            Ok(value) => Err(crate::Error::new(format!(
                "Should have failed but got:\n{}",
                value.to_string_pretty().unwrap()
            ))),
            Err(err) => Ok(err),
        }
    }

    fn name(&self) -> &str;
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Command {
    bin: std::path::PathBuf,
}

impl Command {
    pub fn new(path: impl AsRef<std::path::Path>) -> Self {
        Self {
            bin: path.as_ref().to_owned(),
        }
    }
}

impl Encoder for Command {
    fn encode(&self, data: crate::decoded::Decoded) -> Result<String, crate::Error> {
        let data = data.to_string_pretty()?;

        let mut cmd = std::process::Command::new(&self.bin);
        cmd.stdin(std::process::Stdio::piped())
            .stdout(std::process::Stdio::piped())
            .stderr(std::process::Stdio::piped());
        let child = cmd.spawn().map_err(crate::Error::new)?;
        child
            .stdin
            .as_ref()
            .unwrap()
            .write_all(data.as_bytes())
            .map_err(crate::Error::new)?;

        let output = child.wait_with_output().map_err(crate::Error::new)?;
        if output.status.success() {
            let output = String::from_utf8(output.stdout).map_err(crate::Error::new)?;
            Ok(output)
        } else {
            let message = String::from_utf8_lossy(&output.stderr);
            Err(crate::Error::new(format!(
                "{} failed with {:?}: {}",
                self.bin.display(),
                output.status.code(),
                message
            )))
        }
    }

    fn name(&self) -> &str {
        self.bin.to_str().expect("we'll always get valid UTF-8")
    }
}

impl Decoder for Command {
    fn decode(&self, data: &[u8]) -> Result<crate::decoded::Decoded, crate::Error> {
        let mut cmd = std::process::Command::new(&self.bin);
        cmd.stdin(std::process::Stdio::piped())
            .stdout(std::process::Stdio::piped())
            .stderr(std::process::Stdio::piped());
        let child = cmd.spawn().map_err(crate::Error::new)?;
        child
            .stdin
            .as_ref()
            .unwrap()
            .write_all(data)
            .map_err(crate::Error::new)?;

        let output = child.wait_with_output().map_err(crate::Error::new)?;
        if output.status.success() {
            let output =
                crate::decoded::Decoded::from_slice(&output.stdout).map_err(crate::Error::new)?;
            Ok(output)
        } else {
            let message = String::from_utf8_lossy(&output.stderr);
            Err(crate::Error::new(format!(
                "{} failed with {:?}: {}",
                self.bin.display(),
                output.status.code(),
                message
            )))
        }
    }

    fn name(&self) -> &str {
        self.bin.to_str().expect("we'll always get valid UTF-8")
    }
}