Skip to content

Commit f5cbf1d

Browse files
committed
tests: make known_failure = true check-specific
Root-level `known_failure = true` now only except the trace output check to fail; if other checks (e.g. image comparisons) are expected to fail, they should specify their own `known_failure = true`.
1 parent dd9729a commit f5cbf1d

File tree

28 files changed

+116
-89
lines changed

28 files changed

+116
-89
lines changed

tests/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ sleep_to_meet_frame_rate = false
3535
# Prefer setting `known_failure = true` to ignoring the test.
3636
ignore = false
3737

38-
# If true, this test is known to fail and the test runner will expect it to fail.
38+
# If true, this test is known to fail and the test runner will expect the check against
39+
# the trace output (specified `output_path`) to fail.
3940
# When the test passes in the future, it'll fail and alert that it now passes.
4041
# This will not catch Ruffle panics; if the test is expected to panic, use
4142
# `known_failure.panic = "panic message"`
@@ -100,6 +101,10 @@ with_default_font = false
100101
# This requires a render to be setup for this test
101102
[image_comparisons.COMPARISON_NAME] # COMPARISON_NAME is a name of this particular image
102103

104+
# If true, this image comparison is known to fail and the test runner will expect it to fail.
105+
# When the comparison passes in the future, it'll fail and alert that it now passes.
106+
known_failure = false
107+
103108
# The tolerance per pixel channel to be considered "the same".
104109
# Increase as needed with tests that aren't pixel perfect across platforms.
105110
# Prefer running tests with higher sample count to make a better use of this option.

