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:
@@ -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).
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:21f70bc7146e43b6b10fe1e4cb32597d6f3507b42a6aa4c619c4e8c688ea4c85
|
||||
size 7290
|
||||
oid sha256:b3a4ea95569b812ea46bc706f91d5ac03fa18ef1707a726b729422e9e9b18680
|
||||
size 7305
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6ca504cc7ef988f122fcc099914e5b6f7c39a3a86c5869a0a982c4342c48058a
|
||||
size 10516
|
||||
oid sha256:29074de792c3c266b451ed28c940d7278d533570efecf5a64ae8bbae2b851a52
|
||||
size 10533
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:763447271686242b8a2deaa63fa1a5a0d57009ef93dd1bcb0ae906541cd7a6ea
|
||||
size 21052
|
||||
oid sha256:8a12bfee8b9c6b6845ff3cadc40bdb707375f2177095fcd7f0b9ad1fcf1e9f00
|
||||
size 21118
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4e54f7a1ea9ac74b62241c8b662579fd3c8442857b4569ce818342fb56dc30ae
|
||||
size 28218
|
||||
oid sha256:0e70f7ec229d94919346192141272273ff2f56032e1ae3137cc04ffd21aabe51
|
||||
size 28361
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f8443523a671d3c83456c6ee0503fdb59127a33d866c45635a84eee3596985fd
|
||||
size 32831
|
||||
oid sha256:d3295fc14054c31efd7a5c6508f52c4a80b0fb8f91a452808bcfe3e4dddecc9c
|
||||
size 32992
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:60540cb1b5b71f100b2ea367a939cb9d93a91e56ff1f14ebfc988bbe79d69ac7
|
||||
size 19719
|
||||
oid sha256:e2ef3a6fb7d43c85b0f8cdb0eb7a784aa7ae5af9b61ae296e0d1a41871eb2724
|
||||
size 19713
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:341658df1dfe665e79180d4540965a986a21de09c9cbc1a8744bdcff1a7c2086
|
||||
size 1892
|
||||
oid sha256:730bdd28319b140433802740728f096adda749014a1629114b18d6f674ee4d86
|
||||
size 1893
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6298e67d099002808d51e7494e4174adee66d7ef2880728126c1d761d1432372
|
||||
size 2145
|
||||
oid sha256:b8c872f818a2e88cce35d015d16406c225ab6792cc6bfd232de94dbf2665df26
|
||||
size 2142
|
||||
|
||||
Reference in New Issue
Block a user