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}