@@ -4,6 +4,8 @@ use std::fmt::Display;
4
4
use std:: io:: ErrorKind ;
5
5
use std:: path:: PathBuf ;
6
6
7
+ pub type SnapshotResult = Result < ( ) , SnapshotError > ;
8
+
7
9
#[ non_exhaustive]
8
10
pub struct SnapshotOptions {
9
11
/// The threshold for the image comparison.
@@ -189,7 +191,7 @@ pub fn try_image_snapshot_options(
189
191
new : & image:: RgbaImage ,
190
192
name : & str ,
191
193
options : & SnapshotOptions ,
192
- ) -> Result < ( ) , SnapshotError > {
194
+ ) -> SnapshotResult {
193
195
let SnapshotOptions {
194
196
threshold,
195
197
output_path,
@@ -301,7 +303,7 @@ pub fn try_image_snapshot_options(
301
303
/// # Errors
302
304
/// Returns a [`SnapshotError`] if the image does not match the snapshot or if there was an error
303
305
/// reading or writing the snapshot.
304
- pub fn try_image_snapshot ( current : & image:: RgbaImage , name : & str ) -> Result < ( ) , SnapshotError > {
306
+ pub fn try_image_snapshot ( current : & image:: RgbaImage , name : & str ) -> SnapshotResult {
305
307
try_image_snapshot_options ( current, name, & SnapshotOptions :: default ( ) )
306
308
}
307
309
@@ -373,7 +375,7 @@ impl<State> Harness<'_, State> {
373
375
& mut self ,
374
376
name : & str ,
375
377
options : & SnapshotOptions ,
376
- ) -> Result < ( ) , SnapshotError > {
378
+ ) -> SnapshotResult {
377
379
let image = self
378
380
. render ( )
379
381
. map_err ( |err| SnapshotError :: RenderError { err } ) ?;
@@ -388,7 +390,7 @@ impl<State> Harness<'_, State> {
388
390
/// # Errors
389
391
/// Returns a [`SnapshotError`] if the image does not match the snapshot, if there was an
390
392
/// error reading or writing the snapshot, if the rendering fails or if no default renderer is available.
391
- pub fn try_snapshot ( & mut self , name : & str ) -> Result < ( ) , SnapshotError > {
393
+ pub fn try_snapshot ( & mut self , name : & str ) -> SnapshotResult {
392
394
let image = self
393
395
. render ( )
394
396
. map_err ( |err| SnapshotError :: RenderError { err } ) ?;
@@ -455,15 +457,15 @@ impl<State> Harness<'_, State> {
455
457
& mut self ,
456
458
name : & str ,
457
459
options : & SnapshotOptions ,
458
- ) -> Result < ( ) , SnapshotError > {
460
+ ) -> SnapshotResult {
459
461
self . try_snapshot_options ( name, options)
460
462
}
461
463
462
464
#[ deprecated(
463
465
since = "0.31.0" ,
464
466
note = "Use `try_snapshot` instead. This function will be removed in 0.32"
465
467
) ]
466
- pub fn try_wgpu_snapshot ( & mut self , name : & str ) -> Result < ( ) , SnapshotError > {
468
+ pub fn try_wgpu_snapshot ( & mut self , name : & str ) -> SnapshotResult {
467
469
self . try_snapshot ( name)
468
470
}
469
471
@@ -483,3 +485,99 @@ impl<State> Harness<'_, State> {
483
485
self . snapshot ( name) ;
484
486
}
485
487
}
488
+
489
+ /// Utility to collect snapshot errors and display them at the end of the test.
490
+ ///
491
+ /// # Example
492
+ /// ```
493
+ /// # let harness = MockHarness;
494
+ /// # struct MockHarness;
495
+ /// # impl MockHarness {
496
+ /// # fn try_snapshot(&self, _: &str) -> Result<(), egui_kittest::SnapshotError> { Ok(()) }
497
+ /// # }
498
+ ///
499
+ /// // [...] Construct a Harness
500
+ ///
501
+ /// let mut results = egui_kittest::SnapshotResults::new();
502
+ ///
503
+ /// // Call add for each snapshot in your test
504
+ /// results.add(harness.try_snapshot("my_test"));
505
+ ///
506
+ /// // At the end of the test, fail if there are any errors
507
+ /// results.unwrap();
508
+ /// ```
509
+ ///
510
+ /// # Panics
511
+ /// Panics if there are any errors when dropped (this way it is impossible to forget to call `unwrap`).
512
+ #[ derive( Debug , Default ) ]
513
+ pub struct SnapshotResults {
514
+ errors : Vec < SnapshotError > ,
515
+ }
516
+
517
+ impl Display for SnapshotResults {
518
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
519
+ if self . errors . is_empty ( ) {
520
+ write ! ( f, "All snapshots passed" )
521
+ } else {
522
+ writeln ! ( f, "Snapshot errors:" ) ?;
523
+ for error in & self . errors {
524
+ writeln ! ( f, " {error}" ) ?;
525
+ }
526
+ Ok ( ( ) )
527
+ }
528
+ }
529
+ }
530
+
531
+ impl SnapshotResults {
532
+ pub fn new ( ) -> Self {
533
+ Default :: default ( )
534
+ }
535
+
536
+ /// Check if the result is an error and add it to the list of errors.
537
+ pub fn add ( & mut self , result : SnapshotResult ) {
538
+ if let Err ( err) = result {
539
+ self . errors . push ( err) ;
540
+ }
541
+ }
542
+
543
+ /// Check if there are any errors.
544
+ pub fn has_errors ( & self ) -> bool {
545
+ !self . errors . is_empty ( )
546
+ }
547
+
548
+ /// Convert this into a `Result<(), Self>`.
549
+ #[ allow( clippy:: missing_errors_doc) ]
550
+ pub fn into_result ( self ) -> Result < ( ) , Self > {
551
+ if self . has_errors ( ) {
552
+ Err ( self )
553
+ } else {
554
+ Ok ( ( ) )
555
+ }
556
+ }
557
+
558
+ pub fn into_inner ( mut self ) -> Vec < SnapshotError > {
559
+ std:: mem:: take ( & mut self . errors )
560
+ }
561
+
562
+ /// Panics if there are any errors, displaying each.
563
+ #[ allow( clippy:: unused_self) ]
564
+ pub fn unwrap ( self ) {
565
+ // Panic is handled in drop
566
+ }
567
+ }
568
+
569
+ impl From < SnapshotResults > for Vec < SnapshotError > {
570
+ fn from ( results : SnapshotResults ) -> Self {
571
+ results. into_inner ( )
572
+ }
573
+ }
574
+
575
+ impl Drop for SnapshotResults {
576
+ fn drop ( & mut self ) {
577
+ // Don't panic if we are already panicking (the test probably failed for another reason)
578
+ if std:: thread:: panicking ( ) {
579
+ return ;
580
+ }
581
+ assert ! ( !self . has_errors( ) , "{}" , self ) ;
582
+ }
583
+ }
0 commit comments