1use std::fmt::Debug;
5use std::marker::PhantomData;
6use std::ops::Deref;
7use std::sync::Arc;
8
9use crate::aggregate::{Aggregate, Root};
10use crate::event;
11
12#[derive(Clone, Copy)]
15pub struct Scenario<T>(PhantomData<T>)
16where
17 T: Aggregate,
18 T::Id: Clone,
19 T::Event: Debug + PartialEq,
20 T::Error: Debug;
21
22impl<T> Scenario<T>
23where
24 T: Aggregate,
25 T::Id: Clone,
26 T::Event: Debug + PartialEq,
27 T::Error: Debug,
28{
29 #[must_use]
31 pub fn new() -> Self {
32 Self(PhantomData)
33 }
34
35 #[must_use]
40 pub fn given(self, events: Vec<event::Envelope<T::Event>>) -> ScenarioGiven<T> {
41 ScenarioGiven {
42 events,
43 marker: PhantomData,
44 }
45 }
46
47 #[must_use]
52 pub fn when<R, F, Err>(self, f: F) -> ScenarioWhen<T, R, F, Err>
53 where
54 R: From<Root<T>>,
55 F: Fn() -> Result<R, Err>,
56 {
57 ScenarioWhen {
58 mutate: f,
59 marker: PhantomData,
60 err_marker: PhantomData,
61 root_marker: PhantomData,
62 }
63 }
64}
65
66impl<T> Default for Scenario<T>
67where
68 T: Aggregate,
69 T::Id: Clone,
70 T::Event: Debug + PartialEq,
71 T::Error: Debug,
72{
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78#[doc(hidden)]
79pub struct ScenarioGiven<T>
80where
81 T: Aggregate,
82 T::Id: Clone,
83 T::Event: Debug + PartialEq,
84 T::Error: Debug,
85{
86 events: Vec<event::Envelope<T::Event>>,
87 marker: PhantomData<T>,
88}
89
90impl<T> ScenarioGiven<T>
91where
92 T: Aggregate,
93 T::Id: Clone,
94 T::Event: Debug + PartialEq,
95 T::Error: Debug,
96{
97 #[must_use]
110 pub fn when<R, F, Err>(self, f: F) -> ScenarioWhen<T, R, impl Fn() -> Result<R, Err>, Err>
111 where
112 R: From<Root<T>>,
113 F: Fn(&mut R) -> Result<(), Err>,
114 {
115 let events = Arc::new(self.events);
116
117 ScenarioWhen {
118 marker: PhantomData,
119 err_marker: PhantomData,
120 root_marker: PhantomData,
121 mutate: move || -> Result<R, Err> {
122 let mut root: R = Root::<T>::rehydrate(events.iter().cloned())
123 .expect(
124 "no error is expected when applying domain events from a 'given' clause",
125 )
126 .expect("an aggregate root instance is expected, but none was produced")
127 .into();
128
129 match f(&mut root) {
130 Ok(()) => Ok(root),
131 Err(err) => Err(err),
132 }
133 },
134 }
135 }
136}
137
138#[doc(hidden)]
139pub struct ScenarioWhen<T, R, F, Err>
140where
141 T: Aggregate,
142 T::Event: Debug + PartialEq,
143 R: From<Root<T>>,
144 F: Fn() -> Result<R, Err>,
145{
146 mutate: F,
147 marker: PhantomData<T>,
148 err_marker: PhantomData<Err>,
149 root_marker: PhantomData<R>,
150}
151
152impl<T, R, F, Err> ScenarioWhen<T, R, F, Err>
153where
154 T: Aggregate,
155 T::Event: Debug + PartialEq,
156 R: From<Root<T>> + Deref<Target = Root<T>>,
157 F: Fn() -> Result<R, Err>,
158{
159 #[must_use]
162 pub fn then(self, result: Vec<event::Envelope<T::Event>>) -> ScenarioThen<T, R, F, Err> {
163 ScenarioThen {
164 mutate: self.mutate,
165 expected: Ok(result),
166 marker: PhantomData,
167 }
168 }
169
170 #[must_use]
175 pub fn then_error(self, err: Err) -> ScenarioThen<T, R, F, Err> {
176 ScenarioThen {
177 mutate: self.mutate,
178 expected: Err(err),
179 marker: PhantomData,
180 }
181 }
182}
183
184#[doc(hidden)]
185pub struct ScenarioThen<T, R, F, Err>
186where
187 T: Aggregate,
188 T::Event: Debug + PartialEq,
189 R: From<Root<T>> + Deref<Target = Root<T>>,
190 F: Fn() -> Result<R, Err>,
191{
192 mutate: F,
193 expected: Result<Vec<event::Envelope<T::Event>>, Err>,
194 marker: PhantomData<R>,
195}
196
197impl<T, R, F, Err> ScenarioThen<T, R, F, Err>
198where
199 T: Aggregate,
200 T::Event: Debug + PartialEq,
201 R: From<Root<T>> + Deref<Target = Root<T>>,
202 F: Fn() -> Result<R, Err>,
203 Err: PartialEq + Debug,
204{
205 pub fn assert(self) {
212 let result = (self.mutate)().map(|root| root.recorded_events.clone());
213 assert_eq!(self.expected, result);
214 }
215}