1#include <algorithm>
2
3#include <c10/util/ArrayRef.h>
4#include <c10/util/Logging.h>
5#include <gtest/gtest.h>
6
7namespace c10_test {
8
9using std::set;
10using std::string;
11using std::vector;
12
13TEST(LoggingTest, TestEnforceTrue) {
14 // This should just work.
15 CAFFE_ENFORCE(true, "Isn't it?");
16}
17
18TEST(LoggingTest, TestEnforceFalse) {
19 bool kFalse = false;
20 std::swap(FLAGS_caffe2_use_fatal_for_enforce, kFalse);
21 try {
22 CAFFE_ENFORCE(false, "This throws.");
23 // This should never be triggered.
24 ADD_FAILURE();
25 } catch (const ::c10::Error&) {
26 }
27 std::swap(FLAGS_caffe2_use_fatal_for_enforce, kFalse);
28}
29
30TEST(LoggingTest, TestEnforceEquals) {
31 int x = 4;
32 int y = 5;
33 int z = 0;
34 try {
35 CAFFE_ENFORCE_THAT(std::equal_to<void>(), ==, ++x, ++y, "Message: ", z++);
36 // This should never be triggered.
37 ADD_FAILURE();
38 } catch (const ::c10::Error& err) {
39 auto errStr = std::string(err.what());
40 EXPECT_NE(errStr.find("5 vs 6"), string::npos);
41 EXPECT_NE(errStr.find("Message: 0"), string::npos);
42 }
43
44 // arguments are expanded only once
45 CAFFE_ENFORCE_THAT(std::equal_to<void>(), ==, ++x, y);
46 EXPECT_EQ(x, 6);
47 EXPECT_EQ(y, 6);
48 EXPECT_EQ(z, 1);
49}
50
51namespace {
52struct EnforceEqWithCaller {
53 void test(const char* x) {
54 CAFFE_ENFORCE_EQ_WITH_CALLER(1, 1, "variable: ", x, " is a variable");
55 }
56};
57} // namespace
58
59TEST(LoggingTest, TestEnforceMessageVariables) {
60 const char* const x = "hello";
61 CAFFE_ENFORCE_EQ(1, 1, "variable: ", x, " is a variable");
62
63 EnforceEqWithCaller e;
64 e.test(x);
65}
66
67TEST(
68 LoggingTest,
69 EnforceEqualsObjectWithReferenceToTemporaryWithoutUseOutOfScope) {
70 std::vector<int> x = {1, 2, 3, 4};
71 // This case is a little tricky. We have a temporary
72 // std::initializer_list to which our temporary ArrayRef
73 // refers. Temporary lifetime extension by binding a const reference
74 // to the ArrayRef doesn't extend the lifetime of the
75 // std::initializer_list, just the ArrayRef, so we end up with a
76 // dangling ArrayRef. This test forces the implementation to get it
77 // right.
78 CAFFE_ENFORCE_EQ(x, (at::ArrayRef<int>{1, 2, 3, 4}));
79}
80
81namespace {
82struct Noncopyable {
83 int x;
84
85 explicit Noncopyable(int a) : x(a) {}
86
87 Noncopyable(const Noncopyable&) = delete;
88 Noncopyable(Noncopyable&&) = delete;
89 Noncopyable& operator=(const Noncopyable&) = delete;
90 Noncopyable& operator=(Noncopyable&&) = delete;
91
92 bool operator==(const Noncopyable& rhs) const {
93 return x == rhs.x;
94 }
95};
96
97std::ostream& operator<<(std::ostream& out, const Noncopyable& nc) {
98 out << "Noncopyable(" << nc.x << ")";
99 return out;
100}
101} // namespace
102
103TEST(LoggingTest, DoesntCopyComparedObjects) {
104 CAFFE_ENFORCE_EQ(Noncopyable(123), Noncopyable(123));
105}
106
107TEST(LoggingTest, EnforceShowcase) {
108 // It's not really a test but rather a convenient thing that you can run and
109 // see all messages
110 int one = 1;
111 int two = 2;
112 int three = 3;
113#define WRAP_AND_PRINT(exp) \
114 try { \
115 exp; \
116 } catch (const ::c10::Error&) { \
117 /* ::c10::Error already does LOG(ERROR) */ \
118 }
119 WRAP_AND_PRINT(CAFFE_ENFORCE_EQ(one, two));
120 WRAP_AND_PRINT(CAFFE_ENFORCE_NE(one * 2, two));
121 WRAP_AND_PRINT(CAFFE_ENFORCE_GT(one, two));
122 WRAP_AND_PRINT(CAFFE_ENFORCE_GE(one, two));
123 WRAP_AND_PRINT(CAFFE_ENFORCE_LT(three, two));
124 WRAP_AND_PRINT(CAFFE_ENFORCE_LE(three, two));
125
126 WRAP_AND_PRINT(CAFFE_ENFORCE_EQ(
127 one * two + three, three * two, "It's a pretty complicated expression"));
128
129 WRAP_AND_PRINT(CAFFE_ENFORCE_THAT(
130 std::equal_to<void>(), ==, one * two + three, three * two));
131}
132
133TEST(LoggingTest, Join) {
134 auto s = c10::Join(", ", vector<int>({1, 2, 3}));
135 EXPECT_EQ(s, "1, 2, 3");
136 s = c10::Join(":", vector<string>());
137 EXPECT_EQ(s, "");
138 s = c10::Join(", ", set<int>({3, 1, 2}));
139 EXPECT_EQ(s, "1, 2, 3");
140}
141
142TEST(LoggingTest, TestDanglingElse) {
143 if (true)
144 TORCH_DCHECK_EQ(1, 1);
145 else
146 GTEST_FAIL();
147}
148
149#if GTEST_HAS_DEATH_TEST
150TEST(LoggingDeathTest, TestEnforceUsingFatal) {
151 bool kTrue = true;
152 std::swap(FLAGS_caffe2_use_fatal_for_enforce, kTrue);
153 // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto,hicpp-avoid-goto)
154 EXPECT_DEATH(CAFFE_ENFORCE(false, "This goes fatal."), "");
155 std::swap(FLAGS_caffe2_use_fatal_for_enforce, kTrue);
156}
157#endif
158
159} // namespace c10_test
160