Drake
is_dynamic_castable.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 #include <string>
5 
6 #include <gtest/gtest.h>
7 
9 
10 namespace drake {
11 
12 /// Checks if @p ptr, a pointer to `FromType` class, can be safely converted to
13 /// a pointer to `ToType` class. Our motivation is to provide a good diagnostic
14 /// for what @p ptr _actually_ was when the test fails.
15 ///
16 /// Here is an illustrative code snippet. We assume that `Prius` and `Camry` are
17 /// derived classes of `Car`.
18 ///
19 /// @code
20 /// const Car* prius = new Prius{};
21 ///
22 /// // The following assertion fails without diagnostic info.
23 /// EXPECT_TRUE(dynamic_cast<Camry>(ptr) != nullptr)
24 ///
25 /// // The following assertion returns `::testing::AssertionFailure()` with
26 /// // diagnostic info attached.
27 /// EXPECT_TRUE(is_dynamic_castable<Camry>(prius));
28 /// // Output:
29 /// // Value of: is_dynamic_castable<Camry>(prius)
30 /// // Actual: false (is_dynamic_castable<Camry>(Car* ptr) failed
31 /// // because ptr is of dynamic type Prius.)
32 /// // Expected: true
33 /// @endcode
34 template <typename ToType, typename FromType>
35 ::testing::AssertionResult is_dynamic_castable(const FromType* ptr) {
36  if (ptr == nullptr) {
37  const std::string from_name{NiceTypeName::Get<FromType>()};
38  const std::string to_name{NiceTypeName::Get<ToType>()};
39  return ::testing::AssertionFailure()
40  << "is_dynamic_castable<" << to_name << ">(" << from_name << "* ptr)"
41  << " failed because ptr was already nullptr.";
42  }
43  if (dynamic_cast<const ToType* const>(ptr) == nullptr) {
44  const std::string from_name{NiceTypeName::Get<FromType>()};
45  const std::string to_name{NiceTypeName::Get<ToType>()};
46  const std::string dynamic_name{NiceTypeName::Get(*ptr)};
47  return ::testing::AssertionFailure()
48  << "is_dynamic_castable<" << to_name << ">(" << from_name << "* ptr)"
49  << " failed because ptr is of dynamic type " << dynamic_name << ".";
50  }
51  return ::testing::AssertionSuccess();
52 }
53 
54 /// Checks if @p ptr, a shared pointer to `FromType` class, can be safely
55 /// converted to a shared pointer to `ToType` class. Our motivation is to
56 /// provide a good diagnostic for what @p ptr _actually_ was when the test
57 /// fails.
58 template <typename ToType, typename FromType>
59 ::testing::AssertionResult is_dynamic_castable(std::shared_ptr<FromType> ptr) {
60  return is_dynamic_castable<ToType, FromType>(ptr.get());
61 }
62 
63 /// Checks if @p ptr, a shared pointer to `FromType` class, can be safely
64 /// converted to a shared pointer to `ToType` class. Our motivation is to
65 /// provide a good diagnostic for what @p ptr _actually_ was when the test
66 /// fails.
67 template <typename ToType, typename FromType>
68 ::testing::AssertionResult is_dynamic_castable(
69  const std::unique_ptr<FromType>& ptr) {
70  return is_dynamic_castable<ToType, FromType>(ptr.get());
71 }
72 
73 } // namespace drake
Definition: automotive_demo.cc:88
::testing::AssertionResult is_dynamic_castable(const FromType *ptr)
Checks if ptr, a pointer to FromType class, can be safely converted to a pointer to ToType class...
Definition: is_dynamic_castable.h:35
static const std::string & Get()
Attempts to return a nicely demangled and canonicalized type name that is the same on all platforms...
Definition: nice_type_name.h:53