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}