Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: test/plugin/ExceptionTest.cpp

Issue 5137721374801920: Issue #1173 - Default behavior for catch-all blocks
Patch Set: Add ExceptionDefault() Created March 5, 2015, 2:56 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« src/plugin/PluginDebug.cpp ('K') | « src/plugin/PluginDebug.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <gtest/gtest.h>
19
20 #include "../../src/plugin/Exception.h"
21
sergei 2015/03/06 13:51:12 These lines between #include are not necessary.
Eric 2015/03/06 17:29:59 Done.
22 #include <stdexcept>
23
24 void AssignCurrentException(std::exception_ptr& e)
sergei 2015/03/06 13:51:12 I don't think that we need this function
Eric 2015/03/06 17:29:59 It's needed in order for the test 'CurrentExceptio
25 {
26 e = std::current_exception();
27 }
28
29 /*
30 * This test verifies that std::current_exception works during exception handlin g generally,
31 * not just in the immediate context of a 'catch' clause.
32 */
33 TEST(Exception, CurrentExceptionWorksOutsideCatchHandler)
sergei 2015/03/06 13:51:12 What does it test? Standard C++ library? Even more
Eric 2015/03/06 17:29:59 It checks that the implementation of 'current_exce
34 {
35 std::exception_ptr ep;
36 const auto e = std::runtime_error("BJTCiRhkVAmvMg");
37 try
38 {
39 throw e;
40 }
41 catch (...)
42 {
43 AssignCurrentException(ep);
44 ASSERT_TRUE(ep);
45 /*
46 * You might think that the next set would be EXPECT_EQ betwwen the thrown e xception and the original one.
sergei 2015/03/06 13:51:12 This comment is not necessary.
Eric 2015/03/06 17:29:59 I'm leaving it in because I got caught up with deb
47 * Such a test does not pass, nor is in necessary.
48 * The throw statement above is throwing by value, so it makes a copy.
49 */
50 }
51 try
52 {
53 rethrow_exception(ep);
54 FAIL() << "Statement after 'rethrow_exception' executed.";
55 }
56 catch (std::runtime_error& ex)
57 {
58 EXPECT_STREQ(e.what(), ex.what());
59 return;
60 }
61 catch (...)
62 {
63 FAIL() << "Rethrown exception isn't the same type as the original";
64 }
65 FAIL() << "Did not return after catching rethrown exception";
66 }
67
68 /*
69 * A plain exception, not a subclass of std::runtime_error or std::logic_error.
70 */
71 class PlainException
72 : public std::exception
73 {
74 const char* what() const override
75 {
76 return "Plain";
77 };
78 };
79
80 struct NullHandlers
81 {
82 static void Unknown(int y) {}
83 static void Exception(std::exception& ex,int y) {}
84 static void LogicError(std::logic_error& ex,int y) { Exception(ex, y); }
85 static void RuntimeError(std::runtime_error& ex,int y) { Exception(ex, y); }
86 static void SystemError(std::system_error& ex,int y) { RuntimeError(ex, y); }
87 };
88
89 /*
90 * The trivial tests assure that nothing escapes the catch-all function,
91 * that is, we ensure that nothing is thrown or rethrown.
92 */
93 template<class X>
94 void TrivialVoid(X x)
95 {
96 ASSERT_NO_THROW(
97 {
98 try
99 {
100 throw x;
101 }
102 catch (...)
103 {
104 CatchAllVoid<NullHandlers>::Handler(0);
105 }
106 });
107 }
108
109 TEST(Exception, TrivialVoidUnknown)
110 {
111 TrivialVoid(5);
112 }
113
114 TEST(Exception, TrivialVoidException)
115 {
116 TrivialVoid(PlainException());
117 }
118
119 TEST(Exception, TrivialVoidLogicError)
120 {
121 TrivialVoid(std::logic_error(""));
122 }
123
124 TEST(Exception, TrivialVoidRuntimeError)
125 {
126 TrivialVoid(std::runtime_error(""));
127 }
128
129 TEST(Exception, TrivialVoidSystemError)
130 {
131 TrivialVoid(std::system_error(std::error_code()));
132 }
133
134 enum ExceptionCode
sergei 2015/03/06 13:51:12 It's not necessary here but I think it would be be
Eric 2015/03/06 17:29:59 I specifically want an unscoped enumeration here.
sergei 2015/03/31 14:30:51 It's not an extra syntax, it helps to understand t
Eric 2015/05/14 14:42:50 I don't agree with you. It provides nothing extra.
sergei 2015/05/15 13:13:24 If you does see it now it does not mean that it pr
135 {
136 InvalidCode = -1,
137 UnknownCode = 1,
138 ExceptionCode,
139 LogicErrorCode,
140 RuntimeErrorCode,
141 SystemErrorCode
142 };
143
144 struct NullHandlersReturn
145 {
146 typedef int return_t;
sergei 2015/03/31 14:30:51 It's not related whether it's scoped or not (enume
Eric 2015/05/14 14:42:50 Defining a typedef for the symbol 'return_t' refle
sergei 2015/05/15 13:13:24 I really don't understand attempts to create less
147 static return_t Unknown(int) { return UnknownCode; }
148 static return_t Exception(std::exception& ex, int) { return ExceptionCode; }
149 static return_t LogicError(std::logic_error& ex, int) { return LogicErrorCode; }
150 static return_t RuntimeError(std::runtime_error& ex, int) { return RuntimeErro rCode; }
151 static return_t SystemError(std::system_error& ex, int) { return SystemErrorCo de; }
152 };
153
154 template<class X>
155 void TrivialReturn(int n, X x)
156 {
157 ASSERT_NO_THROW(
158 {
159 try
160 {
161 throw x;
162 }
163 catch (...)
164 {
165 ASSERT_EQ(n, CatchAllReturn<NullHandlersReturn>::Handler(0));
166 }
167 });
168 }
169
170 TEST(Exception, TrivialReturnUnknown)
171 {
172 TrivialReturn(UnknownCode, 5);
173 }
174
175 TEST(Exception, TrivialReturnException)
176 {
177 TrivialReturn(ExceptionCode, PlainException());
178 }
179
180 TEST(Exception, TrivialReturnLogicError)
181 {
182 TrivialReturn(LogicErrorCode, std::logic_error(""));
183 }
184
185 TEST(Exception, TrivialReturnRuntimeError)
186 {
187 TrivialReturn(RuntimeErrorCode, std::runtime_error(""));
188 }
189
190 TEST(Exception, TrivialReturnSystemError)
191 {
192 TrivialReturn(SystemErrorCode, std::system_error(std::error_code()));
193 }
194
195 /*
196 * The simple tests ensure that the flow of control arrives in the correct subha ndler.
197 */
198 template<class X, class H>
199 void SimpleVoid(X x, H h)
sergei 2015/03/06 13:51:12 we don't need argument `H h` here as well as we do
Eric 2015/03/06 17:29:59 We need to have 'H' present in order to instantiat
sergei 2015/03/31 14:30:51 How does it simplify? `SimpleVoid(std::runtime_err
Eric 2015/05/14 14:42:50 I picked a different syntax that the one you would
sergei 2015/05/15 13:13:24 So, how does it simplify?
200 {
201 SimpleResult = 0;
Eric 2015/03/06 17:29:59 Good suggestion. Done.
202 SimpleExpected = rand();
sergei 2015/03/06 13:51:12 `std::rand` and seeding is missed.
Eric 2015/03/06 17:29:59 Added namespace scope. If I were to provide a see
203 if (SimpleExpected == 0) { SimpleExpected = 1; }
sergei 2015/03/06 13:51:12 Why do we need random numbers, I would say enum wo
sergei 2015/03/31 14:30:51 Sorry, I don't understand what kind of references
Eric 2015/05/14 14:42:50 The word 'reference' can mean either its generic E
sergei 2015/05/15 13:13:24 Such randomness here does not add any integrity ch
204 ASSERT_NO_THROW(
205 {
206 try
207 {
208 throw x;
209 }
210 catch (...)
211 {
212 CatchAllVoid<H>::Handler(0);
213 }
214 });
215 EXPECT_EQ(SimpleExpected, SimpleResult);
216 }
217
218 /*
219 * VS 2012 supports thread_local semantics for POD only, not arbitrary types.
220 * That's good enough for now.
221 * Remove the definition when VS matures.
222 */
223 #define thread_local __declspec(thread)
224
225 /*
226 * The sub-handlers are purely static functions,
227 * so getting them to return something unique for testing has possible race co nditions.
228 * We're using a thread-local variable as a return code from the simple handlers ,
229 * which ensures that even a multi-threaded test runner will work here.
230 */
231 thread_local int SimpleResult;
232 thread_local int SimpleExpected;
sergei 2015/03/06 13:51:12 I don't like the idea to use global variables, and
Eric 2015/03/06 17:29:59 Sorry, they're needed here. I tried to get rid of
233
234 /*
235 * The base handler class for the simple tests fails every execution path.
236 * Each specific test redefines a single one of the handler functions that it us es.
237 */
238 class SimpleHandlersBase
239 {
240 public:
241 static void Unknown(int) { FAIL() << "Unexpected exception of unknown type"; }
242 static void Exception(std::exception& ex, int) { FAIL() << "Unexpected std::ex ception"; }
243 static void LogicError(std::logic_error& ex, int) { FAIL() << "Unexpected std: :logic_error"; }
244 static void RuntimeError(std::runtime_error& ex, int) { FAIL() << "Unexpected std::runtime_error"; }
245 static void SystemError(std::system_error& ex, int) { FAIL() << "Unexpected st d::system_error"; };
246 protected:
247 static void Ping() { SimpleResult = SimpleExpected; }
248 };
249
250 TEST(Exception, SimpleVoidUnknown)
251 {
252 struct Handler :
253 public SimpleHandlersBase
254 {
255 static void Unknown(int) { Ping(); }
256 };
257 SimpleVoid(5, Handler());
258 }
259
260 TEST(Exception, SimpleVoidException)
261 {
262 struct Handler :
263 public SimpleHandlersBase
264 {
265 static void Exception(std::exception& ex, int) { Ping(); }
266 };
267 SimpleVoid(PlainException(), Handler());
268 }
269
270 TEST(Exception, SimpleVoidLogicError)
271 {
272 struct Handler :
273 public SimpleHandlersBase
274 {
275 static void LogicError(std::logic_error& ex, int) { Ping(); }
276 };
277 SimpleVoid(std::logic_error(""), Handler());
278 }
279
280 TEST(Exception, SimpleVoidRuntimeError)
281 {
282 struct Handler :
283 public SimpleHandlersBase
284 {
285 static void RuntimeError(std::runtime_error& ex, int) { Ping(); }
286 };
287 SimpleVoid(std::runtime_error(""), Handler());
288 }
289
290 TEST(Exception, SimpleVoidSystemError)
291 {
292 struct Handler :
293 public SimpleHandlersBase
294 {
295 static void SystemError(std::system_error& ex, int) { Ping(); }
296 };
297 SimpleVoid(std::system_error(std::error_code()), Handler());
298 }
299
300 template<class X, class H>
301 void SimpleReturn(int n, X x, H h)
302 {
303 SimpleResult = 0;
304 SimpleExpected = rand();
305 if (SimpleExpected == 0) { SimpleExpected = 1; }
306 ASSERT_NO_THROW(
307 {
308 try
309 {
310 throw x;
311 }
312 catch (...)
313 {
314 EXPECT_EQ(n, CatchAllReturn<H>::Handler(0));
315 }
316 });
317 EXPECT_EQ(SimpleExpected, SimpleResult);
318 }
319
320 /*
321 * The base handlers class fails every execution path.
322 */
323 class SimpleHandlersReturnBase
324 {
325 public:
326 typedef int return_t;
327 static return_t Unknown(int) { ADD_FAILURE() << "Unexpected exception of unkno wn type"; return InvalidCode; }
328 static return_t Exception(std::exception& ex, int) { ADD_FAILURE() << "Unexpec ted std::exception"; return InvalidCode; }
329 static return_t LogicError(std::logic_error& ex, int) { ADD_FAILURE() << "Unex pected std::logic_error"; return InvalidCode; }
330 static return_t RuntimeError(std::runtime_error& ex, int) { ADD_FAILURE() << " Unexpected std::runtime_error"; return InvalidCode; }
331 static return_t SystemError(std::system_error& ex, int) { ADD_FAILURE() << "Un expected std::system_error"; return InvalidCode; }
332 protected:
333 static void Ping() { SimpleResult = SimpleExpected; }
334 };
335
336 TEST(Exception, SimpleReturnUnknown)
337 {
338 struct Handler :
339 public SimpleHandlersReturnBase
340 {
341 static int Unknown(int) { Ping(); return UnknownCode; }
342 };
343 SimpleReturn(UnknownCode, 5, Handler());
344 }
345
346 TEST(Exception, SimpleReturnException)
347 {
348 struct Handler :
349 public SimpleHandlersReturnBase
350 {
351 static int Exception(std::exception& ex, int) { Ping(); return ExceptionCode ; }
352 };
353 SimpleReturn(ExceptionCode, PlainException(), Handler());
354 }
355
356 TEST(Exception, SimpleReturnLogicError)
357 {
358 struct Handler :
359 public SimpleHandlersReturnBase
360 {
361 static int LogicError(std::logic_error& ex, int) { Ping(); return LogicError Code; }
362 };
363 SimpleReturn(LogicErrorCode, std::logic_error(""), Handler());
364 }
365
366 TEST(Exception, SimpleReturnRuntimeError)
367 {
368 struct Handler :
369 public SimpleHandlersReturnBase
370 {
371 static int RuntimeError(std::runtime_error& ex, int) { Ping(); return Runtim eErrorCode; }
372 };
373 SimpleReturn(RuntimeErrorCode, std::runtime_error(""), Handler());
374 }
375
376 TEST(Exception, SimpleReturnSystemError)
377 {
378 struct Handler :
379 public SimpleHandlersReturnBase
380 {
381 static int SystemError(std::system_error& ex, int) { Ping(); return SystemEr rorCode; }
382 };
383 SimpleReturn(SystemErrorCode, std::system_error(std::error_code()), Handler()) ;
384 }
385
OLDNEW
« src/plugin/PluginDebug.cpp ('K') | « src/plugin/PluginDebug.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld