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