1pub use peat_schema::node::v1::{
8 AuthorityLevel, BindingType, HumanMachinePair, Operator, OperatorRank,
9};
10
11pub trait OperatorExt {
13 fn new(
15 id: String,
16 name: String,
17 rank: OperatorRank,
18 authority: AuthorityLevel,
19 mos: String,
20 ) -> Self;
21
22 fn update_cognitive_load(&mut self, load: f32);
24
25 fn update_fatigue(&mut self, fatigue: f32);
27
28 fn cognitive_load(&self) -> f32;
30
31 fn fatigue(&self) -> f32;
33
34 fn is_overloaded(&self, threshold: f32) -> bool;
36
37 fn is_fatigued(&self, threshold: f32) -> bool;
39
40 fn effectiveness(&self) -> f32;
43}
44
45impl OperatorExt for Operator {
46 fn new(
47 id: String,
48 name: String,
49 rank: OperatorRank,
50 authority: AuthorityLevel,
51 mos: String,
52 ) -> Self {
53 use serde_json::json;
54 let metadata = json!({
55 "cognitive_load": 0.0,
56 "fatigue": 0.0,
57 });
58
59 Self {
60 id,
61 name,
62 rank: rank as i32,
63 authority_level: authority as i32,
64 mos,
65 metadata_json: metadata.to_string(),
66 }
67 }
68
69 fn update_cognitive_load(&mut self, load: f32) {
70 let load = load.clamp(0.0, 1.0);
71 let mut metadata: serde_json::Value =
72 serde_json::from_str(&self.metadata_json).unwrap_or(serde_json::json!({}));
73 metadata["cognitive_load"] = serde_json::json!(load);
74 self.metadata_json = metadata.to_string();
75 }
76
77 fn update_fatigue(&mut self, fatigue: f32) {
78 let fatigue = fatigue.clamp(0.0, 1.0);
79 let mut metadata: serde_json::Value =
80 serde_json::from_str(&self.metadata_json).unwrap_or(serde_json::json!({}));
81 metadata["fatigue"] = serde_json::json!(fatigue);
82 self.metadata_json = metadata.to_string();
83 }
84
85 fn cognitive_load(&self) -> f32 {
86 let metadata: serde_json::Value =
87 serde_json::from_str(&self.metadata_json).unwrap_or(serde_json::json!({}));
88 metadata["cognitive_load"].as_f64().unwrap_or(0.0) as f32
89 }
90
91 fn fatigue(&self) -> f32 {
92 let metadata: serde_json::Value =
93 serde_json::from_str(&self.metadata_json).unwrap_or(serde_json::json!({}));
94 metadata["fatigue"].as_f64().unwrap_or(0.0) as f32
95 }
96
97 fn is_overloaded(&self, threshold: f32) -> bool {
98 self.cognitive_load() > threshold
99 }
100
101 fn is_fatigued(&self, threshold: f32) -> bool {
102 self.fatigue() > threshold
103 }
104
105 fn effectiveness(&self) -> f32 {
106 let cognitive_factor = 1.0 - self.cognitive_load();
107 let fatigue_factor = 1.0 - self.fatigue();
108 (cognitive_factor * 0.6 + fatigue_factor * 0.4).clamp(0.0, 1.0)
109 }
110}
111
112pub trait OperatorRankExt {
114 fn to_score(self) -> f64;
116
117 fn name(self) -> &'static str;
119}
120
121impl OperatorRankExt for OperatorRank {
122 fn to_score(self) -> f64 {
123 match self {
124 Self::Unspecified => 0.0,
125 Self::E1 => 0.10,
126 Self::E2 => 0.15,
127 Self::E3 => 0.20,
128 Self::E4 => 0.30,
129 Self::E5 => 0.40,
130 Self::E6 => 0.50,
131 Self::E7 => 0.60, Self::E8 => 0.70,
133 Self::E9 => 0.80,
134 Self::W1 => 0.70,
135 Self::W2 => 0.75,
136 Self::W3 => 0.80,
137 Self::W4 => 0.85,
138 Self::W5 => 0.90,
139 Self::O1 => 0.85,
140 Self::O2 => 0.90,
141 Self::O3 => 0.95, Self::O4 => 0.97,
143 Self::O5 => 0.98,
144 Self::O6 => 0.99,
145 Self::O7 => 0.995,
146 Self::O8 => 0.997,
147 Self::O9 => 0.999,
148 Self::O10 => 1.0,
149 }
150 }
151
152 fn name(self) -> &'static str {
153 match self {
154 Self::Unspecified => "Unspecified",
155 Self::E1 => "Private (E-1)",
156 Self::E2 => "Private (E-2)",
157 Self::E3 => "Private First Class",
158 Self::E4 => "Corporal/Specialist",
159 Self::E5 => "Sergeant",
160 Self::E6 => "Staff Sergeant",
161 Self::E7 => "Sergeant First Class",
162 Self::E8 => "Master Sergeant",
163 Self::E9 => "Sergeant Major",
164 Self::W1 => "Warrant Officer 1",
165 Self::W2 => "Chief Warrant Officer 2",
166 Self::W3 => "Chief Warrant Officer 3",
167 Self::W4 => "Chief Warrant Officer 4",
168 Self::W5 => "Chief Warrant Officer 5",
169 Self::O1 => "Second Lieutenant",
170 Self::O2 => "First Lieutenant",
171 Self::O3 => "Captain",
172 Self::O4 => "Major",
173 Self::O5 => "Lieutenant Colonel",
174 Self::O6 => "Colonel",
175 Self::O7 => "Brigadier General",
176 Self::O8 => "Major General",
177 Self::O9 => "Lieutenant General",
178 Self::O10 => "General",
179 }
180 }
181}
182
183pub trait AuthorityLevelExt {
185 fn to_score(self) -> f64;
187
188 fn can_override(self) -> bool;
190
191 fn requires_approval(self) -> bool;
193}
194
195impl AuthorityLevelExt for AuthorityLevel {
196 fn to_score(self) -> f64 {
197 match self {
198 Self::Unspecified => 0.0,
199 Self::Observer => 0.1,
200 Self::Advisor => 0.3,
201 Self::Supervisor => 0.5,
202 Self::Commander => 0.8,
203 }
204 }
205
206 fn can_override(self) -> bool {
207 matches!(self, Self::Supervisor | Self::Commander)
208 }
209
210 fn requires_approval(self) -> bool {
211 matches!(self, Self::Commander)
212 }
213}
214
215pub trait HumanMachinePairExt {
217 fn new(operators: Vec<Operator>, platform_ids: Vec<String>, binding_type: BindingType) -> Self;
219
220 fn autonomous(platform_id: String) -> Self;
222
223 fn one_to_one(operator: Operator, platform_id: String) -> Self;
225
226 fn is_autonomous(&self) -> bool;
228
229 fn primary_operator(&self) -> Option<&Operator>;
231
232 fn max_rank(&self) -> Option<OperatorRank>;
234
235 fn max_authority(&self) -> Option<AuthorityLevel>;
237
238 fn has_overloaded_operator(&self, threshold: f32) -> bool;
240
241 fn avg_effectiveness(&self) -> f32;
243}
244
245impl HumanMachinePairExt for HumanMachinePair {
246 fn new(operators: Vec<Operator>, platform_ids: Vec<String>, binding_type: BindingType) -> Self {
247 Self {
248 operators,
249 platform_ids,
250 binding_type: binding_type as i32,
251 bound_at: None,
252 }
253 }
254
255 fn autonomous(platform_id: String) -> Self {
256 Self {
257 operators: Vec::new(),
258 platform_ids: vec![platform_id],
259 binding_type: BindingType::Unspecified as i32,
260 bound_at: None,
261 }
262 }
263
264 fn one_to_one(operator: Operator, platform_id: String) -> Self {
265 Self::new(vec![operator], vec![platform_id], BindingType::OneToOne)
266 }
267
268 fn is_autonomous(&self) -> bool {
269 self.operators.is_empty()
270 }
271
272 fn primary_operator(&self) -> Option<&Operator> {
273 self.operators.iter().max_by(|a, b| a.rank.cmp(&b.rank))
275 }
276
277 fn max_rank(&self) -> Option<OperatorRank> {
278 self.operators
279 .iter()
280 .map(|op| OperatorRank::try_from(op.rank).ok())
281 .max()
282 .flatten()
283 }
284
285 fn max_authority(&self) -> Option<AuthorityLevel> {
286 self.operators
287 .iter()
288 .map(|op| AuthorityLevel::try_from(op.authority_level).ok())
289 .max()
290 .flatten()
291 }
292
293 fn has_overloaded_operator(&self, threshold: f32) -> bool {
294 self.operators.iter().any(|op| op.is_overloaded(threshold))
295 }
296
297 fn avg_effectiveness(&self) -> f32 {
298 if self.operators.is_empty() {
299 return 1.0; }
301
302 let sum: f32 = self.operators.iter().map(|op| op.effectiveness()).sum();
303 sum / self.operators.len() as f32
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_operator_creation() {
313 let op = Operator::new(
314 "op1".to_string(),
315 "John Doe".to_string(),
316 OperatorRank::E7,
317 AuthorityLevel::Commander,
318 "11B".to_string(),
319 );
320
321 assert_eq!(op.id, "op1");
322 assert_eq!(op.rank, OperatorRank::E7 as i32);
323 assert_eq!(op.cognitive_load(), 0.0);
324 assert_eq!(op.fatigue(), 0.0);
325 }
326
327 #[test]
328 fn test_operator_cognitive_load() {
329 let mut op = Operator::new(
330 "op1".to_string(),
331 "John".to_string(),
332 OperatorRank::E5,
333 AuthorityLevel::Supervisor,
334 "11B".to_string(),
335 );
336
337 op.update_cognitive_load(0.8);
338 assert_eq!(op.cognitive_load(), 0.8);
339 assert!(op.is_overloaded(0.7));
340 assert!(!op.is_overloaded(0.9));
341
342 op.update_cognitive_load(1.5);
344 assert_eq!(op.cognitive_load(), 1.0);
345 }
346
347 #[test]
348 fn test_operator_effectiveness() {
349 let mut op = Operator::new(
350 "op1".to_string(),
351 "John".to_string(),
352 OperatorRank::E5,
353 AuthorityLevel::Supervisor,
354 "11B".to_string(),
355 );
356
357 assert_eq!(op.effectiveness(), 1.0);
359
360 op.update_cognitive_load(0.8);
362 op.update_fatigue(0.2);
363 let eff = op.effectiveness();
364 assert!(eff > 0.0 && eff < 1.0);
365
366 op.update_cognitive_load(0.9);
368 op.update_fatigue(0.9);
369 assert!(op.effectiveness() < 0.2);
370 }
371
372 #[test]
373 fn test_rank_ordering() {
374 assert!(OperatorRank::E7 > OperatorRank::E5);
375 assert!(OperatorRank::O3 > OperatorRank::E9);
376 assert!(OperatorRank::W5 > OperatorRank::W1);
377 }
378
379 #[test]
380 fn test_rank_to_score() {
381 assert_eq!(OperatorRank::E1.to_score(), 0.10);
382 assert_eq!(OperatorRank::E7.to_score(), 0.60);
383 assert_eq!(OperatorRank::O3.to_score(), 0.95);
384 assert_eq!(OperatorRank::O10.to_score(), 1.0);
385 }
386
387 #[test]
388 fn test_authority_level_ordering() {
389 assert!(AuthorityLevel::Commander > AuthorityLevel::Supervisor);
390 assert!(AuthorityLevel::Commander > AuthorityLevel::Observer);
391 }
392
393 #[test]
394 fn test_authority_can_override() {
395 assert!(!AuthorityLevel::Observer.can_override());
396 assert!(!AuthorityLevel::Advisor.can_override());
397 assert!(AuthorityLevel::Supervisor.can_override());
398 assert!(AuthorityLevel::Commander.can_override());
399 }
400
401 #[test]
402 fn test_human_machine_pair_autonomous() {
403 let pair = HumanMachinePair::autonomous("node_1".to_string());
404 assert!(pair.is_autonomous());
405 assert_eq!(pair.operators.len(), 0);
406 assert_eq!(pair.avg_effectiveness(), 1.0);
407 }
408
409 #[test]
410 fn test_human_machine_pair_one_to_one() {
411 let op = Operator::new(
412 "op1".to_string(),
413 "John".to_string(),
414 OperatorRank::E5,
415 AuthorityLevel::Commander,
416 "11B".to_string(),
417 );
418
419 let pair = HumanMachinePair::one_to_one(op, "node_1".to_string());
420
421 assert!(!pair.is_autonomous());
422 assert_eq!(pair.operators.len(), 1);
423 assert_eq!(pair.binding_type, BindingType::OneToOne as i32);
424 assert_eq!(pair.max_rank(), Some(OperatorRank::E5));
425 }
426
427 #[test]
428 fn test_human_machine_pair_primary_operator() {
429 let op1 = Operator::new(
430 "op1".to_string(),
431 "John".to_string(),
432 OperatorRank::E5,
433 AuthorityLevel::Supervisor,
434 "11B".to_string(),
435 );
436 let op2 = Operator::new(
437 "op2".to_string(),
438 "Jane".to_string(),
439 OperatorRank::E7,
440 AuthorityLevel::Commander,
441 "11B".to_string(),
442 );
443
444 let pair = HumanMachinePair::new(
445 vec![op1, op2],
446 vec!["node_1".to_string()],
447 BindingType::ManyToOne,
448 );
449
450 let primary = pair.primary_operator().unwrap();
452 assert_eq!(primary.rank, OperatorRank::E7 as i32);
453 assert_eq!(primary.name, "Jane");
454 }
455
456 #[test]
457 fn test_human_machine_pair_max_authority() {
458 let op1 = Operator::new(
459 "op1".to_string(),
460 "John".to_string(),
461 OperatorRank::E7,
462 AuthorityLevel::Supervisor,
463 "11B".to_string(),
464 );
465 let op2 = Operator::new(
466 "op2".to_string(),
467 "Jane".to_string(),
468 OperatorRank::E5,
469 AuthorityLevel::Commander,
470 "11B".to_string(),
471 );
472
473 let pair = HumanMachinePair::new(
474 vec![op1, op2],
475 vec!["node_1".to_string()],
476 BindingType::ManyToOne,
477 );
478
479 assert_eq!(pair.max_authority(), Some(AuthorityLevel::Commander));
480 }
481
482 #[test]
483 fn test_human_machine_pair_overloaded_check() {
484 let mut op1 = Operator::new(
485 "op1".to_string(),
486 "John".to_string(),
487 OperatorRank::E5,
488 AuthorityLevel::Supervisor,
489 "11B".to_string(),
490 );
491 op1.update_cognitive_load(0.9);
492
493 let op2 = Operator::new(
494 "op2".to_string(),
495 "Jane".to_string(),
496 OperatorRank::E7,
497 AuthorityLevel::Commander,
498 "11B".to_string(),
499 );
500
501 let pair = HumanMachinePair::new(
502 vec![op1, op2],
503 vec!["node_1".to_string()],
504 BindingType::ManyToOne,
505 );
506
507 assert!(pair.has_overloaded_operator(0.8));
508 assert!(!pair.has_overloaded_operator(0.95));
509 }
510
511 #[test]
512 fn test_operator_cognitive_load_clamping() {
513 let mut op = Operator::new(
514 "op1".to_string(),
515 "Test".to_string(),
516 OperatorRank::E5,
517 AuthorityLevel::Supervisor,
518 "11B".to_string(),
519 );
520
521 op.update_cognitive_load(2.0);
523 assert_eq!(op.cognitive_load(), 1.0);
524
525 op.update_cognitive_load(-0.5);
527 assert_eq!(op.cognitive_load(), 0.0);
528
529 op.update_cognitive_load(0.5);
531 assert_eq!(op.cognitive_load(), 0.5);
532 }
533
534 #[test]
535 fn test_operator_fatigue_clamping() {
536 let mut op = Operator::new(
537 "op1".to_string(),
538 "Test".to_string(),
539 OperatorRank::E5,
540 AuthorityLevel::Supervisor,
541 "11B".to_string(),
542 );
543
544 op.update_fatigue(1.5);
546 assert_eq!(op.fatigue(), 1.0);
547
548 op.update_fatigue(-0.3);
550 assert_eq!(op.fatigue(), 0.0);
551 }
552
553 #[test]
554 fn test_operator_is_overloaded_edge_cases() {
555 let mut op = Operator::new(
556 "op1".to_string(),
557 "Test".to_string(),
558 OperatorRank::E5,
559 AuthorityLevel::Supervisor,
560 "11B".to_string(),
561 );
562
563 op.update_cognitive_load(0.75);
564
565 assert!(!op.is_overloaded(0.75));
567 assert!(!op.is_overloaded(0.76));
568 assert!(op.is_overloaded(0.74));
569 assert!(op.is_overloaded(0.0));
570 }
571
572 #[test]
573 fn test_operator_is_fatigued_edge_cases() {
574 let mut op = Operator::new(
575 "op1".to_string(),
576 "Test".to_string(),
577 OperatorRank::E5,
578 AuthorityLevel::Supervisor,
579 "11B".to_string(),
580 );
581
582 op.update_fatigue(0.6);
583
584 assert!(!op.is_fatigued(0.6));
586 assert!(!op.is_fatigued(0.7));
587 assert!(op.is_fatigued(0.5));
588 }
589
590 #[test]
591 fn test_operator_effectiveness_edge_cases() {
592 let mut op = Operator::new(
593 "op1".to_string(),
594 "Test".to_string(),
595 OperatorRank::E5,
596 AuthorityLevel::Supervisor,
597 "11B".to_string(),
598 );
599
600 assert_eq!(op.effectiveness(), 1.0);
602
603 op.update_cognitive_load(1.0);
605 op.update_fatigue(1.0);
606 assert_eq!(op.effectiveness(), 0.0);
607
608 op.update_cognitive_load(1.0);
610 op.update_fatigue(0.0);
611 let eff = op.effectiveness();
612 assert!(eff > 0.0 && eff < 1.0);
613 assert_eq!(eff, 0.4); }
615
616 #[test]
617 fn test_operator_metadata_json_invalid() {
618 let mut op = Operator::new(
619 "op1".to_string(),
620 "Test".to_string(),
621 OperatorRank::E5,
622 AuthorityLevel::Supervisor,
623 "11B".to_string(),
624 );
625
626 op.metadata_json = "not valid json".to_string();
628
629 assert_eq!(op.cognitive_load(), 0.0);
631 assert_eq!(op.fatigue(), 0.0);
632 }
633
634 #[test]
635 fn test_rank_to_score_all_ranks() {
636 let ranks = vec![
640 (OperatorRank::E1, 0.10),
641 (OperatorRank::E2, 0.15),
642 (OperatorRank::E3, 0.20),
643 (OperatorRank::E4, 0.30),
644 (OperatorRank::E5, 0.40),
645 (OperatorRank::E6, 0.50),
646 (OperatorRank::E7, 0.60),
647 (OperatorRank::E8, 0.70),
648 (OperatorRank::E9, 0.80),
649 (OperatorRank::W1, 0.70),
650 (OperatorRank::W2, 0.75),
651 (OperatorRank::W3, 0.80),
652 (OperatorRank::W4, 0.85),
653 (OperatorRank::W5, 0.90),
654 (OperatorRank::O1, 0.85),
655 (OperatorRank::O2, 0.90),
656 (OperatorRank::O3, 0.95),
657 (OperatorRank::O4, 0.97),
658 (OperatorRank::O5, 0.98),
659 (OperatorRank::O6, 0.99),
660 (OperatorRank::O7, 0.995),
661 (OperatorRank::O8, 0.997),
662 (OperatorRank::O9, 0.999),
663 (OperatorRank::O10, 1.0),
664 ];
665
666 for (rank, expected_score) in ranks {
667 let score = rank.to_score();
668 assert_eq!(
669 score, expected_score,
670 "Rank {:?} should have score {}",
671 rank, expected_score
672 );
673 assert!((0.0..=1.0).contains(&score));
674 }
675
676 assert!(OperatorRank::E2.to_score() > OperatorRank::E1.to_score());
678 assert!(OperatorRank::E9.to_score() > OperatorRank::E8.to_score());
679
680 assert!(OperatorRank::W2.to_score() > OperatorRank::W1.to_score());
682 assert!(OperatorRank::W5.to_score() > OperatorRank::W4.to_score());
683
684 assert!(OperatorRank::O2.to_score() > OperatorRank::O1.to_score());
686 assert!(OperatorRank::O10.to_score() > OperatorRank::O9.to_score());
687 }
688
689 #[test]
690 fn test_rank_name_all_ranks() {
691 let ranks = vec![
693 OperatorRank::Unspecified,
694 OperatorRank::E1,
695 OperatorRank::E5,
696 OperatorRank::E9,
697 OperatorRank::W1,
698 OperatorRank::W5,
699 OperatorRank::O1,
700 OperatorRank::O10,
701 ];
702
703 for rank in ranks {
704 let name = rank.name();
705 assert!(!name.is_empty());
706 }
707 }
708
709 #[test]
710 fn test_authority_level_to_score() {
711 assert_eq!(AuthorityLevel::Unspecified.to_score(), 0.0);
712 assert_eq!(AuthorityLevel::Observer.to_score(), 0.1);
713 assert_eq!(AuthorityLevel::Advisor.to_score(), 0.3);
714 assert_eq!(AuthorityLevel::Supervisor.to_score(), 0.5);
715 assert_eq!(AuthorityLevel::Commander.to_score(), 0.8);
716
717 assert!(AuthorityLevel::Commander.to_score() > AuthorityLevel::Supervisor.to_score());
719 assert!(AuthorityLevel::Supervisor.to_score() > AuthorityLevel::Advisor.to_score());
720 assert!(AuthorityLevel::Advisor.to_score() > AuthorityLevel::Observer.to_score());
721 }
722
723 #[test]
724 fn test_authority_requires_approval() {
725 assert!(!AuthorityLevel::Unspecified.requires_approval());
726 assert!(!AuthorityLevel::Observer.requires_approval());
727 assert!(!AuthorityLevel::Advisor.requires_approval());
728 assert!(!AuthorityLevel::Supervisor.requires_approval());
729 assert!(AuthorityLevel::Commander.requires_approval());
730 }
731
732 #[test]
733 fn test_human_machine_pair_avg_effectiveness_multiple() {
734 let mut op1 = Operator::new(
735 "op1".to_string(),
736 "Op1".to_string(),
737 OperatorRank::E5,
738 AuthorityLevel::Supervisor,
739 "11B".to_string(),
740 );
741 op1.update_cognitive_load(0.2);
742 op1.update_fatigue(0.2);
743
744 let mut op2 = Operator::new(
745 "op2".to_string(),
746 "Op2".to_string(),
747 OperatorRank::E6,
748 AuthorityLevel::Supervisor,
749 "11B".to_string(),
750 );
751 op2.update_cognitive_load(0.8);
752 op2.update_fatigue(0.8);
753
754 let pair = HumanMachinePair::new(
755 vec![op1.clone(), op2.clone()],
756 vec!["node_1".to_string()],
757 BindingType::ManyToOne,
758 );
759
760 let avg = pair.avg_effectiveness();
761 let expected = (op1.effectiveness() + op2.effectiveness()) / 2.0;
762 assert_eq!(avg, expected);
763 }
764
765 #[test]
766 fn test_human_machine_pair_multiple_platforms() {
767 let op = Operator::new(
768 "op1".to_string(),
769 "Operator".to_string(),
770 OperatorRank::E6,
771 AuthorityLevel::Supervisor,
772 "11B".to_string(),
773 );
774
775 let platform_ids = vec![
776 "p1".to_string(),
777 "p2".to_string(),
778 "p3".to_string(),
779 "p4".to_string(),
780 "p5".to_string(),
781 ];
782
783 let pair = HumanMachinePair::new(vec![op], platform_ids.clone(), BindingType::OneToMany);
784
785 assert_eq!(pair.platform_ids.len(), 5);
786 assert_eq!(pair.operators.len(), 1);
787 assert!(!pair.is_autonomous());
788 }
789
790 #[test]
791 fn test_human_machine_pair_max_rank_and_authority_mismatch() {
792 let op1 = Operator::new(
794 "op1".to_string(),
795 "Junior Commander".to_string(),
796 OperatorRank::E4,
797 AuthorityLevel::Commander,
798 "11B".to_string(),
799 );
800
801 let op2 = Operator::new(
803 "op2".to_string(),
804 "Senior Advisor".to_string(),
805 OperatorRank::E8,
806 AuthorityLevel::Advisor,
807 "11B".to_string(),
808 );
809
810 let pair = HumanMachinePair::new(
811 vec![op1, op2],
812 vec!["node_1".to_string()],
813 BindingType::ManyToOne,
814 );
815
816 let primary = pair.primary_operator().unwrap();
818 assert_eq!(primary.rank, OperatorRank::E8 as i32);
819
820 assert_eq!(pair.max_authority(), Some(AuthorityLevel::Commander));
822
823 assert_eq!(pair.max_rank(), Some(OperatorRank::E8));
825 }
826
827 #[test]
828 fn test_human_machine_pair_binding_types() {
829 let op = Operator::new(
830 "op1".to_string(),
831 "Operator".to_string(),
832 OperatorRank::E5,
833 AuthorityLevel::Supervisor,
834 "11B".to_string(),
835 );
836
837 for binding_type in [
838 BindingType::Unspecified,
839 BindingType::OneToOne,
840 BindingType::OneToMany,
841 BindingType::ManyToOne,
842 BindingType::ManyToMany,
843 ] {
844 let pair =
845 HumanMachinePair::new(vec![op.clone()], vec!["node_1".to_string()], binding_type);
846 assert_eq!(pair.binding_type, binding_type as i32);
847 }
848 }
849}