use crate::{
Error, RedisError, RedisErrorKind, Result,
resp::{RespBuf, RespDeserializer, RespFrameParser, RespResponse},
tests::log_try_init,
};
use bytes::Bytes;
use serde::Deserialize;
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 (frame, _) = RespFrameParser::new(buf).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 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 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 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
);
}