Repository: google/googletest
File: googlemock/test/gmock-actions_test.cc (C++)

Code before:
TEST(ReturnRefTest, IsCovariant) {
  Base base;
  Derived derived;
  Action<Base&()> a = ReturnRef(base);
  EXPECT_EQ(&base, &a.Perform(std::make_tuple()));

  a = ReturnRef(derived);
  EXPECT_EQ(&derived, &a.Perform(std::make_tuple()));
}

template <typename T, typename = decltype(ReturnRef(std::declval<T&&>()))>
bool CanCallReturnRef(T&&) { return true; }
bool CanCallReturnRef(Unused) { return false; }

// Defined here, because gmock has to work with C++11 (std::void_t is from C++17)
template<typename... Ts> struct precpp17_make_void { typedef void type;};
template<typename... Ts> using precpp17_void_t = typename precpp17_make_void<Ts...>::type;

template <typename T, typename = void>
struct HasReturnRefAction : std::false_type {};
template <typename T>
struct HasReturnRefAction<T, precpp17_void_t<decltype(ReturnRef(std::declval<T>()))>>
    : std::true_type {};

// Just an example of non-POD type
class MyNonPodType {
 public:
  MyNonPodType(int a_value) : value_(a_value) {}

 private:
  int value_;
};
// Just an example of POD type
using MyPodType = int;

// Tests that ReturnRef(v) is working with non-temporaries (T&)
TEST(ReturnRefTest, IsAcceptingNonTemporary) {
  EXPECT_TRUE(HasReturnRefAction<MyPodType&>::value);
  EXPECT_TRUE(HasReturnRefAction<const MyPodType&>::value);
  EXPECT_TRUE(HasReturnRefAction<MyNonPodType&>::value);
  EXPECT_TRUE(HasReturnRefAction<const MyNonPodType&>::value);

  MyNonPodType nonPodValue{123};
  EXPECT_TRUE(CanCallReturnRef(nonPodValue));

  MyPodType podValue{321};
  EXPECT_TRUE(CanCallReturnRef(podValue));

  const MyNonPodType constNonPodValue{123};
  EXPECT_TRUE(CanCallReturnRef(constNonPodValue));


Review comment (suggestion):
Please move these types into the body of the test that uses them to avoid polluting the namespace scope.

Code after:
TEST(ReturnRefTest, IsCovariant) {
  Base base;
  Derived derived;
  Action<Base&()> a = ReturnRef(base);
  EXPECT_EQ(&base, &a.Perform(std::make_tuple()));

  a = ReturnRef(derived);
  EXPECT_EQ(&derived, &a.Perform(std::make_tuple()));
}

template <typename T, typename = decltype(ReturnRef(std::declval<T&&>()))>
bool CanCallReturnRef(T&&) { return true; }
bool CanCallReturnRef(Unused) { return false; }

// Tests that ReturnRef(v) is working with non-temporaries (T&)
TEST(ReturnRefTest, WorksForNonTemporary) {
  int scalar_value = 123;
  EXPECT_TRUE(CanCallReturnRef(scalar_value));

  std::string non_scalar_value("ABC");
  EXPECT_TRUE(CanCallReturnRef(non_scalar_value));

  const int const_scalar_value{321};
  EXPECT_TRUE(CanCallReturnRef(const_scalar_value));

  const std::string const_non_scalar_value("CBA");
  EXPECT_TRUE(CanCallReturnRef(const_non_scalar_value));
}

// Tests that ReturnRef(v) is not working with temporaries (T&&)
TEST(ReturnRefTest, DoesNotWorkForTemporary) {
  auto scalar_value = []()  -> int { return 123; };
  EXPECT_FALSE(CanCallReturnRef(scalar_value()));

  auto non_scalar_value = []() -> std::string { return "ABC"; };
  EXPECT_FALSE(CanCallReturnRef(non_scalar_value()));

  // cannot use here callable returning "const scalar type",
  // because such const for scalar return type is ignored
  EXPECT_FALSE(CanCallReturnRef(static_cast<const int>(321)));

  auto const_non_scalar_value = []() -> const std::string { return "CBA"; };
  EXPECT_FALSE(CanCallReturnRef(const_non_scalar_value()));
}

// Tests that ReturnRefOfCopy(v) works for reference types.
TEST(ReturnRefOfCopyTest, WorksForReference) {
  int n = 42;
  const Action<const int&()> ret = ReturnRefOfCopy(n);

  EXPECT_NE(&n, &ret.Perform(std::make_tuple()));