Alternatives to typing out large struct literals in tests?

I'm writing a language parser here: https://github.com/davesque/rust-vyper/blob/master/parser/src/parsers.rs

Here's an example of some complex expected results which are defined with large struct literals: https://github.com/davesque/rust-vyper/blob/master/parser/tests/test_parsers.rs#L270-L302

My question is, how can I avoid typing out large struct literals in tests for functionality of the sort found in these parsers?

I had the idea of deriving serialization behavior using serde_json for the relevant structs and then testing against an expected serialization. That way, I thought the representation of the desired output might be easier to visually parse in certain cases and it would be easier to figure out why tests are breaking if I did a line diff of conflicting serializations. But this approach feels kinda hacky and it seems to assume that serialzation will always happen in a consistent way which may not be the case.

Anyone have any other ideas?

Constructor functions allow for more brevity:

#[derive(Debug)]
struct EventField {name: String, typ: String}

#[derive(Debug)]
struct EventDef {name: String, fields: Vec<EventField>}

fn event_field(name: &str, typ: &str) -> EventField {
    EventField{name: name.into(), typ: typ.into()}
}

fn event_def(name: &str, fields: &[(&str,&str)]) -> EventDef {
    EventDef{
        name: name.into(),
        fields: fields.iter().map(|t| event_field(t.0,t.1)).collect()
    }
}

fn main() {
    let value = EventDef {
        name: "Greet".into(),
        fields: vec![
            EventField {
                name: "name".into(),
                typ: "bytes32".into(),
            },
            EventField {
                name: "age".into(),
                typ: "uint8".into(),
            },
        ]
    };
    println!("{:#?}",value);

    let value = event_def("Greet",&[("name","bytes32"),("age","uint8")]);
    println!("{:#?}",value);
}

Or you define some macros:

#[derive(Debug)]
struct EventField {name: String, typ: String,}

#[derive(Debug)]
struct EventDef {name: String, fields: Vec<EventField>}

macro_rules! event_fields {
    ( [$( $name:tt: $typ:tt ),*] ) => {
        vec![$(EventField{name: $name.into(), typ: $typ.into()},)*]
    }
}

macro_rules! event_def {
    ( $name:tt: $fields:tt ) => {
        EventDef{name: $name.into(), fields: event_fields!($fields)}
    }
}

fn main() {
    let value = event_def!{"Greet": ["name": "bytes32", "age": "uint8"]};
    println!("{:#?}",value);
}
1 Like