1 #![allow(missing_docs)]
2 use super::{field, metadata, Parent};
3 use std::fmt;
4 
5 /// A mock span.
6 ///
7 /// This is intended for use with the mock subscriber API in the
8 /// `subscriber` module.
9 #[derive(Clone, Default, Eq, PartialEq)]
10 pub struct MockSpan {
11     pub(in crate::support) metadata: metadata::Expect,
12 }
13 
14 #[derive(Default, Eq, PartialEq)]
15 pub struct NewSpan {
16     pub(in crate::support) span: MockSpan,
17     pub(in crate::support) fields: field::Expect,
18     pub(in crate::support) parent: Option<Parent>,
19 }
20 
mock() -> MockSpan21 pub fn mock() -> MockSpan {
22     MockSpan {
23         ..Default::default()
24     }
25 }
26 
27 impl MockSpan {
named<I>(self, name: I) -> Self where I: Into<String>,28     pub fn named<I>(self, name: I) -> Self
29     where
30         I: Into<String>,
31     {
32         Self {
33             metadata: metadata::Expect {
34                 name: Some(name.into()),
35                 ..self.metadata
36             },
37         }
38     }
39 
at_level(self, level: tracing::Level) -> Self40     pub fn at_level(self, level: tracing::Level) -> Self {
41         Self {
42             metadata: metadata::Expect {
43                 level: Some(level),
44                 ..self.metadata
45             },
46         }
47     }
48 
with_target<I>(self, target: I) -> Self where I: Into<String>,49     pub fn with_target<I>(self, target: I) -> Self
50     where
51         I: Into<String>,
52     {
53         Self {
54             metadata: metadata::Expect {
55                 target: Some(target.into()),
56                 ..self.metadata
57             },
58         }
59     }
60 
with_explicit_parent(self, parent: Option<&str>) -> NewSpan61     pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
62         let parent = match parent {
63             Some(name) => Parent::Explicit(name.into()),
64             None => Parent::ExplicitRoot,
65         };
66         NewSpan {
67             parent: Some(parent),
68             span: self,
69             ..Default::default()
70         }
71     }
72 
with_contextual_parent(self, parent: Option<&str>) -> NewSpan73     pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
74         let parent = match parent {
75             Some(name) => Parent::Contextual(name.into()),
76             None => Parent::ContextualRoot,
77         };
78         NewSpan {
79             parent: Some(parent),
80             span: self,
81             ..Default::default()
82         }
83     }
84 
name(&self) -> Option<&str>85     pub fn name(&self) -> Option<&str> {
86         self.metadata.name.as_ref().map(String::as_ref)
87     }
88 
level(&self) -> Option<tracing::Level>89     pub fn level(&self) -> Option<tracing::Level> {
90         self.metadata.level
91     }
92 
target(&self) -> Option<&str>93     pub fn target(&self) -> Option<&str> {
94         self.metadata.target.as_deref()
95     }
96 
with_field<I>(self, fields: I) -> NewSpan where I: Into<field::Expect>,97     pub fn with_field<I>(self, fields: I) -> NewSpan
98     where
99         I: Into<field::Expect>,
100     {
101         NewSpan {
102             span: self,
103             fields: fields.into(),
104             ..Default::default()
105         }
106     }
107 }
108 
109 impl fmt::Debug for MockSpan {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result110     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111         let mut s = f.debug_struct("MockSpan");
112 
113         if let Some(name) = self.name() {
114             s.field("name", &name);
115         }
116 
117         if let Some(level) = self.level() {
118             s.field("level", &format_args!("{:?}", level));
119         }
120 
121         if let Some(target) = self.target() {
122             s.field("target", &target);
123         }
124 
125         s.finish()
126     }
127 }
128 
129 impl fmt::Display for MockSpan {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result130     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131         if self.metadata.name.is_some() {
132             write!(f, "a span{}", self.metadata)
133         } else {
134             write!(f, "any span{}", self.metadata)
135         }
136     }
137 }
138 
139 impl From<MockSpan> for NewSpan {
from(span: MockSpan) -> Self140     fn from(span: MockSpan) -> Self {
141         Self {
142             span,
143             ..Default::default()
144         }
145     }
146 }
147 
148 impl NewSpan {
with_explicit_parent(self, parent: Option<&str>) -> NewSpan149     pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
150         let parent = match parent {
151             Some(name) => Parent::Explicit(name.into()),
152             None => Parent::ExplicitRoot,
153         };
154         NewSpan {
155             parent: Some(parent),
156             ..self
157         }
158     }
159 
with_contextual_parent(self, parent: Option<&str>) -> NewSpan160     pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
161         let parent = match parent {
162             Some(name) => Parent::Contextual(name.into()),
163             None => Parent::ContextualRoot,
164         };
165         NewSpan {
166             parent: Some(parent),
167             ..self
168         }
169     }
170 
with_field<I>(self, fields: I) -> NewSpan where I: Into<field::Expect>,171     pub fn with_field<I>(self, fields: I) -> NewSpan
172     where
173         I: Into<field::Expect>,
174     {
175         NewSpan {
176             fields: fields.into(),
177             ..self
178         }
179     }
180 
check( &mut self, span: &tracing_core::span::Attributes<'_>, get_parent_name: impl FnOnce() -> Option<String>, subscriber_name: &str, )181     pub fn check(
182         &mut self,
183         span: &tracing_core::span::Attributes<'_>,
184         get_parent_name: impl FnOnce() -> Option<String>,
185         subscriber_name: &str,
186     ) {
187         let meta = span.metadata();
188         let name = meta.name();
189         self.span
190             .metadata
191             .check(meta, format_args!("span `{}`", name), subscriber_name);
192         let mut checker = self.fields.checker(name, subscriber_name);
193         span.record(&mut checker);
194         checker.finish();
195 
196         if let Some(expected_parent) = self.parent.as_ref() {
197             let actual_parent = get_parent_name();
198             expected_parent.check_parent_name(
199                 actual_parent.as_deref(),
200                 span.parent().cloned(),
201                 format_args!("span `{}`", name),
202                 subscriber_name,
203             )
204         }
205     }
206 }
207 
208 impl fmt::Display for NewSpan {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result209     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210         write!(f, "a new span{}", self.span.metadata)?;
211         if !self.fields.is_empty() {
212             write!(f, " with {}", self.fields)?;
213         }
214         Ok(())
215     }
216 }
217 
218 impl fmt::Debug for NewSpan {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result219     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220         let mut s = f.debug_struct("NewSpan");
221 
222         if let Some(name) = self.span.name() {
223             s.field("name", &name);
224         }
225 
226         if let Some(level) = self.span.level() {
227             s.field("level", &format_args!("{:?}", level));
228         }
229 
230         if let Some(target) = self.span.target() {
231             s.field("target", &target);
232         }
233 
234         if let Some(ref parent) = self.parent {
235             s.field("parent", &format_args!("{:?}", parent));
236         }
237 
238         if !self.fields.is_empty() {
239             s.field("fields", &self.fields);
240         }
241 
242         s.finish()
243     }
244 }
245