1 | #include <algorithm> |
2 | |
3 | #include <c10/util/ArrayRef.h> |
4 | #include <c10/util/Logging.h> |
5 | #include <gtest/gtest.h> |
6 | |
7 | namespace c10_test { |
8 | |
9 | using std::set; |
10 | using std::string; |
11 | using std::vector; |
12 | |
13 | TEST(LoggingTest, TestEnforceTrue) { |
14 | // This should just work. |
15 | CAFFE_ENFORCE(true, "Isn't it?" ); |
16 | } |
17 | |
18 | TEST(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 | |
30 | TEST(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 | |
51 | namespace { |
52 | struct 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 | |
59 | TEST(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 | |
67 | TEST( |
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 | |
81 | namespace { |
82 | struct 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 | |
97 | std::ostream& operator<<(std::ostream& out, const Noncopyable& nc) { |
98 | out << "Noncopyable(" << nc.x << ")" ; |
99 | return out; |
100 | } |
101 | } // namespace |
102 | |
103 | TEST(LoggingTest, DoesntCopyComparedObjects) { |
104 | CAFFE_ENFORCE_EQ(Noncopyable(123), Noncopyable(123)); |
105 | } |
106 | |
107 | TEST(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 | |
133 | TEST(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 | |
142 | TEST(LoggingTest, TestDanglingElse) { |
143 | if (true) |
144 | TORCH_DCHECK_EQ(1, 1); |
145 | else |
146 | GTEST_FAIL(); |
147 | } |
148 | |
149 | #if GTEST_HAS_DEATH_TEST |
150 | TEST(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 | |