🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

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