1 // Written in the D programming language 2 3 /** 4 * Test routines for floating-point decimal arithmetic. 5 * 6 * An implementation of the 7 * General Decimal Arithmetic Specification. 8 * 9 * Authors: Paul D. Anderson 10 * 11 * Copyright: Copyright 2009-2016 by Paul D. Anderson. 12 * 13 * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a> 14 * 15 * Standards: Conforms to the 16 * General Decimal Arithmetic Specification, 17 * Version 1.70, (25 March 2009). 18 */ 19 20 module eris.decimal.test; 21 22 version(unittest) 23 { 24 25 import std.path : baseName; 26 import std.stdio; 27 import std..string; 28 import std.traits; 29 30 import eris.decimal; 31 import eris.decimal.arithmetic; 32 33 public static bool initialized = false; 34 public static int totalTests; 35 public static int totalPass; 36 public static int totalFail; 37 38 /* package struct Totals() 39 { 40 string report() 41 { 42 string rep = format("%-11s: %s", name, tests(testCount)); 43 if (failCount == 0) 44 { 45 rep ~= format(" (%2d pass)", passCount); 46 } 47 else 48 { 49 rep ~= format(" (%2d pass, %d fail).", passCount, failCount); 50 foreach (msg; messages) 51 { 52 rep ~= format("\n %s", msg); 53 } 54 } 55 return rep; 56 } 57 58 }*/ 59 //----------------------------- 60 // tests 61 //----------------------------- 62 63 /** 64 * S is a struct containing input data and the expected value 65 * T is the return type of the function being tested 66 * N is the number of inputs 67 */ 68 package struct FunctionTest(S,T,string fmt = "%s", int N = S.tupleof.length-1) 69 { 70 string name; 71 int testCount; 72 int passCount; 73 int failCount; 74 string[] messages; 75 76 @disable this(); 77 78 this(string name) 79 { 80 this.name = name; 81 } 82 83 void test(S s, T actual, int precision = 0, 84 string file = __FILE__, int line = __LINE__) 85 { 86 testCount++; 87 totalTests++; 88 auto input = s.tupleof[0..$-1]; 89 auto expect = s.tupleof[$-1]; 90 bool passed = false; 91 92 static if (isDecimal!T) 93 { 94 if (precision > 0) 95 { 96 // if (!__ctfe) writefln("precision = %s", precision); 97 // must be equal at specified precision 98 passed = true; //precisionEquals!T(expect, actual, precision); 99 } 100 else 101 { 102 // equal at type precision 103 passed = (actual == expect); 104 } 105 106 if (!passed) // check for NaN, NaN 107 { 108 passed = actual.isNaN && expect.isNaN; 109 } 110 } 111 else 112 { 113 passed = (actual == expect); 114 } 115 // end static if/else 116 117 if (passed) 118 { 119 passCount++; 120 totalPass++; 121 } 122 else 123 { 124 failCount++; 125 totalFail++; 126 string msg = format("failed at %s(%d)", baseName(file), line); 127 msg ~= format(", test %d", testCount); 128 string description = format(" should be <" ~ fmt ~ "> not <" ~ fmt ~ ">.", expect, actual); 129 130 static if (N == 0) 131 { 132 msg ~= format(": <%s()>", name); 133 } 134 else static if (N == 1) 135 { 136 msg ~= format(": <%s(%s)>", name, input[0]); 137 } 138 else static if (N == 2) 139 { 140 msg ~= format(": <%s(%s,%s)>", name, input[0], input[1]); 141 } 142 else static if (N == 3) 143 { 144 msg ~= format(": <%s(%s,%s,%s)>", name, input[0], input[1], input[2]); 145 } 146 else 147 { 148 msg ~= format(": <%s(%s,%s,%s, ...)>", name, input[0], input[1], input[2]); 149 } 150 messages.length++; 151 messages[$-1] = msg ~ description; 152 } 153 } 154 155 string report() 156 { 157 string rep = format("%-11s: %s", name, tests(testCount)); 158 if (failCount == 0) 159 { 160 rep ~= format(" (%2d pass)", passCount); 161 } 162 else 163 { 164 rep ~= format(" (%2d pass, %d fail).", passCount, failCount); 165 foreach (msg; messages) 166 { 167 // escape any formatting 168 msg = msg.replace("%","%%"); 169 rep ~= format("\n %s", msg); 170 } 171 } 172 return rep; 173 } 174 175 string tests(int n) 176 { 177 if (n == 1) return " 1 test "; 178 else return format("%2d tests", n); 179 } 180 } 181 182 /* /// Returns true if the actual value equals the expected value to the specified precision. 183 /// Otherwise prints an error message and returns false. 184 public bool assertPrecisionEqual(T, U)(T actual, U expected, int precision, 185 string file = __FILE__, int line = __LINE__ ) if (isDecimal!T && isDecimal!U){ 186 // auto context = Context(precision); 187 if (precisionEquals!T(expected, actual, precision)) { 188 return true; 189 } 190 else { 191 writeln("failed at ", baseName(file), "(", line, "):", 192 " expected \"", expected, "\"", 193 " but found \"", actual, "\"."); 194 return false; 195 } 196 } 197 198 /// Returns true if the actual value equals the expected value to the specified precision. 199 /// Otherwise prints an error message and returns false. 200 public bool assertPrecisionEqual(T, U:string)(T actual, U expected, int precision, 201 string file = __FILE__, int line = __LINE__ ) { 202 auto context = Context(precision, T.maxExpo, T.mode); 203 if (equals(T(expected), actual, context)) { 204 return true; 205 } 206 else { 207 writeln("failed at ", baseName(file), "(", line, "):", 208 " expected \"", expected, "\"", 209 " but found \"", actual, "\"."); 210 return false; 211 } 212 }*/ 213 214 } 215 //----------------------------- 216 // asserts 217 //----------------------------- 218 219 220 // TODO: assertCompare? assertCompareTotal? 221 222 /// Returns true if the actual value equals the expected value. 223 /// Otherwise prints an error message and returns false. 224 bool assertEqual(T, U: T)(in T actual, T expected, size_t index = -1, 225 string file = __FILE__, int line = __LINE__ ) 226 { 227 if (expected == actual) 228 { 229 return true; 230 } 231 else 232 { 233 if (index >= 0) 234 { 235 write("failed at ", baseName(file), "(", line, ")[", index + 1, "]:"); 236 } 237 else 238 { 239 write("failed at ", baseName(file), "(", line, "):"); 240 } 241 writeln(" expected \"", expected, "\" but found \"", actual, "\"."); 242 return false; 243 } 244 } 245 246 /// Returns true if the actual value equals the expected value. 247 /// Otherwise prints an error message and returns false. 248 bool assertEqual(T, U)(in T actual, U expected, size_t index = 0, 249 string file = __FILE__, int line = __LINE__ ) { 250 if (expected == actual) { 251 return true; 252 } 253 else { 254 writeln("failed at ", baseName(file), "(", line, ")[", index, "]:", 255 " expected \"", expected, "\"", 256 " but found \"", actual, "\"."); 257 return false; 258 } 259 } 260 261 bool assertNotEqual(T,U = T)(in T actual, in U expected, 262 string file = __FILE__, int line = __LINE__ ) { 263 if (expected != actual) { 264 return true; 265 } 266 else { 267 writeln("failed at ", baseName(file), "(", line, "):", 268 " \"", expected, "\" is equal to \"", actual, "\"."); 269 return false; 270 } 271 } 272 273 /// Returns true if the string representation of the actual value 274 /// equals the string representation of the expected value. 275 /// Otherwise prints an error message and returns false. 276 bool assertStringNotEqual(T,U)(in T actual, in U expected, 277 string file = __FILE__, int line = __LINE__ ) { 278 return assertNotEqual(actual.toString, expected.toString, file, line); 279 } 280 281 /// Returns true if the string representation of the actual value 282 /// equals the string representation of the expected value. 283 /// Otherwise prints an error message and returns false. 284 bool assertStringEqual(T,U)(in T actual, in U expected, 285 string file = __FILE__, int line = __LINE__ ) { 286 return assertEqual!string(actual.toString, expected.toString, 0, file, line); 287 } 288 289 290 /// Returns true if the string representation of the actual value 291 /// equals the string representation of the expected value. 292 /// Otherwise prints an error message and returns false. 293 bool assertStringEqual(T,U:string)(in T actual, U expected, 294 string file = __FILE__, int line = __LINE__ ) { 295 return assertEqual(actual.toString, expected, -1, file, line); 296 } 297 298 /// Returns true if the actual value is true. 299 /// Otherwise prints an error message and returns false. 300 bool assertTrue(T)(T actual, 301 string file = __FILE__, int line = __LINE__ ) { 302 return assertEqual(cast(bool)actual, true, 0, file, line); 303 } 304 305 /// Returns true if the actual value is false. 306 /// Otherwise prints an error message and returns false. 307 bool assertFalse(T)(T actual, 308 string file = __FILE__, int line = __LINE__ ) { 309 return assertEqual(cast(bool)actual, false, 0, file, line); 310 } 311 312 /// Returns true if the value is zero. 313 /// Otherwise prints an error message and returns false. 314 bool assertZero(T)(T actual, 315 string file = __FILE__, int line = __LINE__ ) { 316 if (actual == 0) { 317 return true; 318 } 319 else { 320 writeln("failed at ", baseName(file), "(", line, "):", 321 " expected zero ", 322 " but found \"", actual, "\"."); 323 return false; 324 } 325 } 326 327 /// Returns true if the value is greater than or equal to zero. 328 /// Otherwise prints an error message and returns false. 329 bool assertPositive(T)(T actual, 330 string file = __FILE__, int line = __LINE__ ) { 331 if (actual >= zero) { 332 return true; 333 } 334 else { 335 writeln("failed at ", baseName(file), "(", line, "):", 336 " expected a positive value ", 337 " but found \"", actual, "\"."); 338 return false; 339 } 340 } 341 342 /// Returns true if the value is less than zero. 343 /// Otherwise prints an error message and returns false. 344 bool assertNegative(T)(T actual, 345 string file = __FILE__, int line = __LINE__ ) { 346 if (actual < zero) { 347 return true; 348 } 349 else { 350 writeln("failed at ", baseName(file), "(", line, "):", 351 " expected a negative value ", 352 " but found \"", actual, "\"."); 353 return false; 354 } 355 } 356 357 /// Returns true if the first value is greater than the second value. 358 /// Otherwise prints an error message and returns false. 359 bool assertGreaterThan(T,U)(in T first, in U second, 360 string file = __FILE__, int line = __LINE__ ) { 361 if (first > second) { 362 return true; 363 } 364 else { 365 writeln("failed at ", baseName(file), "(", line, "):", 366 " \"", first, "\"", 367 " is not greater than \"", second, "\"."); 368 return false; 369 } 370 } 371 372 /// Returns true if the first value is greater than the second value. 373 /// Otherwise prints an error message and returns false. 374 bool assertNotGreaterThan(T,U)(in T first, in U second, 375 string file = __FILE__, int line = __LINE__ ) { 376 if (first <= second) { 377 return true; 378 } 379 else { 380 writeln("failed at ", baseName(file), "(", line, "):", 381 " \"", first, "\"", 382 " is greater than \"", second, "\"."); 383 return false; 384 } 385 } 386 387 /// Returns true if the first value is less than the second value. 388 /// Otherwise prints an error message and returns false. 389 bool assertLessThan(T,U)(in T first, in U second, 390 string file = __FILE__, int line = __LINE__ ) { 391 if (first < second) { 392 return true; 393 } 394 else { 395 writeln("failed at ", baseName(file), "(", line, "):", 396 " \"", first, "\"", 397 " is not less than \"", second, "\"."); 398 return false; 399 } 400 } 401 402 /// Returns true if the first value is less than the second value. 403 /// Otherwise prints an error message and returns false. 404 bool assertNotLessThan(T,U)(in T first, in U second, 405 string file = __FILE__, int line = __LINE__ ) { 406 if (first >= second) { 407 return true; 408 } 409 else { 410 writeln("failed at ", baseName(file), "(", line, "):", 411 " \"", first, "\"", 412 " is less than \"", second, "\"."); 413 return false; 414 } 415 } 416 417 /// Returns true if the expression throws. 418 bool assertThrows(T:Throwable = Exception, E)(lazy E expression, 419 string msg = T.stringof, string file = __FILE__, int line = __LINE__ ) { 420 try { 421 std.exception.assertThrown!T(expression, msg, file, line); 422 return true; 423 } 424 catch (Throwable exc) { 425 writeln("failed at ", baseName(file), "(", line, "):", 426 " Did not throw \"", msg, "\"."); 427 return false; 428 } 429 } 430 431