1// These tests require the thread-local scoped dispatcher, which only works when
2// we have a standard library. The behaviour being tested should be the same
3// with the standard lib disabled.
4//
5// The alternative would be for each of these tests to be defined in a separate
6// file, which is :(
7#![cfg(feature = "std")]
8
9use tracing::{
10 debug, error,
11 field::{debug, display},
12 info,
13 subscriber::with_default,
14 trace, warn, Level,
15};
16use tracing_mock::*;
17
18macro_rules! event_without_message {
19 ($name:ident: $e:expr) => {
20 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
21 #[test]
22 fn $name() {
23 let (subscriber, handle) = subscriber::mock()
24 .event(
25 expect::event().with_fields(
26 expect::field("answer")
27 .with_value(&42)
28 .and(
29 expect::field("to_question")
30 .with_value(&"life, the universe, and everything"),
31 )
32 .only(),
33 ),
34 )
35 .only()
36 .run_with_handle();
37
38 with_default(subscriber, || {
39 info!(
40 answer = $e,
41 to_question = "life, the universe, and everything"
42 );
43 });
44
45 handle.assert_finished();
46 }
47 };
48}
49
50event_without_message! {event_without_message: 42}
51event_without_message! {wrapping_event_without_message: std::num::Wrapping(42)}
52event_without_message! {nonzeroi32_event_without_message: std::num::NonZeroI32::new(42).unwrap()}
53// needs API breakage
54//event_without_message!{nonzerou128_event_without_message: std::num::NonZeroU128::new(42).unwrap()}
55
56#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
57#[test]
58fn event_with_message() {
59 let (subscriber, handle) = subscriber::mock()
60 .event(
61 expect::event().with_fields(expect::field("message").with_value(
62 &tracing::field::debug(format_args!(
63 "hello from my tracing::event! yak shaved = {:?}",
64 true
65 )),
66 )),
67 )
68 .only()
69 .run_with_handle();
70
71 with_default(subscriber, || {
72 debug!("hello from my tracing::event! yak shaved = {:?}", true);
73 });
74
75 handle.assert_finished();
76}
77
78#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
79#[test]
80fn message_without_delims() {
81 let (subscriber, handle) = subscriber::mock()
82 .event(
83 expect::event().with_fields(
84 expect::field("answer")
85 .with_value(&42)
86 .and(
87 expect::field("question").with_value(&"life, the universe, and everything"),
88 )
89 .and(field::msg(format_args!(
90 "hello from my event! tricky? {:?}!",
91 true
92 )))
93 .only(),
94 ),
95 )
96 .only()
97 .run_with_handle();
98
99 with_default(subscriber, || {
100 let question = "life, the universe, and everything";
101 debug!(answer = 42, question, "hello from {where}! tricky? {:?}!", true, where = "my event");
102 });
103
104 handle.assert_finished();
105}
106
107#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
108#[test]
109fn string_message_without_delims() {
110 let (subscriber, handle) = subscriber::mock()
111 .event(
112 expect::event().with_fields(
113 expect::field("answer")
114 .with_value(&42)
115 .and(
116 expect::field("question").with_value(&"life, the universe, and everything"),
117 )
118 .and(field::msg(format_args!("hello from my event")))
119 .only(),
120 ),
121 )
122 .only()
123 .run_with_handle();
124
125 with_default(subscriber, || {
126 let question = "life, the universe, and everything";
127 debug!(answer = 42, question, "hello from my event");
128 });
129
130 handle.assert_finished();
131}
132
133#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
134#[test]
135fn one_with_everything() {
136 let (subscriber, handle) = subscriber::mock()
137 .event(
138 expect::event()
139 .with_fields(
140 expect::field("message")
141 .with_value(&tracing::field::debug(format_args!(
142 "{:#x} make me one with{what:.>20}",
143 4_277_009_102u64,
144 what = "everything"
145 )))
146 .and(expect::field("foo").with_value(&666))
147 .and(expect::field("bar").with_value(&false))
148 .and(expect::field("like_a_butterfly").with_value(&42.0))
149 .only(),
150 )
151 .at_level(Level::ERROR)
152 .with_target("whatever"),
153 )
154 .only()
155 .run_with_handle();
156
157 with_default(subscriber, || {
158 tracing::event!(
159 target: "whatever",
160 Level::ERROR,
161 { foo = 666, bar = false, like_a_butterfly = 42.0 },
162 "{:#x} make me one with{what:.>20}", 4_277_009_102u64, what = "everything"
163 );
164 });
165
166 handle.assert_finished();
167}
168
169#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
170#[test]
171fn moved_field() {
172 let (subscriber, handle) = subscriber::mock()
173 .event(
174 expect::event().with_fields(
175 expect::field("foo")
176 .with_value(&display("hello from my event"))
177 .only(),
178 ),
179 )
180 .only()
181 .run_with_handle();
182 with_default(subscriber, || {
183 let from = "my event";
184 tracing::event!(Level::INFO, foo = display(format!("hello from {}", from)))
185 });
186
187 handle.assert_finished();
188}
189
190#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
191#[test]
192fn dotted_field_name() {
193 let (subscriber, handle) = subscriber::mock()
194 .event(
195 expect::event().with_fields(
196 expect::field("foo.bar")
197 .with_value(&true)
198 .and(expect::field("foo.baz").with_value(&false))
199 .only(),
200 ),
201 )
202 .only()
203 .run_with_handle();
204 with_default(subscriber, || {
205 tracing::event!(Level::INFO, foo.bar = true, foo.baz = false);
206 });
207
208 handle.assert_finished();
209}
210
211#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
212#[test]
213fn borrowed_field() {
214 let (subscriber, handle) = subscriber::mock()
215 .event(
216 expect::event().with_fields(
217 expect::field("foo")
218 .with_value(&display("hello from my event"))
219 .only(),
220 ),
221 )
222 .only()
223 .run_with_handle();
224 with_default(subscriber, || {
225 let from = "my event";
226 let mut message = format!("hello from {}", from);
227 tracing::event!(Level::INFO, foo = display(&message));
228 message.push_str(", which happened!");
229 });
230
231 handle.assert_finished();
232}
233
234#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
235#[test]
236// If emitting log instrumentation, this gets moved anyway, breaking the test.
237#[cfg(not(feature = "log"))]
238fn move_field_out_of_struct() {
239 use tracing::field::debug;
240
241 #[derive(Debug)]
242 struct Position {
243 x: f32,
244 y: f32,
245 }
246
247 let pos = Position {
248 x: 3.234,
249 y: -1.223,
250 };
251 let (subscriber, handle) = subscriber::mock()
252 .event(
253 expect::event().with_fields(
254 expect::field("x")
255 .with_value(&debug(3.234))
256 .and(expect::field("y").with_value(&debug(-1.223)))
257 .only(),
258 ),
259 )
260 .event(expect::event().with_fields(expect::field("position").with_value(&debug(&pos))))
261 .only()
262 .run_with_handle();
263
264 with_default(subscriber, || {
265 let pos = Position {
266 x: 3.234,
267 y: -1.223,
268 };
269 debug!(x = debug(pos.x), y = debug(pos.y));
270 debug!(target: "app_events", { position = debug(pos) }, "New position");
271 });
272 handle.assert_finished();
273}
274
275#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
276#[test]
277fn display_shorthand() {
278 let (subscriber, handle) = subscriber::mock()
279 .event(
280 expect::event().with_fields(
281 expect::field("my_field")
282 .with_value(&display("hello world"))
283 .only(),
284 ),
285 )
286 .only()
287 .run_with_handle();
288 with_default(subscriber, || {
289 tracing::event!(Level::TRACE, my_field = %"hello world");
290 });
291
292 handle.assert_finished();
293}
294
295#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
296#[test]
297fn debug_shorthand() {
298 let (subscriber, handle) = subscriber::mock()
299 .event(
300 expect::event().with_fields(
301 expect::field("my_field")
302 .with_value(&debug("hello world"))
303 .only(),
304 ),
305 )
306 .only()
307 .run_with_handle();
308 with_default(subscriber, || {
309 tracing::event!(Level::TRACE, my_field = ?"hello world");
310 });
311
312 handle.assert_finished();
313}
314
315#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
316#[test]
317fn both_shorthands() {
318 let (subscriber, handle) = subscriber::mock()
319 .event(
320 expect::event().with_fields(
321 expect::field("display_field")
322 .with_value(&display("hello world"))
323 .and(expect::field("debug_field").with_value(&debug("hello world")))
324 .only(),
325 ),
326 )
327 .only()
328 .run_with_handle();
329 with_default(subscriber, || {
330 tracing::event!(Level::TRACE, display_field = %"hello world", debug_field = ?"hello world");
331 });
332
333 handle.assert_finished();
334}
335
336#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
337#[test]
338fn explicit_child() {
339 let (subscriber, handle) = subscriber::mock()
340 .new_span(expect::span().named("foo"))
341 .event(expect::event().with_explicit_parent(Some("foo")))
342 .only()
343 .run_with_handle();
344
345 with_default(subscriber, || {
346 let foo = tracing::span!(Level::TRACE, "foo");
347 tracing::event!(parent: foo.id(), Level::TRACE, "bar");
348 });
349
350 handle.assert_finished();
351}
352
353#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
354#[test]
355fn explicit_child_at_levels() {
356 let (subscriber, handle) = subscriber::mock()
357 .new_span(expect::span().named("foo"))
358 .event(expect::event().with_explicit_parent(Some("foo")))
359 .event(expect::event().with_explicit_parent(Some("foo")))
360 .event(expect::event().with_explicit_parent(Some("foo")))
361 .event(expect::event().with_explicit_parent(Some("foo")))
362 .event(expect::event().with_explicit_parent(Some("foo")))
363 .only()
364 .run_with_handle();
365
366 with_default(subscriber, || {
367 let foo = tracing::span!(Level::TRACE, "foo");
368 trace!(parent: foo.id(), "a");
369 debug!(parent: foo.id(), "b");
370 info!(parent: foo.id(), "c");
371 warn!(parent: foo.id(), "d");
372 error!(parent: foo.id(), "e");
373 });
374
375 handle.assert_finished();
376}
377
378#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
379#[test]
380fn option_values() {
381 let (subscriber, handle) = subscriber::mock()
382 .event(
383 expect::event().with_fields(
384 expect::field("some_str")
385 .with_value(&"yes")
386 .and(expect::field("some_bool").with_value(&true))
387 .and(expect::field("some_u64").with_value(&42_u64))
388 .only(),
389 ),
390 )
391 .only()
392 .run_with_handle();
393
394 with_default(subscriber, || {
395 let some_str = Some("yes");
396 let none_str: Option<&'static str> = None;
397 let some_bool = Some(true);
398 let none_bool: Option<bool> = None;
399 let some_u64 = Some(42_u64);
400 let none_u64: Option<u64> = None;
401 trace!(
402 some_str = some_str,
403 none_str = none_str,
404 some_bool = some_bool,
405 none_bool = none_bool,
406 some_u64 = some_u64,
407 none_u64 = none_u64
408 );
409 });
410
411 handle.assert_finished();
412}
413
414#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
415#[test]
416fn option_ref_values() {
417 let (subscriber, handle) = subscriber::mock()
418 .event(
419 expect::event().with_fields(
420 expect::field("some_str")
421 .with_value(&"yes")
422 .and(expect::field("some_bool").with_value(&true))
423 .and(expect::field("some_u64").with_value(&42_u64))
424 .only(),
425 ),
426 )
427 .only()
428 .run_with_handle();
429
430 with_default(subscriber, || {
431 let some_str = &Some("yes");
432 let none_str: &Option<&'static str> = &None;
433 let some_bool = &Some(true);
434 let none_bool: &Option<bool> = &None;
435 let some_u64 = &Some(42_u64);
436 let none_u64: &Option<u64> = &None;
437 trace!(
438 some_str = some_str,
439 none_str = none_str,
440 some_bool = some_bool,
441 none_bool = none_bool,
442 some_u64 = some_u64,
443 none_u64 = none_u64
444 );
445 });
446
447 handle.assert_finished();
448}
449
450#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
451#[test]
452fn option_ref_mut_values() {
453 let (subscriber, handle) = subscriber::mock()
454 .event(
455 expect::event().with_fields(
456 expect::field("some_str")
457 .with_value(&"yes")
458 .and(expect::field("some_bool").with_value(&true))
459 .and(expect::field("some_u64").with_value(&42_u64))
460 .only(),
461 ),
462 )
463 .only()
464 .run_with_handle();
465
466 with_default(subscriber, || {
467 let some_str = &mut Some("yes");
468 let none_str: &mut Option<&'static str> = &mut None;
469 let some_bool = &mut Some(true);
470 let none_bool: &mut Option<bool> = &mut None;
471 let some_u64 = &mut Some(42_u64);
472 let none_u64: &mut Option<u64> = &mut None;
473 trace!(
474 some_str = some_str,
475 none_str = none_str,
476 some_bool = some_bool,
477 none_bool = none_bool,
478 some_u64 = some_u64,
479 none_u64 = none_u64
480 );
481 });
482
483 handle.assert_finished();
484}
485
486#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
487#[test]
488fn string_field() {
489 let (subscriber, handle) = subscriber::mock()
490 .event(expect::event().with_fields(expect::field("my_string").with_value(&"hello").only()))
491 .event(
492 expect::event().with_fields(
493 expect::field("my_string")
494 .with_value(&"hello world!")
495 .only(),
496 ),
497 )
498 .only()
499 .run_with_handle();
500 with_default(subscriber, || {
501 let mut my_string = String::from("hello");
502
503 tracing::event!(Level::INFO, my_string);
504
505 // the string is not moved by using it as a field!
506 my_string.push_str(" world!");
507
508 tracing::event!(Level::INFO, my_string);
509 });
510
511 handle.assert_finished();
512}
513
514#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
515#[test]
516fn constant_field_name() {
517 let expect_event = || {
518 expect::event().with_fields(
519 expect::field("foo")
520 .with_value(&"bar")
521 .and(expect::field("constant string").with_value(&"also works"))
522 .and(expect::field("foo.bar").with_value(&"baz"))
523 .and(expect::field("message").with_value(&debug(format_args!("quux"))))
524 .only(),
525 )
526 };
527 let (subscriber, handle) = subscriber::mock()
528 .event(expect_event())
529 .event(expect_event())
530 .only()
531 .run_with_handle();
532
533 with_default(subscriber, || {
534 const FOO: &str = "foo";
535 tracing::event!(
536 Level::INFO,
537 { std::convert::identity(FOO) } = "bar",
538 { "constant string" } = "also works",
539 foo.bar = "baz",
540 "quux"
541 );
542 tracing::event!(
543 Level::INFO,
544 {
545 { std::convert::identity(FOO) } = "bar",
546 { "constant string" } = "also works",
547 foo.bar = "baz",
548 },
549 "quux"
550 );
551 });
552
553 handle.assert_finished();
554}
555