serde_test limited by equality operator, not helpful when equality behaves differently
tspiteri opened this issue · 2 comments
I have a floating-point structure and I'm writing serde_test
tests for it. However, I have two issues:
- There isn't a way to test its NaN deserialization, since NaN is defined as not equal to anything, not even itself.
- I cannot test that my +0.0 and -0.0 are deserialized distinctly, since +0.0 == -0.0.
In my case, I can test serialization properly as I'm serializing the values themselves as strings, but similar issues could arise for serialization if for example a test for primitive f32 NaNs is attempted.
Is there a way to go around this? Maybe provide functions similar to the following apart from the assert functions:
pub fn to_ser_tokens<T>(value: &T) -> Vec[Token] where T: Serialize;
pub fn from_de_tokens<T>(tokens: &[Token]) -> T where T: Deserialize;
The serde_test crate intentionally does not expose something like to_ser_tokens or from_de_tokens because we want an API that is useless for anything other than testing. Those functions would be too useful, in a sense.
How about using a type that overrides what comparison means for your test? Something like:
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_test;
use serde::{Deserialize, Deserializer};
use serde_test::Token;
// Pretend this is your type with wacky PartialEq.
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
enum Tspiteri {
NaN,
NegZero,
PosZero,
Other(u32),
}
impl PartialEq for Tspiteri {
fn eq(&self, rhs: &Tspiteri) -> bool {
use Tspiteri::*;
match (*self, *rhs) {
(NaN, _) | (_, NaN) => false,
(NegZero, NegZero) |
(NegZero, PosZero) |
(PosZero, NegZero) |
(PosZero, PosZero) => true,
(Other(a), Other(b)) => a == b,
_ => false,
}
}
}
#[derive(Debug)]
struct TestTspiteri(Tspiteri);
impl PartialEq for TestTspiteri {
fn eq(&self, rhs: &TestTspiteri) -> bool {
use Tspiteri::*;
match (self.0, rhs.0) {
(NaN, NaN) => true,
(NegZero, NegZero) => true,
(PosZero, PosZero) => true,
(Other(a), Other(b)) => a == b,
_ => false,
}
}
}
impl<'de> Deserialize<'de> for TestTspiteri {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Tspiteri::deserialize(deserializer).map(TestTspiteri)
}
}
fn main() {
// bad test, passes
serde_test::assert_de_tokens(&Tspiteri::NegZero, &[
Token::UnitVariant { name: "Tspiteri", variant: "PosZero" },
]);
// real test, fails
serde_test::assert_de_tokens(&TestTspiteri(Tspiteri::NegZero), &[
Token::UnitVariant { name: "Tspiteri", variant: "PosZero" },
]);
}
I can see the point of not exposing that functionality, and your solution is good, so I'm closing the bug. Thanks!