php-literal-parser 0.7.1

parser for php literals
Documentation
use indexmap::indexmap;
use miette::Report;
use php_literal_parser::{from_str, Key, Value};
use serde_derive::Deserialize;

#[test]
fn test_parse_struct() {
    let code = r#"
        ['name' => 'Api#get', 'url' => '/api/v{version}/{fileId}', 'verb' => 'GET']
    "#;
    let result: Route = match from_str(code) {
        Ok(result) => result,
        Err(error) => {
            let error = Report::from(error);
            eprintln!("Error while parsing return literal: {error:?}");
            panic!();
        }
    };
    assert_eq!(
        Route {
            name: "Api#get".into(),
            url: "/api/v{version}/{fileId}".into(),
            verb: "GET".into(),
        },
        result
    );
}

#[test]
fn test_parse_vec_of_structs() {
    let code = r#"
        [
            ['name' => 'Api#get', 'url' => '/api/v{version}/{fileId}', 'verb' => 'GET'],
        ]
    "#;
    let result: Vec<Route> = match from_str(code) {
        Ok(result) => result,
        Err(error) => {
            let error = Report::from(error);
            eprintln!("Error while parsing return literal: {error:?}");
            panic!();
        }
    };
    assert_eq!(
        vec![Route {
            name: "Api#get".into(),
            url: "/api/v{version}/{fileId}".into(),
            verb: "GET".into(),
        }],
        result
    );
}

#[test]
fn test_parse_struct_of_vecs_of_structs() {
    let code = r#"[
        'ocs' => [
            ['name' => 'Api#get', 'url' => '/api/v{version}/{fileId}', 'verb' => 'GET'],
        ],
    ]"#;
    let result = match from_str(code) {
        Ok(result) => result,
        Err(error) => {
            let error = Report::from(error);
            eprintln!("Error while parsing return literal: {error:?}");
            panic!();
        }
    };
    assert_eq!(
        AppRoutes {
            routes: Vec::new(),
            ocs: vec![Route {
                name: "Api#get".into(),
                url: "/api/v{version}/{fileId}".into(),
                verb: "GET".into(),
            }]
        },
        result
    );
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq)]
pub struct AppRoutes {
    #[serde(default)]
    routes: Vec<Route>,
    #[serde(default)]
    ocs: Vec<Route>,
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct Route {
    url: String,
    name: String,
    verb: String,
}

#[test]
fn test_value_serde_roundtrip() {
    fn test_roundtrip(val: Value) {
        let json = serde_json::to_string(&val).unwrap();
        let parsed: Value = serde_json::from_str(&json).unwrap();
        assert_eq!(val, parsed);
    }

    test_roundtrip(Value::Bool(false));
    test_roundtrip(Value::Bool(true));

    test_roundtrip(Value::Int(12));
    test_roundtrip(Value::Float(12.12));
    test_roundtrip(Value::String("foo".into()));
    test_roundtrip(Value::Null);
    test_roundtrip(Value::Array(indexmap! {
        Key::Int(0) => Value::Bool(true),
        Key::Int(1) => Value::Int(12),
        Key::Int(2) => Value::Int(-12),
    }));
    test_roundtrip(Value::Array(indexmap! {
        Key::Int(1) => Value::Bool(true),
        Key::Int(2) => Value::Int(12),
        Key::Int(5) => Value::Int(-12),
    }));
    test_roundtrip(Value::Array(indexmap! {
        Key::String("foo".into()) => Value::Bool(true),
        Key::String("var".into()) => Value::Array(indexmap! {
            Key::String("bar".into()) => Value::Bool(true),
            Key::String("asd".into()) => Value::Int(12),
            Key::Int(2) => Value::Array(indexmap! {
                Key::Int(0) => Value::Bool(true),
                Key::Int(1) => Value::Int(12),
                Key::Int(2) => Value::Int(-12),
            }),
        }),
    }));
}