rustyphoenixclockmockbackend 1.7.0

This is the Rust version of https://gitlab.in2p3.fr/CTA-LAPP/PHOENIX_LIBS2/PhoenixClock project. This project aims to ease the use of clock in complex environments, especially distributed environments where latencies measurement has to be precise and reproductible when running unit tests. **PhoenixClock** provide **PGenericClock**, a template classe which takes two arguments : - The main clock backend (could be **clock**, **PClockNs** for nanoseconds, etc) - A mock of a clock, **PClockMock**, which can play, register and replay a sequence of clock calls These clocks are activated with a mode `PClockMode::PClockMode` which can be : - `PClockMode::NO_MOCK` : for a normal usage - `PClockMode::MOCK` : when the mock the desired clock is played - `PClockMode::MOCK_RECORD` : when the real clock backend is used but the clock mock is recording (could be usefull for debugging or to desing new unit tests quickly)
Documentation
/***************************************
	Auteur : Pierre Aubert
	Mail : pierre.aubert@lapp.in2p3.fr
	Licence : CeCILL-C
****************************************/

//{Let's use the \lib{clock_backend} and \lib{rusty_phoenix_data_stream} :
use rustyphoenixclockbackend::{AbstractClockBackend, AbstractClockMockBackend, SimpleTime};
use rustyphoenixdatastream::{datastream_read, datastream_write};

//{Now, we can define our \class{ClockMockBackend} :
///The ClockMockBackend defines a clock backend which implements the `AbstractClockBackend`
///trait and is able to play, record and replay a set of time
#[derive(Debug, Default)]
pub struct ClockMockBackend{
	///Tell if the Backend is in MockRecord mode or not
	is_mock_record: bool,
	///Vector of all times to be read or recorded
	vec_time: Vec<SimpleTime>,
	///Index of the current time
	current_index: usize,
}

//{And, let's implement the \lib{AbstractClockBackend} \b{trait} for \class{ClockMockBackend} :
///Implement the classic clock
impl AbstractClockBackend for ClockMockBackend {
//{The \funct{new} method :
	///Create a ClockMockBackend
	/// # Parameters
	/// - `is_mock_record` - true is the mock record is on
	/// # Returns
	/// constructed ClockMockBackend
	fn new(is_mock_record: bool) -> Self {
		let mut mock = ClockMockBackend{
			is_mock_record: is_mock_record,
			vec_time: vec![],
			current_index: 0
		};
		if !is_mock_record {
			let _ = datastream_read(&String::from("clock.clockmock"), &mut mock.vec_time);
		}
		return mock;
	}
//{The \funct{now} method :
	///Get the current time
	/// # Return
	/// current time
	fn now(&mut self) -> SimpleTime {
		if !self.is_mock_record && self.current_index < self.vec_time.len() {
			let current_time = self.vec_time[self.current_index];
			self.current_index += 1;
			if self.current_index >= self.vec_time.len() {
				self.current_index = 0;
			}
			return current_time;
		}
		return 0;
	}
//{The sleep method :
	///Sleep of the current clock backend
	/// # Parameters
	/// - `_ellapsed_sleep_time` : ellapsed time to sleep the program in the units of the clock
	fn sleep(&self, _ellapsed_sleep_time: SimpleTime){}
//{And the end of our impl :
}

impl AbstractClockMockBackend for ClockMockBackend{
//{The \funct{set_time} method :
	///Set the current time of the clock (does nothing for our current clock)
	/// # Parameters
	/// - `current_time` - current time to be set
	fn set_time(&mut self, current_time: SimpleTime){
		if self.is_mock_record {
			self.vec_time.push(current_time);
		}
	}
//{The \funct{set_is_record} method :
	///Set the record mode in the mock
	/// # Parameters
	/// - `is_mock_record` - true if the mock is in record mode
	fn set_is_record(&mut self, is_mock_record: bool){
		if self.is_mock_record == is_mock_record {
			return;
		}else{
			self.is_mock_record = is_mock_record;
			if self.is_mock_record {
				//We pass in mock record
				self.vec_time.resize(0, 0);
			}else{
				//We pass in standard mode but we were in record mode previously
				//So let's flush what we recorded before
				let _ = datastream_write(&String::from("clock.clockmock"), &self.vec_time);
			}
			//We have to reset the indzex anyway
			self.current_index = 0;
		}
	}
}

//{We also need a desctructor to save the recorded mock if the mock record is enabled :
impl Drop for ClockMockBackend {
	///Destructor of the ClockMockBackend
	fn drop(&mut self) {
		if self.is_mock_record {
			let _ = datastream_write(&String::from("clock.clockmock"), &self.vec_time);
		}
	}
}

//{We can implement unit tests :
#[cfg(test)]
mod tests {
	use super::*;
	
//{Here, we have to be careful because \lib{Rust} will try to be smart and will execute all tests in parallel. But, we cannot do that otherwise we will have read/write of the mock file at the same time which will be bad. So, let's test all in the same function
	///Test the record mode
	fn test_mock_record(){
		let mut mock = ClockMockBackend::new(true);
		mock.set_time(1);
		mock.set_time(2);
		mock.set_time(3);
		mock.set_time(4);
		mock.set_time(5);
		mock.set_is_record(true);
		mock.set_is_record(false);
		//Now, let's replay what we just recorded
		assert_eq!(mock.now(), 1);
		assert_eq!(mock.now(), 2);
		assert_eq!(mock.now(), 3);
		assert_eq!(mock.now(), 4);
		assert_eq!(mock.now(), 5);
		mock.sleep(2);
	}
	
	///Test the normal mode
	fn test_mock_standard(){
		let mut mock = ClockMockBackend::new(false);
		assert_eq!(mock.now(), 1);
		assert_eq!(mock.now(), 2);
		assert_eq!(mock.now(), 3);
		assert_eq!(mock.now(), 4);
		assert_eq!(mock.now(), 5);
		mock.set_is_record(true);
		mock.set_time(1);
		mock.set_time(2);
		mock.set_time(3);
		mock.set_time(4);
		mock.set_time(5);
	}
	
	#[test]
	fn test_full_mock() {
		//We start with the record mode
		test_mock_record();
		//Then the standard mode
		test_mock_standard();
	}
}