use afastdata::{AFastDeserialize, AFastSerialize};
#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct A {
a: i32,
#[afast(
lte(10, 0, "b must be at least 10"),
)]
b: i64,
c: String,
}
#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct B<T> {
a: T,
b: i32,
c: String,
d: Option<bool>,
e: Vec<T>,
f: C,
}
#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
enum C {
Null,
I32(i32),
Struct(A),
Tuple(i32, i64),
Inner { a: i32, b: i64 },
}
#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct D(i32, i64, String);
fn roundtrip<T: AFastSerialize + AFastDeserialize + PartialEq + std::fmt::Debug>(val: &T) {
let bytes = val.to_bytes();
let (decoded, offset) = T::from_bytes(&bytes).unwrap();
assert_eq!(offset, bytes.len());
assert_eq!(*val, decoded);
}
#[test]
fn test_derive_struct_a() {
let a = A {
a: 42,
b: -1000,
c: String::from("hello"),
};
roundtrip(&a);
}
#[test]
fn test_derive_tuple_struct_d() {
let d = D(1, 2, String::from("three"));
roundtrip(&d);
}
#[test]
fn test_derive_enum_c() {
roundtrip(&C::Null);
roundtrip(&C::I32(42));
roundtrip(&C::Tuple(1, 2));
roundtrip(&C::Inner { a: 10, b: 20 });
roundtrip(&C::Struct(A {
a: 1,
b: 2,
c: String::from("nested"),
}));
}
#[test]
fn test_derive_generic_struct_b() {
let b = B {
a: 99i32,
b: 42,
c: String::from("world"),
d: Some(true),
e: vec![1, 2, 3],
f: C::I32(7),
};
roundtrip(&b);
let b_none = B {
a: 0i32,
b: -1,
c: String::from(""),
d: None::<bool>,
e: Vec::<i32>::new(),
f: C::Null,
};
roundtrip(&b_none);
}
#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
enum Command {
Unit,
Login {
#[afast(len(1, 32, 1001, "username ${field} length must be 1-32"))]
username: String,
#[afast(len(6, 128, 1002, "password ${field} length must be 6-128"))]
password: String,
},
Transfer {
#[afast(gte(1, 2001, "amount must be >= 1"))]
amount: i64,
#[afast(len(1, 64, 2002, "to ${field} length must be 1-64"))]
to: String,
},
Config {
#[afast(gte(1, 3001, "timeout must be >= 1"))]
#[afast(lte(3600, 3002, "timeout must be <= 3600"))]
timeout: i64,
},
Send(#[afast(gte(0, 4001, "value must be >= 0"))] i64),
Echo(#[afast(len(1, 256, 4002, "msg ${field} length must be 1-256"))] String),
}
#[test]
fn test_enum_variant_valid_roundtrip() {
let login = Command::Login {
username: String::from("alice"),
password: String::from("secret123"),
};
roundtrip(&login);
let transfer = Command::Transfer {
amount: 100,
to: String::from("bob"),
};
roundtrip(&transfer);
let config = Command::Config { timeout: 30 };
roundtrip(&config);
roundtrip(&Command::Unit);
roundtrip(&Command::Send(42));
roundtrip(&Command::Echo(String::from("hello")));
}
#[test]
fn test_enum_variant_validation_error() {
use afastdata::ErrorKind;
let login = Command::Login {
username: String::new(),
password: String::from("secret123"),
};
let bytes = login.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(1001, _)));
let login = Command::Login {
username: String::from("alice"),
password: String::from("short"),
};
let bytes = login.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(1002, _)));
let transfer = Command::Transfer {
amount: 0,
to: String::from("bob"),
};
let bytes = transfer.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(2001, _)));
let transfer = Command::Transfer {
amount: 100,
to: String::new(),
};
let bytes = transfer.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(2002, _)));
let config = Command::Config { timeout: 0 };
let bytes = config.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(3001, _)));
let config = Command::Config { timeout: 7200 };
let bytes = config.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(3002, _)));
let send = Command::Send(-1);
let bytes = send.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(4001, _)));
let echo = Command::Echo(String::new());
let bytes = echo.to_bytes();
let err = Command::from_bytes(&bytes).unwrap_err();
assert!(matches!(err.kind(), ErrorKind::ValidateError(4002, _)));
}