1
2 package eu.simuline.testhelpers;
3
4 import java.lang.reflect.Modifier;
5 import java.lang.reflect.Array;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.InvocationTargetException;
8
9 import java.util.Comparator;
10 import java.util.Collection;
11
12 import junit.framework.AssertionFailedError;
13
14 /**
15 * Extends the framework of assertions
16 * provided by <code>junit.framework.Assert</code>.
17 * <ul>
18 * <li>
19 * The method {@link #assertNormAbsEquals(Object,Object,String,double)}
20 * generalizes the method
21 * <code>assertEquals(double expected, double actual, double delta)</code>
22 * to objects with a metric defined by a method (name).
23 * There is also a variant for relative precision,
24 * {@link #assertNormRelEquals(Object,Object,String,double)}.
25 * <li>
26 * The methods {@link #assertRelEquals(double,double,double)}
27 * provides relative tolerances suited to numerical applications.
28 * For small number applications (e.g. failure probabilities)
29 * a combination of relative tolerance and absolute one
30 * may be prescribed by
31 * {@link #assertAbsRelEquals(double,double,double,double,double)}.
32 * <li>
33 * Sometimes equality with respect to the equals-method
34 * differs from equality
35 * with respect to <code>Comparator</code>s and the <code>compareTo</code>
36 * method (think e.g. of the package <code>java.math</code>).
37 * To fill this gap {@link #assertIs(Assert.CmpObj,Comparable,Object)}
38 * is useful.
39 * This method can also check for "greater than" or that like.
40 * A variant of this using <code>Comparator</code>s
41 * is {@link #assertIs(Assert.CmpObj,Object,Object,Comparator)}.
42 * <li>
43 * The method {@link #assertArraysEquals(Object,Object)}
44 * tests equality of arrays recursively.
45 * <li>
46 * The method {@link #assertArraysEquals(Object,Object,double)}
47 * is a combination ot the two.
48 * <li>
49 * The method
50 * {@link #assertRelEquals(double expected, double actual, double reldev)}
51 * is for testing relative deviations.
52 * <li>
53 * The method
54 * {@link #assertStringEquals(String expected, String actual)}
55 * is designed for testing long strings.
56 * It provides error messages suitable to find deviations quickly.
57 * </ul>
58 *
59 * @param <E>
60 * the element type of a {@link Collection}
61 * or the element to be compared by a {@link Comparator}.
62 *
63 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
64 */
65 public abstract class Assert<E> extends org.junit.Assert {
66
67 /* -------------------------------------------------------------------- *
68 * inner classes. *
69 * -------------------------------------------------------------------- */
70
71 /**
72 * Represents an ordering relation.
73 *
74 * To be used as a parameter for the methods
75 * {@link #assertIs(Assert.CmpObj, Comparable, Object)},
76 * {@link #assertIs(Assert.CmpObj, Object, Object, Comparator)}
77 * and variants thereof.
78 *
79 * @see #LESS_EQ
80 * @see #LESS
81 * @see #GREATER
82 * @see #GREATER_EQ
83 * @see #EQUAL
84 * @see #NOT_EQUAL
85 */
86 public enum CmpObj {
87
88 LESS_EQ(" less or equal") {
89 boolean isValid(int flag3) {
90 return flag3 <= 0;
91 }
92 },
93
94 LESS(" less") {
95 boolean isValid(int flag3) {
96 return flag3 < 0;
97 }
98 },
99
100 GREATER(" greater") {
101 boolean isValid(int flag3) {
102 return flag3 > 0;
103 }
104 },
105
106 GREATER_EQ(" greater or equal") {
107 boolean isValid(int flag3) {
108 return flag3 >= 0;
109 }
110 },
111
112 EQUAL(" equal") {
113 boolean isValid(int flag3) {
114 return flag3 == 0;
115 }
116 },
117
118 NOT_EQUAL(" not equal") {
119 boolean isValid(int flag3) {
120 return flag3 != 0;
121 }
122 };
123
124 /**
125 * Core part of the message when the relation fails.
126 */
127 private String message;
128
129 /**
130 * Creates a new <code>CmpObj</code>
131 * with the given fractin of message;
132 * also the implementation of method {@link #isValid}
133 * has to be provided hereafter.
134 *
135 * @param message a <code>String</code> value
136 */
137 CmpObj(String message) {
138 this.message = message;
139 }
140
141 /**
142 * Returns whether <code>isValid</code> method here.
143 *
144 * @param flag3
145 * an <code>int</code> which is the output
146 * of a method {@link java.lang.Comparable#compareTo}
147 * or {@link java.util.Comparator#compare}.
148 * @return
149 * a <code>boolean</code> value
150 * signifying whether <code>flag3</code> is allowed.
151 */
152 abstract boolean isValid(int flag3);
153
154 /**
155 * Returns <code>expected.compareTo(actual)</code> if possible.
156 *
157 * @param expected
158 * an instance of an <code>Object</code>.
159 * @param actual
160 * an <code>Object</code> or <code>null</code>.
161 * @return
162 * the <code>int</code> value which results in invoking
163 * <code>expected.compare(actual)</code>.
164 * @throws IllegalArgumentException
165 * <ul>
166 * <li>
167 * if <code>expected</code> is not an instance
168 * of <code>Comparable</code>
169 * and in particular for <code>expected == null</code>,
170 * <li>
171 * if invoking <code>expected.compareTo(actual)</code>
172 * raises an exception.
173 * </ul>
174 * @throws IllegalStateException
175 * if <code>expected.compare(actual)</code> is evaluated
176 * for <code>actual == null</code> without throwing an exception
177 * as specified for {@link java.lang.Comparable#compareTo}.
178 */
179 @edu.umd.cs.findbugs.annotations.SuppressWarnings
180 (value = "NP_LOAD_OF_KNOWN_NULL_VALUE",
181 justification = "expected is null and acutal is null are both ok. ")
182 private boolean invokeCompareTo(Comparable<?> expected,
183 Object actual) {
184
185 // Check "expected".
186 if (expected == null) {
187 throw new IllegalArgumentException
188 ("Found expected value " + expected +
189 " -- Use method assertNull instead. ");
190 }
191 // Here, expected instanceof Comparable
192 // and in particular expected != null.
193
194 Method compareTo;
195 try {
196 compareTo = expected.getClass().getMethod("compareTo",
197 Object.class);
198 } catch (NoSuchMethodException e) {
199 throw new IllegalStateException// NOPMD
200 (STR_OBJECT + expected + STR_DN_PROV +
201 "public int compareTo(Object)\" - impossible " +
202 "because expected is declared as Comparable. ");
203 }
204 // this is necessary
205 // despite compareTo(Object) is supposed to be public,
206 // because the including class
207 // may not be accessible from within this Accessor.
208 compareTo.setAccessible(true);
209
210 try {
211 Integer result = (Integer) compareTo.invoke(expected, actual);
212 if (actual != null) {
213 return isValid(result);
214 }
215 // by symmetry, expected.compareTo(actual)
216 // should have thrown a NullPointerException.
217
218 throw new IllegalStateException
219 ("Tried to compare <" + expected +
220 "> to: <" + actual +
221 "> which should raise a NullPointerException. ");
222 } catch (IllegalAccessException iace) {
223 thrwAccessible(compareTo);
224 } catch (IllegalArgumentException iage) {
225 thrwWrongArgs(compareTo);
226 } catch (InvocationTargetException ite) {
227 throw new IllegalArgumentException// NOPMD
228 ("Could not test ordering because method " + compareTo +
229 STR_RAISED + ite.getTargetException() + ". ");
230 }
231 throw new IllegalStateException();
232 }
233
234 } // enum CmpObj
235
236 /* -------------------------------------------------------------------- *
237 * constants. *
238 * -------------------------------------------------------------------- */
239
240 // private static final String STR_METHOD = "Method ";
241 private static final String STR_OBJECT = "Object ";
242 private static final String STR_DN_PROV = " does not provide a method \"";
243 private static final String STR_RAISED = " raised ";
244 // private static final String STR_EXPECTED = "expected: <";
245 private static final String STR_BUTWAS = "> but was: <";
246 private static final String STR_ASTOP = ">. ";
247 private static final String STR_IN_ABS_VAL = " in absolute value. ";
248
249 /* -------------------------------------------------------------------- *
250 * thrower methods. *
251 * -------------------------------------------------------------------- */
252
253 private static void thrwAccessible(Method method) {
254 throw new IllegalStateException
255 ("Method " + method + " is not accessible although it should. ");
256 }
257
258 private static void thrwWrongArgs(Method method) {
259 throw new IllegalStateException
260 ("Method " + method +
261 " is provided with illegal arguments " +
262 "although this should not be possible. ");
263 }
264
265 /* -------------------------------------------------------------------- *
266 * methods: assertEquals. *
267 * -------------------------------------------------------------------- */
268
269
270 // in fact, norm is more a metric.
271 /**
272 * Returns the distance
273 * of the two objects <code>expected</code> and <code>actual</code>
274 * defined by the metric defined by the method named <code>norm</code>;
275 * typically something like the norm of a kind of difference.
276 * <p>
277 * CAUTION: This method shall be designed to compute values close to zero,
278 * i.e. is applied to <code>actual</code> cloase to <code>expected</code>.
279 * This must be reflected in the definition
280 * of the method given by <code>norm</code>.
281 *
282 * @param norm
283 * the non-null name of a metric method,
284 * i.e. of a member method of the form
285 * <code>public double norm(other)</code>
286 * with the properties of a metric:
287 * <ul>
288 * <li><code>x.norm(x)</code> yields <code>0</code>
289 * <li><code>x.norm(y)</code> and <code>y.norm(x)</code>
290 * yield the same result,
291 * <li><code>x.norm(y)+y.norm(z)\(\ge\) x.norm(z)</code>.
292 * </ul>
293 * CAUTION: This method must be designed to be applied
294 * to <code>actual</code> close to <code>expected</code>
295 * i.e. with a lot of extinction.
296 * For certain arithmetic types, this requires care
297 * to obtain reasonable performance.
298 * @throws IllegalArgumentException
299 * if the test cannot be performed, i.e.
300 * <ul>
301 * <li>
302 * <code>norm</code> does not represent a metric method,
303 * i.e. a member method of the form
304 * <code>public double norm(other)</code>.
305 * Of course, the properties of a metric cannot be proved.
306 * <li>
307 * invoking <code>expected.norm(actual)</code> raises an exception
308 * </ul>
309 * @see #assertNormAbsEquals(String, Object, Object, String, double)
310 * @see #assertNormRelEquals(String, Object, Object, String, double)
311 * @see #computeNorm1(String, Object)
312 *///<code></code>
313 private static double computeNorm2(String norm,
314 Object expected,
315 Object actual
316 //Object... actuals
317 ) {
318
319 // get the norm2 method or null
320 Method mNorm2 = Accessor.getToBeInvoked(expected.getClass(),
321 norm,
322 expected.getClass());
323
324
325 // ensure that a method with given signature exists
326 if (mNorm2 == null) {
327 throw new IllegalArgumentException
328 (STR_OBJECT + expected + STR_DN_PROV +
329 "public ... " + norm + "(" + expected.getClass() +
330 ") as expected. ");
331 }
332
333 // ensure the right return type
334 if (!Double.TYPE.equals(mNorm2.getReturnType())) {
335 throw new IllegalArgumentException
336 (STR_OBJECT + expected + STR_DN_PROV +
337 "public double " + norm + "(" + expected.getClass() +
338 ") as expected (have a look at the return type). ");
339 }
340
341 // ensure that the method is a member method
342 if (Modifier.isStatic(mNorm2.getModifiers())) {
343 throw new IllegalArgumentException
344 (STR_OBJECT + expected + " provides a static method " +
345 "\"public static double " + norm + "(" + expected.getClass() +
346 ") not a member method as expected. ");
347 }
348
349 // Here, mNorm contains the correct method representing a norm
350 // resp. a metric
351 // (we expect this is unique). *****
352
353 try {
354 // invoke norm method
355 return (Double) mNorm2.invoke(expected, actual);
356 } catch (IllegalAccessException iace) {
357 // throws IllegalStateException but shall never occur
358 thrwAccessible(mNorm2);
359 } catch (InvocationTargetException ite) {
360 ite.getTargetException().printStackTrace();
361 throw new IllegalArgumentException // NOPMD
362 ("Could not test deviation, because method " + mNorm2 +
363 STR_RAISED + ite.getTargetException() + ". ");
364 }
365 throw new IllegalStateException("Reached unreachable statement. ");
366 } // computeNorm2(...)
367
368
369 /**
370 * Fails if <code>actual</code> is <code>null</code>
371 * or <code>actual</code> deviates from <code>expected</code>
372 * by at least <code>delta</code>,
373 * provided the test can be executed at all.
374 * The deviation is computed with respect to the metric
375 * given by <code>expected.norm(actual)</code>
376 * which is assumed to have signature <code>double norm(Cls actual)</code>
377 * with <code>Cls</code> the class of <code>expected</code>.
378 *
379 * @param message
380 * the error message displayed if the test fails regularly,
381 * i.e. if <code>computeNorm2(norm, expected, actual)</code>
382 * can be evaluated without throwing an exception.
383 * @param expected
384 * The expected object (see the actual object).
385 * @param actual
386 * The actual object
387 * which is expected to deviate from <code>expected</code>
388 * by at most <code>delta</code> in norm
389 * @param norm
390 * the name of a metric method,
391 * i.e. of a member method of the form
392 * <code>public double norm(other)</code>
393 * with the properties of a metric:
394 * <ul>
395 * <li><code>x.norm(x)</code> yields <code>0</code>
396 * <li><code>x.norm(y)</code> and <code>y.norm(x)</code>
397 * yield the same result,
398 * <li><code>x.norm(y)+y.norm(z)\(\ge\) x.norm(z)</code>.
399 * </ul>
400 * @param delta
401 * the allowed deviation as a <code>double</code> value.
402 * @throws IllegalArgumentException
403 * if the test cannot be performed, i.e.
404 * <ul>
405 * <li>
406 * <code>norm</code> is <code>null</code>
407 * or does not represent a metric method,
408 * i.e. a member method of the form
409 * <code>public double norm(other)</code>.
410 * Of course, the properties of a metric cannot be proved.
411 * <li>
412 * invoking <code>expected.norm(actual)</code> raises an exception
413 * </ul>
414 * @throws IllegalArgumentException
415 * if <code>expected==null</code>.
416 * @throws AssertionFailedError
417 * if the test can be performed,
418 * i.e. no IllegalArgumentException is thrown but
419 * <ul>
420 * <li>
421 * <code>actual==null</code> or
422 * <li>the distance returned by the metric exceeds <code>delta</code>.
423 * </ul>
424 *///<code></code>
425 public static void assertNormAbsEquals(String message,
426 Object expected,
427 Object actual,
428 String norm,
429 double delta) {
430 checkNullsB(norm, expected, actual);
431 double diff = computeNorm2(norm, expected, actual);
432
433 if (diff > delta) {
434 fail(message);
435 }
436 } // assertNormAbsEquals(...)
437
438 public static void assertNormAbsEquals(Object expected,
439 Object actual,
440 String norm,
441 double delta) {
442 assertNormAbsEquals(expectedActual(expected, actual) +
443 ": deviation " +
444 computeNorm2(norm, expected, actual) +
445 " exceeds " + delta + STR_IN_ABS_VAL,
446 expected,
447 actual,
448 norm,
449 delta);
450 } // assertNormAbsEquals(...)
451
452 /**
453 * Returns the norm of <code>expected</code>
454 * defined by the method named <code>norm</code>.
455 *
456 * @param norm
457 * the non-null name of a norm method,
458 * i.e. of a member method of the form
459 * <code>public double norm()</code>
460 * with the properties of a norm:
461 * <ul>
462 * <li>
463 * <code>x.norm()</code> yields <code>0</code>
464 * iff <code>x</code> represents the zero vector.
465 * <li>
466 * <code>(sx).norm()=s(x.norm())</code>
467 * where <code>sx</code> and <code>s(...)</code>
468 * represent scalar multiplication.
469 * <li>
470 * <code>x.norm()+y.norm()\(\ge (x+y)\).norm(z)</code>,
471 * where \(x+y\) represents the sum of vectors.
472 * </ul>
473 * @param expected
474 * The object from which the norm is to be computed.
475 * @return
476 * the norm of <code>expected</code>
477 * defined by the method named <code>norm</code>.
478 * @throws IllegalArgumentException
479 * if the test cannot be performed, i.e.
480 * <ul>
481 * <li>
482 * <code>norm</code> does not represent a norm method,
483 * i.e. a member method of the form
484 * <code>public double norm(other)</code>.
485 * Of course, the properties of a norm cannot be proved.
486 * <li>
487 * invoking <code>expected.norm()</code> raises an exception
488 * </ul>
489 *///<code></code>
490 private static double computeNorm1(String norm,
491 Object expected) {
492 //Object[] actuals = new Object[0];
493 //checkNullsB(norm, expected); checked by computeNorm2 already
494 //assert expected != null && norm != null;
495
496 // get the norm1 method or null
497 Method mNorm1 = Accessor.getToBeInvoked(expected.getClass(),
498 norm);
499
500 // ensure that a method with given signature exists
501 if (mNorm1 == null) {
502 throw new IllegalArgumentException
503 (STR_OBJECT + expected + STR_DN_PROV +
504 "public ... " + norm + "(" + expected.getClass() +
505 ") as expected. ");
506 }
507
508 // ensure the right return type
509 if (!Double.TYPE.equals(mNorm1.getReturnType())) {
510 throw new IllegalArgumentException
511 (STR_OBJECT + expected + STR_DN_PROV +
512 "public double " + norm +
513 "() as expected (have a look at the return type). ");
514 }
515
516 // ensure that the method is a member method
517 if (Modifier.isStatic(mNorm1.getModifiers())) {
518 throw new IllegalArgumentException
519 (STR_OBJECT + expected + " provides a static method " +
520 "\"public static double " + norm +
521 "() not a member method as expected. ");
522 }
523
524 // Here, mNorm1 contains the correct method representing a norm
525 // (we expect this is unique). *****
526
527 try {
528 // invoke norm method
529 return (Double) mNorm1.invoke(expected);
530 } catch (IllegalAccessException iace) {
531 // throws IllegalStateException but shall never occur
532 thrwAccessible(mNorm1);
533 } catch (InvocationTargetException ite) {
534 throw new IllegalArgumentException // NOPMD
535 ("Could not test deviation, because method " + mNorm1 +
536 STR_RAISED + ite.getTargetException() + ". ");
537 }
538 throw new IllegalStateException("Reached unreachable statement. ");
539 } // computeNorm1(...)
540
541
542 /**
543 * Fails if <code>actual</code> is <code>null</code>
544 * or <code>actual</code> deviates from <code>expected</code>
545 * by at least <code>delta</code>,
546 * provided the test can be executed at all.
547 */
548 public static void assertNormRelEquals(Object expected,
549 Object actual,
550 String norm,
551 double reldev) {
552 assertNormRelEquals(expectedActual(expected, actual) +
553 ": relative deviation " +
554 computeNorm2(norm, expected, actual) /
555 computeNorm1(norm, expected) +
556 " exceeds " + reldev + STR_IN_ABS_VAL,
557 expected,
558 actual,
559 norm,
560 reldev);
561 } // assertNormEquals(...)
562
563 public static void assertNormRelEquals(String message,
564 Object expected,
565 Object actual,
566 String norm,
567 double reldev) {
568
569 checkNullsB(norm, expected, actual);
570 double diff = computeNorm2(norm, expected, actual);
571 // get the norm method
572 //Method mNorm1 = Accessor.getToBeInvoked(expected.getClass(), norm);
573 double dNorm = computeNorm1(norm, expected);
574
575 if (diff / dNorm > reldev) {
576 fail(message);
577 }
578 } // assertNormEquals(...)
579
580 private static String expectedActual(Object expected,
581 Object actual) {
582 return "expected: <" + expected + STR_BUTWAS + actual + ">";
583 }
584
585 /**
586 * Fails if the test can be executed, i.e.
587 * neither <code>norm</code> nor <code>expected</code>
588 * is <code>null</code>, and <code>actual</code> is <code>null</code>.
589 *
590 * @param norm
591 * name of a member method in class <code>Cls</code>
592 * with signature <code>double norm(Cls actual)</code>.
593 * @param expected
594 * an <code>Object</code> with type <code>Cls</code>;
595 * in particular not <code>null</code>.
596 * @param actual
597 * another <code>Object</code>; in particular not <code>null</code>.
598 * @throws IllegalArgumentException
599 * if <code>norm==null</code> or <code>expected==null</code>.
600 * @throws AssertionFailedError
601 * if <code>norm,expected!=null</code> but <code>actual==null</code>.
602 * @see #assertNormAbsEquals(String, Object, Object, String, double)
603 * @see #assertNormRelEquals(String, Object, Object, String, double)
604 * @see #checkNulls(String, Object, Object)
605 */
606 @edu.umd.cs.findbugs.annotations.SuppressWarnings
607 (value = "NP_LOAD_OF_KNOWN_NULL_VALUE",
608 justification = "expected is null and acutal is null are both ok. ")
609 private static void checkNullsB(String norm,
610 Object expected,
611 Object actual) {
612
613 if (norm == null) {
614 throw new IllegalArgumentException
615 ("Norm is " + norm +
616 "; could not prove whether deviation exceeds some threshold. ");
617 }
618
619 if (expected == null) {
620 throw new IllegalArgumentException
621 (expectedActual(expected, actual) + "; " +
622 "could not prove whether deviation exceeds some threshold. ");
623 }
624
625 if (actual == null) {
626 fail(expectedActual(expected, actual) + "; " +
627 "could not prove whether deviation exceeds some threshold. ");
628 }
629 }
630
631 /**
632 * Fails for <code>!expected.equals(actual)</code>
633 * and raises an exception if this expression cannot be evaluated.
634 *
635 * @param expected
636 * an instance of an <code>Object</code>.
637 * @param actual
638 * an <code>Object</code> or <code>null</code>.
639 * @throws IllegalArgumentException
640 * <ul>
641 * <li>
642 * for <code>expected == null</code>,
643 * <li>
644 * if invoking <code>expected.equals(actual)</code>
645 * raises an exception.
646 * </ul>
647 * @throws AssertionFailedError
648 * for <code>!expected.equals(actual)</code>.
649 */
650 @edu.umd.cs.findbugs.annotations.SuppressWarnings
651 (value = "NP_LOAD_OF_KNOWN_NULL_VALUE",
652 justification = "expected is null is ok. ")
653 public static void assertEquals(Object expected,
654 Object actual) {
655
656 // Exclude expected == null.
657 if (expected == null) {
658 throw new IllegalArgumentException
659 ("Found expected value " + expected +
660 " -- Use method assertNull instead. ");
661 }
662 // Here, expected != null.
663
664 Method equals;
665 try {
666 equals = expected.getClass().getMethod("equals", Object.class);
667 } catch (NoSuchMethodException e) {
668 throw new IllegalStateException// NOPMD
669 (STR_OBJECT + expected + STR_DN_PROV +
670 "public boolean equals(Object)\" - " +
671 "impossible because this is inherited from class Object. ");
672 }
673 // Here, equals contains the equals method of object expected.
674
675 // this is necessary
676 // despite equals(Object, double) is supposed to be public,
677 // because the including class
678 // may not be accessible from within this Accessor.
679 equals.setAccessible(true);
680
681 try {
682 Boolean result = (Boolean) equals.invoke(expected, actual);
683 // for actual == null, result is Boolean.FALSE.
684
685 if (!Boolean.TRUE.equals(result)) {
686 fail(expectedActual(expected, actual) + ". ");
687 }
688 } catch (IllegalAccessException iace) {
689 thrwAccessible(equals);
690 } catch (IllegalArgumentException iage) {
691 thrwWrongArgs(equals);
692 } catch (InvocationTargetException ite) {
693 throw new IllegalArgumentException// NOPMD
694 ("Could not test equality because method " + equals +
695 STR_RAISED + ite.getTargetException() + ". ");
696 }
697 }
698
699 public static void assertEquals(String message,
700 Object expected,
701 Object actual) {
702
703 try {
704 assertEquals(expected, actual);
705 } catch (AssertionFailedError e) {
706 fail(message);
707 }
708 }
709
710 /* -------------------------------------------------------------------- *
711 * methods concerning subset and containment relations. *
712 * -------------------------------------------------------------------- */
713
714 /**
715 * Fails if <code>actualElement</code> is not an element
716 * of <code>expectedContainer</code>.
717 *
718 * @param expectedContainer
719 * a <code>Collection</code> the object <code>actualElement</code>
720 * is expected to be contained in.
721 * @param actualElement
722 * an instance of an <code>Object</code>.
723 * @throws AssertionFailedError
724 * if <code>actualElement</code>
725 * is not in <code>expectedContainer</code>
726 * and in particular if it is <code>null</code>.
727 */
728 public static <E> void assertIsIn(Collection<E> expectedContainer,
729 Object actualElement) {
730 if (actualElement == null ||
731 !expectedContainer.contains(actualElement)) {
732 fail("Expected an element of <" + expectedContainer +
733 "> but found <" + actualElement + STR_ASTOP);
734 }
735 }
736
737 /**
738 * Fails if <code>actual</code> is not a subcollection
739 * of <code>expected</code>.
740 *
741 * @param expected
742 * a <code>Collection</code>
743 * @param actual
744 * another <code>Collection</code>
745 * @throws AssertionFailedError
746 * if <code>actual</code> is not a subcollection
747 * of <code>expectedContainer</code>.
748 * This includes the cases where a parameter is <code>null</code>.
749 */
750 public static <E> void assertIsContainedAll(Collection<E> expected,
751 Collection<E> actual) {
752 if (expected == null) {
753 fail("Found expected set value null; use assertNull instead. ");
754 }
755
756 if (actual == null) {
757 fail("Tried to perform containment check on null-collection. ");
758 }
759
760 assertTrue("Expected <" + actual +
761 "> to be a subset of <" + expected + STR_ASTOP,
762 expected.containsAll(actual));
763 }
764
765 /* -------------------------------------------------------------------- *
766 * methods: assertions based on comparisons. *
767 * -------------------------------------------------------------------- */
768
769 /**
770 * Fails if <code>expected.compareTo(actual)</code>
771 * is not as expected
772 * and raises an exception if this expression cannot be evaluated.
773 *
774 * @param message
775 * the error message displayed if the test fails regularly,
776 * i.e. if <code>expected.compareTo(actual)</code> can be evaluated
777 * without throwing an exception.
778 * @param cmpObj
779 * The action that decides whether the relation is satisfied.
780 * @param expected
781 * an instance of a <code>Comparable</code>.
782 * @param actual
783 * an <code>Object</code> or <code>null</code>.
784 * Actually this should be a <code>Comparable</code> as well.
785 * @throws IllegalArgumentException
786 * if invoking <code>expected.compareTo(actual)</code>
787 * raises an exception.
788 * In particular for <code>expected == null</code>
789 * @throws IllegalStateException
790 * if <code>expected.compare(actual)</code> is evaluated
791 * for <code>actual == null</code> without throwing an exception
792 * as specified for {@link java.lang.Comparable#compareTo}.
793 * @throws AssertionFailedError
794 * if the value of <code>expected.compareTo(actual)</code>
795 * is not as specified by <code>cmpObj</code>.
796 * @see #assertIs(CmpObj, Comparable, Object)
797 */
798 public static <E> void assertIs(CmpObj cmpObj,
799 String message,
800 Comparable<E> expected,
801 E actual) {
802 if (!(cmpObj.invokeCompareTo(expected, actual))) {
803 fail(message);
804 }
805 }
806
807 /**
808 * Fails if <code>cmp.compare(expected, actual)</code>
809 * is not as expected
810 * and raises an exception if this expression cannot be evaluated.
811 *
812 * @param message
813 * the error message displayed if the test fails regularly,
814 * i.e. if <code>cmp.compare(expected, actual)</code> can be evaluated
815 * without throwing an exception.
816 * @param cmpObj
817 * The action that decides whether the relation is satisfied.
818 * @param expected
819 * an <code>Object</code>.
820 * @param actual
821 * another <code>Object</code>.
822 * @throws IllegalArgumentException
823 * if invoking <code>cmp.compare(expected, actual)</code>
824 * raises an exception.
825 * @throws AssertionFailedError
826 * if the value of <code>cmp.compare(expected, actual)</code>
827 * is not as specified by <code>cmpObj</code>.
828 * @see #assertIs(CmpObj, Object, Object, Comparator)
829 */
830 public static <E> void assertIs(CmpObj cmpObj,
831 String message,
832 E expected,
833 E actual,
834 Comparator<E> cmp) {
835 if (!(cmpObj.isValid(invokeCompare(expected, actual, cmp)))) {
836 fail(message);
837 }
838 }
839
840 /**
841 * Fails if <code>expected.compareTo(actual)</code>
842 * is not as expected
843 * and raises an exception if this expression cannot be evaluated.
844 *
845 * @param cmpObj
846 * The action that decides whether the relation is satisfied.
847 * @param expected
848 * an instance of a <code>Comparable</code>.
849 * @param actual
850 * an <code>Object</code> or <code>null</code>.
851 * Actually this should be a <code>Comparable</code> as well.
852 * @throws IllegalArgumentException
853 * if invoking <code>expected.compareTo(actual)</code>
854 * raises an exception.
855 * In particular for <code>expected == null</code>
856 * @throws IllegalStateException
857 * if <code>expected.compare(actual)</code> is evaluated
858 * for <code>actual == null</code> without throwing an exception
859 * as specified for {@link java.lang.Comparable#compareTo}.
860 * @throws AssertionFailedError
861 * if the value of <code>expected.compareTo(actual)</code>
862 * is not as specified by <code>cmpObj</code>.
863 * @see #assertIs(CmpObj, String, Comparable, Object)
864 */
865 public static <E> void assertIs(CmpObj cmpObj,
866 Comparable<E> expected,
867 E actual) {
868
869 assertIs(cmpObj,
870 "expected: <" + expected +
871 "> to be" + cmpObj.message +
872 ": <" + actual + STR_ASTOP,
873 expected, actual);
874 }
875
876 /**
877 * Fails if <code>cmp.compare(expected, actual)</code>
878 * is not as expected
879 * and raises an exception if this expression cannot be evaluated.
880 *
881 * @param cmpObj
882 * The action that decides whether the relation is satisfied.
883 * @param expected
884 * an <code>Object</code>.
885 * @param actual
886 * another <code>Object</code>.
887 * @throws IllegalArgumentException
888 * if invoking <code>cmp.compare(expected, actual)</code>
889 * raises an exception.
890 * @throws AssertionFailedError
891 * if the value of <code>cmp.compare(expected, actual)</code>
892 * is not as specified by <code>cmpObj</code>.
893 * @see #assertIs(CmpObj, String, Object, Object, Comparator)
894 */
895 public static <E> void assertIs(CmpObj cmpObj,
896 E expected,
897 E actual,
898 Comparator<E> cmp) {
899
900 assertIs(cmpObj,
901 "expected: <" + expected +
902 "> to be" + cmpObj.message +
903 ": <" + actual +
904 "> with respect to the comparator <" + cmp + STR_ASTOP,
905 expected, actual, cmp);
906 }
907
908
909 /**
910 * Returns <code>cmp.compare(expected, actual)</code> if possible.
911 *
912 * @param obj1
913 * an <code>Object</code>.
914 * @param obj2
915 * another <code>Object</code>.
916 * @param cmp
917 * a comparator which is capable of comparing
918 * <code>obj1</code> with <code>obj2</code>.
919 * @return
920 * the <code>int</code> value which results in invoking
921 * <code>cmp.compare(expected, actual)</code>.
922 * @throws IllegalArgumentException
923 * <ul>
924 * <li>
925 * for <code>cmp == null</code>,
926 * <li>
927 * if invoking <code>cmp.compare(expected, actual)</code>
928 * raises an exception.
929 * </ul>
930 */
931 private static <E> int invokeCompare(E obj1,
932 E obj2,
933 Comparator<E> cmp) {
934
935 // Check comparator.
936 if (cmp == null) {
937 throw new IllegalArgumentException
938 ("Found null-comparator . ");
939 }
940 // Here, the comparator is not null.
941
942 Method compare;
943 try {
944 compare = cmp.getClass().getMethod("compare",
945 Object.class,
946 Object.class);
947 } catch (NoSuchMethodException e) {
948 throw new IllegalStateException // NOPMD
949 ("Comparator " + cmp + STR_DN_PROV +
950 "public int compare(Object, Object)\" - impossible. ");
951 }
952 // this is necessary
953 // despite compare(Object, Object) is supposed to be public,
954 // because the including Comparator
955 // may not be accessible from within this Accessor.
956 compare.setAccessible(true);
957
958
959 try {
960 return (Integer) compare.invoke(cmp, obj1, obj2);
961 } catch (IllegalAccessException iace) {
962 thrwAccessible(compare);
963 } catch (IllegalArgumentException iage) {
964 thrwWrongArgs(compare);
965 } catch (InvocationTargetException ite) {
966 throw new IllegalArgumentException// NOPMD
967 ("Could not test ordering because method " + compare +
968 STR_RAISED + ite.getTargetException() + ". ");
969 }
970 throw new IllegalStateException();
971 }
972
973 /**
974 * Throws an error if exactly one of the parameters are <code>null</code>
975 * and otherwise returns whether both are <code>null</code>.
976 *
977 * @param message
978 * the error message used in case the assertion fails.
979 * @param expected
980 * an <code>Object</code>.
981 * @param actual
982 * another <code>Object</code>.
983 * @return
984 * whether both are <code>null</code>,
985 * if either both, <code>expected</code> and <code>actual</code>
986 * are <code>null</code>.
987 * @throws AssertionFailedError
988 * if exactly one of the parameters are <code>null</code>.
989 */
990 private static boolean checkNulls(String message,
991 Object expected,
992 Object actual) {
993
994 if (expected == null ^ actual == null) {
995 fail(message);
996 }
997 return expected == null;
998 }
999
1000 /* -------------------------------------------------------------------- */
1001 /* methods for tests of arrays */
1002 /* -------------------------------------------------------------------- */
1003
1004
1005
1006 /**
1007 * Is a deep version of method
1008 * <code>junit.framework.Assert.assertEquals(Object, Object)</code>
1009 * for arrays: checks
1010 * <ul>
1011 * <li>
1012 * whether the two arguments are arrays and whether they are arrays,
1013 * <li>
1014 * recursively whether the lengths coincide
1015 * and if the entries do so.
1016 * </ul>
1017 *
1018 * @param message
1019 * the error message used in case the assertion fails.
1020 * @param expected
1021 * an array.
1022 * @param actual
1023 * an array.
1024 * @exception IllegalArgumentException
1025 * if <code>expected</code> is not an array.
1026 * @exception AssertionFailedError
1027 * if the types of the two arguments do not coincide
1028 * (e.g. because the second one is not an array).
1029 * See also {@link #assertRecArraysEquals}.
1030 * @throws AssertionFailedError
1031 * if the the two arrays do not coincide in their lenght
1032 * or in some entry.
1033 */
1034 public static void assertArraysEquals(String message,
1035 Object expected,
1036 Object actual) {
1037
1038
1039 try {
1040 assertArraysEquals(expected, actual);
1041 } catch (AssertionFailedError e) {
1042 fail(message);
1043 }
1044 }
1045
1046 public static void assertArraysEquals(Object expected,
1047 Object actual) {
1048
1049 // Exclude the case that either "expected" or "actual" is null.
1050 if (checkNulls(expectedActual(expected, actual) + ". ",
1051 expected,
1052 actual)) {
1053 return;
1054 }
1055 // Here, neither "expected" nor "actual" is null.
1056
1057 checkArraysSameClass(expected, actual);
1058 // Here, both are arrays or neither of them.
1059 assertRecArraysEquals(expected, actual, new int[0]);
1060 }
1061
1062 /**
1063 * Checks whether <code>expected</code> is an array
1064 * and whether its type coincides with the type of <code>actual</code>.
1065 * If not an exception is thrown.
1066 * Invokes {@link #fail} if the types of <code>expected</code>
1067 * and of <code>actual</code> do not coincide.
1068 *
1069 * @param expected
1070 * the expected array.
1071 * @param actual
1072 * the actual array.
1073 * @throws IllegalArgumentException
1074 * if <code>expected</code> is not an array.
1075 */
1076 private static void checkArraysSameClass(Object expected,
1077 Object actual) {
1078 if (!expected.getClass().isArray()) {
1079 throw new IllegalArgumentException
1080 ("Array expected; found type " + expected.getClass() + ". ");
1081 }
1082
1083 if (!expected.getClass().equals(actual.getClass())) {
1084 fail("expected class: <" + expected.getClass() +
1085 STR_BUTWAS + actual.getClass() + STR_ASTOP);
1086 }
1087 }
1088
1089 /**
1090 * Is a deep version of method
1091 * <code>junit.framework.Assert.assertEquals(Object, Object)</code>
1092 * for arrays:
1093 * checks recursively whether the lengths coincide
1094 * and if the entries do so.
1095 * Contract: the classes of the two arguments coincide
1096 * and both are arrays.
1097 *
1098 * @param expected
1099 * the expected array.
1100 * @param actual
1101 * the actual array.
1102 * @param indices
1103 * contains the list of indices of the arrays
1104 * <code>expected</code> and <code>actual</code>
1105 * within the arrays comprising them.
1106 * The recursion starts with <code>indices = new int[] {}</code>.
1107 * @throws AssertionFailedError
1108 * if the the two arrays do not coincide in their lenght
1109 * or in some entry.
1110 */
1111 private static void assertRecArraysEquals(Object expected,
1112 Object actual,
1113 int[] indices) {
1114
1115 if (Array.getLength(expected) != Array.getLength(actual)) {
1116
1117 fail(failLengthMessage(expected, actual, indices));
1118 //fail("expected length: <" + Array.getLength(expected) +
1119 // STR_BUTWAS + Array.getLength(actual) + STR_ASTOP);
1120 }
1121 // Here, both are arrays and their lengths coincide.
1122
1123 // Check the entries of the arrays.
1124 Object expectedEntry;
1125 Object actualEntry;
1126 for (int i = 0; i < Array.getLength(expected); i++) {
1127 // Check the i-th entries.
1128
1129 // This works even for primitive types.
1130 // Instead their wrappers are returned.
1131 expectedEntry = Array.get(expected, i);
1132 actualEntry = Array.get(actual, i);
1133
1134 int[] newInd = new int[indices.length + 1];
1135 System.arraycopy(indices, 0, newInd, 0, indices.length);
1136 newInd[newInd.length - 1] = i;
1137
1138 if (checkNulls(failMessage(expectedEntry, actualEntry, newInd),
1139 expectedEntry, actualEntry)) {
1140 return;
1141 }
1142 // Here, neither "expectedEntry" nor "actualEntry" is null.
1143
1144 if (expectedEntry.getClass().isArray()) {
1145 // Here, both of the objects are arrays with the same type.
1146 // Exclude that either "expected" or "actual" is null.
1147
1148 assertRecArraysEquals(expectedEntry,
1149 actualEntry,
1150 newInd);
1151 } else {
1152 // Here, neither of the objects are arrays
1153 // (but their types coincide).
1154
1155 assertEquals(failMessage(expectedEntry, actualEntry, newInd),
1156 expectedEntry, actualEntry);
1157 }
1158 }
1159 }
1160
1161 /*
1162 private static String getEntries(int[] indices) {
1163
1164 // Determine indices of entry
1165 StringBuffer message = new StringBuffer();
1166 if (indices.length == 0) {
1167 return null;
1168 }
1169 message.append("In entry [" + indices[0]);
1170 for (int j = 1; j < indices.length; j++) {
1171 message.append(", " + indices[j]);
1172 }
1173 message.append("]");
1174 return message.toString();
1175 }
1176 */
1177
1178 private static String failInd(int[] indices) {
1179
1180 StringBuffer message = new StringBuffer();
1181 // Determine indices of entry
1182 if (indices.length > 0) {
1183 message.append("In entry [");
1184 for (int j = 0; j < indices.length - 1; j++) {
1185 message.append("" + indices[j] + ", ");
1186 }
1187 message.append("" + indices[indices.length - 1] + "] expected ");
1188 } else {
1189 message.append("Expected ");
1190 }
1191 return message.toString();
1192 }
1193
1194
1195 private static String failLengthMessage(Object expectedEntry,
1196 Object actualEntry,
1197 int[] indices) {
1198 StringBuffer message = new StringBuffer();
1199 // Determine indices of entry
1200 message.append(failInd(indices));
1201
1202 // ""+obj works for null; obj.toString() does not
1203 message.append("array with length <");
1204 message.append(Array.getLength(expectedEntry));
1205 message.append("> but was array with length <");
1206 message.append(Array.getLength(actualEntry));
1207 message.append(STR_ASTOP);
1208 return message.toString();
1209 }
1210
1211 private static String failMessage(Object expectedEntry,
1212 Object actualEntry,
1213 int[] indices) {
1214
1215 // Determine indices of entry
1216 StringBuffer message = new StringBuffer();
1217 // Determine indices of entry
1218 message.append(failInd(indices));
1219
1220 // ""+obj works for null; obj.toString() does not
1221 message.append(" <");
1222 message.append(expectedEntry);
1223 message.append(STR_BUTWAS);
1224 message.append(actualEntry);
1225 message.append(STR_ASTOP);
1226 return message.toString();
1227 }
1228
1229 /**
1230 * Returns a failure message indicating that
1231 * in comparing nested arrays of final float type
1232 * as <code>double[][]</code>,
1233 * the corresponding entries given by index path <code>indices</code>
1234 * deviate at least <code>delta</code>.
1235 *
1236 */
1237 // used in assertRecArraysEquals(Object, Object, int[], double)
1238 private static String failMessageDelta(double expectedEntry,
1239 double actualEntry,
1240 int[] indices,
1241 double delta) {
1242
1243 // Determine indices of entry
1244 StringBuffer message = new StringBuffer();
1245 if (indices.length > 0) {
1246 message.append("In entry [");
1247 for (int j = 0; j < indices.length - 1; j++) {
1248 message.append(indices[j]);
1249 message.append(", ");
1250 }
1251 message.append(indices[indices.length - 1]); // NOPMD
1252 message.append("] expected <");
1253 } else {
1254 message.append("Expected <");
1255 }
1256
1257 // ""+obj works for null; obj.toString() does not
1258 message.append(expectedEntry);
1259 message.append(STR_BUTWAS);
1260 message.append(actualEntry);
1261 message.append(">: deviation exceeds ");
1262 message.append(delta);
1263 message.append(STR_IN_ABS_VAL);
1264 return message.toString();
1265 }
1266
1267 private static String failMessageLength(int expectedLen,
1268 int actualLen,
1269 int[] indices) {
1270 // Determine indices of entry
1271 StringBuffer message = new StringBuffer();
1272 if (indices.length > 0) {
1273 message.append("In entry [");
1274 for (int j = 0; j < indices.length - 1; j++) {
1275 message.append(indices[j]);
1276 message.append(", ");
1277 }
1278 message.append(indices[indices.length - 1]); // NOPMD
1279 message.append("] expected lengths <");
1280 } else {
1281 message.append("Expected lengths <");
1282 }
1283
1284 // ""+obj works for null; obj.toString() does not
1285 message.append(expectedLen);
1286 message.append(STR_BUTWAS);
1287 message.append(actualLen);
1288 message.append(STR_ASTOP);
1289 return message.toString();
1290 }
1291
1292
1293 /**
1294 * Is a deep version of method
1295 * <code>junit.framework.Assert.assertEquals(Object, Object)</code>
1296 * for arrays: checks
1297 * <ul>
1298 * <li>
1299 * whether the two arguments are arrays and whether they are arrays,
1300 * <li>
1301 * recursively whether the lengths coincide
1302 * and if the entries do so.
1303 * </ul>
1304 *
1305 * @param expected
1306 * the expected array.
1307 * @param actual
1308 * the actual array
1309 * which is assumed to be of same type as <code>expected</code>.
1310 * @param delta
1311 * the allowed deviation as a <code>double</code> value.
1312 * @exception IllegalArgumentException
1313 * if <code>expected</code> is not an array.
1314 * @exception AssertionFailedError
1315 * if the types of the two arguments do not coincide
1316 * (e.g. because the second one is not an array).
1317 * See also {@link #assertRecArraysEquals}.
1318 * @throws AssertionFailedError
1319 * if the the two arrays do not coincide in their lenght
1320 * or in some entry.
1321 */
1322 public static void assertArraysEquals(Object expected,
1323 Object actual,
1324 double delta) {
1325
1326 checkArraysSameClass(expected, actual);
1327 // Here, both are arrays or neither of them.
1328 assertRecArraysEquals(expected, actual, new int[0], delta);
1329 }
1330
1331 /**
1332 * Is a deep version of method
1333 * <code>junit.framework.Assert.assertEquals(Object, Object)</code>
1334 * for arrays:
1335 * checks recursively whether the lengths coincide
1336 * and if the entries do so.
1337 * Contract: the classes of the two arguments coincide
1338 * and both are arrays.
1339 *
1340 * @param expected
1341 * the expected array.
1342 * @param actual
1343 * the actual array
1344 * which is assumed to be of same type as <code>expected</code>.
1345 * @param indices
1346 * contains the list of indices of the arrays
1347 * <code>expected</code> and <code>actual</code>
1348 * within the arrays comprising them.
1349 * The recursion starts with <code>indices = new int[] {}</code>.
1350 * This is for generating an appropriate message
1351 * for an <code>AssertionFailedError</code>.
1352 * @param delta
1353 * the allowed deviation as a <code>double</code> value.
1354 * @throws IllegalArgumentException
1355 * if <code>expected</code> or <code>actual</code> is not an array.
1356 * @throws AssertionFailedError
1357 * if the the two arrays do not coincide in their length
1358 * or in some entry.
1359 * @throws eu.simuline.util.NotYetImplementedException
1360 * if <code>expected</code> is not 'finally' of primitive type.
1361 */
1362 private static void assertRecArraysEquals(Object expected,
1363 Object actual,
1364 int[] indices,
1365 double delta) {
1366
1367 // throws IllegalArgumentException if not an array
1368 if (Array.getLength(expected) != Array.getLength(actual)) {
1369 fail(failMessageLength(Array.getLength(expected),
1370 Array.getLength(actual),
1371 indices));
1372 }
1373 // Here, both are arrays and their lengths coincide.
1374
1375 // Check the entries of the arrays.
1376 Object expectedEntry;
1377 Object actualEntry;
1378 for (int i = 0; i < Array.getLength(expected); i++) {
1379 // Check the i-th entries.
1380
1381 // This works even for primitive types.
1382 // Instead their wrappers are returned.
1383 expectedEntry = Array.get(expected, i);
1384 actualEntry = Array.get(actual, i);
1385
1386 int[] newInd = new int[indices.length + 1];
1387 System.arraycopy(indices, 0, newInd, 0, indices.length);
1388 newInd[newInd.length - 1] = i;
1389
1390 Class<?> entryClass = expectedEntry.getClass();
1391 if (entryClass.isArray()) {
1392 // Here, both of the objects are arrays with the same type.
1393 assertRecArraysEquals(expectedEntry, actualEntry,
1394 newInd, delta);
1395 return;
1396 }
1397
1398 // Here, neither of the objects are arrays
1399 // (but their types coincide).
1400 if (entryClass.isPrimitive()) {
1401 // primitive: unwrap before use.
1402 if (entryClass == Double.TYPE) {
1403 assertEquals(failMessageDelta((double) expectedEntry,
1404 (double) actualEntry,
1405 newInd,
1406 delta),
1407 (double) expectedEntry,
1408 (double) actualEntry,
1409 delta);
1410 } else if (entryClass == Float.TYPE) {
1411 assertEquals(failMessageDelta((double) expectedEntry,
1412 (double) actualEntry,
1413 newInd,
1414 delta),
1415 (float) expectedEntry,
1416 (float) actualEntry,
1417 (float) delta);
1418 } else {
1419 throw new IllegalArgumentException
1420 ("For primitive type " + entryClass +
1421 " no method assertEquals(" + entryClass +
1422 "," + entryClass + "," + entryClass +
1423 ") exists. ");
1424 }
1425 } else {
1426 // not primitive: use as is.
1427 // **** no, this requires a special norm or metric
1428 // and can thus not be handled uniformly.
1429 throw new eu.simuline.util.NotYetImplementedException();
1430 // ("Primitive type expected; found " +
1431 // expectedEntry.getClass() + ". ");
1432 // assertEquals(failMessage(expectedEntry,
1433 // actualEntry,
1434 // newInd),
1435 // expectedEntry,actualEntry,delta);
1436 } // else
1437 } // for
1438 }
1439
1440 /**
1441 * Returns whether the relative deviation
1442 * between <code>expected</code> and <code>actual</code>
1443 * exceeds <code>reldiv</code> in absolute value.
1444 *
1445 * @param expected
1446 * the <code>double</code> value expected.
1447 * This may be neither <code>0.0</code>, nor an infinite value
1448 * nor <code>NaN</code>.
1449 * @param actual
1450 * the actual <code>double</code> value.
1451 * @param reldev
1452 * the maximum relative deviation
1453 * between <code>expected</code> and <code>actual</code>.
1454 * This must be a non-negative value;
1455 * in particular, <code>NaN</code> is not allowed.
1456 * @return
1457 * whether the relative deviation
1458 * between <code>expected</code> and <code>actual</code>
1459 * exceeds <code>reldiv</code> in absolute value.
1460 * @throws IllegalArgumentException
1461 * <ul>
1462 * <li>
1463 * if <code>expected</code> is either <code>0.0</code>,
1464 * infinite or <code>NaN</code>.
1465 * <li>
1466 * if <code>reldev</code> is negative or <code>NaN</code>.
1467 * </ul>
1468 * @see #assertRelEquals(String, double, double, double)
1469 */
1470 public static boolean testRelEquals(double expected,
1471 double actual,
1472 double reldev) {
1473 if (expected == 0.0 ||
1474 Double.isInfinite(expected) ||
1475 Double.isNaN(expected)) {
1476 throw new IllegalArgumentException
1477 ("Relative deviation for expected value <" +
1478 expected + "> is not defined. ");
1479 }
1480
1481 if (Double.isNaN(reldev) || reldev < 0.0) {
1482 throw new IllegalArgumentException
1483 ("The relative deviation may not be <" + reldev + STR_ASTOP);
1484 }
1485
1486 return Math.abs((expected - actual) / expected) <= reldev;
1487 }
1488
1489 /**
1490 * Fails if the relative deviation
1491 * between <code>expected</code> and <code>actual</code>
1492 * exceeds <code>reldiv</code> in absolute value.
1493 *
1494 * @param message
1495 * the error message used in case the assertion fails.
1496 * @param expected
1497 * the <code>double</code> value expected.
1498 * This may be neither <code>0.0</code>, nor an infinite value
1499 * nor <code>NaN</code>.
1500 * @param actual
1501 * the actual <code>double</code> value.
1502 * @param reldev
1503 * the maximum relative deviation
1504 * between <code>expected</code> and <code>actual</code>.
1505 * This must be a non-negative value;
1506 * in particular, <code>NaN</code> is not allowed.
1507 * @throws IllegalArgumentException
1508 * <ul>
1509 * <li>
1510 * if <code>expected</code> is either <code>0.0</code>,
1511 * infinite or <code>NaN</code>.
1512 * <li>
1513 * if <code>reldev</code> is negative or <code>NaN</code>.
1514 * </ul>
1515 * @see #assertRelEquals(double, double, double)
1516 * @see #testRelEquals(double, double, double)
1517 */
1518 public static void assertRelEquals(String message,
1519 double expected,
1520 double actual,
1521 double reldev) {
1522 if (!testRelEquals(expected, actual, reldev)) {
1523 fail(message);
1524 }
1525 }
1526
1527 /**
1528 * Fails reporting a standard message if the relative deviation
1529 * between <code>expected</code> and <code>actual</code>
1530 * exceeds <code>reldiv</code> in absolute value.
1531 *
1532 * @param expected
1533 * the <code>double</code> value expected.
1534 * This may be neither <code>0.0</code>, nor an infinite value
1535 * nor <code>NaN</code>.
1536 * @param actual
1537 * the actual <code>double</code> value.
1538 * @param reldev
1539 * the maximum relative deviation
1540 * between <code>expected</code> and <code>actual</code>.
1541 * This must be a non-negative value;
1542 * in particular, <code>NaN</code> is not allowed.
1543 * @throws IllegalArgumentException
1544 * <ul>
1545 * <li>
1546 * if <code>expected</code> is either <code>0.0</code>,
1547 * infinite or <code>NaN</code>.
1548 * <li>
1549 * if <code>reldev</code> is negative or <code>NaN</code>.
1550 * </ul>
1551 * @see #assertRelEquals(String, double, double, double)
1552 */
1553 public static void assertRelEquals(double expected,
1554 double actual,
1555 double reldev) {
1556 assertRelEquals(expectedActual(expected, actual) +
1557 "; relative deviation <" +
1558 ((expected - actual) / expected) +
1559 "> exceeds <" + reldev + "> in absolute value. ",
1560 expected, actual, reldev);
1561 }
1562
1563 /**
1564 * For <code>expected<= separateAbsRel</code> behaves like
1565 * {@link junit.framework.Assert#assertEquals(String,double,double,double)}
1566 * ignoring <code>reldev</code>, whereas otherwise behaves like
1567 * {@link #assertEquals(String, double, double, double)}
1568 * ignoring <code>absdev</code>.
1569 *
1570 * @param message
1571 * the error message used in case the assertion fails.
1572 * @param expected
1573 * the <code>double</code> value expected.
1574 * @param separateAbsRel
1575 * a non-negative <code>double</code> value
1576 * separating the two parts of the domain of this method.
1577 * @param actual
1578 * the actual <code>double</code> value.
1579 * @param absdev
1580 * the maximum absolute deviation
1581 * between <code>expected</code> and <code>actual</code>.
1582 * This is relevant for <code>expected<= separateAbsRel</code>
1583 * but ignored otherwise.
1584 * @param reldev
1585 * the maximum relative deviation
1586 * between <code>expected</code> and <code>actual</code>.
1587 * This is relevant for <code>expected > separateAbsRel</code>
1588 * but ignored otherwise.
1589 * @throws IllegalArgumentException
1590 * for <code>separateAbsRel < 0</code>.
1591 */
1592 public static void assertAbsRelEquals(String message,
1593 double expected,
1594 double separateAbsRel,
1595 double actual,
1596 double absdev,
1597 double reldev) {
1598 if (separateAbsRel < 0) {
1599 throw new IllegalArgumentException
1600 ("Found negative separator " + separateAbsRel + ". ");
1601 }
1602 if (Math.abs(expected) <= separateAbsRel) {
1603 assertEquals (message, expected, actual, absdev);
1604 } else {
1605 assertRelEquals(message, expected, actual, reldev);
1606 }
1607 }
1608
1609 /**
1610 * For <code>expected<= separateAbsRel</code> behaves like
1611 * {@link junit.framework.Assert#assertEquals(String,double,double,double)}
1612 * ignoring <code>reldev</code>, whereas otherwise behaves like
1613 * {@link #assertEquals(String, double, double, double)}
1614 * ignoring <code>absdev</code>.
1615 *
1616 * @param expected
1617 * the <code>double</code> value expected.
1618 * @param separateAbsRel
1619 * a non-negative <code>double</code> value
1620 * separating the two parts of the domain of this method.
1621 * @param actual
1622 * the actual <code>double</code> value.
1623 * @param absdev
1624 * the maximum absolute deviation
1625 * between <code>expected</code> and <code>actual</code>.
1626 * This is relevant for <code>expected<= separateAbsRel</code>
1627 * but ignored otherwise.
1628 * @param reldev
1629 * the maximum relative deviation
1630 * between <code>expected</code> and <code>actual</code>.
1631 * This is relevant for <code>expected > separateAbsRel</code>
1632 * but ignored otherwise.
1633 * @throws IllegalArgumentException
1634 * for <code>separateAbsRel < 0</code>.
1635 */
1636 public static void assertAbsRelEquals(double expected,
1637 double separateAbsRel,
1638 double actual,
1639 double absdev,
1640 double reldev) {
1641 if (separateAbsRel < 0) {
1642 throw new IllegalArgumentException
1643 ("Found negative separator " + separateAbsRel + ". ");
1644 }
1645 if (Math.abs(expected) <= separateAbsRel) {
1646 assertEquals (expected, actual, absdev);
1647 } else {
1648 assertRelEquals(expected, actual, reldev);
1649 }
1650 }
1651
1652 /**
1653 * Returns whether the absolute deviation
1654 * between <code>expected</code> and <code>actual</code>
1655 * exceeds <code>absdiv</code> in absolute value.
1656 *
1657 * @param expected
1658 * the <code>double</code> value expected.
1659 * This may not be <code>NaN</code>.
1660 * @param actual
1661 * the actual <code>double</code> value.
1662 * @param absdev
1663 * the maximum absolute deviation
1664 * between <code>expected</code> and <code>actual</code>.
1665 * This must be a non-negative value;
1666 * in particular, <code>NaN</code> is not allowed.
1667 * @return
1668 * whether the absolute deviation
1669 * between <code>expected</code> and <code>actual</code>
1670 * exceeds <code>absdiv</code> in absolute value.
1671 * @throws IllegalArgumentException
1672 * <ul>
1673 * <li>
1674 * if <code>expected</code> is <code>NaN</code>.
1675 * <li>
1676 * if <code>absdev</code> is negative or <code>NaN</code>.
1677 * </ul>
1678 * @see #assertAbsEquals(String, double, double, double)
1679 */
1680 public static boolean testAbsEquals(double expected,
1681 double actual,
1682 double absdev) {
1683 if (Double.isNaN(expected)) {
1684 throw new IllegalArgumentException
1685 ("Absolute deviation for expected value <" +
1686 expected + "> is not defined. ");
1687 }
1688
1689 if (Double.isNaN(absdev) || absdev < 0.0) {
1690 throw new IllegalArgumentException
1691 ("The absolute deviation may not be <" + absdev + STR_ASTOP);
1692 }
1693
1694 if (Double.isInfinite(expected)) {
1695 return expected == actual;
1696 }
1697
1698
1699 return Math.abs(expected - actual) <= absdev;
1700 }
1701
1702 /**
1703 * Fails if the absolute deviation
1704 * between <code>expected</code> and <code>actual</code>
1705 * exceeds <code>absdiv</code> in absolute value.
1706 *
1707 * @param message
1708 * the error message used in case the assertion fails.
1709 * @param expected
1710 * the <code>double</code> value expected.
1711 * This may not be neither <code>NaN</code>.
1712 * @param actual
1713 * the actual <code>double</code> value.
1714 * @param absdev
1715 * the maximum absolute deviation
1716 * between <code>expected</code> and <code>actual</code>.
1717 * This must be a non-negative value;
1718 * in particular, <code>NaN</code> is not allowed.
1719 * @throws IllegalArgumentException
1720 * <ul>
1721 * <li>
1722 * if <code>expected</code> is <code>NaN</code>.
1723 * <li>
1724 * if <code>absdev</code> is negative or <code>NaN</code>.
1725 * </ul>
1726 * @see #assertAbsEquals(double, double, double)
1727 * @see #testAbsEquals(double, double, double)
1728 */
1729 public static void assertAbsEquals(String message,
1730 double expected,
1731 double actual,
1732 double absdev) {
1733 if (!testAbsEquals(expected, actual, absdev)) {
1734 fail(message);
1735 }
1736 }
1737
1738 /**
1739 * Fails if the absolute deviation
1740 * between <code>expected</code> and <code>actual</code>
1741 * exceeds <code>absdiv</code> in absolute value.
1742 *
1743 * @param expected
1744 * the <code>double</code> value expected.
1745 * This may not be neither <code>NaN</code>.
1746 * @param actual
1747 * the actual <code>double</code> value.
1748 * @param absdev
1749 * the maximum absolute deviation
1750 * between <code>expected</code> and <code>actual</code>.
1751 * This must be a non-negative value;
1752 * in particular, <code>NaN</code> is not allowed.
1753 * @throws IllegalArgumentException
1754 * <ul>
1755 * <li>
1756 * if <code>expected</code> is <code>NaN</code>.
1757 * <li>
1758 * if <code>absdev</code> is negative or <code>NaN</code>.
1759 * </ul>
1760 * @see #assertAbsEquals(String, double, double, double)
1761 */
1762 public static void assertAbsEquals(double expected,
1763 double actual,
1764 double absdev) {
1765 assertAbsEquals(expectedActual(expected, actual) +
1766 "; absolute deviation <" +
1767 ((expected - actual)) +
1768 "> exceeds <" + absdev + "> in absolute value. ",
1769 expected, actual, absdev);
1770 }
1771
1772 /**
1773 * Special case of <code>assertEquals(Object, Object)</code>
1774 * which provides an error message specifying the common prefix
1775 * of <code>expected</code> with <code>actual</code>.
1776 * This is suitable for keeping long strings under control.
1777 * If one of the arguments is <code>null</code>,
1778 * this method behaves like
1779 * {@link junit.framework.Assert#assertEquals(Object, Object)}.
1780 *
1781 * @param expected
1782 * the <code>String</code> expected.
1783 * This ma
1784 * @param actual
1785 * a <code>String</code> value
1786 */
1787 public static void assertStringEquals(String expected, String actual) {
1788 if (expected == null || actual == null) {
1789 assertEquals(expected, actual);
1790 }
1791 // Here, neither expected nor actual is null.
1792
1793 int minLen = Math.min(expected.length(), actual.length());
1794 for (int i = 0; i < minLen; i++) {
1795 if (expected.charAt(i) != actual.charAt(i)) {
1796 throw new AssertionFailedError
1797 (expectedActual(expected, actual) + ". " +
1798 "Common prefix is <" +
1799 expected.substring(0, i) + STR_ASTOP);
1800 }
1801 } // end of for ()
1802
1803 if (expected.length() < actual.length()) {
1804 throw new AssertionFailedError
1805 ("Expected: <" + expected +
1806 "> but was prolongation <" + actual + STR_ASTOP);
1807 }
1808
1809 if (expected.length() > actual.length()) {
1810 throw new AssertionFailedError
1811 ("Expected: <" + expected +
1812 "> but was prefix <" + actual + STR_ASTOP);
1813 }
1814 }
1815
1816
1817 public static double test() {
1818 return Double.NaN;
1819 }
1820
1821 // public static void main(String[] args) throws Exception {
1822 // Double res = (Double)Assert.class.getMethod("test").invoke(null);
1823 // }
1824 }
1825
1826 // Assert.java:63: warning: [deprecation]
1827 // Assert in junit.framework has been deprecated
1828 // public abstract class Assert<E> extends junit.framework.Assert {
1829 // ^
1830 // 1 warning
1831
1832 // Compilation finished at Tue Jun 21 20:36:15