Skip to content

Commit 61b92b0

Browse files
Googlercopybara-github
authored andcommitted
Add a new formatter module that provides a macro to conditionally print different things for Debug and non-Debug values using inherent-method specialization as described in dtolnay/case-studies#14.
PiperOrigin-RevId: 690016541
1 parent 3801d22 commit 61b92b0

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

googletest/src/fmt.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/// Functions for use only by the procedural macros in this module.
16+
///
17+
/// **For internal use only. API stablility is not guaranteed!**
18+
#[doc(hidden)]
19+
pub mod internal {
20+
use std::fmt::{Debug, Write};
21+
22+
/// Wrapper to allow for inherent-method specialization based on whether a
23+
/// type implements `Debug`.
24+
pub struct FormatWrapper<'a, T: ?Sized>(pub &'a T);
25+
26+
/// Default implementation to render values that implement `Debug`.
27+
///
28+
/// Used for autoref specialization to conditionally
29+
/// render only values that implement `Debug`. See also
30+
/// [`FormatNonDebugFallback`].
31+
impl<'a, T: Debug + ?Sized> FormatWrapper<'a, T> {
32+
#[track_caller]
33+
pub fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
34+
write!(output, "\n {} = {:?},", expr_label, self.0)
35+
.expect("Formatting to String should never fail");
36+
}
37+
}
38+
39+
/// Fallback implementation for rendering values for non-`Debug` types..
40+
///
41+
/// Used for inherent-method specialization to conditionally render only
42+
/// values that implement `Debug`. See also the specialized inherent impl on
43+
/// [`FormatWrapper`] above.
44+
pub trait FormatNonDebugFallback {
45+
fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str);
46+
}
47+
48+
impl<'a, T: ?Sized> FormatNonDebugFallback for FormatWrapper<'a, T> {
49+
#[track_caller]
50+
fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
51+
write!(output, "\n {} does not implement Debug,", expr_label)
52+
.expect("Formatting to String should never fail");
53+
}
54+
}
55+
56+
#[macro_export]
57+
macro_rules! __googletest__write_expr_value(
58+
($output:expr, $expr_str:expr, $value:expr $(,)?) => {
59+
{
60+
use $crate::fmt::internal::FormatNonDebugFallback as _;
61+
$crate::fmt::internal::FormatWrapper(&$value)
62+
.__googletest_write_expr_value(&mut $output, $expr_str)
63+
}
64+
}
65+
);
66+
pub use __googletest__write_expr_value;
67+
}

googletest/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ extern crate quickcheck;
2323
pub mod assertions;
2424
pub mod description;
2525
pub mod fixtures;
26+
#[macro_use]
27+
pub mod fmt;
2628
pub mod internal;
2729
pub mod matcher;
2830
pub mod matcher_support;

googletest/tests/fmt_test.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
mod write_expr_value {
16+
use googletest::prelude::*;
17+
18+
// Converts the formatting call to a `String` for testing.
19+
macro_rules! write_expr_value {
20+
($expr_str:expr, $expr: expr $(,)?) => {{
21+
let mut s = String::new();
22+
::googletest::fmt::internal::__googletest__write_expr_value!(s, $expr_str, $expr);
23+
s
24+
}};
25+
}
26+
27+
#[test]
28+
fn test_with_debug_value_references() -> Result<()> {
29+
#[derive(Debug)]
30+
struct Foo;
31+
let mut val = Foo;
32+
33+
verify_that!(write_expr_value!("val", val), eq("\n val = Foo,"))?;
34+
verify_that!(write_expr_value!("val", &val), eq("\n val = Foo,"))?;
35+
verify_that!(write_expr_value!("val", &&val), eq("\n val = Foo,"))?;
36+
verify_that!(write_expr_value!("val", &mut val), eq("\n val = Foo,"))?;
37+
verify_that!(write_expr_value!("val", &mut &mut val), eq("\n val = Foo,"))?;
38+
39+
Ok(())
40+
}
41+
42+
#[test]
43+
fn test_with_non_debug_value_references() -> Result<()> {
44+
struct Foo;
45+
let mut val = Foo;
46+
47+
verify_that!(write_expr_value!("val", val), eq("\n val does not implement Debug,"))?;
48+
verify_that!(write_expr_value!("val", &val), eq("\n val does not implement Debug,"))?;
49+
verify_that!(write_expr_value!("val", &&val), eq("\n val does not implement Debug,"))?;
50+
verify_that!(write_expr_value!("val", &mut val), eq("\n val does not implement Debug,"))?;
51+
verify_that!(
52+
write_expr_value!("val", &mut &mut val),
53+
eq("\n val does not implement Debug,")
54+
)?;
55+
56+
Ok(())
57+
}
58+
}

0 commit comments

Comments
 (0)