1use std::borrow::Cow;
5use std::error::Error as StdError;
6
7use crate::{EnrichmentEntry, OhnoCore};
8
9pub trait Enrichable {
14 fn add_enrichment(&mut self, entry: EnrichmentEntry);
24}
25
26impl<T, E> Enrichable for Result<T, E>
27where
28 E: StdError + Enrichable,
29{
30 fn add_enrichment(&mut self, entry: EnrichmentEntry) {
31 if let Err(e) = self {
32 e.add_enrichment(entry);
33 }
34 }
35}
36
37impl Enrichable for OhnoCore {
38 fn add_enrichment(&mut self, entry: EnrichmentEntry) {
39 self.data.enrichment.push(entry);
40 }
41}
42
43pub trait EnrichableExt: Enrichable {
45 #[must_use]
50 fn enrich(mut self, msg: impl Into<Cow<'static, str>>) -> Self
51 where
52 Self: Sized,
53 {
54 let location = std::panic::Location::caller();
55 self.add_enrichment(EnrichmentEntry::new(msg, location.file(), location.line()));
56 self
57 }
58
59 #[must_use]
64 fn enrich_with<F, R>(mut self, f: F) -> Self
65 where
66 F: FnOnce() -> R,
67 R: Into<Cow<'static, str>>,
68 Self: Sized,
69 {
70 let location = std::panic::Location::caller();
71 self.add_enrichment(EnrichmentEntry::new(f(), location.file(), location.line()));
72 self
73 }
74}
75
76impl<T: Enrichable> EnrichableExt for T {}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[derive(Default, ohno::Error)]
84 pub struct TestError {
85 pub data: OhnoCore,
86 }
87
88 #[test]
89 fn test_enrich() {
90 let mut error = TestError::default();
91 error.add_enrichment(EnrichmentEntry::new("Test enrichment", "test.rs", 5));
92 assert_eq!(error.data.data.enrichment.len(), 1);
93 assert_eq!(error.data.data.enrichment[0].message, "Test enrichment");
94 assert_eq!(error.data.data.enrichment[0].location.file, "test.rs");
95 assert_eq!(error.data.data.enrichment[0].location.line, 5);
96
97 error.add_enrichment(EnrichmentEntry::new("Test enrichment", "test.rs", 10));
98 assert_eq!(error.data.data.enrichment.len(), 2);
99 assert_eq!(error.data.data.enrichment[1].message, "Test enrichment");
100 let location = &error.data.data.enrichment[1].location;
101 assert_eq!(location.file, "test.rs");
102 assert_eq!(location.line, 10);
103 }
104
105 #[test]
106 fn test_enrichable_ext() {
107 let error = TestError::default();
108 let mut result: Result<(), _> = Err(error);
109
110 result.add_enrichment(EnrichmentEntry::new("Immediate enrichment", "test.rs", 15));
111
112 let err = result.unwrap_err();
113 assert_eq!(err.data.data.enrichment.len(), 1);
114 assert_eq!(err.data.data.enrichment[0].message, "Immediate enrichment");
115 assert_eq!(err.data.data.enrichment[0].location.file, "test.rs");
116 assert_eq!(err.data.data.enrichment[0].location.line, 15);
117
118 result = Err(err).enrich("Detailed enrichment");
119 let err = result.unwrap_err();
120
121 assert_eq!(err.data.data.enrichment.len(), 2);
122 assert_eq!(err.data.data.enrichment[1].message, "Detailed enrichment");
123 let location = &err.data.data.enrichment[1].location;
124 assert!(location.file.ends_with("enrichable.rs"));
125 }
126}