calvin
calvin

Reputation: 2945

Is there any ways to attach some debug fields for a rust struct?

For example, I want struct S to have a name_count field only when testing, so I can manipulate last_name to validate some properties about name_count in tests.

pub struct S {
    last_name: String,
    #[cfg(test)] {
        // This field only exists in tests
        name_count: HashMap<String, i32>,
    }
}

impl S {
    fn record_last_name(&mut self, name: String) {
        self.last_name = name;
        if cfg!(test) {
            // Increase self.name_count[self.last_name]
        }
    }
}

#[test]
fn test_last_name_count() {
    let mut s = S {};
    ...
    // assert some properties about name_count
}

However, this code can't compile, seems Rust don't support a #[cfg(test)] inside definition of a struct, so I wonder how can I do that.

Upvotes: 4

Views: 957

Answers (1)

Jeremy Meadows
Jeremy Meadows

Reputation: 2561

You can do that, but #[cfg(test)] is an attribute macro, so it applies to whatever follows it, and doesn't need a block scope like you had written it.

You also need add the #[cfg(...)] attributes to functions and methods to make sure you don't get "missing field"/"no field named ..." compiler errors.

use std::collections::HashMap;

pub struct S {
    last_name: String,
    #[cfg(test)]
    // This field only exists in tests
    name_count: HashMap<String, i32>,
}

impl S {
    #[cfg(test)]
    fn record_last_name(&mut self, name: String) {
        self.last_name = name;
        // Increase self.name_count[self.last_name]
    }
}

#[cfg(not(test))]
fn main() {
    let mut s = S { last_name: "Foo".to_string() };
}

#[test]
fn test_last_name_count() {
    let mut s = S { last_name: "Foo".to_string(), name_count: HashMap::new() };
    // assert some properties about name_count
}

Upvotes: 2

Related Questions