xianyun_executor/exec/
context.rs1use std::fmt;
17use std::sync::Arc;
18
19use super::CommandRunner;
20
21#[derive(Debug)]
23pub struct ErrRunnerMissing;
24
25impl fmt::Display for ErrRunnerMissing {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(f, "command runner missing from context")
28 }
29}
30
31impl std::error::Error for ErrRunnerMissing {}
32
33#[derive(Clone, Default)]
38pub struct Context {
39 runner: Option<Arc<dyn CommandRunner + Send + Sync>>,
40}
41
42pub fn with_context(_ctx: Context, runner: Arc<dyn CommandRunner + Send + Sync>) -> Context {
44 Context {
45 runner: Some(runner),
46 }
47}
48
49pub fn from_context(ctx: &Context) -> Arc<dyn CommandRunner + Send + Sync> {
52 match &ctx.runner {
53 Some(runner) => runner.clone(),
54 None => panic!("{ErrRunnerMissing}"),
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::exec::mock::MockCommandRunner;
62
63 #[test]
64 fn panics_on_empty_context() {
65 let ctx = Context::default();
66
67 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| from_context(&ctx)));
68 assert!(result.is_err());
69 }
70
71 #[test]
72 fn same_from_used_context() {
73 let runner: Arc<dyn CommandRunner + Send + Sync> = Arc::new(MockCommandRunner::new());
74 let ctx = with_context(Context::default(), runner.clone());
75
76 let runner1 = from_context(&ctx);
77 let runner2 = from_context(&ctx);
78
79 assert!(
80 Arc::ptr_eq(&runner, &runner1),
81 "FromContext should return original client"
82 );
83 assert!(
84 Arc::ptr_eq(&runner, &runner2),
85 "FromContext should return original client"
86 );
87 }
88
89 #[test]
90 fn nested_context() {
91 let runner: Arc<dyn CommandRunner + Send + Sync> = Arc::new(MockCommandRunner::new());
96 let ctx = with_context(Context::default(), runner.clone());
97 let nested = ctx.clone();
98
99 let runner1 = from_context(&nested);
100 assert!(
101 Arc::ptr_eq(&runner, &runner1),
102 "FromContext should return original client from nested context"
103 );
104 }
105}