@@ -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,
@@ -306,7 +308,7 @@ pub fn try_image_snapshot_options(
306
308
/// # Errors
307
309
/// Returns a [`SnapshotError`] if the image does not match the snapshot or if there was an error
308
310
/// reading or writing the snapshot.
309
- pub fn try_image_snapshot ( current : & image:: RgbaImage , name : & str ) -> Result < ( ) , SnapshotError > {
311
+ pub fn try_image_snapshot ( current : & image:: RgbaImage , name : & str ) -> SnapshotResult {
310
312
try_image_snapshot_options ( current, name, & SnapshotOptions :: default ( ) )
311
313
}
312
314
@@ -378,7 +380,7 @@ impl<State> Harness<'_, State> {
378
380
& mut self ,
379
381
name : & str ,
380
382
options : & SnapshotOptions ,
381
- ) -> Result < ( ) , SnapshotError > {
383
+ ) -> SnapshotResult {
382
384
let image = self
383
385
. render ( )
384
386
. map_err ( |err| SnapshotError :: RenderError { err } ) ?;
@@ -393,7 +395,7 @@ impl<State> Harness<'_, State> {
393
395
/// # Errors
394
396
/// Returns a [`SnapshotError`] if the image does not match the snapshot, if there was an
395
397
/// error reading or writing the snapshot, if the rendering fails or if no default renderer is available.
396
- pub fn try_snapshot ( & mut self , name : & str ) -> Result < ( ) , SnapshotError > {
398
+ pub fn try_snapshot ( & mut self , name : & str ) -> SnapshotResult {
397
399
let image = self
398
400
. render ( )
399
401
. map_err ( |err| SnapshotError :: RenderError { err } ) ?;
@@ -460,15 +462,15 @@ impl<State> Harness<'_, State> {
460
462
& mut self ,
461
463
name : & str ,
462
464
options : & SnapshotOptions ,
463
- ) -> Result < ( ) , SnapshotError > {
465
+ ) -> SnapshotResult {
464
466
self . try_snapshot_options ( name, options)
465
467
}
466
468
467
469
#[ deprecated(
468
470
since = "0.31.0" ,
469
471
note = "Use `try_snapshot` instead. This function will be removed in 0.32"
470
472
) ]
471
- pub fn try_wgpu_snapshot ( & mut self , name : & str ) -> Result < ( ) , SnapshotError > {
473
+ pub fn try_wgpu_snapshot ( & mut self , name : & str ) -> SnapshotResult {
472
474
self . try_snapshot ( name)
473
475
}
474
476
@@ -488,3 +490,105 @@ impl<State> Harness<'_, State> {
488
490
self . snapshot ( name) ;
489
491
}
490
492
}
493
+
494
+ /// Utility to collect snapshot errors and display them at the end of the test.
495
+ ///
496
+ /// # Example
497
+ /// ```
498
+ /// # let harness = MockHarness;
499
+ /// # struct MockHarness;
500
+ /// # impl MockHarness {
501
+ /// # fn try_snapshot(&self, _: &str) -> Result<(), egui_kittest::SnapshotError> { Ok(()) }
502
+ /// # }
503
+ ///
504
+ /// // [...] Construct a Harness
505
+ ///
506
+ /// let mut results = egui_kittest::SnapshotResults::new();
507
+ ///
508
+ /// // Call add for each snapshot in your test
509
+ /// results.add(harness.try_snapshot("my_test"));
510
+ ///
511
+ /// // If there are any errors, SnapshotResults will panic once dropped.
512
+ /// ```
513
+ ///
514
+ /// # Panics
515
+ /// Panics if there are any errors when dropped (this way it is impossible to forget to call `unwrap`).
516
+ /// If you don't want to panic, you can use [`SnapshotResults::into_result`] or [`SnapshotResults::into_inner`].
517
+ /// If you want to panic early, you can use [`SnapshotResults::unwrap`].
518
+ #[ derive( Debug , Default ) ]
519
+ pub struct SnapshotResults {
520
+ errors : Vec < SnapshotError > ,
521
+ }
522
+
523
+ impl Display for SnapshotResults {
524
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
525
+ if self . errors . is_empty ( ) {
526
+ write ! ( f, "All snapshots passed" )
527
+ } else {
528
+ writeln ! ( f, "Snapshot errors:" ) ?;
529
+ for error in & self . errors {
530
+ writeln ! ( f, " {error}" ) ?;
531
+ }
532
+ Ok ( ( ) )
533
+ }
534
+ }
535
+ }
536
+
537
+ impl SnapshotResults {
538
+ pub fn new ( ) -> Self {
539
+ Default :: default ( )
540
+ }
541
+
542
+ /// Check if the result is an error and add it to the list of errors.
543
+ pub fn add ( & mut self , result : SnapshotResult ) {
544
+ if let Err ( err) = result {
545
+ self . errors . push ( err) ;
546
+ }
547
+ }
548
+
549
+ /// Check if there are any errors.
550
+ pub fn has_errors ( & self ) -> bool {
551
+ !self . errors . is_empty ( )
552
+ }
553
+
554
+ /// Convert this into a `Result<(), Self>`.
555
+ #[ allow( clippy:: missing_errors_doc) ]
556
+ pub fn into_result ( self ) -> Result < ( ) , Self > {
557
+ if self . has_errors ( ) {
558
+ Err ( self )
559
+ } else {
560
+ Ok ( ( ) )
561
+ }
562
+ }
563
+
564
+ pub fn into_inner ( mut self ) -> Vec < SnapshotError > {
565
+ std:: mem:: take ( & mut self . errors )
566
+ }
567
+
568
+ /// Panics if there are any errors, displaying each.
569
+ #[ allow( clippy:: unused_self) ]
570
+ #[ track_caller]
571
+ pub fn unwrap ( self ) {
572
+ // Panic is handled in drop
573
+ }
574
+ }
575
+
576
+ impl From < SnapshotResults > for Vec < SnapshotError > {
577
+ fn from ( results : SnapshotResults ) -> Self {
578
+ results. into_inner ( )
579
+ }
580
+ }
581
+
582
+ impl Drop for SnapshotResults {
583
+ #[ track_caller]
584
+ fn drop ( & mut self ) {
585
+ // Don't panic if we are already panicking (the test probably failed for another reason)
586
+ if std:: thread:: panicking ( ) {
587
+ return ;
588
+ }
589
+ #[ allow( clippy:: manual_assert) ]
590
+ if self . has_errors ( ) {
591
+ panic ! ( "{}" , self ) ;
592
+ }
593
+ }
594
+ }
0 commit comments