Hayden Stainsby c6983d5167 mock: document public APIs in span module (#2442)
This change adds documentation to the tracing-mock span module and all
the public APIs within it. This includes doctests on all the methods
which serve as examples.

Additionally, the validation on `ExpectedSpan` was improved so that it
validates the level and target during `enter` and `exit` as well as on
`new_span`.

The method `ExpectedSpan::with_field` was renamed to `with_fields`
(plural) to match the same method on `ExpectedEvent` (and because
multiple fields can be passed to it).

A copy-paste typo was also fixed in the documentation for
`ExpectedEvent::with_contextual_parent`.

Refs: #539

Co-authored-by: David Barsky <me@davidbarsky.com>
2024-11-20 15:57:49 +01:00

255 lines
6.3 KiB
Rust

use tracing::subscriber::with_default;
use tracing::Level;
use tracing_attributes::instrument;
use tracing_mock::*;
// Reproduces a compile error when an instrumented function body contains inner
// attributes (https://github.com/tokio-rs/tracing/issues/2294).
#[deny(unused_variables)]
#[instrument]
fn repro_2294() {
#![allow(unused_variables)]
let i = 42;
}
#[test]
fn override_everything() {
#[instrument(target = "my_target", level = "debug")]
fn my_fn() {}
#[instrument(level = Level::DEBUG, target = "my_target")]
fn my_other_fn() {}
let span = expect::span()
.named("my_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let span2 = expect::span()
.named("my_other_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let (subscriber, handle) = subscriber::mock()
.new_span(span.clone())
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.new_span(span2.clone())
.enter(span2.clone())
.exit(span2.clone())
.drop_span(span2)
.only()
.run_with_handle();
with_default(subscriber, || {
my_fn();
my_other_fn();
});
handle.assert_finished();
}
#[test]
fn fields() {
#[instrument(target = "my_target", level = "debug")]
fn my_fn(arg1: usize, arg2: bool, arg3: String) {}
let span = expect::span()
.named("my_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let span2 = expect::span()
.named("my_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let (subscriber, handle) = subscriber::mock()
.new_span(
span.clone().with_fields(
expect::field("arg1")
.with_value(&2usize)
.and(expect::field("arg2").with_value(&false))
.and(expect::field("arg3").with_value(&"Cool".to_string()))
.only(),
),
)
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.new_span(
span2.clone().with_fields(
expect::field("arg1")
.with_value(&3usize)
.and(expect::field("arg2").with_value(&true))
.and(expect::field("arg3").with_value(&"Still Cool".to_string()))
.only(),
),
)
.enter(span2.clone())
.exit(span2.clone())
.drop_span(span2)
.only()
.run_with_handle();
with_default(subscriber, || {
my_fn(2, false, "Cool".to_string());
my_fn(3, true, "Still Cool".to_string());
});
handle.assert_finished();
}
#[test]
fn skip() {
struct UnDebug();
#[instrument(target = "my_target", level = "debug", skip(_arg2, _arg3))]
fn my_fn(arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
#[instrument(target = "my_target", level = "debug", skip_all)]
fn my_fn2(_arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
let span = expect::span()
.named("my_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let span2 = expect::span()
.named("my_fn")
.at_level(Level::DEBUG)
.with_target("my_target");
let span3 = expect::span()
.named("my_fn2")
.at_level(Level::DEBUG)
.with_target("my_target");
let (subscriber, handle) = subscriber::mock()
.new_span(
span.clone()
.with_fields(expect::field("arg1").with_value(&2usize).only()),
)
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.new_span(
span2
.clone()
.with_fields(expect::field("arg1").with_value(&3usize).only()),
)
.enter(span2.clone())
.exit(span2.clone())
.drop_span(span2)
.new_span(span3.clone())
.enter(span3.clone())
.exit(span3.clone())
.drop_span(span3)
.only()
.run_with_handle();
with_default(subscriber, || {
my_fn(2, UnDebug(), UnDebug());
my_fn(3, UnDebug(), UnDebug());
my_fn2(2, UnDebug(), UnDebug());
});
handle.assert_finished();
}
#[test]
fn generics() {
#[derive(Debug)]
struct Foo;
#[instrument]
fn my_fn<S, T: std::fmt::Debug>(arg1: S, arg2: T)
where
S: std::fmt::Debug,
{
}
let span = expect::span().named("my_fn");
let (subscriber, handle) = subscriber::mock()
.new_span(
span.clone().with_fields(
expect::field("arg1")
.with_value(&format_args!("Foo"))
.and(expect::field("arg2").with_value(&format_args!("false"))),
),
)
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.only()
.run_with_handle();
with_default(subscriber, || {
my_fn(Foo, false);
});
handle.assert_finished();
}
#[test]
fn methods() {
#[derive(Debug)]
struct Foo;
impl Foo {
#[instrument]
fn my_fn(&self, arg1: usize) {}
}
let span = expect::span().named("my_fn");
let (subscriber, handle) = subscriber::mock()
.new_span(
span.clone().with_fields(
expect::field("self")
.with_value(&format_args!("Foo"))
.and(expect::field("arg1").with_value(&42usize)),
),
)
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.only()
.run_with_handle();
with_default(subscriber, || {
let foo = Foo;
foo.my_fn(42);
});
handle.assert_finished();
}
#[test]
fn impl_trait_return_type() {
#[instrument]
fn returns_impl_trait(x: usize) -> impl Iterator<Item = usize> {
0..x
}
let span = expect::span().named("returns_impl_trait");
let (subscriber, handle) = subscriber::mock()
.new_span(
span.clone()
.with_fields(expect::field("x").with_value(&10usize).only()),
)
.enter(span.clone())
.exit(span.clone())
.drop_span(span)
.only()
.run_with_handle();
with_default(subscriber, || {
for _ in returns_impl_trait(10) {
// nop
}
});
handle.assert_finished();
}