diff --git a/.idea/runConfigurations/Test_All.xml b/.idea/runConfigurations/Test_All.xml
new file mode 100644
index 0000000..6f884df
--- /dev/null
+++ b/.idea/runConfigurations/Test_All.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/core/executable.rs b/src/core/executable.rs
index b0fdf5a..aca2692 100644
--- a/src/core/executable.rs
+++ b/src/core/executable.rs
@@ -26,6 +26,7 @@ pub trait Executable: Send {
}
/// This function allows executing one task which implements the [Executable][Executable] trait
+///
/// # Arguments
///
/// * `executable`: Executable task
@@ -74,6 +75,7 @@ pub fn exec_sched_single<
/// This function allows executing multiple tasks as long as the tasks implement the
/// [Executable][Executable] trait
+///
/// # Arguments
///
/// * `executable_vec`: Vector of executable objects
@@ -134,10 +136,11 @@ pub fn exec_sched_multi<
#[cfg(test)]
mod tests {
use super::{exec_sched_multi, exec_sched_single, Executable, ExecutionType, OpResult};
+ use bus::Bus;
use std::error::Error;
- use std::fmt;
use std::sync::{Arc, Mutex};
use std::time::Duration;
+ use std::{fmt, thread};
struct TestInfo {
exec_num: u32,
@@ -154,32 +157,41 @@ mod tests {
exec_num: Arc>,
}
- #[derive(Debug, PartialEq)]
+ #[derive(Clone, Debug)]
struct ExampleError {
- details: String,
- code: i32,
+ kind: ErrorKind,
+ }
+
+ /// The kind of an error that can occur.
+ #[derive(Clone, Debug)]
+ pub enum ErrorKind {
+ Generic(String, i32)
}
impl ExampleError {
fn new(msg: &str, code: i32) -> ExampleError {
ExampleError {
- details: msg.to_string(),
- code,
+ kind: ErrorKind::Generic(msg.to_string(), code)
}
}
+
+ /// Return the kind of this error.
+ pub fn kind(&self) -> &ErrorKind {
+ &self.kind
+ }
}
impl fmt::Display for ExampleError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.details)
+ match self.kind() {
+ ErrorKind::Generic(str, code) => {
+ write!(f, "{str} with code {code}")
+ }
+ }
}
}
- impl Error for ExampleError {
- fn description(&self) -> &str {
- &self.details
- }
- }
+ impl Error for ExampleError {}
const ONE_SHOT_TASK_NAME: &str = "One Shot Task";
@@ -233,6 +245,8 @@ mod tests {
}
}
+ const PERIODIC_TASK_NAME: &str = "Periodic Task";
+
impl Executable for PeriodicTask {
type Error = ExampleError;
@@ -241,7 +255,7 @@ mod tests {
}
fn task_name(&self) -> &'static str {
- "Periodic Task"
+ PERIODIC_TASK_NAME
}
fn periodic_op(&mut self, op_code: i32) -> Result {
@@ -282,6 +296,41 @@ mod tests {
assert_eq!(data.op_code, expected_op_code);
}
+ #[test]
+ fn test_failed_one_shot() {
+ let op_code_inducing_failure = -1;
+ let shared = Arc::new(Mutex::new(TestInfo {
+ exec_num: 0,
+ op_code: 0,
+ }));
+ let exec_task = OneShotTask {
+ exec_num: shared.clone(),
+ };
+ let task = Box::new(exec_task);
+ let jhandle = exec_sched_single(
+ task,
+ Some(Duration::from_millis(100)),
+ op_code_inducing_failure,
+ None,
+ );
+ let thread_res = jhandle.join().expect("One Shot Task failed");
+ assert!(thread_res.is_err());
+ let error = thread_res.unwrap_err();
+ let err = error.kind();
+ assert!(matches!(err, &ErrorKind::Generic { .. }));
+ match err {
+ ErrorKind::Generic(str, op_code) => {
+ assert_eq!(str, &String::from("One Shot Task Failure"));
+ assert_eq!(op_code, &op_code_inducing_failure);
+ }
+ }
+ let error_display = error.to_string();
+ assert_eq!(error_display, "One Shot Task Failure with code -1");
+ let data = shared.lock().expect("Locking Mutex failed");
+ assert_eq!(data.exec_num, 1);
+ assert_eq!(data.op_code, op_code_inducing_failure);
+ }
+
#[test]
fn test_simple_multi_one_shot() {
let expected_op_code = 43;
@@ -314,7 +363,7 @@ mod tests {
}
#[test]
- fn test_cycles() {
+ fn test_cycles_single() {
let expected_op_code = 44;
let shared = Arc::new(Mutex::new(TestInfo {
exec_num: 0,
@@ -325,7 +374,12 @@ mod tests {
cycles: 1,
});
assert_eq!(cycled_task.task_name(), CYCLE_TASK_NAME);
- let jh = exec_sched_single(cycled_task, Some(Duration::from_millis(100)), expected_op_code, None);
+ let jh = exec_sched_single(
+ cycled_task,
+ Some(Duration::from_millis(100)),
+ expected_op_code,
+ None,
+ );
let thread_res = jh.join().expect("Cycles Task failed");
assert!(thread_res.is_ok());
let data = shared.lock().expect("Locking Mutex failed");
@@ -334,22 +388,107 @@ mod tests {
assert_eq!(data.op_code, expected_op_code);
}
+ #[test]
+ fn test_single_and_cycles() {
+ let expected_op_code = 50;
+ let shared = Arc::new(Mutex::new(TestInfo {
+ exec_num: 0,
+ op_code: 0,
+ }));
+ let one_shot_task = Box::new(OneShotTask {
+ exec_num: shared.clone(),
+ });
+ let cycled_task_0 = Box::new(FixedCyclesTask {
+ exec_num: shared.clone(),
+ cycles: 1,
+ });
+ let cycled_task_1 = Box::new(FixedCyclesTask {
+ exec_num: shared.clone(),
+ cycles: 1,
+ });
+ assert_eq!(cycled_task_0.task_name(), CYCLE_TASK_NAME);
+ assert_eq!(one_shot_task.task_name(), ONE_SHOT_TASK_NAME);
+ let task_vec: Vec>> = vec![one_shot_task, cycled_task_0, cycled_task_1];
+ let jh = exec_sched_multi(
+ task_vec,
+ Some(Duration::from_millis(100)),
+ expected_op_code,
+ None,
+ );
+ let thread_res = jh.join().expect("Cycles Task failed");
+ assert!(thread_res.is_ok());
+ let data = shared.lock().expect("Locking Mutex failed");
+ assert_eq!(thread_res.unwrap(), OpResult::Ok);
+ assert_eq!(data.exec_num, 3);
+ assert_eq!(data.op_code, expected_op_code);
+ }
+
#[test]
#[ignore]
- fn test_periodic() {
+ fn test_periodic_single() {
+ let mut terminator = Bus::new(5);
let expected_op_code = 45;
let shared = Arc::new(Mutex::new(TestInfo {
exec_num: 0,
op_code: 0,
}));
let periodic_task = Box::new(PeriodicTask {
- exec_num: shared.clone()
+ exec_num: shared.clone(),
});
- let jh = exec_sched_single(periodic_task, Some(Duration::from_millis(50)), expected_op_code, None);
+ assert_eq!(periodic_task.task_name(), PERIODIC_TASK_NAME);
+ let jh = exec_sched_single(
+ periodic_task,
+ Some(Duration::from_millis(20)),
+ expected_op_code,
+ Some(terminator.add_rx()),
+ );
+ thread::sleep(Duration::from_millis(40));
+ terminator.broadcast(());
let thread_res = jh.join().expect("Periodic Task failed");
assert!(thread_res.is_ok());
let data = shared.lock().expect("Locking Mutex failed");
assert_eq!(thread_res.unwrap(), OpResult::Ok);
+ let range = 2..4;
+ assert!(range.contains(&data.exec_num));
+ assert_eq!(data.op_code, expected_op_code);
+ }
+
+ #[test]
+ #[ignore]
+ fn test_periodic_multi() {
+ let mut terminator = Bus::new(5);
+ let expected_op_code = 46;
+ let shared = Arc::new(Mutex::new(TestInfo {
+ exec_num: 0,
+ op_code: 0,
+ }));
+ let cycled_task = Box::new(FixedCyclesTask {
+ exec_num: shared.clone(),
+ cycles: 1,
+ });
+ let periodic_task_0 = Box::new(PeriodicTask {
+ exec_num: shared.clone(),
+ });
+ let periodic_task_1 = Box::new(PeriodicTask {
+ exec_num: shared.clone(),
+ });
+ assert_eq!(periodic_task_0.task_name(), PERIODIC_TASK_NAME);
+ assert_eq!(periodic_task_1.task_name(), PERIODIC_TASK_NAME);
+ let task_vec: Vec>> = vec![cycled_task, periodic_task_0, periodic_task_1];
+ let jh = exec_sched_multi(
+ task_vec,
+ Some(Duration::from_millis(20)),
+ expected_op_code,
+ Some(terminator.add_rx()),
+ );
+ thread::sleep(Duration::from_millis(60));
+ terminator.broadcast(());
+ let thread_res = jh.join().expect("Periodic Task failed");
+ assert!(thread_res.is_ok());
+ let data = shared.lock().expect("Locking Mutex failed");
+ assert_eq!(thread_res.unwrap(), OpResult::Ok);
+ let range = 7..11;
+ assert!(range.contains(&data.exec_num));
assert_eq!(data.op_code, expected_op_code);
}
}