| 1 | // =============================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : arb_misc.cxx // |
|---|
| 4 | // Purpose : misc that doesnt fit elsewhere // |
|---|
| 5 | // // |
|---|
| 6 | // Coded by Ralf Westram (coder@reallysoft.de) in October 2012 // |
|---|
| 7 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 8 | // http://www.arb-home.de/ // |
|---|
| 9 | // // |
|---|
| 10 | // =============================================================== // |
|---|
| 11 | |
|---|
| 12 | #include "arb_misc.h" |
|---|
| 13 | #include "arb_msg.h" |
|---|
| 14 | #include "arb_file.h" |
|---|
| 15 | #include "arb_string.h" |
|---|
| 16 | |
|---|
| 17 | #include <cmath> |
|---|
| 18 | |
|---|
| 19 | // AISC_MKPT_PROMOTE:#ifndef _GLIBCXX_CSTDLIB |
|---|
| 20 | // AISC_MKPT_PROMOTE:#include <cstdlib> |
|---|
| 21 | // AISC_MKPT_PROMOTE:#endif |
|---|
| 22 | |
|---|
| 23 | const char *GBS_readable_size(unsigned long long size, const char *unit_suffix) { |
|---|
| 24 | // return human readable size information |
|---|
| 25 | // returned string is maximal 6+strlen(unit_suffix) characters long |
|---|
| 26 | // (using "b" as 'unit_suffix' produces '### b', '### Mb' etc) |
|---|
| 27 | |
|---|
| 28 | if (size<1000) return GBS_global_string("%llu %s", size, unit_suffix); |
|---|
| 29 | |
|---|
| 30 | const char *units = "kMGTPEZY"; // kilo, Mega, Giga, Tera, ... should be enough forever |
|---|
| 31 | int i; |
|---|
| 32 | |
|---|
| 33 | for (i = 0; units[i]; ++i) { |
|---|
| 34 | char unit = units[i]; |
|---|
| 35 | if (size<1000*1024) { |
|---|
| 36 | double amount = size/(double)1024; |
|---|
| 37 | if (amount<10.0) return GBS_global_string("%4.2f %c%s", amount+0.005, unit, unit_suffix); |
|---|
| 38 | if (amount<100.0) return GBS_global_string("%4.1f %c%s", amount+0.05, unit, unit_suffix); |
|---|
| 39 | return GBS_global_string("%i %c%s", (int)(amount+0.5), unit, unit_suffix); |
|---|
| 40 | } |
|---|
| 41 | size /= 1024; // next unit |
|---|
| 42 | } |
|---|
| 43 | return GBS_global_string("MUCH %s", unit_suffix); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | const char *GBS_readable_timediff(size_t seconds) { |
|---|
| 47 | size_t mins = seconds/60; seconds -= mins * 60; |
|---|
| 48 | size_t hours = mins/60; mins -= hours * 60; |
|---|
| 49 | size_t days = hours/24; hours -= days * 24; |
|---|
| 50 | |
|---|
| 51 | const int MAXPRINT = 40; |
|---|
| 52 | int printed = 0; |
|---|
| 53 | static char buffer[MAXPRINT+1]; |
|---|
| 54 | |
|---|
| 55 | if (days>0) printed += sprintf(buffer+printed, "%zud", days); |
|---|
| 56 | if (printed || hours>0) printed += sprintf(buffer+printed, "%zuh", hours); |
|---|
| 57 | if (printed || mins>0) printed += sprintf(buffer+printed, "%zum", mins); |
|---|
| 58 | |
|---|
| 59 | printed += sprintf(buffer+printed, "%zus", seconds); |
|---|
| 60 | |
|---|
| 61 | arb_assert(printed>0 && printed<MAXPRINT); |
|---|
| 62 | |
|---|
| 63 | return buffer; |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | const char *ARB_float_2_ascii(const float f) { |
|---|
| 67 | /*! calculate the "best" ascii representation for float 'f' |
|---|
| 68 | * - smaller conversion error is better |
|---|
| 69 | * - shorter representation is better (for equal conversion errors) |
|---|
| 70 | */ |
|---|
| 71 | |
|---|
| 72 | const int MAXSIZE = 50; |
|---|
| 73 | static char result[MAXSIZE]; |
|---|
| 74 | char buffer[MAXSIZE]; |
|---|
| 75 | |
|---|
| 76 | int printed_e = snprintf(result, MAXSIZE, "%e", f); arb_assert(printed_e<MAXSIZE); |
|---|
| 77 | float back_e = strtof(result, NULp); |
|---|
| 78 | float diff_e = fabsf(f-back_e); |
|---|
| 79 | |
|---|
| 80 | int printed_g = snprintf(buffer, MAXSIZE, "%g", f); arb_assert(printed_g<MAXSIZE); |
|---|
| 81 | float back_g = strtof(buffer, NULp); |
|---|
| 82 | float diff_g = fabsf(f-back_g); |
|---|
| 83 | |
|---|
| 84 | if (diff_g<diff_e || (diff_g == diff_e && printed_g<printed_e)) { |
|---|
| 85 | printed_e = printed_g; |
|---|
| 86 | back_e = back_g; |
|---|
| 87 | diff_e = diff_g; |
|---|
| 88 | memcpy(result, buffer, printed_g+1); |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | int printed_f = snprintf(buffer, MAXSIZE, "%f", f); arb_assert(printed_f<MAXSIZE); |
|---|
| 92 | float back_f = strtof(buffer, NULp); |
|---|
| 93 | float diff_f = fabsf(f-back_f); |
|---|
| 94 | |
|---|
| 95 | if (diff_f<diff_e || (diff_f == diff_e && printed_f<printed_e)) { |
|---|
| 96 | memcpy(result, buffer, printed_f+1); |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | return result; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | const char *ARB_getenv_ignore_empty(const char *envvar) { |
|---|
| 103 | const char *result = getenv(envvar); |
|---|
| 104 | return (result && result[0]) ? result : NULp; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | char *ARB_executable(const char *exe_name, const char *path) { |
|---|
| 108 | char *buffer = ARB_alloc<char>(strlen(path)+1+strlen(exe_name)+1); |
|---|
| 109 | const char *start = path; |
|---|
| 110 | int found = 0; |
|---|
| 111 | |
|---|
| 112 | while (!found && start) { |
|---|
| 113 | const char *colon = strchr(start, ':'); |
|---|
| 114 | int len = colon ? (colon-start) : (int)strlen(start); |
|---|
| 115 | |
|---|
| 116 | memcpy(buffer, start, len); |
|---|
| 117 | buffer[len] = '/'; |
|---|
| 118 | strcpy(buffer+len+1, exe_name); |
|---|
| 119 | |
|---|
| 120 | found = GB_is_executablefile(buffer); |
|---|
| 121 | start = colon ? colon+1 : NULp; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | char *executable = found ? ARB_strdup(buffer) : NULp; |
|---|
| 125 | free(buffer); |
|---|
| 126 | return executable; |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | // -------------------------------------------------------------------------------- |
|---|
| 130 | |
|---|
| 131 | char ARB_path_contains_unwanted_chars(const char *path) { |
|---|
| 132 | if (strchr(path, ' ') != NULp) { |
|---|
| 133 | return ' '; |
|---|
| 134 | } |
|---|
| 135 | return 0; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | void ARB_warn_about_unwanted_chars(const char *path, const char *path_description) { |
|---|
| 139 | // annoy user with warnings if paths contain unwanted characters. |
|---|
| 140 | // |
|---|
| 141 | // motivation: I tried to fix some scripts to correctly handle the case |
|---|
| 142 | // where arb is installed in a path containing spaces. |
|---|
| 143 | // |
|---|
| 144 | // Since that is a bottomless pit, I decided to deny spaces there. |
|---|
| 145 | |
|---|
| 146 | char unwantedChar = ARB_path_contains_unwanted_chars(path); |
|---|
| 147 | if (unwantedChar) { |
|---|
| 148 | GB_warningf( |
|---|
| 149 | "arb may not work as expected, because\n" |
|---|
| 150 | "%s\n" |
|---|
| 151 | " (='%s')\n" |
|---|
| 152 | "contains an unwanted character ('%c').", |
|---|
| 153 | path_description, |
|---|
| 154 | path, |
|---|
| 155 | unwantedChar); |
|---|
| 156 | } |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | // -------------------------------------------------------------------------------- |
|---|
| 160 | |
|---|
| 161 | #ifdef UNIT_TESTS |
|---|
| 162 | #ifndef TEST_UNIT_H |
|---|
| 163 | #include <test_unit.h> |
|---|
| 164 | #endif |
|---|
| 165 | |
|---|
| 166 | #if 0 |
|---|
| 167 | // simple test |
|---|
| 168 | #define TEST_EXPECT_FLOAT_2_ASCII(f,a) TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a) |
|---|
| 169 | #else |
|---|
| 170 | // also test back-conversion (ascii->float->ascii) is stable |
|---|
| 171 | #define TEST_EXPECT_FLOAT_2_ASCII(f,a) do{ \ |
|---|
| 172 | TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a); \ |
|---|
| 173 | TEST_EXPECT_EQUAL(ARB_float_2_ascii(strtof(a, NULp)), a); \ |
|---|
| 174 | }while(0) |
|---|
| 175 | #endif |
|---|
| 176 | |
|---|
| 177 | __ATTR__REDUCED_OPTIMIZE void TEST_float_2_ascii() { |
|---|
| 178 | TEST_EXPECT_FLOAT_2_ASCII(3.141592e+00, "3.141592"); |
|---|
| 179 | TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592"); |
|---|
| 180 | TEST_EXPECT_FLOAT_2_ASCII(3.14159, "3.14159"); |
|---|
| 181 | |
|---|
| 182 | TEST_EXPECT_FLOAT_2_ASCII(0.1, "0.1"); |
|---|
| 183 | TEST_EXPECT_FLOAT_2_ASCII(0.01, "0.01"); |
|---|
| 184 | TEST_EXPECT_FLOAT_2_ASCII(0.001, "0.001"); |
|---|
| 185 | TEST_EXPECT_FLOAT_2_ASCII(0.0001, "0.0001"); |
|---|
| 186 | TEST_EXPECT_FLOAT_2_ASCII(0.00001, "1e-05"); |
|---|
| 187 | TEST_EXPECT_FLOAT_2_ASCII(0.000001, "1e-06"); |
|---|
| 188 | TEST_EXPECT_FLOAT_2_ASCII(0.0000001, "1e-07"); |
|---|
| 189 | TEST_EXPECT_FLOAT_2_ASCII(0.00000001, "1e-08"); |
|---|
| 190 | TEST_EXPECT_FLOAT_2_ASCII(0.000000001, "1e-09"); |
|---|
| 191 | TEST_EXPECT_FLOAT_2_ASCII(0.0000000001, "1e-10"); |
|---|
| 192 | TEST_EXPECT_FLOAT_2_ASCII(0.00000000001, "1e-11"); |
|---|
| 193 | |
|---|
| 194 | TEST_EXPECT_FLOAT_2_ASCII(10, "10"); |
|---|
| 195 | TEST_EXPECT_FLOAT_2_ASCII(100, "100"); |
|---|
| 196 | TEST_EXPECT_FLOAT_2_ASCII(1000, "1000"); |
|---|
| 197 | TEST_EXPECT_FLOAT_2_ASCII(10000, "10000"); |
|---|
| 198 | TEST_EXPECT_FLOAT_2_ASCII(100000, "100000"); |
|---|
| 199 | TEST_EXPECT_FLOAT_2_ASCII(1000000, "1e+06"); |
|---|
| 200 | TEST_EXPECT_FLOAT_2_ASCII(10000000, "1e+07"); |
|---|
| 201 | TEST_EXPECT_FLOAT_2_ASCII(100000000, "1e+08"); |
|---|
| 202 | TEST_EXPECT_FLOAT_2_ASCII(1000000000, "1e+09"); |
|---|
| 203 | |
|---|
| 204 | TEST_EXPECT_FLOAT_2_ASCII(3141592, "3.141592e+06"); |
|---|
| 205 | TEST_EXPECT_FLOAT_2_ASCII(314159.2, "3.141592e+05"); |
|---|
| 206 | TEST_EXPECT_FLOAT_2_ASCII(31415.92, "3.141592e+04"); |
|---|
| 207 | TEST_EXPECT_FLOAT_2_ASCII(3141.592, "3141.592041"); |
|---|
| 208 | TEST_EXPECT_FLOAT_2_ASCII(3141.592041, "3141.592041"); |
|---|
| 209 | TEST_EXPECT_FLOAT_2_ASCII(314.1592, "314.159210"); |
|---|
| 210 | TEST_EXPECT_FLOAT_2_ASCII(314.159210, "314.159210"); |
|---|
| 211 | TEST_EXPECT_FLOAT_2_ASCII(31.41592, "31.415920"); |
|---|
| 212 | TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592"); |
|---|
| 213 | TEST_EXPECT_FLOAT_2_ASCII(.3141592, "3.141592e-01"); |
|---|
| 214 | TEST_EXPECT_FLOAT_2_ASCII(.03141592, "3.141592e-02"); |
|---|
| 215 | TEST_EXPECT_FLOAT_2_ASCII(.003141592, "3.141592e-03"); |
|---|
| 216 | TEST_EXPECT_FLOAT_2_ASCII(.0003141592, "3.141592e-04"); |
|---|
| 217 | TEST_EXPECT_FLOAT_2_ASCII(.00003141592, "3.141592e-05"); |
|---|
| 218 | TEST_EXPECT_FLOAT_2_ASCII(M_PI, "3.141593"); |
|---|
| 219 | |
|---|
| 220 | TEST_EXPECT_FLOAT_2_ASCII(1/2.0, "0.5"); |
|---|
| 221 | TEST_EXPECT_FLOAT_2_ASCII(1/3.0, "3.333333e-01"); |
|---|
| 222 | TEST_EXPECT_FLOAT_2_ASCII(1/4.0, "0.25"); |
|---|
| 223 | TEST_EXPECT_FLOAT_2_ASCII(1/5.0, "0.2"); |
|---|
| 224 | TEST_EXPECT_FLOAT_2_ASCII(1/6.0, "1.666667e-01"); |
|---|
| 225 | |
|---|
| 226 | TEST_EXPECT_FLOAT_2_ASCII(37550000.0, "3.755e+07"); |
|---|
| 227 | TEST_EXPECT_FLOAT_2_ASCII(3755000.0, "3.755e+06"); |
|---|
| 228 | TEST_EXPECT_FLOAT_2_ASCII(375500.0, "375500"); |
|---|
| 229 | TEST_EXPECT_FLOAT_2_ASCII(37550.0, "37550"); |
|---|
| 230 | TEST_EXPECT_FLOAT_2_ASCII(3755.0, "3755"); |
|---|
| 231 | TEST_EXPECT_FLOAT_2_ASCII(375.5, "375.5"); |
|---|
| 232 | TEST_EXPECT_FLOAT_2_ASCII(37.55, "37.55"); |
|---|
| 233 | TEST_EXPECT_FLOAT_2_ASCII(3.755, "3.755"); |
|---|
| 234 | TEST_EXPECT_FLOAT_2_ASCII(0.3755, "0.3755"); |
|---|
| 235 | TEST_EXPECT_FLOAT_2_ASCII(0.03755, "0.03755"); |
|---|
| 236 | TEST_EXPECT_FLOAT_2_ASCII(0.003755, "0.003755"); |
|---|
| 237 | TEST_EXPECT_FLOAT_2_ASCII(0.0003755, "0.0003755"); |
|---|
| 238 | TEST_EXPECT_FLOAT_2_ASCII(0.00003755, "3.755e-05"); |
|---|
| 239 | TEST_EXPECT_FLOAT_2_ASCII(0.000003755, "3.755e-06"); |
|---|
| 240 | |
|---|
| 241 | TEST_EXPECT_FLOAT_2_ASCII(1000.0*1000.0*1000.0, "1e+09"); |
|---|
| 242 | TEST_EXPECT_FLOAT_2_ASCII(25000.0*25000.0*25000.0, "1.5625e+13"); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | // ------------------------------------------------------------ |
|---|
| 246 | // test to ensure sanitizers work as expected |
|---|
| 247 | |
|---|
| 248 | #if 0 |
|---|
| 249 | void TEST_fail_address_sanitizer() { |
|---|
| 250 | static int array[5]; |
|---|
| 251 | array[2] = 1; |
|---|
| 252 | array[5] = 1; // <- fails with AddressSanitizer |
|---|
| 253 | |
|---|
| 254 | printf("array[5]=%i\n", array[5]); |
|---|
| 255 | } |
|---|
| 256 | #endif |
|---|
| 257 | |
|---|
| 258 | #if 0 |
|---|
| 259 | void TEST_fail_undef_sanitizer() { |
|---|
| 260 | // error below are not reported if AddressSanitizer bails out (TEST_fail_address_sanitizer) |
|---|
| 261 | int x = 7; |
|---|
| 262 | int y1 = -1; |
|---|
| 263 | |
|---|
| 264 | int s = x<<y1; // runtime error with ubsan: shift exponent -1 is negative (does not terminate) |
|---|
| 265 | printf("s=%i\n", s); |
|---|
| 266 | |
|---|
| 267 | int o = INT_MAX; |
|---|
| 268 | int u = INT_MIN; |
|---|
| 269 | o++; // runtime error: signed integer overflow |
|---|
| 270 | u--; // runtime error: signed integer overflow |
|---|
| 271 | printf("o=%i u=%i\n", o, u); |
|---|
| 272 | |
|---|
| 273 | #if 0 |
|---|
| 274 | int y2 = 0; |
|---|
| 275 | int z1 = x/y1; |
|---|
| 276 | int z2 = x/y2; // runtime error with ubsan: division by zero (terminates with SEGV; also w/o sanitizers) |
|---|
| 277 | printf("z1=%i z2=%i\n", z1, z2); |
|---|
| 278 | #endif |
|---|
| 279 | } |
|---|
| 280 | #endif |
|---|
| 281 | |
|---|
| 282 | #if 0 |
|---|
| 283 | void TEST_fail_leak_sanitizer() { |
|---|
| 284 | int *p = new int[5]; // <- fails with LeakSanitizer (only reported if AddressSanitizer does not bail out (TEST_fail_address_sanitizer)) |
|---|
| 285 | printf("p[3]=%i\n", p[3]); |
|---|
| 286 | } |
|---|
| 287 | #endif |
|---|
| 288 | |
|---|
| 289 | // ------------------------------------------------------------ |
|---|
| 290 | |
|---|
| 291 | #include "StrUniquifier.h" |
|---|
| 292 | |
|---|
| 293 | void TEST_StrUniquifier() { |
|---|
| 294 | StrUniquifier uniq("->"); |
|---|
| 295 | TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey"); |
|---|
| 296 | TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey->2"); |
|---|
| 297 | TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey"); |
|---|
| 298 | TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey->2"); |
|---|
| 299 | |
|---|
| 300 | TEST_EXPECT_EQUAL(uniq.make_unique_key(""), ""); |
|---|
| 301 | TEST_EXPECT_EQUAL(uniq.make_unique_key(""), "->2"); |
|---|
| 302 | |
|---|
| 303 | StrUniquifier fresh("."); |
|---|
| 304 | TEST_EXPECT_EQUAL(fresh.make_unique_key(""), ""); |
|---|
| 305 | TEST_EXPECT_EQUAL(fresh.make_unique_key(""), ".2"); |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | // ------------------------------------------------------------ |
|---|
| 309 | |
|---|
| 310 | #include <arb_error.h> |
|---|
| 311 | #include <ErrorOrType.h> |
|---|
| 312 | |
|---|
| 313 | static const char *SOME_ERROR = "whatever"; |
|---|
| 314 | |
|---|
| 315 | static void drop_unused_ARB_ERROR() { |
|---|
| 316 | ARB_ERROR e0; |
|---|
| 317 | } |
|---|
| 318 | static void drop_ARB_ERROR() { |
|---|
| 319 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 320 | } |
|---|
| 321 | static void overwrite_ARB_ERROR() { |
|---|
| 322 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 323 | ARB_ERROR e2 = SOME_ERROR; |
|---|
| 324 | |
|---|
| 325 | e1 = e2; // expect this command to trigger assertion |
|---|
| 326 | ARB_SIGSEGV(true); // -> this is never reached |
|---|
| 327 | } |
|---|
| 328 | |
|---|
| 329 | static ARB_ERROR forwardError(ARB_ERROR err) { |
|---|
| 330 | return err; |
|---|
| 331 | } |
|---|
| 332 | static ARB_ERROR annotateError(ARB_ERROR err) { |
|---|
| 333 | if (err) { |
|---|
| 334 | ARB_ERROR ann_err = GBS_global_string("annotated '%s'", err.deliver()); |
|---|
| 335 | err = ann_err; |
|---|
| 336 | } |
|---|
| 337 | return err; |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | void TEST_misuse_ARB_ERROR_crashtest() { |
|---|
| 341 | TEST_EXPECT_CODE_ASSERTION_FAILS(drop_unused_ARB_ERROR); |
|---|
| 342 | TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ARB_ERROR); |
|---|
| 343 | TEST_EXPECT_CODE_ASSERTION_FAILS(overwrite_ARB_ERROR); |
|---|
| 344 | } |
|---|
| 345 | void TEST_ARB_ERROR() { |
|---|
| 346 | // unused error: |
|---|
| 347 | { |
|---|
| 348 | ARB_ERROR e0; |
|---|
| 349 | TEST_EXPECT_NULL(e0.deliver()); |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | // simple error delivery: |
|---|
| 353 | { |
|---|
| 354 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 355 | TEST_EXPECT_EQUAL(e1.deliver(), SOME_ERROR); |
|---|
| 356 | } |
|---|
| 357 | |
|---|
| 358 | // deliver reassigned error (copy ctor): |
|---|
| 359 | { |
|---|
| 360 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 361 | ARB_ERROR e2(e1); |
|---|
| 362 | TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR); |
|---|
| 363 | } |
|---|
| 364 | // deliver reassigned error (also copy ctor): |
|---|
| 365 | { |
|---|
| 366 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 367 | ARB_ERROR e2 = e1; // assign in definition == copy-ctor |
|---|
| 368 | TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR); |
|---|
| 369 | } |
|---|
| 370 | // deliver reassigned error (op=): |
|---|
| 371 | { |
|---|
| 372 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 373 | ARB_ERROR e2; |
|---|
| 374 | e2 = e1; // real assignment |
|---|
| 375 | TEST_EXPECT_EQUAL(e2.deliver(), SOME_ERROR); |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | // deliver error forwarded through function: |
|---|
| 379 | { |
|---|
| 380 | ARB_ERROR e0; |
|---|
| 381 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 382 | ARB_ERROR f0 = forwardError(e0); |
|---|
| 383 | ARB_ERROR f1 = forwardError(e1); |
|---|
| 384 | TEST_EXPECT_NULL(f0.deliver()); |
|---|
| 385 | TEST_EXPECT_EQUAL(f1.deliver(), SOME_ERROR); |
|---|
| 386 | } |
|---|
| 387 | // forward and annotate error: |
|---|
| 388 | { |
|---|
| 389 | ARB_ERROR e0; |
|---|
| 390 | ARB_ERROR e1 = SOME_ERROR; |
|---|
| 391 | ARB_ERROR a0 = annotateError(e0); |
|---|
| 392 | ARB_ERROR a1 = annotateError(e1); |
|---|
| 393 | TEST_EXPECT_NULL(a0.deliver()); |
|---|
| 394 | TEST_EXPECT_EQUAL(a1.deliver(), "annotated 'whatever'"); |
|---|
| 395 | } |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | typedef ErrorOr<int> ErrorOrInt; |
|---|
| 399 | |
|---|
| 400 | static void drop_ErrorOr0() { |
|---|
| 401 | ErrorOrInt e(NULp, 42); |
|---|
| 402 | } |
|---|
| 403 | static void drop_ErrorOr1() { |
|---|
| 404 | ErrorOrInt e(SOME_ERROR, 0); |
|---|
| 405 | } |
|---|
| 406 | static void retrieve_unchecked_ErrorOr0() { |
|---|
| 407 | ErrorOrInt e(NULp, 21); |
|---|
| 408 | int v = e.getValue(); // getValue w/o previous mandatory hasError |
|---|
| 409 | TEST_EXPECT_EQUAL(v, 21); |
|---|
| 410 | } |
|---|
| 411 | static void retrieve_unchecked_ErrorOr1() { |
|---|
| 412 | ErrorOrInt e(SOME_ERROR, 0); |
|---|
| 413 | ARB_ERROR ae = e.getError(); // getError w/o previous mandatory hasError |
|---|
| 414 | TEST_REJECT_NULL(ae.deliver()); |
|---|
| 415 | } |
|---|
| 416 | |
|---|
| 417 | static ErrorOrInt generateErrorOr(int i) { |
|---|
| 418 | return ErrorOrInt(NULp, i); |
|---|
| 419 | } |
|---|
| 420 | static ErrorOrInt generateErrorOr(const char *msg) { |
|---|
| 421 | return ErrorOrInt(msg, -1); |
|---|
| 422 | } |
|---|
| 423 | |
|---|
| 424 | void TEST_misuse_ErrorOr_crashtest() { |
|---|
| 425 | TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ErrorOr0); |
|---|
| 426 | TEST_EXPECT_CODE_ASSERTION_FAILS(drop_ErrorOr1); |
|---|
| 427 | TEST_EXPECT_CODE_ASSERTION_FAILS(retrieve_unchecked_ErrorOr0); |
|---|
| 428 | TEST_EXPECT_CODE_ASSERTION_FAILS(retrieve_unchecked_ErrorOr1); |
|---|
| 429 | } |
|---|
| 430 | void TEST_ErrorOr() { |
|---|
| 431 | // simple uses (create, check, use + destroy): |
|---|
| 432 | { |
|---|
| 433 | ErrorOrInt e(SOME_ERROR, 0); |
|---|
| 434 | TEST_EXPECT(e.hasError()); |
|---|
| 435 | TEST_EXPECT_EQUAL(e.getError().deliver(), SOME_ERROR); |
|---|
| 436 | } |
|---|
| 437 | { |
|---|
| 438 | ErrorOrInt v(NULp, 7); |
|---|
| 439 | TEST_EXPECT(v.hasValue()); |
|---|
| 440 | TEST_EXPECT_EQUAL(v.getValue(), 7); |
|---|
| 441 | } |
|---|
| 442 | |
|---|
| 443 | // test copy-construction: |
|---|
| 444 | { |
|---|
| 445 | ErrorOrInt e(SOME_ERROR, 0); |
|---|
| 446 | ErrorOrInt c = e; |
|---|
| 447 | TEST_EXPECT(c.hasError()); |
|---|
| 448 | TEST_EXPECT_EQUAL(c.getError().deliver(), SOME_ERROR); |
|---|
| 449 | } |
|---|
| 450 | { |
|---|
| 451 | ErrorOrInt v(NULp, 17); |
|---|
| 452 | ErrorOrInt c = v; |
|---|
| 453 | TEST_EXPECT(c.hasValue()); |
|---|
| 454 | TEST_EXPECT_EQUAL(c.getValue(), 17); |
|---|
| 455 | } |
|---|
| 456 | { |
|---|
| 457 | ErrorOrInt v = generateErrorOr(17); |
|---|
| 458 | TEST_EXPECT(v.hasValue()); |
|---|
| 459 | TEST_EXPECT_EQUAL(v.getValue(), 17); |
|---|
| 460 | } |
|---|
| 461 | { |
|---|
| 462 | ErrorOrInt e = generateErrorOr(SOME_ERROR); |
|---|
| 463 | TEST_EXPECT(e.hasError()); |
|---|
| 464 | TEST_EXPECT_EQUAL(e.getError().deliver(), SOME_ERROR); |
|---|
| 465 | } |
|---|
| 466 | } |
|---|
| 467 | |
|---|
| 468 | #endif // UNIT_TESTS |
|---|
| 469 | |
|---|
| 470 | // -------------------------------------------------------------------------------- |
|---|
| 471 | |
|---|