Skip to content

Commit d73d043

Browse files
committed
Use std::panic::Location instead of custom SourceLocation.
1 parent 6e0a18e commit d73d043

File tree

10 files changed

+119
-94
lines changed

10 files changed

+119
-94
lines changed

googletest/src/assertions.rs

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ macro_rules! verify_that {
126126
$actual.check(
127127
$crate::matchers::elements_are![$($expecteds),+],
128128
stringify!($actual),
129-
$crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
130129
)
131130
}
132131
};
@@ -136,7 +135,6 @@ macro_rules! verify_that {
136135
$actual.check(
137136
$crate::matchers::unordered_elements_are![$($expecteds),+],
138137
stringify!($actual),
139-
$crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
140138
)
141139
}
142140
};
@@ -146,7 +144,6 @@ macro_rules! verify_that {
146144
$actual.check(
147145
$expected,
148146
stringify!($actual),
149-
$crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
150147
)
151148
}
152149
};
@@ -226,11 +223,6 @@ macro_rules! verify_pred {
226223
$crate::assertions::internal::report_failed_predicate(
227224
concat!(stringify!($($predicate)*), stringify!(($($arg),*))),
228225
vec![$((format!(concat!(stringify!($arg), " = {:?}"), $arg))),*],
229-
$crate::internal::source_location::SourceLocation::new(
230-
file!(),
231-
line!(),
232-
column!(),
233-
),
234226
)
235227
} else {
236228
Ok(())
@@ -294,9 +286,6 @@ macro_rules! fail {
294286
($($message:expr),+ $(,)?) => {{
295287
$crate::assertions::internal::create_fail_result(
296288
format!($($message),*),
297-
file!(),
298-
line!(),
299-
column!(),
300289
)
301290
}};
302291

@@ -327,9 +316,9 @@ macro_rules! fail {
327316
macro_rules! succeed {
328317
($($message:expr),+ $(,)?) => {{
329318
println!(
330-
"{}\n{}",
319+
"{}\n at {}:{}:{}",
331320
format!($($message),*),
332-
$crate::internal::source_location::SourceLocation::new(file!(), line!(), column!())
321+
file!(), line!(), column!()
333322
);
334323
}};
335324

@@ -372,9 +361,6 @@ macro_rules! add_failure {
372361
use $crate::GoogleTestSupport;
373362
$crate::assertions::internal::create_fail_result(
374363
format!($($message),*),
375-
file!(),
376-
line!(),
377-
column!(),
378364
).and_log_failure();
379365
}};
380366

@@ -423,10 +409,7 @@ macro_rules! add_failure_at {
423409
use $crate::GoogleTestSupport;
424410
$crate::assertions::internal::create_fail_result(
425411
format!($($message),*),
426-
$file,
427-
$line,
428-
$column,
429-
).and_log_failure();
412+
).map_err(|e| e.with_fake_location($file, $line, $column)).and_log_failure();
430413
}};
431414

432415
($file:expr, $line:expr, $column:expr $(,)?) => {
@@ -462,11 +445,7 @@ macro_rules! add_failure_at {
462445
macro_rules! verify_true {
463446
($condition:expr) => {{
464447
use $crate::assertions::internal::Subject;
465-
($condition).check(
466-
$crate::matchers::eq(true),
467-
stringify!($condition),
468-
$crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
469-
)
448+
($condition).check($crate::matchers::eq(true), stringify!($condition))
470449
}};
471450
}
472451

@@ -701,7 +680,7 @@ macro_rules! expect_pred {
701680
#[doc(hidden)]
702681
pub mod internal {
703682
use crate::{
704-
internal::{source_location::SourceLocation, test_outcome::TestAssertionFailure},
683+
internal::test_outcome::TestAssertionFailure,
705684
matcher::{create_assertion_failure, Matcher, MatcherResult},
706685
};
707686
use std::fmt::Debug;
@@ -728,16 +707,16 @@ pub mod internal {
728707
///
729708
/// **For internal use only. API stablility is not guaranteed!**
730709
#[must_use = "The assertion result must be evaluated to affect the test result."]
710+
#[track_caller]
731711
fn check(
732712
self,
733713
expected: impl Matcher<Self>,
734714
actual_expr: &'static str,
735-
source_location: SourceLocation,
736715
) -> Result<(), TestAssertionFailure> {
737716
match expected.matches(self) {
738717
MatcherResult::Match => Ok(()),
739718
MatcherResult::NoMatch => {
740-
Err(create_assertion_failure(&expected, self, actual_expr, source_location))
719+
Err(create_assertion_failure(&expected, self, actual_expr))
741720
}
742721
}
743722
}
@@ -751,34 +730,25 @@ pub mod internal {
751730
/// This intended only for use by the macro [`crate::verify_pred`].
752731
///
753732
/// **For internal use only. API stablility is not guaranteed!**
733+
#[track_caller]
754734
#[must_use = "The assertion result must be evaluated to affect the test result."]
755735
pub fn report_failed_predicate(
756736
actual_expr: &'static str,
757737
formatted_arguments: Vec<String>,
758-
source_location: SourceLocation,
759738
) -> Result<(), TestAssertionFailure> {
760739
Err(TestAssertionFailure::create(format!(
761-
"{} was false with\n {}\n{}",
740+
"{} was false with\n {}",
762741
actual_expr,
763-
formatted_arguments.join(",\n "),
764-
source_location,
742+
formatted_arguments.join(",\n ")
765743
)))
766744
}
767745

768746
/// Creates a failure at specified location.
769747
///
770748
/// **For internal use only. API stability is not guaranteed!**
771749
#[must_use = "The assertion result must be evaluated to affect the test result."]
772-
pub fn create_fail_result(
773-
message: String,
774-
file: &'static str,
775-
line: u32,
776-
column: u32,
777-
) -> crate::Result<()> {
778-
Err(crate::internal::test_outcome::TestAssertionFailure::create(format!(
779-
"{}\n{}",
780-
message,
781-
crate::internal::source_location::SourceLocation::new(file, line, column),
782-
)))
750+
#[track_caller]
751+
pub fn create_fail_result(message: String) -> crate::Result<()> {
752+
Err(crate::internal::test_outcome::TestAssertionFailure::create(message))
783753
}
784754
}

googletest/src/internal/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@
1515
#![doc(hidden)]
1616

1717
pub(crate) mod description_renderer;
18-
pub mod source_location;
1918
pub mod test_outcome;

googletest/src/internal/source_location.rs

Lines changed: 0 additions & 44 deletions
This file was deleted.

googletest/src/internal/test_outcome.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ impl TestOutcome {
8686

8787
/// Returns a `Result` corresponding to the outcome of the currently running
8888
/// test.
89+
#[track_caller]
8990
pub(crate) fn get_current_test_outcome() -> Result<(), TestAssertionFailure> {
9091
TestOutcome::with_current_test_outcome(|mut outcome| {
9192
let outcome = outcome
@@ -162,14 +163,50 @@ pub struct TestAssertionFailure {
162163
/// A human-readable formatted string describing the error.
163164
pub description: String,
164165
pub custom_message: Option<String>,
166+
location: Location,
167+
}
168+
169+
/// A code location.
170+
///
171+
/// `std::panic::Location` does not provide a constructor, hence we cannot
172+
/// construct a fake value.
173+
///
174+
/// **For internal use only. API stablility is not guaranteed!**
175+
#[doc(hidden)]
176+
#[derive(Clone)]
177+
enum Location {
178+
Real(&'static std::panic::Location<'static>),
179+
Fake { file: &'static str, line: u32, column: u32 },
180+
}
181+
182+
impl Display for Location {
183+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
184+
match self {
185+
Location::Real(l) => write!(f, "{}", l),
186+
Location::Fake { file, line, column } => write!(f, "{}:{}:{}", file, line, column),
187+
}
188+
}
165189
}
166190

167191
impl TestAssertionFailure {
168192
/// Creates a new instance with the given `description`.
169193
///
170194
/// **For internal use only. API stablility is not guaranteed!**
195+
#[track_caller]
171196
pub fn create(description: String) -> Self {
172-
Self { description, custom_message: None }
197+
Self {
198+
description,
199+
custom_message: None,
200+
location: Location::Real(std::panic::Location::caller()),
201+
}
202+
}
203+
204+
/// Set `location`` to a fake value.
205+
///
206+
/// **For internal use only. API stablility is not guaranteed!**
207+
pub fn with_fake_location(mut self, file: &'static str, line: u32, column: u32) -> Self {
208+
self.location = Location::Fake { file, line, column };
209+
self
173210
}
174211

175212
pub(crate) fn log(&self) {
@@ -184,7 +221,7 @@ impl Display for TestAssertionFailure {
184221
if let Some(custom_message) = &self.custom_message {
185222
writeln!(f, "{}", custom_message)?;
186223
}
187-
Ok(())
224+
writeln!(f, " at {}", self.location)
188225
}
189226
}
190227

@@ -198,6 +235,7 @@ impl Debug for TestAssertionFailure {
198235
}
199236

200237
impl<T: std::error::Error> From<T> for TestAssertionFailure {
238+
#[track_caller]
201239
fn from(value: T) -> Self {
202240
TestAssertionFailure::create(format!("{value}"))
203241
}

googletest/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub type Result<T> = std::result::Result<T, TestAssertionFailure>;
111111
/// }
112112
/// # verify_that!(should_fail_and_not_execute_last_assertion(), err(displays_as(contains_substring("Test failed")))).unwrap();
113113
/// ```
114+
#[track_caller]
114115
pub fn verify_current_test_outcome() -> Result<()> {
115116
TestOutcome::get_current_test_outcome()
116117
}
@@ -260,6 +261,7 @@ pub trait IntoTestResult<T> {
260261

261262
#[cfg(feature = "anyhow")]
262263
impl<T> IntoTestResult<T> for std::result::Result<T, anyhow::Error> {
264+
#[track_caller]
263265
fn into_test_result(self) -> std::result::Result<T, TestAssertionFailure> {
264266
self.map_err(|e| TestAssertionFailure::create(format!("{e}")))
265267
}

googletest/src/matcher.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
//! The components required to implement matchers.
1616
1717
use crate::description::Description;
18-
use crate::internal::source_location::SourceLocation;
1918
use crate::internal::test_outcome::TestAssertionFailure;
2019
use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
2120
use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
@@ -230,11 +229,11 @@ const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
230229
///
231230
/// The parameter `actual_expr` contains the expression which was evaluated to
232231
/// obtain `actual`.
232+
#[track_caller]
233233
pub(crate) fn create_assertion_failure<T: Debug + Copy>(
234234
matcher: &impl Matcher<T>,
235235
actual: T,
236236
actual_expr: &'static str,
237-
source_location: SourceLocation,
238237
) -> TestAssertionFailure {
239238
let actual_formatted = format!("{actual:?}");
240239
let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
@@ -247,8 +246,7 @@ pub(crate) fn create_assertion_failure<T: Debug + Copy>(
247246
Value of: {actual_expr}
248247
Expected: {}
249248
Actual: {actual_formatted},
250-
{}
251-
{source_location}",
249+
{}",
252250
matcher.describe(MatcherResult::Match),
253251
matcher.explain_match(actual).indent(),
254252
))

integration_tests/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ name = "failure_due_to_returned_error"
165165
path = "src/failure_due_to_returned_error.rs"
166166
test = false
167167

168+
[[bin]]
169+
name = "failure_due_to_returned_error_with_line_numbers"
170+
path = "src/failure_due_to_returned_error_with_line_numbers.rs"
171+
test = false
172+
168173
[[bin]]
169174
name = "fatal_and_non_fatal_failure"
170175
path = "src/fatal_and_non_fatal_failure.rs"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2022 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+
fn main() {}
16+
17+
#[cfg(test)]
18+
mod tests {
19+
20+
use googletest::prelude::*;
21+
22+
#[derive(Debug)]
23+
struct FakeError;
24+
25+
impl std::fmt::Display for FakeError {
26+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27+
write!(f, "{:?}", self)
28+
}
29+
}
30+
impl std::error::Error for FakeError {}
31+
32+
fn return_error() -> std::result::Result<String, FakeError> {
33+
Err(FakeError)
34+
}
35+
36+
#[googletest::test]
37+
fn should_fail_due_to_returned_error() -> Result<()> {
38+
return_error()?;
39+
40+
Ok(())
41+
}
42+
}

0 commit comments

Comments
 (0)