1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.io.ObjectInputStream;
24  import java.io.ObjectOutputStream;
25  
26  import junit.framework.Assert;
27  import junit.framework.AssertionFailedError;
28  
29  import org.apache.commons.math.complex.Complex;
30  import org.apache.commons.math.complex.ComplexFormat;
31  import org.apache.commons.math.linear.FieldMatrix;
32  import org.apache.commons.math.linear.RealMatrix;
33  
34  /**
35   * @version $Revision: 776939 $ $Date: 2009-05-20 23:17:52 -0400 (Wed, 20 May 2009) $
36   */
37  public class TestUtils {
38      /**
39       * Collection of static methods used in math unit tests.
40       */
41      private TestUtils() {
42          super();
43      }
44  
45      /**
46       * Verifies that expected and actual are within delta, or are both NaN or
47       * infinities of the same sign.
48       */
49      public static void assertEquals(double expected, double actual, double delta) {
50          assertEquals(null, expected, actual, delta);
51      }
52  
53      /**
54       * Verifies that expected and actual are within delta, or are both NaN or
55       * infinities of the same sign.
56       */
57      public static void assertEquals(String msg, double expected, double actual, double delta) {
58          // check for NaN
59          if(Double.isNaN(expected)){
60              Assert.assertTrue("" + actual + " is not NaN.",
61                  Double.isNaN(actual));
62          } else {
63              Assert.assertEquals(msg, expected, actual, delta);
64          }
65      }
66      
67      /**
68       * Verifies that the two arguments are exactly the same, either
69       * both NaN or infinities of same sign, or identical floating point values.
70       */
71      public static void assertSame(double expected, double actual) {
72       assertEquals(expected, actual, 0);
73      }
74      
75      /**
76       * Verifies that real and imaginary parts of the two complex arguments
77       * are exactly the same.  Also ensures that NaN / infinite components match.
78       */
79      public static void assertSame(Complex expected, Complex actual) {
80          assertSame(expected.getReal(), actual.getReal());
81          assertSame(expected.getImaginary(), actual.getImaginary());
82      }
83      
84      /**
85       * Verifies that real and imaginary parts of the two complex arguments
86       * differ by at most delta.  Also ensures that NaN / infinite components match.
87       */
88      public static void assertEquals(Complex expected, Complex actual, double delta) {
89          assertEquals(expected.getReal(), actual.getReal(), delta);
90          assertEquals(expected.getImaginary(), actual.getImaginary(), delta);
91      }
92      
93      /**
94       * Verifies that two double arrays have equal entries, up to tolerance
95       */
96      public static void assertEquals(double expected[], double observed[], double tolerance) {
97          assertEquals("Array comparison failure", expected, observed, tolerance);
98      }
99      
100     /**
101      * Serializes an object to a bytes array and then recovers the object from the bytes array.
102      * Returns the deserialized object.
103      * 
104      * @param o  object to serialize and recover
105      * @return  the recovered, deserialized object
106      */
107     public static Object serializeAndRecover(Object o) {
108         try {
109             // serialize the Object
110             ByteArrayOutputStream bos = new ByteArrayOutputStream();
111             ObjectOutputStream so = new ObjectOutputStream(bos);
112             so.writeObject(o);
113 
114             // deserialize the Object
115             ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
116             ObjectInputStream si = new ObjectInputStream(bis);
117             return si.readObject();
118         } catch (IOException ioe) {
119             return null;
120         } catch (ClassNotFoundException cnfe) {
121             return null;
122         }
123     }
124     
125     /**
126      * Verifies that serialization preserves equals and hashCode.
127      * Serializes the object, then recovers it and checks equals and hash code.
128      * 
129      * @param object  the object to serialize and recover
130      */
131     public static void checkSerializedEquality(Object object) {
132         Object object2 = serializeAndRecover(object);
133         Assert.assertEquals("Equals check", object, object2);
134         Assert.assertEquals("HashCode check", object.hashCode(), object2.hashCode());
135     }
136 
137     /**
138      * Verifies that the relative error in actual vs. expected is less than or
139      * equal to relativeError.  If expected is infinite or NaN, actual must be
140      * the same (NaN or infinity of the same sign).
141      * 
142      * @param expected expected value
143      * @param actual  observed value
144      * @param relativeError  maximum allowable relative error
145      */
146     public static void assertRelativelyEquals(double expected, double actual,
147             double relativeError) {
148         assertRelativelyEquals(null, expected, actual, relativeError);
149     }
150     
151     /**
152      * Verifies that the relative error in actual vs. expected is less than or
153      * equal to relativeError.  If expected is infinite or NaN, actual must be
154      * the same (NaN or infinity of the same sign).
155      * 
156      * @param msg  message to return with failure
157      * @param expected expected value
158      * @param actual  observed value
159      * @param relativeError  maximum allowable relative error
160      */
161     public static void assertRelativelyEquals(String msg, double expected,
162             double actual, double relativeError) {
163         if (Double.isNaN(expected)) {
164             Assert.assertTrue(msg, Double.isNaN(actual));
165         } else if (Double.isNaN(actual)) {
166             Assert.assertTrue(msg, Double.isNaN(expected));
167         } else if (Double.isInfinite(actual) || Double.isInfinite(expected)) {
168             Assert.assertEquals(expected, actual, relativeError);
169         } else if (expected == 0.0) {
170             Assert.assertEquals(msg, actual, expected, relativeError);
171         } else {
172             double x = Math.abs((expected - actual) / expected);
173             Assert.assertEquals(msg, 0.0, x, relativeError);
174         }
175     }
176     
177     /**
178      * Fails iff values does not contain a number within epsilon of z.
179      * 
180      * @param msg  message to return with failure
181      * @param values complex array to search
182      * @param z  value sought
183      * @param epsilon  tolerance
184      */
185     public static void assertContains(String msg, Complex[] values,
186             Complex z, double epsilon) {
187         int i = 0;
188         boolean found = false;
189         while (!found && i < values.length) {
190             try {
191                 assertEquals(values[i], z, epsilon);
192                 found = true; 
193             } catch (AssertionFailedError er) {
194                 // no match
195             }
196             i++;
197         }
198         if (!found) {
199             Assert.fail(msg + 
200                 " Unable to find " + ComplexFormat.formatComplex(z));
201         }
202     }
203     
204     /**
205      * Fails iff values does not contain a number within epsilon of z.
206      * 
207      * @param values complex array to search
208      * @param z  value sought
209      * @param epsilon  tolerance
210      */
211     public static void assertContains(Complex[] values,
212             Complex z, double epsilon) {
213         assertContains(null, values, z, epsilon);      
214     }
215     
216     /**
217      * Fails iff values does not contain a number within epsilon of x.
218      * 
219      * @param msg  message to return with failure
220      * @param values double array to search
221      * @param x value sought
222      * @param epsilon  tolerance
223      */
224     public static void assertContains(String msg, double[] values,
225             double x, double epsilon) {
226         int i = 0;
227         boolean found = false;
228         while (!found && i < values.length) {
229             try {
230                 assertEquals(values[i], x, epsilon);
231                 found = true; 
232             } catch (AssertionFailedError er) {
233                 // no match
234             }
235             i++;
236         }
237         if (!found) {
238             Assert.fail(msg + " Unable to find" + x);
239         }
240     }
241     
242     /**
243      * Fails iff values does not contain a number within epsilon of x.
244      * 
245      * @param values double array to search
246      * @param x value sought
247      * @param epsilon  tolerance
248      */
249     public static void assertContains(double[] values, double x,
250             double epsilon) {
251        assertContains(null, values, x, epsilon);
252     }
253     
254     /** verifies that two matrices are close (1-norm) */              
255     public static void assertEquals(String msg, RealMatrix expected, RealMatrix observed,
256         double tolerance) {
257         
258         if (observed == null) {
259             Assert.fail(msg + "\nObserved is null");
260         }
261         
262         if (expected.getColumnDimension() != observed.getColumnDimension() || 
263                 expected.getRowDimension() != observed.getRowDimension()) {
264             StringBuffer messageBuffer = new StringBuffer(msg);
265             messageBuffer.append("\nObserved has incorrect dimensions."); 
266             messageBuffer.append("\nobserved is " + observed.getRowDimension() +
267                     " x " + observed.getColumnDimension());
268             messageBuffer.append("\nexpected " + expected.getRowDimension() +
269                     " x " + expected.getColumnDimension());
270             Assert.fail(messageBuffer.toString());
271         }
272 
273         RealMatrix delta = expected.subtract(observed);
274         if (delta.getNorm() >= tolerance) {
275             StringBuffer messageBuffer = new StringBuffer(msg);
276             messageBuffer.append("\nExpected: " + expected);
277             messageBuffer.append("\nObserved: " + observed);
278             messageBuffer.append("\nexpected - observed: " + delta);
279             Assert.fail(messageBuffer.toString());
280         }
281     }
282     
283     /** verifies that two matrices are equal */              
284     public static void assertEquals(FieldMatrix<? extends FieldElement<?>> expected,
285                                     FieldMatrix<? extends FieldElement<?>> observed) {
286         
287         if (observed == null) {
288             Assert.fail("Observed is null");
289         }
290         
291         if (expected.getColumnDimension() != observed.getColumnDimension() || 
292                 expected.getRowDimension() != observed.getRowDimension()) {
293             StringBuffer messageBuffer = new StringBuffer();
294             messageBuffer.append("Observed has incorrect dimensions."); 
295             messageBuffer.append("\nobserved is " + observed.getRowDimension() +
296                     " x " + observed.getColumnDimension());
297             messageBuffer.append("\nexpected " + expected.getRowDimension() +
298                     " x " + expected.getColumnDimension());
299             Assert.fail(messageBuffer.toString());
300         }
301 
302         for (int i = 0; i < expected.getRowDimension(); ++i) {
303             for (int j = 0; j < expected.getColumnDimension(); ++j) {
304                 FieldElement<?> eij = expected.getEntry(i, j);
305                 FieldElement<?> oij = observed.getEntry(i, j);
306                 Assert.assertEquals(eij, oij);
307             }
308         }
309     }
310     
311     /** verifies that two arrays are close (sup norm) */
312     public static void assertEquals(String msg, double[] expected, double[] observed,
313         double tolerance) {
314         StringBuffer out = new StringBuffer(msg);
315         if (expected.length != observed.length) {
316             out.append("\n Arrays not same length. \n");
317             out.append("expected has length ");
318             out.append(expected.length);
319             out.append(" observed length = ");
320             out.append(observed.length);
321             Assert.fail(out.toString());
322         }
323         boolean failure = false;
324         for (int i=0; i < expected.length; i++) {
325             try {
326                 assertEquals(expected[i], observed[i], tolerance);
327             } catch (AssertionFailedError ex) {
328                 failure = true;
329                 out.append("\n Elements at index ");
330                 out.append(i);
331                 out.append(" differ. ");
332                 out.append(" expected = ");
333                 out.append(expected[i]);
334                 out.append(" observed = ");
335                 out.append(observed[i]); 
336             }
337         }
338         if (failure) {
339             Assert.fail(out.toString());
340         }
341     }
342     
343     /** verifies that two arrays are equal */
344     public static <T extends FieldElement<T>> void assertEquals(T[] m, T[] n) {
345         if (m.length != n.length) {
346             Assert.fail("vectors not same length");
347         }
348         for (int i = 0; i < m.length; i++) {
349             Assert.assertEquals(m[i],n[i]);
350         }
351     }
352     
353 }