1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

kittest: Add UPDATE_SNAPSHOTS=force (#7508)

This adds a new mode, `UPDATE_SNAPSHOTS=force`, which will lower the
threshold to zero, overwriting every image that is not _exactly_ the
same.

Most comparisons has a threshold because different GPUs render slightly
differently. However, setting that threshold accurately can be hard.

Sometimes a test will pass locally, but fail on CI. In those cases you
want to force an update of the failing test. You can use
`UPDATE_SNAPSHOTS=force` for that.

And sometimes a small change _should_ update all images, but the change
is so tiny that it falls under the threshold. Still, you want to make a
point of showing that these images have changes. You can use
`UPDATE_SNAPSHOTS=force` for that.
This commit is contained in:
Emil Ernerfeldt
2025-09-05 16:45:36 +02:00
committed by GitHub
parent eceb0b11c9
commit aedd43c88f
75 changed files with 213 additions and 171 deletions

View File

@@ -44,7 +44,11 @@ Once enabled, you can call `Harness::snapshot` to render the ui and save the ima
To update the snapshots, run your tests with `UPDATE_SNAPSHOTS=true`, so e.g. `UPDATE_SNAPSHOTS=true cargo test`.
Running with `UPDATE_SNAPSHOTS=true` will cause the tests to succeed.
This is so that you can set `UPDATE_SNAPSHOTS=true` and update _all_ tests, without `cargo test` failing on the first failing crate.
This is so that you can set `UPDATE_SNAPSHOTS=true` and update all tests, without `cargo test` failing on the first failing crate.
`UPDATE_SNAPSHOTS=true` will only update the images of _failing_ tests.
If you want to update all snapshot images, even those that are within error margins,
run with `UPDATE_SNAPSHOTS=force`.
If you want to have multiple snapshots in the same test, it makes sense to collect the results in a `Vec`
([look here](https://github.com/emilk/egui/blob/70a01138b77f9c5724a35a6ef750b9ae1ab9f2dc/crates/egui_demo_lib/src/demo/demo_app_windows.rs#L388-L427) for an example).

View File

@@ -285,14 +285,34 @@ impl Display for SnapshotError {
}
}
/// If this is set, we update the snapshots (if different),
/// and _succeed_ the test.
/// This is so that you can set `UPDATE_SNAPSHOTS=true` and update _all_ tests,
/// without `cargo test` failing on the first failing crate.
fn should_update_snapshots() -> bool {
match std::env::var("UPDATE_SNAPSHOTS") {
Ok(value) => !matches!(value.as_str(), "false" | "0" | "no" | "off"),
Err(_) => false,
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Mode {
Test,
UpdateFailing,
UpdateAll,
}
impl Mode {
fn from_env() -> Self {
let Ok(value) = std::env::var("UPDATE_SNAPSHOTS") else {
return Self::Test;
};
match value.as_str() {
"false" | "0" | "no" | "off" => Self::Test,
"true" | "1" | "yes" | "on" => Self::UpdateFailing,
"force" => Self::UpdateAll,
unknown => {
panic!("Unsupported value for UPDATE_SNAPSHOTS: {unknown:?}");
}
}
}
fn is_update(&self) -> bool {
match self {
Self::Test => false,
Self::UpdateFailing | Self::UpdateAll => true,
}
}
}
@@ -330,6 +350,8 @@ fn try_image_snapshot_options_impl(
) -> SnapshotResult {
#![expect(clippy::print_stdout)]
let mode = Mode::from_env();
let SnapshotOptions {
threshold,
output_path,
@@ -386,7 +408,7 @@ fn try_image_snapshot_options_impl(
Ok(image) => image.to_rgba8(),
Err(err) => {
// No previous snapshot - probablye a new test.
if should_update_snapshots() {
if mode.is_update() {
return update_snapshot();
} else {
return Err(SnapshotError::OpenSnapshot {
@@ -398,7 +420,7 @@ fn try_image_snapshot_options_impl(
};
if previous.dimensions() != new.dimensions() {
if should_update_snapshots() {
if mode.is_update() {
return update_snapshot();
} else {
return Err(SnapshotError::SizeMismatch {
@@ -410,29 +432,45 @@ fn try_image_snapshot_options_impl(
}
// Compare existing image to the new one:
let result =
dify::diff::get_results(previous, new.clone(), *threshold, true, None, &None, &None);
let threshold = if mode == Mode::UpdateAll {
0.0
} else {
*threshold
};
if let Some((num_wrong_pixels, result_image)) = result {
result_image
let result =
dify::diff::get_results(previous, new.clone(), threshold, true, None, &None, &None);
if let Some((num_wrong_pixels, diff_image)) = result {
diff_image
.save(diff_path.clone())
.map_err(|err| SnapshotError::WriteSnapshot {
path: diff_path.clone(),
err,
})?;
if num_wrong_pixels as i64 <= *failed_pixel_count_threshold as i64 {
return Ok(());
}
let is_sameish = num_wrong_pixels as i64 <= *failed_pixel_count_threshold as i64;
if should_update_snapshots() {
update_snapshot()
} else {
Err(SnapshotError::Diff {
name,
diff: num_wrong_pixels,
diff_path,
})
match mode {
Mode::Test => {
if is_sameish {
Ok(())
} else {
Err(SnapshotError::Diff {
name,
diff: num_wrong_pixels,
diff_path,
})
}
}
Mode::UpdateFailing => {
if is_sameish {
Ok(())
} else {
update_snapshot()
}
}
Mode::UpdateAll => update_snapshot(),
}
} else {
Ok(())

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21f70bc7146e43b6b10fe1e4cb32597d6f3507b42a6aa4c619c4e8c688ea4c85
size 7290
oid sha256:b3a4ea95569b812ea46bc706f91d5ac03fa18ef1707a726b729422e9e9b18680
size 7305

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6ca504cc7ef988f122fcc099914e5b6f7c39a3a86c5869a0a982c4342c48058a
size 10516
oid sha256:29074de792c3c266b451ed28c940d7278d533570efecf5a64ae8bbae2b851a52
size 10533

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:763447271686242b8a2deaa63fa1a5a0d57009ef93dd1bcb0ae906541cd7a6ea
size 21052
oid sha256:8a12bfee8b9c6b6845ff3cadc40bdb707375f2177095fcd7f0b9ad1fcf1e9f00
size 21118

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4e54f7a1ea9ac74b62241c8b662579fd3c8442857b4569ce818342fb56dc30ae
size 28218
oid sha256:0e70f7ec229d94919346192141272273ff2f56032e1ae3137cc04ffd21aabe51
size 28361

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f8443523a671d3c83456c6ee0503fdb59127a33d866c45635a84eee3596985fd
size 32831
oid sha256:d3295fc14054c31efd7a5c6508f52c4a80b0fb8f91a452808bcfe3e4dddecc9c
size 32992

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:60540cb1b5b71f100b2ea367a939cb9d93a91e56ff1f14ebfc988bbe79d69ac7
size 19719
oid sha256:e2ef3a6fb7d43c85b0f8cdb0eb7a784aa7ae5af9b61ae296e0d1a41871eb2724
size 19713

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:341658df1dfe665e79180d4540965a986a21de09c9cbc1a8744bdcff1a7c2086
size 1892
oid sha256:730bdd28319b140433802740728f096adda749014a1629114b18d6f674ee4d86
size 1893

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6298e67d099002808d51e7494e4174adee66d7ef2880728126c1d761d1432372
size 2145
oid sha256:b8c872f818a2e88cce35d015d16406c225ab6792cc6bfd232de94dbf2665df26
size 2142