use super::Accept;
use crate::timestamp::timestamp::TimeStamp;
use deku::prelude::*;
use rand::random;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "big")]
pub struct ServerStart {
#[deku(assert_eq = "[0u8; 15]")]
mbz_start: [u8; 15],
accept: Accept,
server_iv: [u8; 16],
start_time: TimeStamp,
#[deku(assert_eq = "[0u8; 8]")]
mbz_end: [u8; 8],
}
impl ServerStart {
pub fn new(accept: Accept, start_time: Duration) -> Self {
ServerStart {
mbz_start: [0; 15],
accept,
server_iv: Vec::from([0; 16])
.iter()
.map(|_| random())
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
start_time: TimeStamp::try_from(start_time)
.expect("should have converted duration to timestamp."),
mbz_end: [0; 8],
}
}
pub fn accept(&self) -> &Accept {
&self.accept
}
pub fn start_time(&self) -> &TimeStamp {
&self.start_time
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
const SERVER_START_LENGTH_IN_BYTES: usize = 48;
const TIME: Duration = Duration::new(1713023152, 123456789);
#[test]
fn create_server_start_with_accept_ok() {
let accept = Accept::Ok;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn create_server_start_with_accept_failure() {
let accept = Accept::Failure;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn create_server_start_with_accept_internal_error() {
let accept = Accept::InternalError;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn create_server_start_with_accept_not_supported() {
let accept = Accept::NotSupported;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn create_server_start_with_accept_permanent_resource_limitation() {
let accept = Accept::PermanentResourceLimitation;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn create_server_start_with_accept_temporary_resource_limitation() {
let accept = Accept::TemporaryResourceLimitation;
let server_start = ServerStart::new(accept, TIME);
let server_start_accept: u8 = server_start.accept.into();
assert_eq!(server_start_accept, accept.into());
}
#[test]
fn first_mbz_are_zeros() {
let server_start = ServerStart::new(Accept::Ok, TIME);
assert!(server_start.mbz_start == [0; 15]);
}
#[test]
fn last_mbz_are_zeros() {
let server_start = ServerStart::new(Accept::Ok, TIME);
assert!(server_start.mbz_end == [0; 8]);
}
#[test]
fn server_iv_is_random() {
let server_start = ServerStart::new(Accept::Ok, TIME);
let server_iv_bytes_unique = server_start.server_iv.iter().collect::<HashSet<_>>();
assert!(server_iv_bytes_unique.len() > 1);
}
#[test]
fn should_serialize_to_correct_bytes() {
let server_start = ServerStart::new(Accept::Ok, TIME);
let encoded = server_start.to_bytes().unwrap();
assert_eq!(encoded.len(), SERVER_START_LENGTH_IN_BYTES);
}
#[test]
fn should_deserialize_to_correct_struct() {
let server_start = ServerStart::new(Accept::Ok, TIME);
let encoded = server_start.to_bytes().unwrap();
let (_rest, val) = ServerStart::from_bytes((&encoded, 0)).unwrap();
assert_eq!(val, server_start);
}
}