rede_parser 0.2.2

Parser in charge of modeling Rede's files
Documentation
use crate::schema::table::{FormDataTable, PrimitiveTable, Transform};
use crate::schema::types::PrimitiveArray;
use rede_schema::Body as SchemaBody;
use serde::Deserialize;

#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum Body {
    #[default]
    None,
    #[serde(alias = "text")]
    Raw(String),
    #[serde(alias = "file")]
    Binary(String),
    #[serde(
        alias = "form-data",
        alias = "form_data",
        alias = "multipart_form_data",
        alias = "multipart-form-data"
    )]
    FormData(FormDataTable),
    #[serde(
        alias = "x-www-form-urlencoded",
        alias = "form_urlencoded",
        alias = "form-urlencoded"
    )]
    XFormUrlEncoded(PrimitiveTable),
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub(crate) enum FormDataValue {
    Text(PrimitiveArray),
    File(String),
}

impl From<Body> for SchemaBody {
    fn from(value: Body) -> Self {
        match value {
            Body::None => SchemaBody::None,
            Body::Raw(content) => SchemaBody::Raw {
                content,
                mime: mime::TEXT_PLAIN_UTF_8,
            },
            Body::Binary(path) => SchemaBody::Binary {
                path,
                mime: mime::APPLICATION_OCTET_STREAM,
            },
            Body::FormData(table) => SchemaBody::FormData(table.into_map()),
            Body::XFormUrlEncoded(table) => SchemaBody::XFormUrlEncoded(table.into_map()),
        }
    }
}

use rede_schema::body::FormDataValue as SchemaFDV;
impl Transform<FormDataValue, SchemaFDV> for FormDataTable {
    fn map_value(value: FormDataValue) -> SchemaFDV {
        match value {
            FormDataValue::Text(value) => SchemaFDV::Text(value.into()),
            FormDataValue::File(path) => SchemaFDV::File(path),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::schema::types::{Primitive, PrimitiveArray};

    #[derive(Debug, Deserialize)]
    struct Parent {
        body: Body,
    }

    #[test]
    fn deserialize() {
        assert_eq!(
            toml::from_str::<Parent>(r#"body.raw = "content""#)
                .unwrap()
                .body,
            Body::Raw("content".to_string())
        );

        let toml = r#"body.form-urlencoded = { type = "integer", value = 1 }"#;
        let body = toml::from_str::<Parent>(toml).unwrap().body;
        assert!(matches!(&body, Body::XFormUrlEncoded(map) if map.len() == 2));
        if let Body::XFormUrlEncoded(map) = &body {
            assert_eq!(
                map["type"],
                PrimitiveArray::Single(Primitive::Str("integer".to_string()))
            );
            assert_eq!(map["value"], PrimitiveArray::Single(Primitive::Int(1)));
        }

        let toml = r#"
        [body.form_data]
        raw.text = "raw"
        binary.file = "path"
        "#;
        let body = toml::from_str::<Parent>(toml).unwrap().body;
        assert!(matches!(&body, Body::FormData(map) if map.len() == 2));
        if let Body::FormData(map) = &body {
            assert_eq!(
                map["raw"],
                FormDataValue::Text(PrimitiveArray::Single(Primitive::Str("raw".to_string())))
            );
            assert_eq!(map["binary"], FormDataValue::File("path".to_string()));
        }
    }

    #[test]
    fn only_one_type() {
        let toml = r#"
        [body]
        raw = "raw"
        binary = "file"
        "#;
        let err = toml::from_str::<Parent>(toml).err().unwrap();
        assert!(err.to_string().contains("wanted exactly 1 element"));

        let toml = r#"
        [body.form-data]
        key.text = 2
        key.file = "path"
        "#;
        let err = toml::from_str::<Parent>(toml).err().unwrap();
        assert!(err.to_string().contains("wanted exactly 1 element"));
    }

    #[test]
    fn deserialize_empty() {
        let err = toml::from_str::<Parent>("[body]").err().unwrap();
        assert!(err.to_string().contains("wanted exactly 1 element"));
    }
}