    001/*-
    002 * Copyright (c) 2012, 2016 Diamond Light Source Ltd.
    003 *
    004 * All rights reserved. This program and the accompanying materials
    005 * are made available under the terms of the Eclipse Public License v1.0
    006 * which accompanies this distribution, and is available at
    007 * http://www.eclipse.org/legal/epl-v10.html
    008 */
    009
    010package org.eclipse.january.asserts;
    011
    012import java.util.Arrays;
    013
    014import org.eclipse.january.dataset.BooleanDataset;
    015import org.eclipse.january.dataset.Dataset;
    016import org.eclipse.january.dataset.IndexIterator;
    017import org.eclipse.january.dataset.InterfaceUtils;
    018import org.eclipse.january.dataset.ObjectDataset;
    019import org.eclipse.january.dataset.StringDataset;
    020import org.junit.Assert;
    021import org.junit.runner.Description;
    022import org.junit.runner.notification.RunListener;
    023import org.junit.runner.notification.RunNotifier;
    024import org.junit.runners.Suite;
    025import org.junit.runners.model.InitializationError;
    026import org.junit.runners.model.RunnerBuilder;
    027
    028public class TestUtils {
    029        static RunListener listener;
    030        static {
    031                listener = new RunListener() {
    032                        @Override
    033                        public void testStarted(Description description) throws Exception {
    034                                if (verbosity != Verbosity.QUIET) {
    035                                        System.out.println("Starting: " + description.getMethodName());
    036                                }
    037                                super.testStarted(description);
    038                        }
    039
    040                        @Override
    041                        public void testFinished(Description description) throws Exception {
    042                                super.testFinished(description);
    043                                if (verbosity != Verbosity.QUIET) {
    044                                        System.out.println("Finished: " + description.getMethodName());
    045                                }
    046                        }
    047                };
    048        }
    049
    050        /**
    051         * Suite that adds a Run listener that prints when methods start and finish
    052         */
    053        public static class VerboseSuite extends Suite {
    054
    055                // TODO handle suites of suites properly
    056                public VerboseSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
    057                        super(klass, builder);
    058                }
    059
    060                @Override
    061                public void run(RunNotifier notifier) {
    062                        // To avoid duplicates need to do N-1 times if there's N levels of these suites
    063                        // Note, in this notifier implementation it does not matter if we try to remove
    064                        // a listener if is not contained with the notifier
    065                        notifier.removeListener(listener);
    066
    067                        notifier.addListener(listener);
    068                        super.run(notifier);
    069                        notifier.removeListener(listener);
    070                }
    071        }
    072
    073        /**
    074         * Assert equality of datasets where each item is true if they are equal or
    075         * for floating point datasets, if <code>abs(a - b) &le; 1e-12 + 1e-12*abs(b)</code>
    076         * <p>
    077         * The dataset types have to match and so does the number of elements in each item.
    078         * <p>
    079         * Same as <pre>TestUtils.assertDatasetEquals(expected, actual, true, 1e-12, 1e-12)</pre>
    080         * @param expected dataset
    081         * @param actual dataset
    082         */
    083        public static void assertDatasetEquals(Dataset expected, Dataset actual) {
    084                assertDatasetEquals(expected, actual, true, 1e-12, 1e-12);
    085        }
    086
    087        /**
    088         * Assert equality of datasets where each element is true if they are equal or
    089         * for floating point datasets, if <code>abs(a - b) &le; 1e-12 + 1e-12*abs(b)</code>
    090         * @param expected dataset
    091         * @param actual dataset
    092         * @param testDTypeAndItemSize if true, check dataset type and number of elements
    093         */
    094        public static void assertDatasetEquals(Dataset expected, Dataset actual, boolean testDTypeAndItemSize) {
    095                assertDatasetEquals(expected, actual, testDTypeAndItemSize, 1e-12, 1e-12);
    096        }
    097
    098        /**
    099         * Assert equality of datasets where each element is true if they are equal or
    100         * for floating point datasets, if <code>abs(a - b) &le; absTolerance + relTolerance*abs(b)</code>.
    101         * <p>
    102         * The dataset types does not have to match nor does the number of elements in each item.
    103         * @param expected dataset
    104         * @param actual dataset
    105         * @param relTolerance relative tolerance
    106         * @param absTolerance absolute tolerance
    107         */
    108        public static void assertDatasetEquals(Dataset expected, Dataset actual, double relTolerance, double absTolerance) {
    109                assertDatasetEquals(expected, actual, false, relTolerance, absTolerance);
    110        }
    111
    112        /**
    113         * Assert equality of datasets where each element is true if they are equal or
    114         * for floating point datasets, if <code>abs(a - b) &le; absTolerance + relTolerance*abs(b)</code>.
    115         * @param expected dataset
    116         * @param actual dataset
    117         * @param testDTypeAndItemSize if true, check dataset type and number of elements
    118         * @param relTolerance relative tolerance
    119         * @param absTolerance absolute tolerance
    120         */
    121        public static void assertDatasetEquals(Dataset expected, Dataset actual, boolean testDTypeAndItemSize, double relTolerance, double absTolerance) {
    122                final int eis = expected.getElementsPerItem();
    123                final int ais = actual.getElementsPerItem();
    124                Class<? extends Dataset> clazz = InterfaceUtils.findSubInterface(expected.getClass());
    125                if (testDTypeAndItemSize) {
    126                        Assert.assertEquals("Interface", clazz, InterfaceUtils.findSubInterface(actual.getClass()));
    127                        Assert.assertEquals("Itemsize", eis, ais);
    128                }
    129                Assert.assertEquals("Size", expected.getSize(), actual.getSize());
    130                try {
    131                        Assert.assertArrayEquals("Shape", expected.getShapeRef(), actual.getShapeRef());
    132                } catch (AssertionError e) {
    133                        if (actual.getSize() == 1) {
    134                                Assert.assertArrayEquals("Shape", new int[0], actual.getShapeRef());
    135                        } else {
    136                                throw e;
    137                        }
    138                }
    139                IndexIterator et = expected.getIterator(true);
    140                IndexIterator at = actual.getIterator();
    141                final int is = Math.max(eis, ais);
    142
    143                int n = 0;
    144                if (InterfaceUtils.isInteger(clazz)) {
    145                        while (et.hasNext() && at.hasNext()) {
    146                                for (int j = 0; j < is; j++) {
    147                                        long e = j >= eis ? 0 : expected.getElementLongAbs(et.index + j);
    148                                        long a = j >= ais ? 0 : actual.getElementLongAbs(at.index + j);
    149                                        Assert.assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + "; " + j +
    150                                                        ": ", e, a);
    151                                }
    152                                n++;
    153                        }
    154                } else if (InterfaceUtils.isFloating(clazz)) {
    155                        while (et.hasNext() && at.hasNext()) {
    156                                for (int j = 0; j < is; j++) {
    157                                        double e = j >= eis ? 0 : expected.getElementDoubleAbs(et.index + j);
    158                                        double a = j >= ais ? 0 : actual.getElementDoubleAbs(at.index + j);
    159                                        assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + "; " + j +
    160                                                        ": ", e, a, relTolerance, absTolerance);
    161                                }
    162                                n++;
    163                        }
    164                } else if (BooleanDataset.class.isAssignableFrom(clazz)) {
    165                        while (et.hasNext() && at.hasNext()) {
    166                                for (int j = 0; j < is; j++) {
    167                                        boolean e = j >= eis ? false : expected.getElementBooleanAbs(et.index + j);
    168                                        boolean a = j >= ais ? false : actual.getElementBooleanAbs(at.index + j);
    169                                        Assert.assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + "; " + j +
    170                                                        ": ", e, a);
    171                                }
    172                                n++;
    173                        }
    174                } else if (StringDataset.class.isAssignableFrom(clazz)) {
    175                        StringDataset es = (StringDataset) expected;
    176                        StringDataset as = (StringDataset) actual;
    177
    178                        while (et.hasNext() && at.hasNext()) {
    179                                Assert.assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + ": ",
    180                                                es.getAbs(et.index), as.getAbs(at.index));
    181                                n++;
    182                        }
    183                } else if (ObjectDataset.class.isAssignableFrom(clazz)) {
    184                        ObjectDataset eo = (ObjectDataset) expected;
    185                        ObjectDataset ao = (ObjectDataset) actual;
    186
    187                        while (et.hasNext() && at.hasNext()) {
    188                                Assert.assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + ": ",
    189                                                eo.getAbs(et.index), ao.getAbs(at.index));
    190                                n++;
    191                        }
    192                } else {
    193                        while (et.hasNext() && at.hasNext()) {
    194                                Assert.assertEquals("Value does not match at " + Arrays.toString(et.getPos()) + ": ",
    195                                                expected.getObjectAbs(et.index), actual.getObjectAbs(at.index));
    196                                n++;
    197                        }
    198                }
    199
    200                Assert.assertEquals("Total items checked", expected.getSize(), n);
    201        }
    202
    203        /**
    204         * Assert equality if <code>abs(e - a) &le; max(1e-20, 1e-14*max(abs(e), abs(a)))</code>
    205         * @param s message for assert exception
    206         * @param e expected value
    207         * @param a actual value
    208         */
    209        public static void assertEquals(String s, double e, double a) {
    210                assertEquals(s, e, a, 1e-14, 1e-20);
    211        }
    212
    213        /**
    214         * Assert equality if <code>abs(e - a) &le; max(absTol, relTol*max(abs(e), abs(a)))</code>
    215         * @param s message for assert exception
    216         * @param e expected value
    217         * @param a actual value
    218         * @param relTol relative tolerance
    219         * @param absTol absolute tolerance
    220         */
    221        public static void assertEquals(String s, double e, double a, double relTol, double absTol) {
    222                double t = Math.max(absTol, relTol*Math.max(Math.abs(e), Math.abs(a)));
    223                Assert.assertEquals(s, e, a, t);
    224        }
    225
    226        public static enum Verbosity {
    227                /**
    228                 * Completely quiet
    229                 */
    230                QUIET,
    231                /**
    232                 * Output test method entry and exit
    233                 */
    234                TEST_METHOD,
    235                /**
    236                 * Output all
    237                 */
    238                VERBOSE;
    239        }
    240
    241        private static Verbosity verbosity = Verbosity.QUIET;
    242
    243        /**
    244         * @param verbosity level
    245         */
    246        public static void setVerbosity(Verbosity verbosity) {
    247                TestUtils.verbosity = verbosity;
    248        }
    249
    250        /**
    251         * Print when verbosity set to verbose
    252         * @param fmt format
    253         * @param args arguments
    254         */
    255        public static void verbosePrintf(String fmt, Object... args) {
    256                if (verbosity == Verbosity.VERBOSE) {
    257                        System.out.printf(fmt, args);
    258                }
    259        }
    260
    261        /**
    262         * Print when verbosity set to verbose
    263         * @param arg argument
    264         */
    265        public static void verbosePrintln(String arg) {
    266                if (verbosity == Verbosity.VERBOSE) {
    267                        System.out.println(arg);
    268                }
    269        }
    270}