tests/framework/src/options.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ impl TestOptions {
182182

183183
pub fn has_known_failure(&self) -> bool {
184184
!matches!(self.known_failure, KnownFailure::None)
185+
|| self.image_comparisons.values().any(|cmp| cmp.known_failure)
185186
}
186187

187188
pub fn output_path(&self, test_directory: &VfsPath) -> Result<VfsPath> {

tests/framework/src/options/image_comparison.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub struct ImageComparison {
1111
max_outliers: Option<usize>,
1212
checks: Vec<ImageComparisonCheck>,
1313
pub trigger: ImageTrigger,
14+
pub known_failure: bool,
1415
}
1516

1617
impl ImageComparison {

tests/framework/src/options/known_failure.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use serde::{
99
pub enum KnownFailure {
1010
#[default]
1111
None,
12-
AnyCheck,
12+
TraceOutput,
1313
Panic {
1414
message: String,
1515
},
@@ -32,7 +32,7 @@ impl<'de> de::Visitor<'de> for KnownFailureVisitor {
3232

3333
fn visit_bool<E: de::Error>(self, v: bool) -> Result<Self::Value, E> {
3434
Ok(match v {
35-
true => KnownFailure::AnyCheck,
35+
true => KnownFailure::TraceOutput,
3636
false => KnownFailure::None,
3737
})
3838
}

tests/framework/src/runner.rs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -183,23 +183,10 @@ impl TestRunner {
183183
(Err(panic), _) => resume_unwind(panic),
184184
}
185185

186-
match (self.test(), &self.options.known_failure) {
187-
(Ok(()), _) => (),
188-
(Err(_), KnownFailure::AnyCheck) => return Ok(TestStatus::Finished),
189-
(Err(err), _) => return Err(err),
190-
}
186+
self.test()?;
191187

192-
match (self.remaining_iterations, &self.options.known_failure) {
193-
(0, KnownFailure::None) => self.last_test().map(|_| TestStatus::Finished),
194-
(0, KnownFailure::Panic { .. }) => Err(anyhow!(
195-
"Test was known to be panicking, but now finishes successfully. Please update it and remove `known_failure.panic = '...'`!",
196-
)),
197-
(0, KnownFailure::AnyCheck) => match self.last_test() {
198-
Ok(()) => Err(anyhow!(
199-
"Test was known to be failing, but now passes successfully. Please update it and remove `known_failure = true`!",
200-
)),
201-
Err(_) => Ok(TestStatus::Finished),
202-
},
188+
match self.remaining_iterations {
189+
0 => self.last_test().map(|_| TestStatus::Finished),
203190
_ if self.options.sleep_to_meet_frame_rate => {
204191
// If requested, ensure that the 'expected' amount of
205192
// time actually elapses between frames. This is useful for
@@ -267,7 +254,6 @@ impl TestRunner {
267254
&self.player,
268255
&name,
269256
image_comparison,
270-
matches!(self.options.known_failure, KnownFailure::AnyCheck),
271257
self.render_interface.as_deref(),
272258
)?;
273259
} else {
@@ -293,7 +279,6 @@ impl TestRunner {
293279
&self.player,
294280
&name,
295281
comp,
296-
matches!(self.options.known_failure, KnownFailure::AnyCheck),
297282
self.render_interface.as_deref(),
298283
)?;
299284
}
@@ -303,6 +288,12 @@ impl TestRunner {
303288

304289
fn last_test(&mut self) -> Result<()> {
305290
// Last iteration, let's check everything went well
291+
if let KnownFailure::Panic { .. } = &self.options.known_failure {
292+
return Err(anyhow!(
293+
"Test was known to be panicking, but now finishes successfully. \
294+
Please update it and remove `known_failure.panic = '...'`!",
295+
));
296+
}
306297

307298
let trigger = ImageTrigger::LastFrame;
308299
if let Some((name, comp)) = self.take_image_comparison_by_trigger(trigger) {
@@ -311,7 +302,6 @@ impl TestRunner {
311302
&self.player,
312303
&name,
313304
comp,
314-
matches!(self.options.known_failure, KnownFailure::AnyCheck),
315305
self.render_interface.as_deref(),
316306
)?;
317307
}
@@ -325,13 +315,12 @@ impl TestRunner {
325315

326316
self.executor.run();
327317

328-
let trace = self.log.trace_output();
329-
// Null bytes are invisible, and interfere with constructing
330-
// the expected output.txt file. Any tests dealing with null
331-
// bytes should explicitly test for them in ActionScript.
332-
let normalized_trace = trace.replace('\0', "");
333-
compare_trace_output(&self.output_path, &self.options, &normalized_trace)?;
334-
Ok(())
318+
compare_trace_output(
319+
&self.log,
320+
&self.output_path,
321+
self.options.approximations.as_ref(),
322+
matches!(self.options.known_failure, KnownFailure::TraceOutput),
323+
)
335324
}
336325

337326
fn take_image_comparison_by_trigger(

tests/framework/src/runner/image_test.rs

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,53 @@ pub fn capture_and_compare_image(
1414
player: &Arc<Mutex<Player>>,
1515
name: &String,
1616
image_comparison: ImageComparison,
17-
known_failure: bool,
1817
render_interface: Option<&dyn RenderInterface>,
1918
) -> anyhow::Result<()> {
2019
use anyhow::Context;
2120

22-
if let Some(render_interface) = render_interface {
23-
let mut player_lock = player.lock().unwrap();
24-
player_lock.render();
21+
let Some(render_interface) = render_interface else {
22+
return Ok(());
23+
};
2524

26-
let actual_image = render_interface.capture(player_lock.renderer_mut());
25+
let mut player_lock = player.lock().unwrap();
26+
player_lock.render();
2727

28-
let expected_image_path = base_path.join(format!("{name}.expected.png"))?;
29-
if expected_image_path.is_file()? {
30-
let expected_image = image::load_from_memory(&read_bytes(&expected_image_path)?)
31-
.context("Failed to open expected image")?
32-
.into_rgba8();
28+
let actual_image = render_interface.capture(player_lock.renderer_mut());
3329

34-
test(
35-
&image_comparison,
36-
name,
37-
actual_image,
38-
expected_image,
39-
base_path,
40-
render_interface.name(),
41-
known_failure,
42-
)?;
43-
} else if known_failure {
44-
return Err(anyhow!(
45-
"No image to compare to, pretending this failed since we don't know if it worked."
46-
));
47-
} else {
48-
// If we're expecting this to be wrong, don't save a likely wrong image
49-
write_image(&expected_image_path, &actual_image, ImageFormat::Png)?;
50-
}
51-
} else if known_failure {
52-
// It's possible that the trace output matched but the image might not.
53-
// If we aren't checking the image, pretend the match failed (which makes it actually pass, since it's expecting failure).
30+
let expected_image_path = base_path.join(format!("{name}.expected.png"))?;
31+
let expected_image = if expected_image_path.is_file()? {
32+
image::load_from_memory(&read_bytes(&expected_image_path)?)
33+
.context("Failed to open expected image")?
34+
.into_rgba8()
35+
} else if image_comparison.known_failure {
36+
// If we're expecting this to be wrong, don't save a likely wrong image
37+
return Err(anyhow!("Image '{name}': No image to compare to!"));
38+
} else {
39+
write_image(&expected_image_path, &actual_image, ImageFormat::Png)?;
5440
return Err(anyhow!(
55-
"Not checking images, pretending this failed since we don't know if it worked."
41+
"Image '{name}': No image to compare to! Saved actual image as expected."
5642
));
57-
}
43+
};
5844

59-
Ok(())
45+
let result = test(
46+
&image_comparison,
47+
name,
48+
actual_image,
49+
expected_image,
50+
base_path,
51+
render_interface.name(),
52+
// If we're expecting failure, spamming files isn't productive.
53+
!image_comparison.known_failure,
54+
);
55+
56+
match (result, image_comparison.known_failure) {
57+
(result, false) => result,
58+
(Ok(()), true) => Err(anyhow!(
59+
"Image '{name}': Check was known to be failing, but now passes successfully. \
60+
Please update the test and remove `known_failure = true`!",
61+
)),
62+
(Err(_), true) => Ok(()),
63+
}
6064
}
6165

6266
pub fn test(
@@ -66,13 +70,12 @@ pub fn test(
6670
expected_image: image::RgbaImage,
6771
test_path: &VfsPath,
6872
environment_name: String,
69-
known_failure: bool,
73+
save_failures: bool,
7074
) -> anyhow::Result<()> {
7175
use anyhow::Context;
7276

7377
let save_actual_image = || {
74-
if !known_failure {
75-
// If we're expecting failure, spamming files isn't productive.
78+
if save_failures {
7679
write_image(
7780
&test_path.join(format!("{name}.actual-{environment_name}.png"))?,
7881
&actual_image,
@@ -141,8 +144,7 @@ pub fn test(
141144
difference_color.extend_from_slice(&p[..3]);
142145
}
143146

144-
if !known_failure {
145-
// If we're expecting failure, spamming files isn't productive.
147+
if save_failures {
146148
let difference_image = image::RgbImage::from_raw(
147149
actual_image.width(),
148150
actual_image.height(),
@@ -163,8 +165,7 @@ pub fn test(
163165
difference_alpha.push(p[3])
164166
}
165167

166-
if !known_failure {
167-
// If we're expecting failure, spamming files isn't productive.
168+
if save_failures {
168169
let difference_image = image::GrayImage::from_raw(
169170
actual_image.width(),
170171
actual_image.height(),

tests/framework/src/runner/trace.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,39 @@
1-
use crate::options::TestOptions;
1+
use crate::backends::TestLogBackend;
2+
use crate::options::approximations::Approximations;
23
use anyhow::{Error, anyhow};
34
use pretty_assertions::Comparison;
45
use vfs::VfsPath;
56

67
pub fn compare_trace_output(
8+
log: &TestLogBackend,
79
expected_path: &VfsPath,
8-
options: &TestOptions,
9-
actual_output: &str,
10+
approximations: Option<&Approximations>,
11+
known_failure: bool,
1012
) -> anyhow::Result<()> {
11-
let expected_output = expected_path.read_to_string()?.replace("\r\n", "\n");
13+
let expected_trace = expected_path.read_to_string()?.replace("\r\n", "\n");
14+
15+
// Null bytes are invisible, and interfere with constructing
16+
// the expected output.txt file. Any tests dealing with null
17+
// bytes should explicitly test for them in ActionScript.
18+
let actual_trace = log.trace_output().replace('\0', "");
1219

13-
if let Some(approximations) = &options.approximations {
20+
let result = test(&expected_trace, approximations, &actual_trace);
21+
match (result, known_failure) {
22+
(res, false) => res,
23+
(Ok(()), true) => Err(anyhow!(
24+
"Trace output check was known to be failing, but now passes successfully. \
25+
Please update the test and remove `known_failure = true`!",
26+
)),
27+
(Err(_), true) => Ok(()),
28+
}
29+
}
30+
31+
pub fn test(
32+
expected_output: &str,
33+
approximations: Option<&Approximations>,
34+
actual_output: &str,
35+
) -> anyhow::Result<()> {
36+
if let Some(approximations) = approximations {
1437
let add_comparison_to_err = |err: Error| -> Error {
1538
let left_pretty = PrettyString(actual_output);
1639
let right_pretty = PrettyString(&expected_output);

tests/tests/swfs/avm2/bitmapdata_draw_filters/test.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
num_ticks = 1
22

3+
[image_comparisons.output]
34
# FIXME Ruffle does not use CAB in BitmapData.draw
45
known_failure = true
56

6-
[image_comparisons.output]
77
tolerance = 0
88

99
[player_options]

tests/tests/swfs/fonts/embed_matching/no_font_found/test.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# There are no fonts embedded in this swf. It should not render anything at all, or error.
22

33
num_frames = 1
4-
known_failure = true # Right now we intentionally fall back, because we don't support DefineFont4 embedded fonts yet
54

65
[image_comparisons.output]
6+
known_failure = true # Right now we intentionally fall back, because we don't support DefineFont4 embedded fonts yet
77
tolerance = 0
88

99
[player_options]

tests/tests/swfs/from_gnash/misc-ming.all/BeginBitmapFill/test.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
num_frames = 30
2-
known_failure = true
32

43
[image_comparisons.output]
4+
known_failure = true
55
tolerance = 50
66
max_outliers = 100
77

0 commit comments

Comments
 (0)