use crate::{
ClientError, Error, RedisError, RedisErrorKind, Result,
resp::{RespBuf, RespDeserializer, RespFrameParser, RespResponse, RespTapeMut},
tests::log_try_init,
};
use bytes::Bytes;
use serde::{Deserialize, Deserializer};
use smallvec::SmallVec;
use std::collections::HashMap;
fn deserialize<T>(str: &str) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let buf = str.as_bytes();
let mut tape = RespTapeMut::default();
let (frame, _) = RespFrameParser::new(buf, &mut tape).parse()?;
let response = RespResponse::new(RespBuf::from(Bytes::copy_from_slice(buf)), frame);
deserialize_from_resp_response(response)
}
fn deserialize_from_resp_response<T>(response: RespResponse) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let deserializer = RespDeserializer::new(response.view()?);
T::deserialize(deserializer)
}
#[test]
fn bool() -> Result<()> {
log_try_init();
let result: Result<bool> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: bool = deserialize("#t\r\n")?; assert!(result);
let result: bool = deserialize("#f\r\n")?; assert!(!result);
let result: bool = deserialize("$1\r\n1\r\n")?; assert!(result);
let result: bool = deserialize("$1\r\n0\r\n")?; assert!(!result);
let result: bool = deserialize("$4\r\ntrue\r\n")?; assert!(result);
let result: bool = deserialize("$5\r\nfalse\r\n")?; assert!(!result);
let result: bool = deserialize(":1\r\n")?; assert!(result);
let result: bool = deserialize(":0\r\n")?; assert!(!result);
let result: bool = deserialize("+OK\r\n")?; assert!(result);
let result: bool = deserialize("+KO\r\n")?; assert!(!result);
let result: bool = deserialize("_\r\n")?; assert!(!result);
Ok(())
}
#[test]
fn integer() {
log_try_init();
let result: Result<i64> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: i64 = deserialize(":12\r\n").unwrap(); assert_eq!(12, result);
let result: i64 = deserialize("_\r\n").unwrap(); assert_eq!(0, result);
let result: i64 = deserialize("$2\r\n12\r\n").unwrap(); assert_eq!(12, result);
let result: i64 = deserialize("+12\r\n").unwrap(); assert_eq!(12, result);
let result: i64 = deserialize("*1\r\n:12\r\n").unwrap(); assert_eq!(12, result);
let result: u64 = deserialize("*1\r\n:12\r\n").unwrap(); assert_eq!(12, result);
}
#[test]
fn integer_from_multi_element_array() {
log_try_init();
macro_rules! assert_rejected {
($($ty:ty),+) => {$(
let result: Result<$ty> = deserialize("*2\r\n:12\r\n:13\r\n");
assert!(
matches!(
result,
Err(Error::Client(ClientError::CannotParseInteger))
),
"{} accepted a 2-element array",
stringify!($ty)
);
)+};
}
assert_rejected!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
}
#[test]
fn float() -> Result<()> {
log_try_init();
let result: Result<f64> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: f64 = deserialize(":12\r\n")?; assert_eq!(12.0, result);
let result: f64 = deserialize(",12.12\r\n")?; assert_eq!(12.12, result);
let result: f64 = deserialize("_\r\n")?; assert_eq!(0.0, result);
let result: f64 = deserialize("$5\r\n12.12\r\n")?; assert_eq!(12.12, result);
let result: f64 = deserialize("+12.12\r\n")?; assert_eq!(12.12, result);
Ok(())
}
#[test]
fn char() -> Result<()> {
log_try_init();
let result: Result<char> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: char = deserialize("$1\r\nm\r\n")?; assert_eq!('m', result);
let result: char = deserialize("+m\r\n")?; assert_eq!('m', result);
Ok(())
}
#[test]
fn string() -> Result<()> {
log_try_init();
let result: Result<String> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: String = deserialize("$5\r\nhello\r\n")?; assert_eq!("hello", result);
let result: String = deserialize("+hello\r\n")?; assert_eq!("hello", result);
let result: String = deserialize("$0\r\n\r\n")?; assert_eq!("", result);
Ok(())
}
#[test]
fn a_numeric_reply_read_as_a_string_is_verbatim() -> Result<()> {
log_try_init();
let result: String = deserialize(":12\r\n")?;
assert_eq!("12", result);
let result: String = deserialize(":-9223372036854775808\r\n")?;
assert_eq!("-9223372036854775808", result);
let result: String = deserialize(",12.50\r\n")?;
assert_eq!("12.50", result);
let result: String = deserialize(",1e21\r\n")?;
assert_eq!("1e21", result);
let result: String = deserialize(",12\r\n")?;
assert_eq!("12", result);
let result: String = deserialize(",inf\r\n")?;
assert_eq!("inf", result);
let result: String = deserialize("(3492890328409238509324850943850943825024385\r\n")?;
assert_eq!("3492890328409238509324850943850943825024385", result);
Ok(())
}
#[test]
fn a_synthesized_numeric_reply_renders_from_its_value() -> Result<()> {
log_try_init();
let result: String = deserialize_from_resp_response(RespResponse::integer(42))?;
assert_eq!("42", result);
Ok(())
}
struct CaptureStr;
impl<'de> serde::de::Visitor<'de> for CaptureStr {
type Value = String;
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("a string")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> std::result::Result<String, E> {
Ok(v.to_owned())
}
}
#[test]
fn the_two_string_entry_points_agree() -> Result<()> {
log_try_init();
let cases = [
"+hello\r\n",
"$5\r\nhello\r\n",
"$0\r\n\r\n",
":12\r\n",
",12.50\r\n",
"#t\r\n",
"#f\r\n",
"_\r\n",
];
for resp in cases {
let buf = resp.as_bytes();
let mut tape = RespTapeMut::default();
let (frame, _) = RespFrameParser::new(buf, &mut tape).parse()?;
let response = RespResponse::new(RespBuf::from(Bytes::copy_from_slice(buf)), frame);
let as_str =
Deserializer::deserialize_str(RespDeserializer::new(response.view()?), CaptureStr);
let as_string =
Deserializer::deserialize_string(RespDeserializer::new(response.view()?), CaptureStr);
match (as_str, as_string) {
(Ok(a), Ok(b)) => assert_eq!(a, b, "different text for {resp:?}"),
(Err(_), Err(_)) => {}
(a, b) => panic!("{resp:?} readable through one entry point only: {a:?} / {b:?}"),
}
}
let response = RespResponse::integer(42);
let as_str =
Deserializer::deserialize_str(RespDeserializer::new(response.view()?), CaptureStr)?;
let as_string =
Deserializer::deserialize_string(RespDeserializer::new(response.view()?), CaptureStr)?;
assert_eq!(as_str, as_string);
assert_eq!("42", as_str);
Ok(())
}
#[test]
fn a_boolean_reply_read_as_a_string_renders_as_true_or_false() -> Result<()> {
log_try_init();
let result: String = deserialize("#t\r\n")?;
assert_eq!("true", result);
let result: String = deserialize("#f\r\n")?;
assert_eq!("false", result);
let result: String = deserialize("_\r\n")?;
assert_eq!("", result);
Ok(())
}
#[test]
fn option() -> Result<()> {
log_try_init();
let result: Result<Option<String>> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Option<String> = deserialize("$5\r\nhello\r\n")?; assert_eq!(Some("hello".to_owned()), result);
let result: Option<String> = deserialize("$0\r\n\r\n")?; assert_eq!(Some("".to_owned()), result);
let result: Option<String> = deserialize("_\r\n")?; assert_eq!(None, result);
let result: Option<i64> = deserialize(":12\r\n")?; assert_eq!(Some(12), result);
let result: Option<i64> = deserialize("_\r\n")?; assert_eq!(None, result);
let result: Option<Vec<i32>> = deserialize("*1\r\n:12\r\n")?; assert_eq!(Some(vec![12]), result);
let result: Option<Vec<i32>> = deserialize("*0\r\n")?; assert_eq!(None, result);
Ok(())
}
#[test]
fn unit() -> Result<()> {
log_try_init();
let result: Result<()> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Result<()> = deserialize("+OK\r\n"); assert!(result.is_ok());
let result: Result<()> = deserialize("_\r\n"); assert!(result.is_ok());
let result: Result<()> = deserialize("$5\r\nhello\r\n"); assert!(result.is_ok());
let result: Result<()> = deserialize(":1\r\n"); assert!(result.is_ok(), "{result:?}");
Ok(())
}
#[test]
fn unit_struct() -> Result<()> {
log_try_init();
#[derive(Deserialize)]
struct Unit;
let result: Result<Unit> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Result<Unit> = deserialize("_\r\n"); assert!(result.is_ok());
let result: Result<Unit> = deserialize("$5\r\nhello\r\n"); assert!(result.is_ok());
Ok(())
}
#[test]
fn newtype_struct() -> Result<()> {
log_try_init();
#[derive(Deserialize)]
struct Millimeters(u8);
let result: Result<Millimeters> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Millimeters = deserialize(":12\r\n")?; assert_eq!(12, result.0);
Ok(())
}
#[test]
fn seq() -> Result<()> {
log_try_init();
let result: Result<Vec<i32>> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Vec<i32> = deserialize("*2\r\n:12\r\n:13\r\n")?; assert_eq!(2, result.len());
assert_eq!(12, result[0]);
assert_eq!(13, result[1]);
let result: Vec<i32> = deserialize("*2\r\n$2\r\n12\r\n$2\r\n13\r\n")?; assert_eq!(2, result.len());
assert_eq!(12, result[0]);
assert_eq!(13, result[1]);
let result: Vec<bool> = deserialize("*2\r\n#t\r\n#f\r\n")?; assert_eq!(2, result.len());
assert!(result[0]);
assert!(!result[1]);
let result: Vec<bool> = deserialize("*2\r\n:1\r\n:0\r\n")?; assert_eq!(2, result.len());
assert!(result[0]);
assert!(!result[1]);
let result: SmallVec<[String; 2]> = deserialize("*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n")?; assert_eq!(2, result.len());
assert_eq!("hello", result[0]);
assert_eq!("world", result[1]);
Ok(())
}
#[test]
fn integer_array() {
log_try_init();
let result: Vec<i32> =
deserialize_from_resp_response(RespResponse::IntegerArray(vec![12, 13])).unwrap();
assert_eq!(2, result.len());
assert_eq!(12, result[0]);
assert_eq!(13, result[1]);
let result: Vec<bool> =
deserialize_from_resp_response(RespResponse::IntegerArray(vec![1, 0])).unwrap();
assert_eq!(2, result.len());
assert!(result[0]);
assert!(!result[1]);
}
#[test]
fn tuple() -> Result<()> {
log_try_init();
let result: Result<(i32, i32)> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Result<(i32, i32)> = deserialize("!9\r\nERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: (i32, i32) = deserialize("*2\r\n:12\r\n:13\r\n")?; assert_eq!((12, 13), result);
let result: (String, String) = deserialize("*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n")?; assert_eq!(("hello".to_string(), "world".to_string()), result);
Ok(())
}
#[test]
fn tuple_struct() -> Result<()> {
log_try_init();
#[derive(Debug, Deserialize, PartialEq)]
struct Rgb(u8, u8, u8);
let result: Result<Rgb> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Rgb = deserialize("*3\r\n:12\r\n:13\r\n:14\r\n")?; assert_eq!(Rgb(12, 13, 14), result);
Ok(())
}
#[test]
fn map() {
log_try_init();
let result: Result<HashMap<i32, i32>> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: HashMap<i32, i32> = deserialize("*4\r\n:12\r\n:13\r\n:14\r\n:15\r\n").unwrap(); assert_eq!(Some(&13), result.get(&12));
assert_eq!(Some(&15), result.get(&14));
let result: HashMap<i32, i32> = deserialize("%2\r\n:12\r\n:13\r\n:14\r\n:15\r\n").unwrap(); assert_eq!(Some(&13), result.get(&12));
assert_eq!(Some(&15), result.get(&14));
let result: HashMap<i32, i32> =
deserialize("*2\r\n*2\r\n:12\r\n:13\r\n*2\r\n:14\r\n:15\r\n").unwrap(); assert_eq!(Some(&13), result.get(&12));
assert_eq!(Some(&15), result.get(&14));
}
#[test]
fn r#struct() {
log_try_init();
#[derive(Debug, Deserialize, PartialEq)]
struct Person {
pub id: u64,
pub name: String,
}
let result: Result<Person> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: Person =
deserialize("*4\r\n$2\r\nid\r\n:12\r\n$4\r\nname\r\n$4\r\nMike\r\n").unwrap(); assert_eq!(
Person {
id: 12,
name: "Mike".to_owned()
},
result
);
let result: Person =
deserialize("%2\r\n$2\r\nid\r\n:12\r\n$4\r\nname\r\n$4\r\nMike\r\n").unwrap(); assert_eq!(
Person {
id: 12,
name: "Mike".to_owned()
},
result
);
let result: Person = deserialize("*2\r\n:12\r\n$4\r\nMike\r\n").unwrap(); assert_eq!(
Person {
id: 12,
name: "Mike".to_owned()
},
result
);
}
#[test]
fn struct_flat_array_shapes() {
log_try_init();
#[derive(Debug, Deserialize, PartialEq)]
struct Person {
id: u64,
name: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct PartialPerson {
id: u64,
name: String,
ttl: Option<u64>,
tag: Option<String>,
}
let mike = Person {
id: 12,
name: "Mike".to_owned(),
};
let result: Person =
deserialize("*6\r\n$2\r\nid\r\n:12\r\n$4\r\nname\r\n$4\r\nMike\r\n$3\r\nttl\r\n:99\r\n")
.unwrap();
assert_eq!(mike, result);
let result: Person = deserialize("*4\r\n+id\r\n:12\r\n+name\r\n$4\r\nMike\r\n").unwrap();
assert_eq!(mike, result);
let result: Person = deserialize("*3\r\n:12\r\n$4\r\nMike\r\n:99\r\n").unwrap();
assert_eq!(mike, result);
let result: PartialPerson =
deserialize("*4\r\n$2\r\nid\r\n:12\r\n$4\r\nname\r\n$4\r\nMike\r\n").unwrap();
assert_eq!(
PartialPerson {
id: 12,
name: "Mike".to_owned(),
ttl: None,
tag: None
},
result
);
let result: Result<Person> = deserialize("*2\r\n$2\r\nid\r\n:12\r\n");
assert!(
matches!(&result, Err(Error::Client(ClientError::SerdeDeserialize(msg))) if msg.contains("name")),
"{result:?}"
);
}
#[test]
fn struct_from_synthesized_arrays() {
log_try_init();
#[derive(Debug, Deserialize, PartialEq)]
struct Pair {
first: i64,
second: i64,
}
let result: Pair = deserialize_from_resp_response(RespResponse::integer_array(vec![12, 13]))
.expect("integer array");
assert_eq!(
Pair {
first: 12,
second: 13
},
result
);
let result: Pair = deserialize_from_resp_response(RespResponse::owned_array(vec![
RespResponse::integer(12),
RespResponse::integer(13),
]))
.expect("owned array");
assert_eq!(
Pair {
first: 12,
second: 13
},
result
);
}
#[test]
fn r#enum() {
log_try_init();
#[derive(Debug, Deserialize, PartialEq)]
enum E {
A, B(u8), C(u8, u8), D { r: u8, g: u8, b: u8 }, }
let result: Result<E> = deserialize("-ERR error\r\n"); assert!(matches!(
result,
Err(Error::Redis(RedisError {
kind: RedisErrorKind::Err,
description: _
}))
));
let result: E = deserialize("$1\r\nA\r\n").unwrap(); assert_eq!(E::A, result);
let result: E = deserialize("+A\r\n").unwrap(); assert_eq!(E::A, result);
let result: E = deserialize("*2\r\n$1\r\nB\r\n:12\r\n").unwrap(); assert_eq!(E::B(12), result);
let result: E = deserialize("%1\r\n$1\r\nB\r\n:12\r\n").unwrap(); assert_eq!(E::B(12), result);
let result: E = deserialize("*2\r\n$1\r\nC\r\n*2\r\n:12\r\n:13\r\n").unwrap(); assert_eq!(E::C(12, 13), result);
let result: E = deserialize("%1\r\n$1\r\nC\r\n*2\r\n:12\r\n:13\r\n").unwrap(); assert_eq!(E::C(12, 13), result);
let result: E = deserialize(
"*2\r\n$1\r\nD\r\n*6\r\n$1\r\nr\r\n:12\r\n$1\r\ng\r\n:13\r\n$1\r\nb\r\n:14\r\n",
)
.unwrap(); assert_eq!(
E::D {
r: 12,
g: 13,
b: 14
},
result
);
let result: E = deserialize(
"%1\r\n$1\r\nD\r\n*6\r\n$1\r\nr\r\n:12\r\n$1\r\ng\r\n:13\r\n$1\r\nb\r\n:14\r\n",
)
.unwrap(); assert_eq!(
E::D {
r: 12,
g: 13,
b: 14
},
result
);
let result: E = deserialize(
"%1\r\n$1\r\nD\r\n%3\r\n$1\r\nr\r\n:12\r\n$1\r\ng\r\n:13\r\n$1\r\nb\r\n:14\r\n",
)
.unwrap(); assert_eq!(
E::D {
r: 12,
g: 13,
b: 14
},
result
);
}
#[test]
fn map_malformed_nested_scalar_errors() -> Result<()> {
log_try_init();
let result: Result<HashMap<i64, i64>> = deserialize("*1\r\n*2\r\n:abc\r\n:1\r\n");
assert!(result.is_err(), "expected a decode error, got {result:?}");
Ok(())
}
#[test]
fn resp_buf_display_never_panics() {
log_try_init();
let empty = RespBuf::from(Bytes::new());
let _ = format!("{empty}");
let _ = format!("{empty:?}");
let big = RespBuf::from(Bytes::from(vec![b'x'; 64 * 1024]));
let rendered = format!("{big}");
assert!(
rendered.contains("RESP buffer of"),
"large buffer should be summarized, got {rendered}"
);
}
#[test]
fn empty_collections_are_not_null() {
use crate::resp::Value;
log_try_init();
assert_eq!(
Value::Array(vec![]),
deserialize::<Value>("*0\r\n").unwrap()
);
assert!(matches!(
deserialize::<Value>("%0\r\n").unwrap(),
Value::Map(m) if m.is_empty()
));
assert_eq!(Value::Null, deserialize::<Value>("_\r\n").unwrap());
assert_eq!(Value::Null, deserialize::<Value>("*-1\r\n").unwrap());
}
#[test]
fn value_map_with_boolean_key_hashes() -> Result<()> {
use crate::resp::Value;
log_try_init();
let value: Value = deserialize("%1\r\n#t\r\n:1\r\n")?;
let Value::Map(map) = value else {
panic!("expected a Value::Map");
};
assert_eq!(Some(&Value::Integer(1)), map.get(&Value::Boolean(true)));
Ok(())
}
#[test]
fn out_of_range_integer_errors_instead_of_truncating() {
log_try_init();
let result: Result<u8> = deserialize(":300\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"u8 from 300 should error, got {result:?}"
);
let result: Result<u32> = deserialize(":-1\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"u32 from -1 should error, got {result:?}"
);
let value: u8 = deserialize(":42\r\n").unwrap();
assert_eq!(42, value);
}
#[test]
fn i64_min_is_parsed_not_rejected() {
log_try_init();
let value: i64 = deserialize(":-9223372036854775808\r\n").unwrap();
assert_eq!(i64::MIN, value);
let value: i64 = deserialize(":9223372036854775807\r\n").unwrap();
assert_eq!(i64::MAX, value);
}
#[test]
fn null_still_deserializes_to_integer_default() {
log_try_init();
let value: i32 = deserialize("_\r\n").unwrap();
assert_eq!(0, value);
}
#[test]
fn lossy_double_to_integer_errors_instead_of_truncating() {
log_try_init();
let result: Result<i64> = deserialize(",3.9\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"i64 from 3.9 should error, got {result:?}"
);
let result: Result<i64> = deserialize(",1e300\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"i64 from 1e300 should error, got {result:?}"
);
let result: Result<i8> = deserialize(",300\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"i8 from 300 should error, got {result:?}"
);
let result: Result<u32> = deserialize(",-1\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"u32 from -1.0 should error, got {result:?}"
);
let result: Result<i64> = deserialize(",nan\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"i64 from NaN should error, got {result:?}"
);
let result: Result<i64> = deserialize(",inf\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"i64 from inf should error, got {result:?}"
);
let value: i64 = deserialize(",3\r\n").unwrap();
assert_eq!(3, value);
let value: u8 = deserialize(",255.0\r\n").unwrap();
assert_eq!(255, value);
let value: i128 = deserialize(",-42\r\n").unwrap();
assert_eq!(-42, value);
}
#[test]
fn negative_integer_to_u128_errors_instead_of_wrapping() {
log_try_init();
let result: Result<u128> = deserialize(":-1\r\n");
assert!(
matches!(result, Err(Error::Client(ClientError::CannotParseInteger))),
"u128 from -1 should error, got {result:?}"
);
let value: u128 = deserialize(":42\r\n").unwrap();
assert_eq!(42, value);
}