Skip to content

Commit 401101f

Browse files
committed
tests: Move known_failure logic inside of TestRunner
This'll make it easier to tweak it in the future.
1 parent 3fa954c commit 401101f

File tree

4 files changed

+121
-126
lines changed

4 files changed

+121
-126
lines changed

tests/framework/src/runner.rs

Lines changed: 99 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,64 @@ impl TestRunner {
154154
self.remaining_iterations == 1
155155
}
156156

157-
/// Tick this test forward, running any actionscript and progressing the timeline by one.
158-
pub fn tick(&mut self) {
157+
pub fn is_preloaded(&self) -> bool {
158+
self.preloaded
159+
}
160+
161+
/// Ticks this test forward: runs actionscript, progresses the timeline by one,
162+
/// executes custom FsCommands and performs scheduled tests.
163+
pub fn tick(&mut self) -> Result<TestStatus> {
164+
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
165+
166+
let unwind_result = catch_unwind(AssertUnwindSafe(|| self.tick_inner()));
167+
168+
match (unwind_result, self.options.known_failure) {
169+
(Ok(ret), _) => ret,
170+
// known_failure tests may pass by panicking.
171+
(Err(_), true) => Ok(TestStatus::Finished),
172+
(Err(panic), false) => resume_unwind(panic),
173+
}
174+
}
175+
176+
fn tick_inner(&mut self) -> Result<TestStatus> {
177+
self.do_tick();
178+
179+
match (self.test(), self.options.known_failure) {
180+
(Ok(()), _) => (),
181+
(Err(_), true) => return Ok(TestStatus::Finished),
182+
(Err(err), false) => return Err(err),
183+
}
184+
185+
match self.remaining_iterations {
186+
0 => match (self.last_test(), self.options.known_failure) {
187+
(Ok(()), true) => Err(anyhow!(
188+
"Test was known to be failing, but now passes successfully. Please update it and remove `known_failure = true`!",
189+
)),
190+
(Ok(()), false) => Ok(TestStatus::Finished),
191+
(Err(_), true) => Ok(TestStatus::Finished),
192+
(Err(err), false) => Err(err),
193+
},
194+
_ if self.options.sleep_to_meet_frame_rate => {
195+
// If requested, ensure that the 'expected' amount of
196+
// time actually elapses between frames. This is useful for
197+
// tests that call 'flash.utils.getTimer()' and use
198+
// 'setInterval'/'flash.utils.Timer'
199+
//
200+
// Note that when Ruffle actually runs frames, we can
201+
// execute frames faster than this in order to 'catch up'
202+
// if we've fallen behind. However, in order to make regression
203+
// tests deterministic, we always call 'update_timers' with
204+
// an elapsed time of 'frame_time'. By sleeping for 'frame_time_duration',
205+
// we ensure that the result of 'flash.utils.getTimer()' is consistent
206+
// with timer execution (timers will see an elapsed time of *at least*
207+
// the requested timer interval).
208+
Ok(TestStatus::Sleep(self.frame_time_duration))
209+
}
210+
_ => Ok(TestStatus::Continue),
211+
}
212+
}
213+
214+
fn do_tick(&mut self) {
159215
if !self
160216
.player
161217
.lock()
@@ -179,14 +235,10 @@ impl TestRunner {
179235
self.executor.run();
180236
}
181237

182-
pub fn is_preloaded(&self) -> bool {
183-
self.preloaded
184-
}
185-
186238
/// After a tick, run any custom fdcommands that were queued up and perform any scheduled tests.
187-
pub fn test(&mut self) -> Result<TestStatus> {
239+
fn test(&mut self) -> Result<()> {
188240
if !self.preloaded {
189-
return Ok(TestStatus::Continue);
241+
return Ok(());
190242
}
191243
for command in self.fs_commands.try_iter() {
192244
match command {
@@ -225,86 +277,58 @@ impl TestRunner {
225277
// Rendering has side-effects (such as processing 'DisplayObject.scrollRect' updates)
226278
self.player.lock().unwrap().render();
227279

228-
if let Some(name) = self
229-
.images
230-
.iter()
231-
.find(|(_k, v)| v.trigger == ImageTrigger::SpecificIteration(self.current_iteration))
232-
.map(|(k, _v)| k.to_owned())
233-
{
234-
let image_comparison = self
235-
.images
236-
.remove(&name)
237-
.expect("Name was just retrieved from map, should not be missing!");
280+
let trigger = ImageTrigger::SpecificIteration(self.current_iteration);
281+
if let Some((name, comp)) = self.take_image_comparison_by_trigger(trigger) {
238282
capture_and_compare_image(
239283
&self.root_path,
240284
&self.player,
241285
&name,
242-
image_comparison,
286+
comp,
243287
self.options.known_failure,
244288
self.render_interface.as_deref(),
245289
)?;
246290
}
247291

248-
if self.remaining_iterations == 0 {
249-
// Last iteration, let's check everything went well
250-
251-
if let Some(name) = self
252-
.images
253-
.iter()
254-
.find(|(_k, v)| v.trigger == ImageTrigger::LastFrame)
255-
.map(|(k, _v)| k.to_owned())
256-
{
257-
let image_comparison = self
258-
.images
259-
.remove(&name)
260-
.expect("Name was just retrieved from map, should not be missing!");
261-
262-
capture_and_compare_image(
263-
&self.root_path,
264-
&self.player,
265-
&name,
266-
image_comparison,
267-
self.options.known_failure,
268-
self.render_interface.as_deref(),
269-
)?;
270-
}
292+
Ok(())
293+
}
271294

272-
if !self.images.is_empty() {
273-
return Err(anyhow!(
274-
"Image comparisons didn't trigger: {:?}",
275-
self.images.keys()
276-
));
277-
}
295+
fn last_test(&mut self) -> Result<()> {
296+
// Last iteration, let's check everything went well
278297

279-
self.executor.run();
298+
let trigger = ImageTrigger::LastFrame;
299+
if let Some((name, comp)) = self.take_image_comparison_by_trigger(trigger) {
300+
capture_and_compare_image(
301+
&self.root_path,
302+
&self.player,
303+
&name,
304+
comp,
305+
self.options.known_failure,
306+
self.render_interface.as_deref(),
307+
)?;
308+
}
280309

281-
let trace = self.log.trace_output();
282-
// Null bytes are invisible, and interfere with constructing
283-
// the expected output.txt file. Any tests dealing with null
284-
// bytes should explicitly test for them in ActionScript.
285-
let normalized_trace = trace.replace('\0', "");
286-
compare_trace_output(&self.output_path, &self.options, &normalized_trace)?;
310+
if !self.images.is_empty() {
311+
return Err(anyhow!(
312+
"Image comparisons didn't trigger: {:?}",
313+
self.images.keys()
314+
));
287315
}
288316

289-
Ok(match self.remaining_iterations {
290-
0 => TestStatus::Finished,
291-
_ if self.options.sleep_to_meet_frame_rate => {
292-
// If requested, ensure that the 'expected' amount of
293-
// time actually elapses between frames. This is useful for
294-
// tests that call 'flash.utils.getTimer()' and use
295-
// 'setInterval'/'flash.utils.Timer'
296-
//
297-
// Note that when Ruffle actually runs frames, we can
298-
// execute frames faster than this in order to 'catch up'
299-
// if we've fallen behind. However, in order to make regression
300-
// tests deterministic, we always call 'update_timers' with
301-
// an elapsed time of 'frame_time'. By sleeping for 'frame_time_duration',
302-
// we ensure that the result of 'flash.utils.getTimer()' is consistent
303-
// with timer execution (timers will see an elapsed time of *at least*
304-
// the requested timer interval).
305-
TestStatus::Sleep(self.frame_time_duration)
306-
}
307-
_ => TestStatus::Continue,
308-
})
317+
self.executor.run();
318+
319+
let trace = self.log.trace_output();
320+
// Null bytes are invisible, and interfere with constructing
321+
// the expected output.txt file. Any tests dealing with null
322+
// bytes should explicitly test for them in ActionScript.
323+
let normalized_trace = trace.replace('\0', "");
324+
compare_trace_output(&self.output_path, &self.options, &normalized_trace)?;
325+
Ok(())
326+
}
327+
328+
fn take_image_comparison_by_trigger(
329+
&mut self,
330+
trigger: ImageTrigger,
331+
) -> Option<(String, ImageComparison)> {
332+
self.images.extract_if(|_k, v| v.trigger == trigger).next()
309333
}
310334
}

tests/tests/external_interface/tests.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,16 @@ pub fn external_interface_avm1(
3030
let mut first = true;
3131

3232
loop {
33-
runner.tick();
34-
if !runner.is_preloaded() {
35-
continue;
36-
}
37-
38-
match runner.test()? {
33+
match runner.tick()? {
3934
TestStatus::Continue => {}
4035
TestStatus::Sleep(duration) => sleep(duration),
4136
TestStatus::Finished => break,
4237
}
4338

39+
if !runner.is_preloaded() {
40+
continue;
41+
}
42+
4443
if first {
4544
first = false;
4645
let mut player_locked = runner.player().lock().unwrap();
@@ -102,17 +101,16 @@ pub fn external_interface_avm2(
102101
let mut first = true;
103102

104103
loop {
105-
runner.tick();
106-
if !runner.is_preloaded() {
107-
continue;
108-
}
109-
110-
match runner.test()? {
104+
match runner.tick()? {
111105
TestStatus::Continue => {}
112106
TestStatus::Sleep(duration) => sleep(duration),
113107
TestStatus::Finished => break,
114108
}
115109

110+
if !runner.is_preloaded() {
111+
continue;
112+
}
113+
116114
if first {
117115
first = false;
118116
let mut player_locked = runner.player().lock().unwrap();

tests/tests/regression_tests.rs

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use crate::environment::NativeEnvironment;
66
use crate::external_interface::tests::{external_interface_avm1, external_interface_avm2};
77
use crate::shared_object::{shared_object_avm1, shared_object_avm2, shared_object_self_ref_avm1};
88
use anyhow::Context;
9-
use anyhow::Result;
109
use clap::Parser;
1110
use libtest_mimic::Trial;
1211
use ruffle_fs_tests_runner::FsTestsRunner;
@@ -15,7 +14,6 @@ use ruffle_test_framework::runner::TestStatus;
1514
use ruffle_test_framework::test::Test;
1615
use ruffle_test_framework::vfs::VfsPath;
1716
use std::borrow::Cow;
18-
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
1917
use std::path::PathBuf;
2018
use std::thread::sleep;
2119

@@ -116,32 +114,13 @@ fn trial_for_test(opts: &RuffleTestOpts, test: Test, list_only: bool) -> Trial {
116114
}
117115

118116
let trial = Trial::test(test.name.clone(), move || {
119-
let test = AssertUnwindSafe(test);
120-
let unwind_result = catch_unwind(|| {
121-
let mut runner = test.create_test_runner(&NativeEnvironment)?;
122-
123-
loop {
124-
runner.tick();
125-
match runner.test()? {
126-
TestStatus::Continue => {}
127-
TestStatus::Sleep(duration) => sleep(duration),
128-
TestStatus::Finished => break,
129-
}
130-
}
117+
let mut runner = test.create_test_runner(&NativeEnvironment)?;
131118

132-
Result::<_>::Ok(())
133-
});
134-
if test.options.known_failure {
135-
match unwind_result {
136-
Ok(Ok(())) => Err(
137-
format!("{} was known to be failing, but now passes successfully. Please update it and remove `known_failure = true`!", test.name).into()
138-
),
139-
Ok(Err(_)) | Err(_) => Ok(()),
140-
}
141-
} else {
142-
match unwind_result {
143-
Ok(r) => Ok(r?),
144-
Err(e) => resume_unwind(e),
119+
loop {
120+
match runner.tick()? {
121+
TestStatus::Continue => (),
122+
TestStatus::Sleep(duration) => sleep(duration),
123+
TestStatus::Finished => break Ok(()),
145124
}
146125
}
147126
});

tests/tests/shared_object/mod.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ pub fn shared_object_avm1(environment: &impl Environment) -> Result<(), libtest_
2525
let mut runner = test1.create_test_runner(environment)?;
2626

2727
loop {
28-
runner.tick();
29-
match runner.test()? {
28+
match runner.tick()? {
3029
TestStatus::Continue => {}
3130
TestStatus::Sleep(duration) => sleep(duration),
3231
TestStatus::Finished => break,
@@ -67,8 +66,7 @@ pub fn shared_object_avm1(environment: &impl Environment) -> Result<(), libtest_
6766
}
6867

6968
loop {
70-
runner.tick();
71-
match runner.test()? {
69+
match runner.tick()? {
7270
TestStatus::Continue => {}
7371
TestStatus::Sleep(duration) => sleep(duration),
7472
TestStatus::Finished => break,
@@ -99,8 +97,7 @@ pub fn shared_object_self_ref_avm1(
9997
let mut runner = test1.create_test_runner(environment)?;
10098

10199
loop {
102-
runner.tick();
103-
match runner.test()? {
100+
match runner.tick()? {
104101
TestStatus::Continue => {}
105102
TestStatus::Sleep(duration) => sleep(duration),
106103
TestStatus::Finished => break,
@@ -140,8 +137,7 @@ pub fn shared_object_self_ref_avm1(
140137
}
141138

142139
loop {
143-
runner.tick();
144-
match runner.test()? {
140+
match runner.tick()? {
145141
TestStatus::Continue => {}
146142
TestStatus::Sleep(duration) => sleep(duration),
147143
TestStatus::Finished => break,
@@ -170,8 +166,7 @@ pub fn shared_object_avm2(environment: &impl Environment) -> Result<(), libtest_
170166
let mut runner = test1.create_test_runner(environment)?;
171167

172168
loop {
173-
runner.tick();
174-
match runner.test()? {
169+
match runner.tick()? {
175170
TestStatus::Continue => {}
176171
TestStatus::Sleep(duration) => sleep(duration),
177172
TestStatus::Finished => break,
@@ -211,8 +206,7 @@ pub fn shared_object_avm2(environment: &impl Environment) -> Result<(), libtest_
211206
}
212207

213208
loop {
214-
runner.tick();
215-
match runner.test()? {
209+
match runner.tick()? {
216210
TestStatus::Continue => {}
217211
TestStatus::Sleep(duration) => sleep(duration),
218212
TestStatus::Finished => break,

0 commit comments

Comments
 (0)