Nothing to see here, move along
1use lancer_core::error::KernelError;
2use lancer_core::process_state::ProcessState;
3
4#[test]
5fn all_valid_transitions_succeed() {
6 let valid_pairs: &[(ProcessState, ProcessState)] = &[
7 (ProcessState::Free, ProcessState::Created),
8 (ProcessState::Created, ProcessState::Ready),
9 (ProcessState::Ready, ProcessState::Running),
10 (ProcessState::Running, ProcessState::Ready),
11 (ProcessState::Running, ProcessState::Blocked),
12 (ProcessState::Blocked, ProcessState::Ready),
13 (ProcessState::Running, ProcessState::Dead),
14 (ProcessState::Ready, ProcessState::Dead),
15 (ProcessState::Blocked, ProcessState::Dead),
16 (ProcessState::Created, ProcessState::Dead),
17 (ProcessState::Dead, ProcessState::Free),
18 (ProcessState::Running, ProcessState::Zombie),
19 (ProcessState::Ready, ProcessState::Zombie),
20 (ProcessState::Blocked, ProcessState::Zombie),
21 (ProcessState::Created, ProcessState::Zombie),
22 (ProcessState::Zombie, ProcessState::Free),
23 ];
24
25 valid_pairs.iter().for_each(|&(from, to)| {
26 let mut state = from;
27 assert!(
28 state.transition(to).is_ok(),
29 "transition {:?} -> {:?} should succeed",
30 from,
31 to
32 );
33 assert_eq!(state, to);
34 });
35}
36
37#[test]
38fn all_invalid_transitions_fail() {
39 let valid_count = ProcessState::ALL
40 .iter()
41 .flat_map(|&from| ProcessState::ALL.iter().map(move |&to| (from, to)))
42 .filter(|&(from, to)| {
43 let mut state = from;
44 match state.transition(to) {
45 Ok(()) => {
46 assert!(
47 ProcessState::is_valid_transition(from, to),
48 "transition {:?} -> {:?} succeeded but is_valid_transition says no",
49 from,
50 to
51 );
52 true
53 }
54 Err(KernelError::BadState) => {
55 assert!(
56 !ProcessState::is_valid_transition(from, to),
57 "transition {:?} -> {:?} failed but is_valid_transition says yes",
58 from,
59 to
60 );
61 false
62 }
63 Err(e) => panic!("unexpected error {:?} for {:?} -> {:?}", e, from, to),
64 }
65 })
66 .count();
67
68 assert_eq!(valid_count, 16, "expected exactly 16 valid transitions");
69}
70
71#[test]
72fn self_transitions_are_invalid() {
73 ProcessState::ALL.iter().for_each(|&state| {
74 assert!(
75 !ProcessState::is_valid_transition(state, state),
76 "self-transition {:?} -> {:?} should be invalid",
77 state,
78 state
79 );
80 });
81}
82
83#[test]
84fn free_can_only_reach_created() {
85 let reachable: Vec<ProcessState> = ProcessState::ALL
86 .iter()
87 .copied()
88 .filter(|&to| ProcessState::is_valid_transition(ProcessState::Free, to))
89 .collect();
90
91 assert_eq!(reachable, vec![ProcessState::Created]);
92}
93
94#[test]
95fn dead_can_only_reach_free() {
96 let reachable: Vec<ProcessState> = ProcessState::ALL
97 .iter()
98 .copied()
99 .filter(|&to| ProcessState::is_valid_transition(ProcessState::Dead, to))
100 .collect();
101
102 assert_eq!(reachable, vec![ProcessState::Free]);
103}
104
105#[test]
106fn full_lifecycle() {
107 let mut state = ProcessState::Free;
108 state.transition(ProcessState::Created).unwrap();
109 state.transition(ProcessState::Ready).unwrap();
110 state.transition(ProcessState::Running).unwrap();
111 state.transition(ProcessState::Blocked).unwrap();
112 state.transition(ProcessState::Ready).unwrap();
113 state.transition(ProcessState::Dead).unwrap();
114 state.transition(ProcessState::Free).unwrap();
115 assert_eq!(state, ProcessState::Free);
116}
117
118#[test]
119fn every_non_free_state_can_die() {
120 [
121 ProcessState::Created,
122 ProcessState::Ready,
123 ProcessState::Running,
124 ProcessState::Blocked,
125 ]
126 .iter()
127 .for_each(|&from| {
128 assert!(
129 ProcessState::is_valid_transition(from, ProcessState::Dead),
130 "{:?} should be able to transition to Dead",
131 from
132 );
133 });
134}
135
136#[test]
137fn every_non_free_state_can_zombify() {
138 [
139 ProcessState::Created,
140 ProcessState::Ready,
141 ProcessState::Running,
142 ProcessState::Blocked,
143 ]
144 .iter()
145 .for_each(|&from| {
146 assert!(
147 ProcessState::is_valid_transition(from, ProcessState::Zombie),
148 "{:?} should be able to transition to Zombie",
149 from
150 );
151 });
152}
153
154#[test]
155fn zombie_can_only_reach_free() {
156 let reachable: Vec<ProcessState> = ProcessState::ALL
157 .iter()
158 .copied()
159 .filter(|&to| ProcessState::is_valid_transition(ProcessState::Zombie, to))
160 .collect();
161
162 assert_eq!(reachable, vec![ProcessState::Free]);
163}
164
165#[test]
166fn zombie_cannot_transition_to_ready_or_running() {
167 [
168 ProcessState::Ready,
169 ProcessState::Running,
170 ProcessState::Dead,
171 ]
172 .iter()
173 .for_each(|&to| {
174 let mut state = ProcessState::Zombie;
175 assert!(
176 state.transition(to).is_err(),
177 "Zombie -> {:?} should be invalid",
178 to,
179 );
180 });
181}
182
183#[test]
184fn zombie_lifecycle() {
185 let mut state = ProcessState::Free;
186 state.transition(ProcessState::Created).unwrap();
187 state.transition(ProcessState::Ready).unwrap();
188 state.transition(ProcessState::Running).unwrap();
189 state.transition(ProcessState::Zombie).unwrap();
190 state.transition(ProcessState::Free).unwrap();
191 assert_eq!(state, ProcessState::Free);
192}
193
194#[test]
195fn zombie_lifecycle_from_blocked() {
196 let mut state = ProcessState::Free;
197 state.transition(ProcessState::Created).unwrap();
198 state.transition(ProcessState::Ready).unwrap();
199 state.transition(ProcessState::Running).unwrap();
200 state.transition(ProcessState::Blocked).unwrap();
201 state.transition(ProcessState::Zombie).unwrap();
202 state.transition(ProcessState::Free).unwrap();
203 assert_eq!(state, ProcessState::Free);
204}
205
206#[test]
207fn free_and_dead_cannot_zombify() {
208 [ProcessState::Free, ProcessState::Dead]
209 .iter()
210 .for_each(|&from| {
211 assert!(
212 !ProcessState::is_valid_transition(from, ProcessState::Zombie),
213 "{:?} -> Zombie should be invalid",
214 from
215 );
216 });
217}
218
219#[test]
220fn zombie_is_not_a_self_transition() {
221 assert!(
222 !ProcessState::is_valid_transition(ProcessState::Zombie, ProcessState::Zombie),
223 "Zombie -> Zombie should be invalid"
224 );
225}