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