#[cfg(test)]
mod tests {
use super::super::redis::RespValue;
#[test]
fn test_resp3_nested_map_set_value_model_conformance() {
test_complex_mixed_scenario();
test_nested_map_basic();
test_nested_set_basic();
test_edge_cases();
}
fn test_complex_mixed_scenario() {
let value = RespValue::Map(vec![
(
RespValue::BulkString(Some(b"numbers".to_vec())),
RespValue::Set(vec![
RespValue::Integer(1),
RespValue::BulkString(Some(b"two".to_vec())),
]),
),
(
RespValue::BulkString(Some(b"meta".to_vec())),
RespValue::Map(vec![
(
RespValue::SimpleString("proto".to_string()),
RespValue::Integer(3),
),
(
RespValue::SimpleString("mode".to_string()),
RespValue::SimpleString("standalone".to_string()),
),
]),
),
]);
let expected_golden = concat!(
"%2\r\n", "$7\r\nnumbers\r\n", "~2\r\n", ":1\r\n", "$3\r\ntwo\r\n", "$4\r\nmeta\r\n", "%2\r\n", "+proto\r\n", ":3\r\n", "+mode\r\n", "+standalone\r\n", )
.as_bytes();
let actual = value.encode();
assert_eq!(
actual,
expected_golden,
"RESP3 wire format must match redis-rs value model golden bytes\n\
Expected: {:?}\n\
Actual: {:?}",
String::from_utf8_lossy(expected_golden),
String::from_utf8_lossy(&actual)
);
let (decoded, consumed) = RespValue::try_decode(&actual)
.expect("decode should succeed")
.expect("should have complete value");
assert_eq!(decoded, value, "round-trip decode must preserve value");
assert_eq!(consumed, actual.len(), "must consume entire input");
}
fn test_nested_map_basic() {
let nested_map = RespValue::Map(vec![
(
RespValue::BulkString(Some(b"level1".to_vec())),
RespValue::Map(vec![
(
RespValue::BulkString(Some(b"level2".to_vec())),
RespValue::Integer(42),
),
(
RespValue::SimpleString("key".to_string()),
RespValue::SimpleString("value".to_string()),
),
]),
),
(
RespValue::BulkString(Some(b"direct".to_vec())),
RespValue::Integer(123),
),
]);
let encoded = nested_map.encode();
let (decoded, consumed) = RespValue::try_decode(&encoded)
.expect("decode should succeed")
.expect("should have complete value");
assert_eq!(decoded, nested_map, "nested map round-trip failed");
assert_eq!(consumed, encoded.len(), "must consume entire input");
}
fn test_nested_set_basic() {
let nested_set = RespValue::Set(vec![
RespValue::Integer(1),
RespValue::Set(vec![
RespValue::BulkString(Some(b"inner1".to_vec())),
RespValue::BulkString(Some(b"inner2".to_vec())),
]),
RespValue::Integer(3),
]);
let encoded = nested_set.encode();
let (decoded, consumed) = RespValue::try_decode(&encoded)
.expect("decode should succeed")
.expect("should have complete value");
assert_eq!(decoded, nested_set, "nested set round-trip failed");
assert_eq!(consumed, encoded.len(), "must consume entire input");
}
fn test_edge_cases() {
let empty_map = RespValue::Map(vec![]);
let encoded = empty_map.encode();
assert_eq!(encoded, b"%0\r\n");
let (decoded, consumed) = RespValue::try_decode(&encoded).unwrap().unwrap();
assert_eq!(decoded, empty_map);
assert_eq!(
consumed,
encoded.len(),
"empty map must consume entire input"
);
let empty_set = RespValue::Set(vec![]);
let encoded = empty_set.encode();
assert_eq!(encoded, b"~0\r\n");
let (decoded, consumed) = RespValue::try_decode(&encoded).unwrap().unwrap();
assert_eq!(decoded, empty_set);
assert_eq!(
consumed,
encoded.len(),
"empty set must consume entire input"
);
let single_map = RespValue::Map(vec![(
RespValue::SimpleString("key".to_string()),
RespValue::Integer(42),
)]);
let encoded = single_map.encode();
let (decoded, consumed) = RespValue::try_decode(&encoded).unwrap().unwrap();
assert_eq!(decoded, single_map);
assert_eq!(
consumed,
encoded.len(),
"single-element map must consume entire input"
);
let single_set = RespValue::Set(vec![RespValue::Integer(42)]);
let encoded = single_set.encode();
let (decoded, consumed) = RespValue::try_decode(&encoded).unwrap().unwrap();
assert_eq!(decoded, single_set);
assert_eq!(
consumed,
encoded.len(),
"single-element set must consume entire input"
);
}
}