diff --git a/src/constants.rs b/src/constants.rs index a41a07d..bc0b12a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,9 +1,9 @@ -pub const RESPONSE_VALUE: i32 = 1; // VALUE (VA) -pub const RESPONSE_SUCCESS: i32 = 2; // SUCCESS (OK or HD) -pub const RESPONSE_NOT_STORED: i32 = 3; // NOT_STORED (NS) -pub const RESPONSE_CONFLICT: i32 = 4; // CONFLICT (EX) -pub const RESPONSE_MISS: i32 = 5; // MISS (EN or NF) -pub const RESPONSE_NOOP: i32 = 100; // NOOP (MN) +pub const RESPONSE_VALUE: u8 = 1; // VALUE (VA) +pub const RESPONSE_SUCCESS: u8 = 2; // SUCCESS (OK or HD) +pub const RESPONSE_NOT_STORED: u8 = 3; // NOT_STORED (NS) +pub const RESPONSE_CONFLICT: u8 = 4; // CONFLICT (EX) +pub const RESPONSE_MISS: u8 = 5; // MISS (EN or NF) +pub const RESPONSE_NOOP: u8 = 100; // NOOP (MN) // Set modes: // E: "add" command. LRU bump and return NS if item exists. Else add. diff --git a/src/impl_build_cmd.rs b/src/impl_build_cmd.rs index 1a33dc9..f09f94e 100644 --- a/src/impl_build_cmd.rs +++ b/src/impl_build_cmd.rs @@ -71,197 +71,3 @@ pub fn impl_build_cmd( buf.push(b'\n'); Some(buf) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_impl_build_cmd_with_flags() { - let cmd = b"mg"; - let key = b"key"; - let request_flags = RequestFlags::new( - true, // no_reply - true, // return_client_flag - true, // return_cas_token - true, // return_value - true, // return_ttl - true, // return_size - true, // return_last_access - true, // return_fetched - true, // return_key - true, // no_update_lru - true, // mark_stale - Some(111), // cache_ttl - Some(222), // recache_ttl - Some(333), // vivify_on_miss_ttl - Some(444), // client_flag - Some(555), // ma_initial_value - Some(666), // ma_delta_value, - Some(777), // cas_token - Some(b"opaque".to_vec()), // opaque - Some(65 as u8), // mode - ); - - let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!( - result, - b"mg key q f c v t s l h k u I T111 R222 N333 F444 J555 D666 C777 Oopaque MA\r\n" - ); - } - - #[test] - fn test_impl_build_cmd_no_flags() { - let cmd = b"mg"; - let key = b"key"; - let request_flags = RequestFlags::new( - false, // no_reply - false, // return_client_flag - false, // return_cas_token - false, // return_value - false, // return_ttl - false, // return_size - false, // return_last_access - false, // return_fetched - false, // return_key - false, // no_update_lru - false, // mark_stale - None, // cache_ttl - None, // recache_ttl - None, // vivify_on_miss_ttl - None, // client_flag - None, // ma_initial_value - None, // ma_delta_value, - None, // cas_token - None, // opaque - None, // mode - ); - - let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!(result, b"mg key\r\n"); - } - - #[test] - fn test_impl_build_cmd_binary_key() { - let cmd = b"mg"; - let key = b"Key_with_binary\x00"; - let request_flags = RequestFlags::new( - false, // no_reply - false, // return_client_flag - false, // return_cas_token - false, // return_value - false, // return_ttl - false, // return_size - false, // return_last_access - false, // return_fetched - false, // return_key - false, // no_update_lru - false, // mark_stale - None, // cache_ttl - None, // recache_ttl - None, // vivify_on_miss_ttl - None, // client_flag - None, // ma_initial_value - None, // ma_delta_value, - None, // cas_token - None, // opaque - None, // mode - ); - - let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!(result, b"mg S2V5X3dpdGhfYmluYXJ5AA== b\r\n"); - } - - #[test] - fn test_impl_build_cmd_key_with_spaces() { - let cmd = b"mg"; - let key = b"Key with spaces"; - let request_flags = RequestFlags::new( - false, // no_reply - false, // return_client_flag - false, // return_cas_token - false, // return_value - false, // return_ttl - false, // return_size - false, // return_last_access - false, // return_fetched - false, // return_key - false, // no_update_lru - false, // mark_stale - None, // cache_ttl - None, // recache_ttl - None, // vivify_on_miss_ttl - None, // client_flag - None, // ma_initial_value - None, // ma_delta_value, - None, // cas_token - None, // opaque - None, // mode - ); - - let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!(result, b"mg S2V5IHdpdGggc3BhY2Vz b\r\n"); - } - - #[test] - fn test_impl_build_cmd_large_key() { - let cmd = b"mg"; - let key = &vec![b'X'; 250]; - let no_result = impl_build_cmd(cmd, key, None, None, false); - assert!(no_result.is_none()); - } - - #[test] - fn test_cmd_with_size() { - let cmd = b"ms"; - let key = b"key"; - let size = 123; - let request_flags = RequestFlags::new( - false, // no_reply - false, // return_client_flag - false, // return_cas_token - false, // return_value - false, // return_ttl - false, // return_size - false, // return_last_access - false, // return_fetched - false, // return_key - false, // no_update_lru - false, // mark_stale - Some(111), // cache_ttl - None, // recache_ttl - None, // vivify_on_miss_ttl - None, // client_flag - None, // ma_initial_value - None, // ma_delta_value, - None, // cas_token - None, // opaque - None, // mode - ); - - let result = impl_build_cmd(cmd, key, Some(size), Some(&request_flags), false).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!(result, b"ms key 123 T111\r\n"); - } - - #[test] - fn test_cmd_with_legacy_size() { - let cmd = b"ms"; - let key = b"key"; - let size = 123; - - let result = impl_build_cmd(cmd, key, Some(size), None, true).unwrap(); - let string = String::from_utf8_lossy(&result); - println!("{:?}", string); - assert_eq!(result, b"ms key S123\r\n"); - } -} diff --git a/src/impl_build_cmd_tests.rs b/src/impl_build_cmd_tests.rs new file mode 100644 index 0000000..86be468 --- /dev/null +++ b/src/impl_build_cmd_tests.rs @@ -0,0 +1,194 @@ +#[cfg(test)] +mod tests { + use crate::impl_build_cmd; + use crate::request_flags::RequestFlags; + + #[test] + fn test_impl_build_cmd_with_flags() { + let cmd = b"mg"; + let key = b"key"; + let request_flags = RequestFlags::new( + true, // no_reply + true, // return_client_flag + true, // return_cas_token + true, // return_value + true, // return_ttl + true, // return_size + true, // return_last_access + true, // return_fetched + true, // return_key + true, // no_update_lru + true, // mark_stale + Some(111), // cache_ttl + Some(222), // recache_ttl + Some(333), // vivify_on_miss_ttl + Some(444), // client_flag + Some(555), // ma_initial_value + Some(666), // ma_delta_value, + Some(777), // cas_token + Some(b"opaque".to_vec()), // opaque + Some(65 as u8), // mode + ); + + let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!( + result, + b"mg key q f c v t s l h k u I T111 R222 N333 F444 J555 D666 C777 Oopaque MA\r\n" + ); + } + + #[test] + fn test_impl_build_cmd_no_flags() { + let cmd = b"mg"; + let key = b"key"; + let request_flags = RequestFlags::new( + false, // no_reply + false, // return_client_flag + false, // return_cas_token + false, // return_value + false, // return_ttl + false, // return_size + false, // return_last_access + false, // return_fetched + false, // return_key + false, // no_update_lru + false, // mark_stale + None, // cache_ttl + None, // recache_ttl + None, // vivify_on_miss_ttl + None, // client_flag + None, // ma_initial_value + None, // ma_delta_value, + None, // cas_token + None, // opaque + None, // mode + ); + + let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!(result, b"mg key\r\n"); + } + + #[test] + fn test_impl_build_cmd_binary_key() { + let cmd = b"mg"; + let key = b"Key_with_binary\x00"; + let request_flags = RequestFlags::new( + false, // no_reply + false, // return_client_flag + false, // return_cas_token + false, // return_value + false, // return_ttl + false, // return_size + false, // return_last_access + false, // return_fetched + false, // return_key + false, // no_update_lru + false, // mark_stale + None, // cache_ttl + None, // recache_ttl + None, // vivify_on_miss_ttl + None, // client_flag + None, // ma_initial_value + None, // ma_delta_value, + None, // cas_token + None, // opaque + None, // mode + ); + + let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!(result, b"mg S2V5X3dpdGhfYmluYXJ5AA== b\r\n"); + } + + #[test] + fn test_impl_build_cmd_key_with_spaces() { + let cmd = b"mg"; + let key = b"Key with spaces"; + let request_flags = RequestFlags::new( + false, // no_reply + false, // return_client_flag + false, // return_cas_token + false, // return_value + false, // return_ttl + false, // return_size + false, // return_last_access + false, // return_fetched + false, // return_key + false, // no_update_lru + false, // mark_stale + None, // cache_ttl + None, // recache_ttl + None, // vivify_on_miss_ttl + None, // client_flag + None, // ma_initial_value + None, // ma_delta_value, + None, // cas_token + None, // opaque + None, // mode + ); + + let result = impl_build_cmd(cmd, key, None, Some(&request_flags), false).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!(result, b"mg S2V5IHdpdGggc3BhY2Vz b\r\n"); + } + + #[test] + fn test_impl_build_cmd_large_key() { + let cmd = b"mg"; + let key = &vec![b'X'; 250]; + let no_result = impl_build_cmd(cmd, key, None, None, false); + assert!(no_result.is_none()); + } + + #[test] + fn test_cmd_with_size() { + let cmd = b"ms"; + let key = b"key"; + let size = 123; + let request_flags = RequestFlags::new( + false, // no_reply + false, // return_client_flag + false, // return_cas_token + false, // return_value + false, // return_ttl + false, // return_size + false, // return_last_access + false, // return_fetched + false, // return_key + false, // no_update_lru + false, // mark_stale + Some(111), // cache_ttl + None, // recache_ttl + None, // vivify_on_miss_ttl + None, // client_flag + None, // ma_initial_value + None, // ma_delta_value, + None, // cas_token + None, // opaque + None, // mode + ); + + let result = impl_build_cmd(cmd, key, Some(size), Some(&request_flags), false).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!(result, b"ms key 123 T111\r\n"); + } + + #[test] + fn test_cmd_with_legacy_size() { + let cmd = b"ms"; + let key = b"key"; + let size = 123; + + let result = impl_build_cmd(cmd, key, Some(size), None, true).unwrap(); + let string = String::from_utf8_lossy(&result); + println!("{:?}", string); + assert_eq!(result, b"ms key S123\r\n"); + } +} diff --git a/src/impl_parse_header.rs b/src/impl_parse_header.rs index 511cd8e..531d7b2 100644 --- a/src/impl_parse_header.rs +++ b/src/impl_parse_header.rs @@ -4,7 +4,7 @@ pub fn impl_parse_header( data: &[u8], start: usize, end: usize, -) -> Option<(usize, Option, Option, Option)> { +) -> Option<(usize, Option, Option, Option)> { if end - start < 4 { return None; } @@ -49,166 +49,3 @@ pub fn impl_parse_header( } None } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_no_crnl_in_buffer() { - let data = b"X\rX\nX"; - let no_result = impl_parse_header(data, 0, data.len()); - assert!(no_result.is_none()); - } - #[test] - fn test_value_response() { - let data = b"VA 1234 c1234567 h0 l1111 t2222 f1 Z s3333 MORE_SPACES_ARE_OK_TOO Ofoobar UNKNOWN FLAGS\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_VALUE)); - assert_eq!(size, Some(1234)); - assert!(flags.is_some()); - let flags = flags.unwrap(); - assert_eq!(flags.cas_token, Some(1234567)); - assert_eq!(flags.fetched, Some(false)); - assert_eq!(flags.last_access, Some(1111)); - assert_eq!(flags.ttl, Some(2222)); - assert_eq!(flags.client_flag, Some(1)); - assert_eq!(flags.win, Some(false)); - assert_eq!(flags.stale, false); - assert_eq!(flags.size, Some(3333)); - assert_eq!(flags.opaque, Some(b"foobar".to_vec())); - } - - #[test] - fn test_value_response_no_flags() { - let data = b"VA 1234\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_VALUE)); - assert_eq!(size, Some(1234)); - assert!(flags.is_some()); - let flags = flags.unwrap(); - assert!(flags.cas_token.is_none()); - assert!(flags.fetched.is_none()); - assert!(flags.last_access.is_none()); - assert!(flags.ttl.is_none()); - assert!(flags.client_flag.is_none()); - assert!(flags.win.is_none()); - assert_eq!(flags.stale, false); - assert!(flags.size.is_none()); - assert!(flags.opaque.is_none()); - } - - #[test] - fn test_value_response_no_size() { - let data = b"VA c123\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert!(response_type.is_none()); - assert!(size.is_none()); - assert!(flags.is_none()); - } - - #[test] - fn test_success_reponse() { - let data = b"HD c1234567 h0 l1111 t2222 f1 X W s3333 Ofoobar UNKNOWN FLAGS\r\nOK\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len() - 4); - assert_eq!(response_type, Some(RESPONSE_SUCCESS)); - assert!(size.is_none()); - assert!(flags.is_some()); - let flags = flags.unwrap(); - assert_eq!(flags.cas_token, Some(1234567)); - assert_eq!(flags.fetched, Some(false)); - assert_eq!(flags.last_access, Some(1111)); - assert_eq!(flags.ttl, Some(2222)); - assert_eq!(flags.client_flag, Some(1)); - assert_eq!(flags.win, Some(true)); - assert_eq!(flags.stale, true); - assert_eq!(flags.size, Some(3333)); - assert_eq!(flags.opaque, Some(b"foobar".to_vec())); - let (end_pos, response_type, size, flags) = - impl_parse_header(data, data.len() - 4, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_SUCCESS)); - assert!(size.is_none()); - assert!(flags.is_some()); - let flags = flags.unwrap(); - assert!(flags.cas_token.is_none()); - assert!(flags.fetched.is_none()); - assert!(flags.last_access.is_none()); - assert!(flags.ttl.is_none()); - assert!(flags.client_flag.is_none()); - assert!(flags.win.is_none()); - assert_eq!(flags.stale, false); - assert!(flags.size.is_none()); - assert!(flags.opaque.is_none()); - } - - #[test] - fn test_not_stored_response() { - let data = b"NS\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_NOT_STORED)); - assert!(size.is_none()); - assert!(flags.is_none()); - } - #[test] - fn test_conflict_response() { - let data = b"EX\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_CONFLICT)); - assert!(size.is_none()); - assert!(flags.is_none()); - } - #[test] - fn test_miss_response() { - let data = b"EN\r\nNF\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, 4); // Only reads the first response header - assert_eq!(response_type, Some(RESPONSE_MISS)); - assert!(size.is_none()); - assert!(flags.is_none()); - let (end_pos, response_type, size, flags) = impl_parse_header(data, 4, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_MISS)); - assert!(size.is_none()); - assert!(flags.is_none()); - } - #[test] - fn test_noop_response() { - let data = b"MN\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert_eq!(response_type, Some(RESPONSE_NOOP)); - assert!(size.is_none()); - assert!(flags.is_none()); - } - - #[test] - fn test_unknown_response() { - let data = b"XX 33 c1 Z f1\r\n"; - let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); - assert_eq!(end_pos, data.len()); - assert!(response_type.is_none()); - assert!(size.is_none()); - assert!(flags.is_none()); - } - - #[test] - fn test_response_too_small() { - let data = b"X\r\n"; - let no_result = impl_parse_header(data, 0, data.len()); - assert!(no_result.is_none()); - } - - #[test] - fn test_end_is_out_of_bounds() { - let data = b"NOENDLINE"; - let no_result = impl_parse_header(data, 0, data.len() + 100); - assert!(no_result.is_none()); - } -} diff --git a/src/impl_parse_header_tests.rs b/src/impl_parse_header_tests.rs new file mode 100644 index 0000000..8fb3a40 --- /dev/null +++ b/src/impl_parse_header_tests.rs @@ -0,0 +1,163 @@ +#[cfg(test)] +mod tests { + use crate::constants::*; + use crate::impl_parse_header; + + #[test] + fn test_no_crnl_in_buffer() { + let data = b"X\rX\nX"; + let no_result = impl_parse_header(data, 0, data.len()); + assert!(no_result.is_none()); + } + #[test] + fn test_value_response() { + let data = b"VA 1234 c1234567 h0 l1111 t2222 f1 Z s3333 MORE_SPACES_ARE_OK_TOO Ofoobar UNKNOWN FLAGS\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_VALUE)); + assert_eq!(size, Some(1234)); + assert!(flags.is_some()); + let flags = flags.unwrap(); + assert_eq!(flags.cas_token, Some(1234567)); + assert_eq!(flags.fetched, Some(false)); + assert_eq!(flags.last_access, Some(1111)); + assert_eq!(flags.ttl, Some(2222)); + assert_eq!(flags.client_flag, Some(1)); + assert_eq!(flags.win, Some(false)); + assert_eq!(flags.stale, false); + assert_eq!(flags.size, Some(3333)); + assert_eq!(flags.opaque, Some(b"foobar".to_vec())); + } + + #[test] + fn test_value_response_no_flags() { + let data = b"VA 1234\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_VALUE)); + assert_eq!(size, Some(1234)); + assert!(flags.is_some()); + let flags = flags.unwrap(); + assert!(flags.cas_token.is_none()); + assert!(flags.fetched.is_none()); + assert!(flags.last_access.is_none()); + assert!(flags.ttl.is_none()); + assert!(flags.client_flag.is_none()); + assert!(flags.win.is_none()); + assert_eq!(flags.stale, false); + assert!(flags.size.is_none()); + assert!(flags.opaque.is_none()); + } + + #[test] + fn test_value_response_no_size() { + let data = b"VA c123\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert!(response_type.is_none()); + assert!(size.is_none()); + assert!(flags.is_none()); + } + + #[test] + fn test_success_reponse() { + let data = b"HD c1234567 h0 l1111 t2222 f1 X W s3333 Ofoobar UNKNOWN FLAGS\r\nOK\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len() - 4); + assert_eq!(response_type, Some(RESPONSE_SUCCESS)); + assert!(size.is_none()); + assert!(flags.is_some()); + let flags = flags.unwrap(); + assert_eq!(flags.cas_token, Some(1234567)); + assert_eq!(flags.fetched, Some(false)); + assert_eq!(flags.last_access, Some(1111)); + assert_eq!(flags.ttl, Some(2222)); + assert_eq!(flags.client_flag, Some(1)); + assert_eq!(flags.win, Some(true)); + assert_eq!(flags.stale, true); + assert_eq!(flags.size, Some(3333)); + assert_eq!(flags.opaque, Some(b"foobar".to_vec())); + let (end_pos, response_type, size, flags) = + impl_parse_header(data, data.len() - 4, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_SUCCESS)); + assert!(size.is_none()); + assert!(flags.is_some()); + let flags = flags.unwrap(); + assert!(flags.cas_token.is_none()); + assert!(flags.fetched.is_none()); + assert!(flags.last_access.is_none()); + assert!(flags.ttl.is_none()); + assert!(flags.client_flag.is_none()); + assert!(flags.win.is_none()); + assert_eq!(flags.stale, false); + assert!(flags.size.is_none()); + assert!(flags.opaque.is_none()); + } + + #[test] + fn test_not_stored_response() { + let data = b"NS\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_NOT_STORED)); + assert!(size.is_none()); + assert!(flags.is_none()); + } + #[test] + fn test_conflict_response() { + let data = b"EX\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_CONFLICT)); + assert!(size.is_none()); + assert!(flags.is_none()); + } + #[test] + fn test_miss_response() { + let data = b"EN\r\nNF\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, 4); // Only reads the first response header + assert_eq!(response_type, Some(RESPONSE_MISS)); + assert!(size.is_none()); + assert!(flags.is_none()); + let (end_pos, response_type, size, flags) = impl_parse_header(data, 4, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_MISS)); + assert!(size.is_none()); + assert!(flags.is_none()); + } + #[test] + fn test_noop_response() { + let data = b"MN\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert_eq!(response_type, Some(RESPONSE_NOOP)); + assert!(size.is_none()); + assert!(flags.is_none()); + } + + #[test] + fn test_unknown_response() { + let data = b"XX 33 c1 Z f1\r\n"; + let (end_pos, response_type, size, flags) = impl_parse_header(data, 0, data.len()).unwrap(); + assert_eq!(end_pos, data.len()); + assert!(response_type.is_none()); + assert!(size.is_none()); + assert!(flags.is_none()); + } + + #[test] + fn test_response_too_small() { + let data = b"X\r\n"; + let no_result = impl_parse_header(data, 0, data.len()); + assert!(no_result.is_none()); + } + + #[test] + fn test_end_is_out_of_bounds() { + let data = b"NOENDLINE"; + let no_result = impl_parse_header(data, 0, data.len() + 100); + assert!(no_result.is_none()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 19a0969..8b9d564 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ mod constants; mod impl_build_cmd; +mod impl_build_cmd_tests; mod impl_parse_header; +mod impl_parse_header_tests; mod request_flags; mod response_flags; pub use constants::*; @@ -28,7 +30,7 @@ pub fn parse_header( buffer: PyBuffer, start: usize, end: usize, -) -> PyResult, Option, Option)>> { +) -> PyResult, Option, Option)>> { if end > buffer.len_bytes() { return Err(pyo3::exceptions::PyValueError::new_err( "End must be less than buffer length",