@@ -2,7 +2,7 @@ use crate::Harness;
2
2
use image:: ImageError ;
3
3
use std:: fmt:: Display ;
4
4
use std:: io:: ErrorKind ;
5
- use std:: path:: { Path , PathBuf } ;
5
+ use std:: path:: PathBuf ;
6
6
7
7
#[ non_exhaustive]
8
8
pub struct SnapshotOptions {
@@ -159,22 +159,6 @@ fn should_update_snapshots() -> bool {
159
159
std:: env:: var ( "UPDATE_SNAPSHOTS" ) . is_ok ( )
160
160
}
161
161
162
- fn maybe_update_snapshot (
163
- snapshot_path : & Path ,
164
- current : & image:: RgbaImage ,
165
- ) -> Result < ( ) , SnapshotError > {
166
- if should_update_snapshots ( ) {
167
- current
168
- . save ( snapshot_path)
169
- . map_err ( |err| SnapshotError :: WriteSnapshot {
170
- err,
171
- path : snapshot_path. into ( ) ,
172
- } ) ?;
173
- println ! ( "Updated snapshot: {snapshot_path:?}" ) ;
174
- }
175
- Ok ( ( ) )
176
- }
177
-
178
162
/// Image snapshot test with custom options.
179
163
///
180
164
/// If you want to change the default options for your whole project, it's recommended to create a
@@ -188,11 +172,14 @@ fn maybe_update_snapshot(
188
172
/// The new image from the most recent test run will be saved under `{output_path}/{name}.new.png`.
189
173
/// If new image didn't match the snapshot, a diff image will be saved under `{output_path}/{name}.diff.png`.
190
174
///
175
+ /// If the env-var `UPDATE_SNAPSHOTS` is set, then the old image will backed up under `{output_path}/{name}.old.png`.
176
+ /// and then new image will be written to `{output_path}/{name}.png`
177
+ ///
191
178
/// # Errors
192
179
/// Returns a [`SnapshotError`] if the image does not match the snapshot or if there was an error
193
180
/// reading or writing the snapshot.
194
181
pub fn try_image_snapshot_options (
195
- current : & image:: RgbaImage ,
182
+ new : & image:: RgbaImage ,
196
183
name : & str ,
197
184
options : & SnapshotOptions ,
198
185
) -> Result < ( ) , SnapshotError > {
@@ -201,45 +188,72 @@ pub fn try_image_snapshot_options(
201
188
output_path,
202
189
} = options;
203
190
204
- let path = output_path. join ( format ! ( "{name}.png" ) ) ;
205
- std:: fs:: create_dir_all ( path. parent ( ) . expect ( "Could not get snapshot folder" ) ) . ok ( ) ;
191
+ std:: fs:: create_dir_all ( output_path) . ok ( ) ;
192
+
193
+ // The one that is checked in to git
194
+ let snapshot_path = output_path. join ( format ! ( "{name}.png" ) ) ;
206
195
196
+ // These should be in .gitignore:
207
197
let diff_path = output_path. join ( format ! ( "{name}.diff.png" ) ) ;
208
- let current_path = output_path. join ( format ! ( "{name}.new.png" ) ) ;
198
+ let old_backup_path = output_path. join ( format ! ( "{name}.old.png" ) ) ;
199
+ let new_path = output_path. join ( format ! ( "{name}.new.png" ) ) ;
200
+
201
+ // Delete old temporary files if they exist:
202
+ std:: fs:: remove_file ( & diff_path) . ok ( ) ;
203
+ std:: fs:: remove_file ( & old_backup_path) . ok ( ) ;
204
+ std:: fs:: remove_file ( & new_path) . ok ( ) ;
205
+
206
+ let maybe_update_snapshot = || {
207
+ if should_update_snapshots ( ) {
208
+ // Keep the old version so the user can compare it:
209
+ std:: fs:: rename ( & snapshot_path, & old_backup_path) . ok ( ) ;
210
+
211
+ // Write the new file to the checked in path:
212
+ new. save ( & snapshot_path)
213
+ . map_err ( |err| SnapshotError :: WriteSnapshot {
214
+ err,
215
+ path : snapshot_path. clone ( ) ,
216
+ } ) ?;
217
+
218
+ // No need for an explicit `.new` file:
219
+ std:: fs:: remove_file ( & new_path) . ok ( ) ;
220
+
221
+ println ! ( "Updated snapshot: {snapshot_path:?}" ) ;
222
+ }
223
+ Ok ( ( ) )
224
+ } ;
209
225
210
- current
211
- . save ( & current_path )
226
+ // Always write a `.new` file so the user can compare:
227
+ new . save ( & new_path )
212
228
. map_err ( |err| SnapshotError :: WriteSnapshot {
213
229
err,
214
- path : current_path ,
230
+ path : new_path . clone ( ) ,
215
231
} ) ?;
216
232
217
- let previous = match image:: open ( & path ) {
233
+ let previous = match image:: open ( & snapshot_path ) {
218
234
Ok ( image) => image. to_rgba8 ( ) ,
219
235
Err ( err) => {
220
- maybe_update_snapshot ( & path, current) ?;
221
- return Err ( SnapshotError :: OpenSnapshot { path, err } ) ;
236
+ // No previous snapshot - probablye a new test.
237
+ maybe_update_snapshot ( ) ?;
238
+ return Err ( SnapshotError :: OpenSnapshot {
239
+ path : snapshot_path. clone ( ) ,
240
+ err,
241
+ } ) ;
222
242
}
223
243
} ;
224
244
225
- if previous. dimensions ( ) != current . dimensions ( ) {
226
- maybe_update_snapshot ( & path , current ) ?;
245
+ if previous. dimensions ( ) != new . dimensions ( ) {
246
+ maybe_update_snapshot ( ) ?;
227
247
return Err ( SnapshotError :: SizeMismatch {
228
248
name : name. to_owned ( ) ,
229
249
expected : previous. dimensions ( ) ,
230
- actual : current . dimensions ( ) ,
250
+ actual : new . dimensions ( ) ,
231
251
} ) ;
232
252
}
233
253
234
- let result = dify:: diff:: get_results (
235
- previous,
236
- current. clone ( ) ,
237
- * threshold,
238
- true ,
239
- None ,
240
- & None ,
241
- & None ,
242
- ) ;
254
+ // Compare existing image to the new one:
255
+ let result =
256
+ dify:: diff:: get_results ( previous, new. clone ( ) , * threshold, true , None , & None , & None ) ;
243
257
244
258
if let Some ( ( diff, result_image) ) = result {
245
259
result_image
@@ -248,15 +262,13 @@ pub fn try_image_snapshot_options(
248
262
path : diff_path. clone ( ) ,
249
263
err,
250
264
} ) ?;
251
- maybe_update_snapshot ( & path , current ) ?;
265
+ maybe_update_snapshot ( ) ?;
252
266
Err ( SnapshotError :: Diff {
253
267
name : name. to_owned ( ) ,
254
268
diff,
255
269
diff_path,
256
270
} )
257
271
} else {
258
- // Delete old diff if it exists
259
- std:: fs:: remove_file ( diff_path) . ok ( ) ;
260
272
Ok ( ( ) )
261
273
}
262
274
}
0 commit comments