#include #include #include #include namespace c10_test { using std::set; using std::string; using std::vector; TEST(LoggingTest, TestEnforceTrue) { // This should just work. CAFFE_ENFORCE(true, "Isn't it?"); } TEST(LoggingTest, TestEnforceFalse) { bool kFalse = false; std::swap(FLAGS_caffe2_use_fatal_for_enforce, kFalse); try { CAFFE_ENFORCE(false, "This throws."); // This should never be triggered. ADD_FAILURE(); } catch (const ::c10::Error&) { } std::swap(FLAGS_caffe2_use_fatal_for_enforce, kFalse); } TEST(LoggingTest, TestEnforceEquals) { int x = 4; int y = 5; int z = 0; try { CAFFE_ENFORCE_THAT(std::equal_to(), ==, ++x, ++y, "Message: ", z++); // This should never be triggered. ADD_FAILURE(); } catch (const ::c10::Error& err) { auto errStr = std::string(err.what()); EXPECT_NE(errStr.find("5 vs 6"), string::npos); EXPECT_NE(errStr.find("Message: 0"), string::npos); } // arguments are expanded only once CAFFE_ENFORCE_THAT(std::equal_to(), ==, ++x, y); EXPECT_EQ(x, 6); EXPECT_EQ(y, 6); EXPECT_EQ(z, 1); } namespace { struct EnforceEqWithCaller { void test(const char* x) { CAFFE_ENFORCE_EQ_WITH_CALLER(1, 1, "variable: ", x, " is a variable"); } }; } // namespace TEST(LoggingTest, TestEnforceMessageVariables) { const char* const x = "hello"; CAFFE_ENFORCE_EQ(1, 1, "variable: ", x, " is a variable"); EnforceEqWithCaller e; e.test(x); } TEST( LoggingTest, EnforceEqualsObjectWithReferenceToTemporaryWithoutUseOutOfScope) { std::vector x = {1, 2, 3, 4}; // This case is a little tricky. We have a temporary // std::initializer_list to which our temporary ArrayRef // refers. Temporary lifetime extension by binding a const reference // to the ArrayRef doesn't extend the lifetime of the // std::initializer_list, just the ArrayRef, so we end up with a // dangling ArrayRef. This test forces the implementation to get it // right. CAFFE_ENFORCE_EQ(x, (at::ArrayRef{1, 2, 3, 4})); } namespace { struct Noncopyable { int x; explicit Noncopyable(int a) : x(a) {} Noncopyable(const Noncopyable&) = delete; Noncopyable(Noncopyable&&) = delete; Noncopyable& operator=(const Noncopyable&) = delete; Noncopyable& operator=(Noncopyable&&) = delete; bool operator==(const Noncopyable& rhs) const { return x == rhs.x; } }; std::ostream& operator<<(std::ostream& out, const Noncopyable& nc) { out << "Noncopyable(" << nc.x << ")"; return out; } } // namespace TEST(LoggingTest, DoesntCopyComparedObjects) { CAFFE_ENFORCE_EQ(Noncopyable(123), Noncopyable(123)); } TEST(LoggingTest, EnforceShowcase) { // It's not really a test but rather a convenient thing that you can run and // see all messages int one = 1; int two = 2; int three = 3; #define WRAP_AND_PRINT(exp) \ try { \ exp; \ } catch (const ::c10::Error&) { \ /* ::c10::Error already does LOG(ERROR) */ \ } WRAP_AND_PRINT(CAFFE_ENFORCE_EQ(one, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_NE(one * 2, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_GT(one, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_GE(one, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_LT(three, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_LE(three, two)); WRAP_AND_PRINT(CAFFE_ENFORCE_EQ( one * two + three, three * two, "It's a pretty complicated expression")); WRAP_AND_PRINT(CAFFE_ENFORCE_THAT( std::equal_to(), ==, one * two + three, three * two)); } TEST(LoggingTest, Join) { auto s = c10::Join(", ", vector({1, 2, 3})); EXPECT_EQ(s, "1, 2, 3"); s = c10::Join(":", vector()); EXPECT_EQ(s, ""); s = c10::Join(", ", set({3, 1, 2})); EXPECT_EQ(s, "1, 2, 3"); } TEST(LoggingTest, TestDanglingElse) { if (true) TORCH_DCHECK_EQ(1, 1); else GTEST_FAIL(); } #if GTEST_HAS_DEATH_TEST TEST(LoggingDeathTest, TestEnforceUsingFatal) { bool kTrue = true; std::swap(FLAGS_caffe2_use_fatal_for_enforce, kTrue); // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto,hicpp-avoid-goto) EXPECT_DEATH(CAFFE_ENFORCE(false, "This goes fatal."), ""); std::swap(FLAGS_caffe2_use_fatal_for_enforce, kTrue); } #endif } // namespace c10_test