Skip to content

Commit

Permalink
chore: reverse the polarity of conversions, fix clippy (tokio-rs#1335)
Browse files Browse the repository at this point in the history
This backports PR tokio-rs#1335 from `master` to `v0.1.x`.

Clippy now warns about implementing `Into` rather than `From`, since
`From` automatically provides `Into` but `Into` does not provide `From`.

This commit fixes the direction of those conversions, placating Clippy.

Additionally, it fixes a redundant use of slice syntax that Clippy also
complained about.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw authored and kaffarell committed May 22, 2024
1 parent 6e46851 commit 0f2abaa
Show file tree
Hide file tree
Showing 2 changed files with 393 additions and 0 deletions.
226 changes: 226 additions & 0 deletions tracing/tests/support/field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
use tracing::{
callsite,
callsite::Callsite,
field::{self, Field, Value, Visit},
metadata::Kind,
};

use std::{collections::HashMap, fmt};

#[derive(Default, Debug, Eq, PartialEq)]
pub struct Expect {
fields: HashMap<String, MockValue>,
only: bool,
}

#[derive(Debug)]
pub struct MockField {
name: String,
value: MockValue,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MockValue {
I64(i64),
U64(u64),
Bool(bool),
Str(String),
Debug(String),
Any,
}

pub fn mock<K>(name: K) -> MockField
where
String: From<K>,
{
MockField {
name: name.into(),
value: MockValue::Any,
}
}

impl MockField {
/// Expect a field with the given name and value.
pub fn with_value(self, value: &dyn Value) -> Self {
Self {
value: MockValue::from(value),
..self
}
}

pub fn and(self, other: MockField) -> Expect {
Expect {
fields: HashMap::new(),
only: false,
}
.and(self)
.and(other)
}

pub fn only(self) -> Expect {
Expect {
fields: HashMap::new(),
only: true,
}
.and(self)
}
}

impl From<MockField> for Expect {
fn from(field: MockField) -> Self {
Expect {
fields: HashMap::new(),
only: false,
}
.and(field)
}
}

impl Expect {
pub fn and(mut self, field: MockField) -> Self {
self.fields.insert(field.name, field.value);
self
}

/// Indicates that no fields other than those specified should be expected.
pub fn only(self) -> Self {
Self { only: true, ..self }
}

fn compare_or_panic(&mut self, name: &str, value: &dyn Value, ctx: &str) {
let value = value.into();
match self.fields.remove(name) {
Some(MockValue::Any) => {}
Some(expected) => assert!(
expected == value,
"\nexpected `{}` to contain:\n\t`{}{}`\nbut got:\n\t`{}{}`",
ctx,
name,
expected,
name,
value
),
None if self.only => panic!(
"\nexpected `{}` to contain only:\n\t`{}`\nbut got:\n\t`{}{}`",
ctx, self, name, value
),
_ => {}
}
}

pub fn checker(&mut self, ctx: String) -> CheckVisitor<'_> {
CheckVisitor { expect: self, ctx }
}

pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}

impl fmt::Display for MockValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MockValue::I64(v) => write!(f, "i64 = {:?}", v),
MockValue::U64(v) => write!(f, "u64 = {:?}", v),
MockValue::Bool(v) => write!(f, "bool = {:?}", v),
MockValue::Str(v) => write!(f, "&str = {:?}", v),
MockValue::Debug(v) => write!(f, "&fmt::Debug = {:?}", v),
MockValue::Any => write!(f, "_ = _"),
}
}
}

pub struct CheckVisitor<'a> {
expect: &'a mut Expect,
ctx: String,
}

impl<'a> Visit for CheckVisitor<'a> {
fn record_i64(&mut self, field: &Field, value: i64) {
self.expect
.compare_or_panic(field.name(), &value, &self.ctx[..])
}

fn record_u64(&mut self, field: &Field, value: u64) {
self.expect
.compare_or_panic(field.name(), &value, &self.ctx[..])
}

fn record_bool(&mut self, field: &Field, value: bool) {
self.expect
.compare_or_panic(field.name(), &value, &self.ctx[..])
}

fn record_str(&mut self, field: &Field, value: &str) {
self.expect
.compare_or_panic(field.name(), &value, &self.ctx[..])
}

fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
self.expect
.compare_or_panic(field.name(), &field::debug(value), &self.ctx)
}
}

impl<'a> CheckVisitor<'a> {
pub fn finish(self) {
assert!(
self.expect.fields.is_empty(),
"{}missing {}",
self.expect,
self.ctx
);
}
}

