View Javadoc
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&lt;= 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&lt;= 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 &gt; separateAbsRel</code> 
1588      *    but ignored otherwise. 
1589      * @throws IllegalArgumentException 
1590      *    for <code>separateAbsRel &lt; 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&lt;= 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&lt;= 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 &gt; separateAbsRel</code> 
1632      *    but ignored otherwise. 
1633      * @throws IllegalArgumentException 
1634      *    for <code>separateAbsRel &lt; 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