1 #include "test.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5
6 #include <exception>
7
8 #define fprintf(...)
9
log(void * ignored)10 void log(void* ignored)
11 {
12 //printf("Cleanup called on %s\n", *(char**)ignored);
13 }
14 #define CLEANUP\
15 __attribute__((cleanup(log))) __attribute__((unused))\
16 const char *f = __func__;
17
18 /**
19 * Simple struct to test throwing.
20 */
21 struct foo
22 {
23 int i;
24 };
25
26 struct bar : foo
27 {
28 float bar;
29 };
30
31
32 /**
33 * Non-pod type to test throwing
34 */
35 class non_pod {
36 public:
non_pod(int i)37 non_pod(int i): x(i) {}
38 int x;
39 };
40
41
42 static int cleanup_count;
43 /**
44 * Simple structure declared with a destructor. Destroying this object will
45 * increment cleanup count. The destructor should be called automatically if
46 * an instance of cl is allocated with automatic storage.
47 */
48 struct cl
49 {
50 int i;
~clcl51 ~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
52 };
53 /**
54 * Test that one cl was destroyed when running the argument.
55 */
56 #define TEST_CLEANUP(x) do {\
57 int cleanups = cleanup_count;\
58 { x; }\
59 TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
60 } while(0)
61
inner(int i)62 int inner(int i)
63 {
64 CLEANUP
65 switch (i)
66 {
67 case 0: throw (int)1.0;
68 case 1: throw (float)1.0;
69 case 2: fprintf(stderr, "Throwing int64_t\n");throw (int64_t)1;
70 case 3: { foo f = {2} ; throw f; }
71 case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
72 case 5: throw non_pod(3);
73 }
74 return -1;
75 }
76
outer(int i)77 int outer(int i) throw(float, int, foo, non_pod)
78 {
79 //CLEANUP
80 inner(i);
81 return 1;
82 }
83
test_const(void)84 static void test_const(void)
85 {
86 int a = 1;
87 try
88 {
89 throw a;
90 }
91 catch (const int b)
92 {
93 TEST(a == b, "Caught int as const int");
94 }
95 catch(...)
96 {
97 TEST(0, "Failed to catch int as const int");
98 }
99 try
100 {
101 throw &a;
102 }
103 catch (const int *b)
104 {
105 TEST(&a == b, "Caught int* as const int*");
106 }
107 catch(...)
108 {
109 TEST(0, "Failed to catch int* as const int*");
110 }
111 }
112
test_catch(int s)113 static void test_catch(int s)
114 {
115 cl c;
116 c.i = 12;
117 fprintf(stderr, "Entering try\n");
118 try
119 {
120 outer(s);
121 }
122 catch(int i)
123 {
124 fprintf(stderr, "Caught int %d in test %d\n", i, s);
125 TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
126 return;
127 }
128 catch (float f)
129 {
130 fprintf(stderr, "Caught float %f!\n", f);
131 TEST(s == 1 && f == 1, "Caught float");
132 return;
133 }
134 catch (foo f)
135 {
136 fprintf(stderr, "Caught struct {%d}!\n", f.i);
137 TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
138 return;
139 }
140 catch (non_pod np) {
141 fprintf(stderr, "Caught non_pod {%d}!\n", np.x);
142 TEST(s == 5 && np.x == 3, "Caught non_pod");
143 return;
144 }
145 //abort();
146 TEST(0, "Unreachable line reached");
147 }
148
test_nested1(void)149 void test_nested1(void)
150 {
151 CLEANUP;
152 cl c;
153 c.i = 123;
154 try
155 {
156 outer(0);
157 }
158 catch (int a)
159 {
160 try
161 {
162 TEST(a == 1, "Caught int");
163 outer(1);
164 }
165 catch (float f)
166 {
167 TEST(f == 1, "Caught float inside outer catch block");
168 throw;
169 }
170 }
171 }
172
test_nested()173 void test_nested()
174 {
175 try
176 {
177 test_nested1();
178 }
179 catch (float f)
180 {
181 fprintf(stderr, "Caught re-thrown float\n");
182 TEST(f == 1, "Caught re-thrown float");
183 }
184 }
185
186 static int violations = 0;
throw_zero()187 static void throw_zero()
188 {
189 violations++;
190 fprintf(stderr, "Throwing 0\n");
191 throw 0;
192 }
193
194 extern "C" void __cxa_bad_cast();
195
test_exceptions(void)196 void test_exceptions(void)
197 {
198 std::set_unexpected(throw_zero);
199 TEST_CLEANUP(test_catch(0));
200 TEST_CLEANUP(test_catch(1));
201 TEST_CLEANUP(test_catch(3));
202 TEST_CLEANUP(test_catch(4));
203 TEST_CLEANUP(test_catch(5));
204 TEST_CLEANUP(test_nested());
205 try{
206 test_catch(2);
207 TEST(violations == 1, "Exactly one exception spec violation");
208 }
209 catch (int64_t i) {
210 TEST(0, "Caught int64_t, but that violates an exception spec");
211 }
212 int a;
213 try {
214 throw &a;
215 }
216 catch (const int *b)
217 {
218 TEST(&a==b, "Caught const int from thrown int");
219 }
220 try {
221 throw &a;
222 }
223 catch (int *b)
224 {
225 TEST(&a==b, "Caught int from thrown int");
226 }
227 try
228 {
229 __cxa_bad_cast();
230 }
231 catch (std::exception b)
232 {
233 TEST(1, "Caught bad cast");
234 }
235 catch (...)
236 {
237 TEST(0, "Bad cast was not caught correctly");
238 }
239 test_const();
240
241
242 //printf("Test: %s\n",
243 }
244