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 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: 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; 51 ~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 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 77 int outer(int i) throw(float, int, foo, non_pod) 78 { 79 //CLEANUP 80 inner(i); 81 return 1; 82 } 83 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 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 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 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; 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 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