tracing_mock/expect.rs
1//! Construct expectations for traces which should be received
2//!
3//! This module contains constructors for expectations defined
4//! in the [`event`], [`span`], and [`field`] modules.
5//!
6//! # Examples
7//!
8//! ```
9//! use tracing_mock::{expect, subscriber};
10//!
11//! let (subscriber, handle) = subscriber::mock()
12//! // Expect an event with message
13//! .event(expect::event().with_fields(expect::msg("message")))
14//! .only()
15//! .run_with_handle();
16//!
17//! tracing::subscriber::with_default(subscriber, || {
18//! tracing::info!("message");
19//! });
20//!
21//! handle.assert_finished();
22//! ```
23use std::fmt;
24
25use crate::{
26 ancestry::ExpectedAncestry,
27 event::ExpectedEvent,
28 field::{ExpectedField, ExpectedFields, ExpectedValue},
29 span::{ExpectedId, ExpectedSpan, NewSpan},
30};
31
32#[derive(Debug, Eq, PartialEq)]
33pub(crate) enum Expect {
34 Event(ExpectedEvent),
35 FollowsFrom {
36 consequence: ExpectedSpan,
37 cause: ExpectedSpan,
38 },
39 Enter(ExpectedSpan),
40 Exit(ExpectedSpan),
41 CloneSpan(ExpectedSpan),
42 DropSpan(ExpectedSpan),
43 Visit(ExpectedSpan, ExpectedFields),
44 NewSpan(NewSpan),
45 OnRegisterDispatch,
46 Nothing,
47}
48
49/// Create a new [`ExpectedEvent`].
50///
51/// For details on how to add additional assertions to the expected
52/// event, see the [`event`] module and the [`ExpectedEvent`] struct.
53///
54/// # Examples
55///
56/// ```
57/// use tracing_mock::{expect, subscriber};
58///
59/// let (subscriber, handle) = subscriber::mock()
60/// .event(expect::event())
61/// .run_with_handle();
62///
63/// tracing::subscriber::with_default(subscriber, || {
64/// tracing::info!(field.name = "field_value");
65/// });
66///
67/// handle.assert_finished();
68/// ```
69///
70/// If we expect an event and instead record something else, the test
71/// will fail:
72///
73/// ```should_panic
74/// use tracing_mock::{expect, subscriber};
75///
76/// let (subscriber, handle) = subscriber::mock()
77/// .event(expect::event())
78/// .run_with_handle();
79///
80/// tracing::subscriber::with_default(subscriber, || {
81/// let span = tracing::info_span!("span");
82/// let _guard = span.enter();
83/// });
84///
85/// handle.assert_finished();
86/// ```
87pub fn event() -> ExpectedEvent {
88 ExpectedEvent {
89 ..Default::default()
90 }
91}
92
93/// Construct a new [`ExpectedSpan`].
94///
95/// For details on how to add additional assertions to the expected
96/// span, see the [`span`] module and the [`ExpectedSpan`] and
97/// [`NewSpan`] structs.
98///
99/// # Examples
100///
101/// ```
102/// use tracing_mock::{expect, subscriber};
103///
104/// let (subscriber, handle) = subscriber::mock()
105/// .new_span(expect::span())
106/// .enter(expect::span())
107/// .run_with_handle();
108///
109/// tracing::subscriber::with_default(subscriber, || {
110/// let span = tracing::info_span!("span");
111/// let _guard = span.enter();
112/// });
113///
114/// handle.assert_finished();
115/// ```
116///
117/// If we expect to enter a span and instead record something else, the test
118/// will fail:
119///
120/// ```should_panic
121/// use tracing_mock::{expect, subscriber};
122///
123/// let (subscriber, handle) = subscriber::mock()
124/// .enter(expect::span())
125/// .run_with_handle();
126///
127/// tracing::subscriber::with_default(subscriber, || {
128/// tracing::info!(field.name = "field_value");
129/// });
130///
131/// handle.assert_finished();
132/// ```
133pub fn span() -> ExpectedSpan {
134 ExpectedSpan {
135 ..Default::default()
136 }
137}
138
139/// Construct a new [`ExpectedField`].
140///
141/// For details on how to set the value of the expected field and
142/// how to expect multiple fields, see the [`field`] module and the
143/// [`ExpectedField`] and [`ExpectedFields`] structs.
144/// span, see the [`span`] module and the [`ExpectedSpan`] and
145/// [`NewSpan`] structs.
146///
147/// # Examples
148///
149/// ```
150/// use tracing_mock::{expect, subscriber};
151///
152/// let event = expect::event()
153/// .with_fields(expect::field("field.name").with_value(&"field_value"));
154///
155/// let (subscriber, handle) = subscriber::mock()
156/// .event(event)
157/// .run_with_handle();
158///
159/// tracing::subscriber::with_default(subscriber, || {
160/// tracing::info!(field.name = "field_value");
161/// });
162///
163/// handle.assert_finished();
164/// ```
165///
166/// A different field value will cause the test to fail:
167///
168/// ```should_panic
169/// use tracing_mock::{expect, subscriber};
170///
171/// let event = expect::event()
172/// .with_fields(expect::field("field.name").with_value(&"field_value"));
173///
174/// let (subscriber, handle) = subscriber::mock()
175/// .event(event)
176/// .run_with_handle();
177///
178/// tracing::subscriber::with_default(subscriber, || {
179/// tracing::info!(field.name = "different_field_value");
180/// });
181///
182/// handle.assert_finished();
183/// ```
184pub fn field<K>(name: K) -> ExpectedField
185where
186 String: From<K>,
187{
188 ExpectedField {
189 name: name.into(),
190 value: ExpectedValue::Any,
191 }
192}
193
194/// Construct a new message [`ExpectedField`].
195///
196/// For details on how to set the value of the message field and
197/// how to expect multiple fields, see the [`field`] module and the
198/// [`ExpectedField`] and [`ExpectedFields`] structs.
199///
200/// This is equivalent to
201/// `expect::field("message").with_value(message)`.
202///
203/// # Examples
204///
205/// ```
206/// use tracing_mock::{expect, subscriber};
207///
208/// let event = expect::event().with_fields(
209/// expect::msg("message"));
210///
211/// let (subscriber, handle) = subscriber::mock()
212/// .event(event)
213/// .run_with_handle();
214///
215/// tracing::subscriber::with_default(subscriber, || {
216/// tracing::info!("message");
217/// });
218///
219/// handle.assert_finished();
220/// ```
221///
222/// A different message value will cause the test to fail:
223///
224/// ```should_panic
225/// use tracing_mock::{expect, subscriber};
226///
227/// let event = expect::event().with_fields(
228/// expect::msg("message"));
229///
230/// let (subscriber, handle) = subscriber::mock()
231/// .event(event)
232/// .run_with_handle();
233///
234/// tracing::subscriber::with_default(subscriber, || {
235/// tracing::info!("different message");
236/// });
237///
238/// handle.assert_finished();
239/// ```
240pub fn msg(message: impl fmt::Display) -> ExpectedField {
241 ExpectedField {
242 name: "message".to_string(),
243 value: ExpectedValue::Debug(message.to_string()),
244 }
245}
246
247/// Returns a new, unset `ExpectedId`.
248///
249/// The `ExpectedId` needs to be attached to a [`NewSpan`] or an
250/// [`ExpectedSpan`] passed to [`MockSubscriber::new_span`] to
251/// ensure that it gets set. When the a clone of the same
252/// `ExpectedSpan` is attached to an [`ExpectedSpan`] and passed to
253/// any other method on [`MockSubscriber`] that accepts it, it will
254/// ensure that it is exactly the same span used across those
255/// distinct expectations.
256///
257/// For more details on how to use this struct, see the documentation
258/// on [`ExpectedSpan::with_id`].
259///
260/// [`MockSubscriber`]: struct@crate::subscriber::MockSubscriber
261/// [`MockSubscriber::new_span`]: fn@crate::subscriber::MockSubscriber::new_span
262pub fn id() -> ExpectedId {
263 ExpectedId::new_unset()
264}
265
266/// Convenience function that returns [`ExpectedAncestry::IsContextualRoot`].
267pub fn is_contextual_root() -> ExpectedAncestry {
268 ExpectedAncestry::IsContextualRoot
269}
270
271/// Convenience function that returns [`ExpectedAncestry::HasContextualParent`] with
272/// provided name.
273pub fn has_contextual_parent<S: Into<ExpectedSpan>>(span: S) -> ExpectedAncestry {
274 ExpectedAncestry::HasContextualParent(span.into())
275}
276
277/// Convenience function that returns [`ExpectedAncestry::IsExplicitRoot`].
278pub fn is_explicit_root() -> ExpectedAncestry {
279 ExpectedAncestry::IsExplicitRoot
280}
281
282/// Convenience function that returns [`ExpectedAncestry::HasExplicitParent`] with
283/// provided name.
284pub fn has_explicit_parent<S: Into<ExpectedSpan>>(span: S) -> ExpectedAncestry {
285 ExpectedAncestry::HasExplicitParent(span.into())
286}
287
288impl Expect {
289 pub(crate) fn bad(&self, name: impl AsRef<str>, what: fmt::Arguments<'_>) {
290 let name = name.as_ref();
291 match self {
292 Expect::Event(e) => panic!(
293 "\n[{}] expected event {}\n[{}] but instead {}",
294 name, e, name, what,
295 ),
296 Expect::FollowsFrom { consequence, cause } => panic!(
297 "\n[{}] expected consequence {} to follow cause {} but instead {}",
298 name, consequence, cause, what,
299 ),
300 Expect::Enter(e) => panic!(
301 "\n[{}] expected to enter {}\n[{}] but instead {}",
302 name, e, name, what,
303 ),
304 Expect::Exit(e) => panic!(
305 "\n[{}] expected to exit {}\n[{}] but instead {}",
306 name, e, name, what,
307 ),
308 Expect::CloneSpan(e) => {
309 panic!(
310 "\n[{}] expected to clone {}\n[{}] but instead {}",
311 name, e, name, what,
312 )
313 }
314 Expect::DropSpan(e) => {
315 panic!(
316 "\n[{}] expected to drop {}\n[{}] but instead {}",
317 name, e, name, what,
318 )
319 }
320 Expect::Visit(e, fields) => panic!(
321 "\n[{}] expected {} to record {}\n[{}] but instead {}",
322 name, e, fields, name, what,
323 ),
324 Expect::NewSpan(e) => panic!(
325 "\n[{}] expected {}\n[{}] but instead {}",
326 name, e, name, what
327 ),
328 Expect::OnRegisterDispatch => panic!(
329 "\n[{}] expected on_register_dispatch to be called\n[{}] but instead {}",
330 name, name, what
331 ),
332 Expect::Nothing => panic!(
333 "\n[{}] expected nothing else to happen\n[{}] but {} instead",
334 name, name, what,
335 ),
336 }
337 }
338}