impl<'a> From<&'a dyn Value> for MockValue {
fn from(value: &'a dyn Value) -> Self {
struct MockValueBuilder {
value: Option<MockValue>,
}

impl Visit for MockValueBuilder {
fn record_i64(&mut self, _: &Field, value: i64) {
self.value = Some(MockValue::I64(value));
}

fn record_u64(&mut self, _: &Field, value: u64) {
self.value = Some(MockValue::U64(value));
}

fn record_bool(&mut self, _: &Field, value: bool) {
self.value = Some(MockValue::Bool(value));
}

fn record_str(&mut self, _: &Field, value: &str) {
self.value = Some(MockValue::Str(value.to_owned()));
}

fn record_debug(&mut self, _: &Field, value: &dyn fmt::Debug) {
self.value = Some(MockValue::Debug(format!("{:?}", value)));
}
}

let fake_field = callsite!(name: "fake", kind: Kind::EVENT, fields: fake_field)
.metadata()
.fields()
.field("fake_field")
.unwrap();
let mut builder = MockValueBuilder { value: None };
value.record(&fake_field, &mut builder);
builder
.value
.expect("finish called before a value was recorded")
}
}

impl fmt::Display for Expect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "fields ")?;
let entries = self
.fields
.iter()
.map(|(k, v)| (field::display(k), field::display(v)));
f.debug_map().entries(entries).finish()
}
}
167 changes: 167 additions & 0 deletions tracing/tests/support/span.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#![allow(missing_docs)]
use super::{field, metadata, Parent};
use std::fmt;

/// A mock span.
///
/// This is intended for use with the mock subscriber API in the
/// `subscriber` module.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MockSpan {
pub(in crate::support) metadata: metadata::Expect,
}

#[derive(Debug, Default, Eq, PartialEq)]
pub struct NewSpan {
pub(in crate::support) span: MockSpan,
pub(in crate::support) fields: field::Expect,
pub(in crate::support) parent: Option<Parent>,
}

pub fn mock() -> MockSpan {
MockSpan {
..Default::default()
}
}

impl MockSpan {
pub fn named<I>(self, name: I) -> Self
where
I: Into<String>,
{
Self {
metadata: metadata::Expect {
name: Some(name.into()),
..self.metadata
},
}
}

pub fn at_level(self, level: tracing::Level) -> Self {
Self {
metadata: metadata::Expect {
level: Some(level),
..self.metadata
},
}
}

pub fn with_target<I>(self, target: I) -> Self
where
I: Into<String>,
{
Self {
metadata: metadata::Expect {
target: Some(target.into()),
..self.metadata
},
}
}

pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Explicit(name.into()),
None => Parent::ExplicitRoot,
};
NewSpan {
parent: Some(parent),
span: self,
..Default::default()
}
}

pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Contextual(name.into()),
None => Parent::ContextualRoot,
};
NewSpan {
parent: Some(parent),
span: self,
..Default::default()
}
}

pub fn name(&self) -> Option<&str> {
self.metadata.name.as_ref().map(String::as_ref)
}

pub fn with_field<I>(self, fields: I) -> NewSpan
where
I: Into<field::Expect>,
{
NewSpan {
span: self,
fields: fields.into(),
..Default::default()
}
}

pub(in crate::support) fn check_metadata(&self, actual: &tracing::Metadata<'_>) {
self.metadata.check(actual, format_args!("span {}", self));
assert!(actual.is_span(), "expected a span but got {:?}", actual);
}
}

impl fmt::Display for MockSpan {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.metadata.name.is_some() {
write!(f, "a span{}", self.metadata)
} else {
write!(f, "any span{}", self.metadata)
}
}
}

impl From<MockSpan> for NewSpan {
fn from(span: MockSpan) -> Self {
Self {
span,
..Default::default()
}
}
}

impl NewSpan {
pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Explicit(name.into()),
None => Parent::ExplicitRoot,
};
NewSpan {
parent: Some(parent),
..self
}
}

pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Contextual(name.into()),
None => Parent::ContextualRoot,
};
NewSpan {
parent: Some(parent),
..self
}
}

pub fn with_field<I>(self, fields: I) -> NewSpan
where
I: Into<field::Expect>,
{
NewSpan {
fields: fields.into(),
..self
}
}
}

impl fmt::Display for NewSpan {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "a new span{}", self.span.metadata)?;
if !self.fields.is_empty() {
write!(f, " with {}", self.fields)?;
}
Ok(())
}
}

0 comments on commit 0f2abaa

Please sign in to comment.