Git Product home page Git Product logo

Comments (9)

luke-biel avatar luke-biel commented on August 25, 2024

If there's a common trait connecting these types, then you should be able to use impl Trait as an arg. You can see this done in tests: https://github.com/frondeus/test-case/blob/master/tests/acceptance_cases/cases_support_generics/src/lib.rs
Does it solve your use case?

from test-case.

SiKreuz avatar SiKreuz commented on August 25, 2024

Thanks for the quick reply. That definitely goes into the right direction. Maybe you can help me better if I make it more precise. Roughly what I have implemented (heavily simplified):

trait Deserialize: Sized {
    fn deserialize(buffer: &Vec<u8>) -> Result<Self, &'static str>;
}

struct Model1 {
    attribute1: u8,
}

struct Model2 {
    attribute2: u8,
    attribute3: u8
}

impl Deserialize for Model1 {
    fn deserialize(buffer: &Vec<u8>) -> Result<Self, &'static str> {
        // Do some stuff
    }
}

impl Deserialize for Model2 {
    fn deserialize(buffer: &Vec<u8>) -> Result<Self, &'static str> {
        // Do some other stuff than in Model1
    }
} 

How would I now test this? I would like to test deserialize() for both structs.

from test-case.

luke-biel avatar luke-biel commented on August 25, 2024

All right, it looks that this is slightly different than I anticipated, however you can still use generics with rust's type coercion:

#[cfg(test)]
mod tests {
    use test_case::test_case;

    trait Deserialize: Sized {
        fn deserialize(buffer: &Vec<u8>) -> Result<Self, &'static str>;
    }

    #[derive(Debug)]
    struct Model1 {
        attribute1: u8,
    }

    #[derive(Debug)]
    struct Model2 {
        attribute2: u8,
        attribute3: u8,
    }

    impl Deserialize for Model1 {
        fn deserialize(buffer: &Vec<u8>) -> Result<Model1, &'static str> {
            if buffer == b"input" {
                Ok(Model1 { attribute1: 0 })
            } else {
                Err("invalid input")
            }
        }
    }

    impl Deserialize for Model2 {
        fn deserialize(buffer: &Vec<u8>) -> Result<Model2, &'static str> {
            if buffer == b"input2" {
                Ok(Model2 { attribute2: 0, attribute3: 1 })
            } else {
                Err("invalid input2")
            }
        }
    }


    #[test_case(b"input" => matches Model1 { attribute1: 0 })]
    #[test_case(b"input2" => matches Model1 { attribute1: 0 }; "will panic 1")]
    #[test_case(b"input2" => matches Model2 { attribute2: 0, attribute3: 1 })]
    #[test_case(b"input" => matches Model2 { attribute2: 0, attribute3: 1 }; "will panic 2")]
    fn test_does_deserialize<T: Deserialize>(input: &[u8]) -> T {
        T::deserialize(&input.to_vec()).unwrap()
    }
}

from test-case.

SiKreuz avatar SiKreuz commented on August 25, 2024

That's already way closer. Thank you! Actually, this gave me an idea on how to replace a lot of my tests through test cases.

For the particular case I was asking for I'm trying to test for an error result of the deserialize method. Something like this for example:

fn deserialize_small_buffer<T: Deserialize>(min_buff_size: usize) {
    let buffer = vec![0u8; min_buff_size - 1];

    let result = T::deserialize(&buffer);

    assert_eq!(result.is_err(), true);
    assert_eq!(result.err().unwrap(), INVALID_BUFFER_SIZE_SMALL_STR);
}

How could I realize that? Seems hard to use matches if I want to check for the result. But maybe I'm missing something.

from test-case.

luke-biel avatar luke-biel commented on August 25, 2024

I realized after writing my comment that you can't really provide the T type in this case, so neither

#[test_case(b"input" => matches Err("text of an error"))]

nor

#[test_case(6, INVALID_BUFFER_SIZE_SMALL_STR)]
fn deserialize_small_buffer<T: Deserialize>(min_buff_size: usize, expected: &str) {
    let buffer = vec![0u8; min_buff_size - 1];

    let result = T::deserialize(&buffer);

    assert_eq!(result.is_err(), true);
    assert_eq!(result.err().unwrap(), expected);
}

would work.

I could expect that there's a way to overcome this issue with

#[test_case(b"input" => matches Result::<Model1, _>::Err("text of an error")]

but this ain't the prettiest solution.

There are however closure validators https://github.com/frondeus/test-case/wiki/Syntax#closure-validator and function validators https://github.com/frondeus/test-case/wiki/Syntax#function-validator you can look at. In the latter case you may be able to create a tester method that's also generic, eg.:

fn check_err<T: Deserialize>(expected: &'static str) -> impl Fn(Result<T, &'static str>) {
    move |actual: Result<T, &'static str>| {
        assert_eq!(expected, actual.unwrap_err())
    }
}

#[test_case(SIZE => using check_err::<Model1>("expected error string")]

from test-case.

SiKreuz avatar SiKreuz commented on August 25, 2024

I could expect that there's a way to overcome this issue with

#[test_case(b"input" => matches Result::<Model1, _>::Err("text of an error")]

but this ain't the prettiest solution.

I also tried out that idea. Works for now and would be a solution I can work with for now.

What I don't like about the two solutions you mentioned, is that I have to hard-code the error message. Would be nicer to use the const instead. So I can change the error message later and that does not break the tests.

from test-case.

luke-biel avatar luke-biel commented on August 25, 2024

This should be possible without use of matches but it will require that Model1 and similar types implement PartialEq.

from test-case.

SiKreuz avatar SiKreuz commented on August 25, 2024

Can you help me out. How would I do this here?

from test-case.

SiKreuz avatar SiKreuz commented on August 25, 2024

Just for the record. With someting like this I got it to work.

#[test_case(b"input" => matches Result::<Model1, _>::Err(x) if x == SOME_ERROR_STRING_CONST)]

@luke-biel Thanks for the help!

from test-case.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.