mq-conv 0.1.4

A CLI tool for converting various file formats to Markdown
Documentation
use std::io::Write;

use crate::converter::Converter;
use crate::error::{Error, Result};
use crate::formats::structured;

pub struct YamlConverter;

impl Converter for YamlConverter {
    fn format_name(&self) -> &'static str {
        "yaml"
    }

    fn convert(&self, input: &[u8], writer: &mut dyn Write) -> Result<()> {
        let value: serde_yaml::Value =
            serde_yaml::from_slice(input).map_err(|e| Error::Conversion {
                format: "yaml",
                message: e.to_string(),
            })?;

        let structured_value = structured::Value::from(value);
        structured::write_value_as_markdown(writer, &structured_value)?;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::converter::Converter;
    use pretty_assertions::assert_eq;
    use rstest::rstest;

    fn convert(input: &str) -> String {
        let converter = YamlConverter;
        let mut output = Vec::new();
        converter.convert(input.as_bytes(), &mut output).unwrap();
        String::from_utf8(output).unwrap()
    }

    #[rstest]
    #[case::flat_mapping(
        "name: Alice\nage: 30",
        "| Key | Value |\n|---|---|\n| name | Alice |\n| age | 30 |\n\n"
    )]
    #[case::nested_mapping(
        "user:\n  name: Bob\n  city: Tokyo",
        "# user\n\n| Key | Value |\n|---|---|\n| name | Bob |\n| city | Tokyo |\n\n"
    )]
    #[case::sequence_of_scalars(
        "items:\n  - apple\n  - banana",
        "# items\n\n- apple\n- banana\n\n"
    )]
    #[case::sequence_of_mappings(
        "users:\n  - name: A\n    id: 1\n  - name: B\n    id: 2",
        "# users\n\n| name | id |\n|---|---|\n| A | 1 |\n| B | 2 |\n\n"
    )]
    fn test_conversion(#[case] input: &str, #[case] expected: &str) {
        assert_eq!(convert(input), expected);
    }

    #[rstest]
    #[case::top_level_sequence("- a\n- b\n- c", "- a\n- b\n- c\n\n")]
    #[case::scalar_string("hello", "hello\n")]
    #[case::scalar_integer("42", "42\n")]
    #[case::null_value(
        "key: null",
        "| Key | Value |\n|---|---|\n| key |  |\n\n"
    )]
    fn test_edge_cases(#[case] input: &str, #[case] expected: &str) {
        assert_eq!(convert(input), expected);
    }

    #[rstest]
    fn test_non_string_keys() {
        let output = convert("true: yes\nfalse: no");
        assert!(output.contains("true"));
        assert!(output.contains("false"));
    }
}