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