1use std::collections::{HashMap, HashSet, VecDeque};
2use std::time::{SystemTime, UNIX_EPOCH};
3
4use wick_config::config::test_case::TestCase;
5use wick_packet::{InherentData, Packet, PacketExt, PacketStream, RuntimeConfig};
6
7use crate::assertion_packet::{TestKind, ToPacket};
8use crate::operators::assert_packet;
9use crate::TestError;
10
11#[derive(Debug, Clone)]
12pub struct UnitTest<'a> {
13 pub test: &'a TestCase,
14 actual: HashMap<String, VecDeque<Packet>>,
15}
16
17impl<'a> UnitTest<'a> {
18 pub(crate) fn new(test: &'a TestCase) -> Self {
19 Self {
20 test,
21 actual: HashMap::new(),
22 }
23 }
24
25 pub fn set_actual(&mut self, actual: Vec<Packet>) {
26 for packet in actual {
27 self
28 .actual
29 .entry(packet.port().to_owned())
30 .or_default()
31 .push_back(packet);
32 }
33 }
34
35 pub(crate) fn check_next(&mut self, expected: &TestKind) -> Result<(), TestError> {
36 let packets = self
37 .actual
38 .get_mut(expected.port())
39 .ok_or(TestError::InvalidPort(expected.port().to_owned()))?;
40
41 #[allow(clippy::never_loop)]
42 while let Some(actual) = packets.pop_front() {
43 assert_packet(expected, actual)?;
44
45 return Ok(());
46 }
47 Ok(())
48 }
49
50 pub(crate) fn finalize(&mut self, _explicit_done: &HashSet<String>) -> Result<(), Vec<Packet>> {
51 let mut with_data = Vec::new();
52 let packets = self.actual.drain().collect::<Vec<_>>();
53 for (port, packets) in packets {
54 for packet in packets {
55 if packet.is_done() {
56 debug!(port, "test: received done packet without assertion, ignoring");
57 continue;
58 }
59 with_data.push(packet);
60 break;
61 }
62 }
63 if with_data.is_empty() {
64 Ok(())
65 } else {
66 Err(with_data)
67 }
68 }
69}
70
71pub(crate) fn get_payload(
72 test: &UnitTest,
73 root_config: Option<&RuntimeConfig>,
74 op_config: Option<&RuntimeConfig>,
75) -> Result<(PacketStream, InherentData, HashSet<String>), TestError> {
76 let mut packets = Vec::new();
77 let mut open_streams = HashSet::new();
78
79 let mut order = Vec::new();
82
83 for packet in test.test.inputs() {
84 if !open_streams.contains(packet.port()) {
86 order.push(packet.port().to_owned());
87 }
88 open_streams.insert(packet.port().to_owned());
89 }
90
91 let mut explicit_done = HashSet::new();
92
93 if test.test.inputs().is_empty() {
94 packets.push(Packet::no_input());
95 } else {
96 for packet in test.test.inputs() {
97 let done = packet.flag().is_done();
98 if done {
99 explicit_done.insert(packet.port().to_owned());
100 open_streams.remove(packet.port());
101 } else if !open_streams.contains(packet.port()) {
102 return Err(TestError::PacketsAfterDone(packet.port().to_owned()));
103 }
104 debug!(?packet, "test packet");
105 packets.push(packet.to_packet(root_config, op_config)?);
106 }
107
108 for port in order {
111 if open_streams.contains(&port) {
112 debug!(input = port, "adding missing done packet for input");
113 packets.push(Packet::done(port));
114 }
115 }
116 }
117
118 let (seed, timestamp) = test.test.inherent().map_or_else(
119 || {
120 (
121 0,
122 SystemTime::now()
123 .duration_since(UNIX_EPOCH)
124 .unwrap()
125 .as_millis()
126 .try_into()
127 .unwrap(),
128 )
129 },
130 |inherent| {
131 let seed = inherent.seed().unwrap_or(0);
132 let timestamp = inherent.timestamp().unwrap_or(
133 SystemTime::now()
134 .duration_since(UNIX_EPOCH)
135 .unwrap()
136 .as_millis()
137 .try_into()
138 .unwrap(),
139 );
140 (seed, timestamp)
141 },
142 );
143
144 Ok((packets.into(), InherentData::new(seed, timestamp), explicit_done))
145}