result_list_parse/
result_list_parse.rs1use std::time::{Duration, Instant};
19
20use rs_teststand::{
21 AdapterKeyName, Engine, Error, PropertyOptions, ResultRecordingOption, ResultValue, Sequence,
22 StepGroup, UIMessageCode, pump_thread_messages,
23};
24
25const RUN_DEADLINE: Duration = Duration::from_secs(30);
26
27const fn none() -> i32 {
28 PropertyOptions::NONE.bits()
29}
30
31const fn insert_if_missing() -> i32 {
32 PropertyOptions::INSERT_IF_MISSING.bits()
33}
34
35fn add_pass_fail(
37 engine: &Engine,
38 sequence: &Sequence,
39 name: &str,
40 source: &str,
41) -> Result<(), Error> {
42 let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "PassFailTest")?;
43 step.set_name(name)?;
44 step.as_property_object()?
45 .set_val_string("DataSource", insert_if_missing(), source)?;
46 sequence.insert_step(
47 &step,
48 sequence.get_num_steps(StepGroup::Main)?,
49 StepGroup::Main,
50 )
51}
52
53fn add_numeric(
55 engine: &Engine,
56 sequence: &Sequence,
57 name: &str,
58 source: &str,
59 low: f64,
60 high: f64,
61) -> Result<(), Error> {
62 let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "NumericLimitTest")?;
63 step.set_name(name)?;
64 let properties = step.as_property_object()?;
65 properties.set_val_string("DataSource", insert_if_missing(), source)?;
66 properties.set_val_number("Limits.Low", insert_if_missing(), low)?;
67 properties.set_val_number("Limits.High", insert_if_missing(), high)?;
68 sequence.insert_step(
69 &step,
70 sequence.get_num_steps(StepGroup::Main)?,
71 StepGroup::Main,
72 )
73}
74
75fn add_unrecorded_filler(engine: &Engine, sequence: &Sequence, name: &str) -> Result<(), Error> {
77 let step = engine.new_step(AdapterKeyName::NoneAdapter.as_str(), "Statement")?;
78 step.set_name(name)?;
79 step.set_result_recording_option(ResultRecordingOption::Disabled)?;
80 sequence.insert_step(
81 &step,
82 sequence.get_num_steps(StepGroup::Main)?,
83 StepGroup::Main,
84 )
85}
86
87fn wait_for_end(engine: &Engine, deadline: Duration) -> Result<bool, Error> {
89 let started = Instant::now();
90 while started.elapsed() < deadline {
91 if pump_thread_messages() {
92 return Ok(false);
93 }
94 while !engine.is_ui_message_queue_empty()? {
95 let message = engine.get_ui_message()?;
96 let ended = matches!(
97 UIMessageCode::from_bits(message.event()?),
98 Ok(UIMessageCode::EndExecution)
99 );
100 message.acknowledge()?;
101 if ended {
102 return Ok(true);
103 }
104 }
105 }
106 Ok(false)
107}
108
109fn main() -> Result<(), Box<dyn std::error::Error>> {
110 let engine = Engine::new()?;
111 engine.set_ui_message_polling_enabled(true)?;
112
113 let sequence_file = engine.new_sequence_file()?;
114 let main_sequence = sequence_file.get_sequence_by_name("MainSequence")?;
115
116 add_pass_fail(&engine, &main_sequence, "Verify Power Rail", "True")?;
117 add_unrecorded_filler(&engine, &main_sequence, "Filler (not recorded)")?;
118 add_numeric(
119 &engine,
120 &main_sequence,
121 "Verify Current Draw",
122 "1.5",
123 1.0,
124 2.0,
125 )?;
126 add_pass_fail(&engine, &main_sequence, "Verify Ground Bond", "True")?;
127
128 let step_count = main_sequence.get_num_steps(StepGroup::Main)?;
129 println!("Running {step_count} steps...");
130 let execution = engine.new_execution(&sequence_file, "MainSequence", None, false, 0)?;
131
132 if !wait_for_end(&engine, RUN_DEADLINE)? {
133 println!("The run did not finish within {RUN_DEADLINE:?}; terminating.");
134 execution.terminate()?;
135 return Ok(());
136 }
137 println!("Finished with status: {}\n", execution.result_status()?);
138
139 let results = execution.result_list()?;
140 let parsed = results.parse()?;
141
142 println!("{} of {step_count} steps recorded a result:", parsed.len());
143 for (index, result) in parsed.iter().enumerate() {
144 let measurement = match &result.value {
145 Some(ResultValue::Number(number)) => format!("measured {number}"),
146 Some(ResultValue::Text(text)) => format!("measured {text:?}"),
147 None => "no measurement".to_owned(),
148 };
149 println!(
150 " [{index}] {} ({}) -> {}, {measurement}",
151 result.name, result.step_type, result.status
152 );
153 }
154
155 println!(
157 "\nThe unrecorded step left no entry, which is why {} < {step_count}.",
158 parsed.len()
159 );
160
161 let failures: Vec<&str> = parsed
164 .iter()
165 .filter(|result| result.status == "Failed")
166 .map(|result| result.name.as_str())
167 .collect();
168 if failures.is_empty() {
169 println!("No failures.");
170 } else {
171 println!("Failed steps: {}", failures.join(", "));
172 }
173
174 engine.release_sequence_file_ex(sequence_file, none())?;
175 Ok(())
176}