/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.rpc.flattening; import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.UUID; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.eclipse.dawnsci.analysis.api.roi.IROI; import org.eclipse.dawnsci.analysis.api.rpc.AnalysisRpcRemoteException; import org.eclipse.dawnsci.analysis.dataset.roi.CircularROI; import org.eclipse.dawnsci.analysis.dataset.roi.CircularROIList; import org.eclipse.dawnsci.analysis.dataset.roi.EllipticalROI; import org.eclipse.dawnsci.analysis.dataset.roi.EllipticalROIList; import org.eclipse.dawnsci.analysis.dataset.roi.GridPreferences; import org.eclipse.dawnsci.analysis.dataset.roi.LinearROI; import org.eclipse.dawnsci.analysis.dataset.roi.LinearROIList; import org.eclipse.dawnsci.analysis.dataset.roi.PointROI; import org.eclipse.dawnsci.analysis.dataset.roi.PointROIList; import org.eclipse.dawnsci.analysis.dataset.roi.ROIBase; import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROI; import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROIList; import org.eclipse.dawnsci.analysis.dataset.roi.SectorROI; import org.eclipse.dawnsci.analysis.dataset.roi.SectorROIList; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.IDataset; import org.eclipse.january.dataset.IntegerDataset; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import uk.ac.diamond.scisoft.analysis.io.DataHolder; import uk.ac.diamond.scisoft.analysis.io.NumPyFileSaver; import uk.ac.diamond.scisoft.analysis.plotserver.AxisMapBean; import uk.ac.diamond.scisoft.analysis.plotserver.DataBean; import uk.ac.diamond.scisoft.analysis.plotserver.DataBeanException; import uk.ac.diamond.scisoft.analysis.plotserver.DatasetWithAxisInformation; import uk.ac.diamond.scisoft.analysis.plotserver.FileOperationBean; import uk.ac.diamond.scisoft.analysis.plotserver.GuiBean; import uk.ac.diamond.scisoft.analysis.plotserver.GuiParameters; import uk.ac.diamond.scisoft.analysis.plotserver.GuiPlotMode; import uk.ac.diamond.scisoft.analysis.rpc.internal.AnalysisRpcDoubleParser; abstract public class FlatteningTestAbstract { /** * Waiting period for server to start up (in milliseconds) */ public static final long SERVER_WAIT_TIME = 200; protected static IRootFlattener flattener; /** * This toggles whether to use NaNs, infinities in tests. * <p> * Note NaN, +/-Inf only work if AnalysisRpc is in the loop or Java is talking to Java. * <p> * Note the subclasses that do not support it don't matter because they were written simply to identify these types * of issues. * See {@link AnalysisRpcDoubleParser} */ protected static boolean handleDoubleSpecials = true; protected RectangularROI createRectangularROI() { // now the rectangular ROI null constructor will have NaNs in some fields return handleDoubleSpecials ? new RectangularROI() : new RectangularROI(10, 0); } @BeforeClass public static void setUp() { flattener = new RootFlattener(); } /** * Special version of Assert.assertEquals that, for some types, uses reflection or other knowledge instead of * equals() to test for equality. The reason for this is to work around insufficient or unsuitable equals * implementations in those classes. Arrays, Lists and Maps are compared deeply. * * @param expected * first object to test * @param actual * second object to test */ protected void assertFlattenEquals(Object expected, Object actual) { if (expected == null) { Assert.assertNull(actual); } else if (expected instanceof IROI|| expected instanceof AxisMapBean) { Assert.assertTrue(EqualsBuilder.reflectionEquals(expected, actual)); } else if (expected instanceof DataBean) { DataBean expDataBean = (DataBean) expected; DataBean actDataBean = (DataBean) actual; assertFlattenEquals(expDataBean.getData(), actDataBean.getData()); assertFlattenEquals(expDataBean.getAxisData(), actDataBean.getAxisData()); // TODO fix this with HDF5 tree // assertFlattenEquals(Collections.emptyList(), actDataBean.getNexusTrees()); } else if (expected instanceof DatasetWithAxisInformation) { DatasetWithAxisInformation expDatasetWithAxisInformation = (DatasetWithAxisInformation) expected; DatasetWithAxisInformation actDatasetWithAxisInformation = (DatasetWithAxisInformation) actual; assertFlattenEquals(expDatasetWithAxisInformation.getData(), actDatasetWithAxisInformation.getData()); assertFlattenEquals(expDatasetWithAxisInformation.getAxisMap(), actDatasetWithAxisInformation.getAxisMap()); } else if (expected instanceof Exception) { Exception expException = (Exception) expected; Exception actException = (Exception) actual; // The message gets supplemented with extra type information, make sure the original expected // message is present in the supplemented info if (!actException.getMessage().contains(expException.getMessage())) Assert.fail("Expected message: " + expException.getMessage() + " actual message: " + actException.getMessage()); StackTraceElement[] expStackTrace = expException.getStackTrace(); StackTraceElement[] actStackTrace = actException.getStackTrace(); Assert.assertArrayEquals(expStackTrace, actStackTrace); } else if (expected instanceof List) { List<?> expectedlist = (List<?>) expected; List<?> actuallist = (List<?>) actual; Assert.assertEquals(expectedlist.size(), actuallist.size()); for (int i = 0; i < actuallist.size(); i++) { assertFlattenEquals(expectedlist.get(i), actuallist.get(i)); } } else if (expected instanceof byte[]) { byte[] expectedarray = (byte[]) expected; byte[] actualarray = (byte[]) actual; Assert.assertArrayEquals(expectedarray, actualarray); } else if (expected instanceof int[]) { int[] expectedarray = (int[]) expected; int[] actualarray = (int[]) actual; Assert.assertArrayEquals(expectedarray, actualarray); } else if (expected instanceof double[]) { double[] expectedarray = (double[]) expected; double[] actualarray = (double[]) actual; Assert.assertArrayEquals(expectedarray, actualarray, 0.0); } else if (expected instanceof boolean[]) { boolean[] expectedarray = (boolean[]) expected; boolean[] actualarray = (boolean[]) actual; Assert.assertTrue(Arrays.equals(expectedarray, actualarray)); } else if (expected instanceof Object[]) { Object[] expectedarray = (Object[]) expected; Object[] actualarray = (Object[]) actual; Assert.assertEquals(expectedarray.length, actualarray.length); for (int i = 0; i < actualarray.length; i++) { assertFlattenEquals(expectedarray[i], actualarray[i]); } } else if (expected instanceof GuiBean) { GuiBean expectedGuiBean = (GuiBean) expected; GuiBean actualGuiBean = (GuiBean) actual; // GuiBeans "lose" some keys when being flattened because they are not // supported. Assert.assertTrue(expectedGuiBean.size() >= actualGuiBean.size()); Set<Entry<GuiParameters, Serializable>> entrySet = expectedGuiBean.entrySet(); for (Entry<GuiParameters, Serializable> entry : entrySet) { if (entry.getKey().equals(GuiParameters.GRIDPREFERENCES) || entry.getKey().equals(GuiParameters.FILEOPERATION) || entry.getKey().getStorageClass().equals(Serializable.class)) { Assert.assertFalse(actualGuiBean.containsKey(entry.getKey())); } else { Assert.assertTrue(actualGuiBean.containsKey(entry.getKey())); assertFlattenEquals(entry.getValue(), actualGuiBean.get(entry.getKey())); } } } else if (expected instanceof Map) { Map<?, ?> expectedMap = (Map<?, ?>) expected; Map<?, ?> actualMap = (Map<?, ?>) actual; Assert.assertEquals(expectedMap.size(), actualMap.size()); Set<?> entrySet = expectedMap.entrySet(); for (Object object : entrySet) { Entry<?, ?> entry = (Entry<?, ?>) object; Assert.assertTrue(actualMap.containsKey(entry.getKey())); assertFlattenEquals(entry.getValue(), actualMap.get(entry.getKey())); } } else { Assert.assertEquals(expected, actual); } } protected Object flattenAndUnflatten(Object inObj) { return flattenAndUnflatten(inObj, inObj); } private Object flattenAndUnflatten(Object inObj, Object expectedObj) { return flattenAndUnflatten(inObj, expectedObj, expectedObj.getClass()); } protected abstract Object doActualFlattenAndUnflatten(Object inObj); private Object flattenAndUnflatten(Object inObj, Object expectedObj, Class<?> expectedType) { final Object out = doActualFlattenAndUnflatten(inObj); assertFlattenEquals(expectedObj, out); if (expectedObj != null && expectedObj.getClass().equals(expectedType)) { Assert.assertEquals(expectedType, out.getClass()); } else if (expectedType != null) { Assert.assertTrue(expectedType.isAssignableFrom(out.getClass())); } // finally, take a unflattened item and make sure it has made something // that is fully flattenable still assertFlattenEquals(out, doActualFlattenAndUnflatten(out)); return out; } @Test public void testInteger() { flattenAndUnflatten(18); flattenAndUnflatten(-7); flattenAndUnflatten(0); flattenAndUnflatten(Integer.MIN_VALUE); flattenAndUnflatten(Integer.MAX_VALUE); } @Test public void testBoolean() { flattenAndUnflatten(true); flattenAndUnflatten(false); } @Test public void testString() { flattenAndUnflatten(""); flattenAndUnflatten("bananas"); flattenAndUnflatten("\nhello\tgoodbye"); } @Test public void testUnicodeString() { flattenAndUnflatten("\u00b0"); } @Test public void testDouble() { flattenAndUnflatten(0); flattenAndUnflatten(Math.PI); flattenAndUnflatten(Double.MIN_VALUE); flattenAndUnflatten(Double.MAX_VALUE); } @Test public void testDoubleSpecialValues() { if (handleDoubleSpecials) { flattenAndUnflatten(Double.NaN); flattenAndUnflatten(Double.NEGATIVE_INFINITY); flattenAndUnflatten(Double.POSITIVE_INFINITY); } } @Test public void testByeArray() { flattenAndUnflatten(new byte[] { 1, 5, -7 }); flattenAndUnflatten(new byte[0]); flattenAndUnflatten(new byte[1000]); } @Test public void testMap() { HashMap<String, Double> hashMap = new HashMap<String, Double>(); hashMap.put("pi", Math.PI); hashMap.put("One", new Double(1)); flattenAndUnflatten(hashMap, hashMap, Map.class); TreeMap<String, Double> treeMap = new TreeMap<String, Double>(hashMap); flattenAndUnflatten(treeMap, treeMap, Map.class); HashMap<String, Object> hashMap2 = new HashMap<String, Object>(hashMap); hashMap2.put("Integer", Integer.valueOf(0)); hashMap2.put("Integer", Integer.valueOf(100)); flattenAndUnflatten(hashMap2, hashMap2, Map.class); HashMap<Object, Object> nonStringKeys = new HashMap<Object, Object>(hashMap2); nonStringKeys.put(Integer.valueOf(0), Integer.valueOf(0)); nonStringKeys.put(GuiParameters.FILENAME, "Filename"); flattenAndUnflatten(nonStringKeys, nonStringKeys, Map.class); } @Test public void testObjectArrays() { flattenAndUnflatten(new Object[] { new Double(1.2), new Integer(2) }); // arrays of things which look like arrays of integers, double or booleans come out as such flattenAndUnflatten(new Object[] { 0, 1, 2, 3 }, new int[] { 0, 1, 2, 3 }); flattenAndUnflatten(new Object[] { new Object[] { 0, 1, 2, 3 }, new Object[] { 4, 5, 6, 7 }, new Object[] { 8, 9, 10, 11 }, new Object[] { 12, 13, 14, 15 } }, new int[][] { new int[] { 0, 1, 2, 3 }, new int[] { 4, 5, 6, 7 }, new int[] { 8, 9, 10, 11 }, new int[] { 12, 13, 14, 15 } }); flattenAndUnflatten(new Object[][] { { 0, 1 }, { 2, 3 } }, new int[][] { new int[] { 0, 1 }, new int[] { 2, 3 } }); // Empty arrays come out as array of Object[] flattenAndUnflatten(new Object[0], new Object[0]); flattenAndUnflatten(new int[0], new Object[0]); flattenAndUnflatten(new String[0], new Object[0]); // arrays of other types come out as arrays if the class of each element of the array is the same flattenAndUnflatten(new String[] { "one", "two" }, new String[] { "one", "two" }); // String[] --> String[] flattenAndUnflatten(new Object[] { "one", "two" }, new String[] { "one", "two" }); // Object[] --> String[] flattenAndUnflatten(new Object[] { createRectangularROI(), createRectangularROI() }, new RectangularROI[] { createRectangularROI(), createRectangularROI() }); // Object[] --> RectangularROI[] flattenAndUnflatten(new Object[] { createRectangularROI(), new LinearROI() }, new IROI[] { createRectangularROI(), new LinearROI() }); // ROIBase[] --> ROIBase[] flattenAndUnflatten(new Object[] { new Integer(0), createRectangularROI(), new LinearROI() }, new Object[] { new Integer(0), createRectangularROI(), new LinearROI() }); // Object[] --> Object[] flattenAndUnflatten(new Object[] { createRectangularROI(), new LinearROI(), new Integer(0) }, new Object[] { createRectangularROI(), new LinearROI(), new Integer(0) }); // Object[] --> Object[] // arrays with some (but not all) nulls follow the rule above flattenAndUnflatten(new String[] { null, "two" }, new String[] { null, "two" }); // String[] --> String[] flattenAndUnflatten(new String[] { "one", null }, new String[] { "one", null }); // String[] --> String[] flattenAndUnflatten(new Object[] { null, "two" }, new String[] { null, "two" }); // Object[] --> String[] // arrays with all nulls in them come out as arrays of Object[] flattenAndUnflatten(new String[] { null, null }, new Object[] { null, null }); // String[] --> Object[] flattenAndUnflatten(new Object[] { null, null }, new Object[] { null, null }); // Object[] --> Object[] // arrays of some special types that every element implements the same interface or extends the same // class unflatten as an array of that super type. But when each element is the same implementation // still unflatten to that implementation // IDataset[] IntegerDataset intDataset = (IntegerDataset) DatasetFactory.createRange(10, Dataset.INT); DoubleDataset fltDataset = (DoubleDataset) DatasetFactory.createRange(10, Dataset.FLOAT); flattenAndUnflatten(new IDataset[] { intDataset, fltDataset }); flattenAndUnflatten(new IntegerDataset[] { intDataset, intDataset }); // IROI[] flattenAndUnflatten(new IROI[] { createRectangularROI(), new SectorROI() }); flattenAndUnflatten(new RectangularROI[] { createRectangularROI(), createRectangularROI() }); } @Test public void testLists() { ArrayList<RectangularROI> rects = new ArrayList<RectangularROI>(); rects.add(new RectangularROI(15, 0.2)); rects.add(new RectangularROI(10.1, 11.2, 0)); rects.add(createRectangularROI()); // Lists are to the same type as every element in the array if they are all the same class... flattenAndUnflatten(rects, rects.toArray(new RectangularROI[0])); ArrayList<Number> nums = new ArrayList<Number>(); nums.add(new Double(0.0)); nums.add(new Integer(1)); // ...otherwise they unflatten to an array of Object[] flattenAndUnflatten(nums, nums.toArray(new Object[0])); } @Test public void testNull() { flattenAndUnflatten(null, null, null); // test null within other data structures Map<Object, Object> map = new HashMap<Object, Object>(); // map, null key map.put(null, "null"); flattenAndUnflatten(map, map, Map.class); // map, null value map.put("null", null); flattenAndUnflatten(map, map, Map.class); // map, null key and value map.put(null, null); flattenAndUnflatten(map, map, Map.class); String[] array = new String[] { "null", null }; // array, null entry flattenAndUnflatten(array); // list, null entry flattenAndUnflatten(Arrays.asList(array), array); } @Test public void testTypedNull() { // A typed null should come out equal TypedNone nullDouble = new TypedNone(Double.class); flattenAndUnflatten(nullDouble, nullDouble); // Make sure a non-built-in type is OK TypedNone nullRect = new TypedNone(RectangularROI.class); flattenAndUnflatten(nullRect, nullRect); } @Test public void testGuiBean() { GuiBean bean = new GuiBean(); bean.put(GuiParameters.FILENAME, "myfile.txt"); bean.put(GuiParameters.TITLE, "My Amazing Plot!"); bean.put(GuiParameters.PLOTID, UUID.fromString("93dfd804-85ba-4074-afce-d621f7f2aac6")); RectangularROI rect = new RectangularROI(1.1, -2, 5.0, 10.0, 0.6, true); rect.setName("Rect 1"); bean.put(GuiParameters.ROIDATA, rect.getName()); RectangularROIList list = new RectangularROIList(); list.add(rect); bean.put(GuiParameters.ROIDATALIST, list); ArrayList<String> fileList = new ArrayList<String>(); fileList.add("File1.plot"); fileList.add("File2.plot"); bean.put(GuiParameters.FILESELECTEDLIST, fileList); Integer[] gridSize = { 12, 14 }; bean.put(GuiParameters.IMAGEGRIDSIZE, gridSize); bean.put(GuiParameters.PLOTMODE, GuiPlotMode.SCATTER2D); bean.put(GuiParameters.GRIDPREFERENCES, new GridPreferences()); bean.put(GuiParameters.FILEOPERATION, new FileOperationBean()); flattenAndUnflatten(bean); } @Test public void testDataBean() throws DataBeanException { DataBean dataBean = new DataBean(); dataBean.addAxis(AxisMapBean.XAXIS, DatasetFactory.createRange(100, Dataset.INT)); dataBean.addAxis(AxisMapBean.XAXIS2, DatasetFactory.createRange(100, Dataset.FLOAT64)); dataBean.addData(DatasetWithAxisInformation.createAxisDataSet(DatasetFactory.createRange(100, Dataset.INT))); flattenAndUnflatten(dataBean); // Test that nexus tree data is removed // TODO fix this to use HDF5 tree // DataBean dataBeanWithNexusTree = new DataBean(); // dataBeanWithNexusTree.setAxisData(dataBean.getAxisData()); // dataBeanWithNexusTree.setData(dataBean.getData()); // flattenAndUnflatten(dataBeanWithNexusTree, dataBean); } @Test public void testDataset() throws Exception { // flatten to an npy file implicitly flattenAndUnflatten(DatasetFactory.createRange(100, Dataset.INT)); // flatten a descriptor of a Dataset that unflattens to an abstract data set Dataset ds = DatasetFactory.createRange(100, Dataset.INT); DataHolder dh = new DataHolder(); dh.addDataset("", ds); File tempFile = File.createTempFile("scisofttmp-", ".npy"); new NumPyFileSaver(tempFile.toString()).saveFile(dh); DatasetDescriptor descriptor = new DatasetDescriptor(); descriptor.setFilename(tempFile.toString()); descriptor.setDeleteAfterLoad(false); descriptor.setIndex(0); descriptor.setName(null); flattenAndUnflatten(descriptor, ds); if (!tempFile.delete()) { tempFile.deleteOnExit(); } } @Test public void testROIBase() { flattenAndUnflatten(new ROIBase()); ROIBase roiBase = new ROIBase(); roiBase.setPoint(new double[] { -0.3, 2.0 }); flattenAndUnflatten(roiBase); roiBase.setPlot(true); flattenAndUnflatten(roiBase); roiBase.setPlot(false); flattenAndUnflatten(roiBase); } @Test public void testPointROI() { flattenAndUnflatten(new PointROI()); PointROI point = new PointROI(); point.setPoint(new double[] { -0.3, 2.0 }); flattenAndUnflatten(point); point.setPlot(true); flattenAndUnflatten(point); point.setPlot(false); flattenAndUnflatten(point); } @Test public void testLinearROI() { flattenAndUnflatten(new LinearROI(1.1, 0.6)); double[] spt = { -0.3, 2.0 }; double[] ept = { 20.0, -22.5 }; LinearROI line = new LinearROI(spt, ept); flattenAndUnflatten(line); line.setCrossHair(true); flattenAndUnflatten(line); } @Test public void testRectangularROI() { flattenAndUnflatten(new RectangularROI(1.1, -2, 5.0, 10.0, 0.6, true)); flattenAndUnflatten(new RectangularROI(-11.2, 2.8, 5.7, 10.2, 0.4, false)); } @Test public void testSectorROI() { SectorROI sector = new SectorROI(0.2, 15.2, 0.1, 0.2, 0.01, -0.2, 1.0, true, SectorROI.XREFLECT); flattenAndUnflatten(sector); sector = new SectorROI(2.3, 1.2, 0.02, 0.04, 0.71, -0.9, 1.0, false, SectorROI.FULL); sector.setAverageArea(true); sector.setCombineSymmetry(true); flattenAndUnflatten(sector); } @Test public void testCircularROI() { flattenAndUnflatten(new CircularROI(1.1, -2, 5.0)); } @Test public void testEllipticalROI() { flattenAndUnflatten(new EllipticalROI(1.1, 0.23, -2, 5.0, -23.5)); } @Test public void testPointROIList() { PointROIList pList = new PointROIList(); pList.add(new PointROI(1, -3.4)); pList.add(new PointROI(-235.6, 0)); flattenAndUnflatten(pList); } @Test public void testLinearROIList() { LinearROIList lList = new LinearROIList(); lList.add(new LinearROI(1.1, 0.6)); lList.add(new LinearROI(0.9, 0.36)); flattenAndUnflatten(lList); } @Test public void testRectangularROIList() { RectangularROIList rList = new RectangularROIList(); rList.add(new RectangularROI(1.1, -2, 5.0, 10.0, 0.6, true)); rList.add(new RectangularROI(-1.9, -2, 5.8, 2.0, 0.9, false)); flattenAndUnflatten(rList); } @Test public void testSectorROIList() { SectorROIList sList = new SectorROIList(); sList.add(new SectorROI(0.2, 15.2, 0.1, 0.2, 0.01, -0.2, 1.0, true, SectorROI.XREFLECT)); sList.add(new SectorROI(0.3, -12, 0.0, 1.1, 0.651, -0.2, 1.0, true, SectorROI.INVERT)); flattenAndUnflatten(sList); } @Test public void testCircularROIList() { CircularROIList cList = new CircularROIList(); cList.add(new CircularROI(1.1, -2, 5.0)); flattenAndUnflatten(cList); } @Test public void testEllipticalROIList() { EllipticalROIList eList = new EllipticalROIList(); eList.add(new EllipticalROI(1.1, 0.23, -2, 5.0, -23.5)); flattenAndUnflatten(eList); } @Test public void testDatasetWithAxisInformation() { DatasetWithAxisInformation ds = DatasetWithAxisInformation.createAxisDataSet(DatasetFactory.createRange(100, Dataset.INT)); flattenAndUnflatten(ds); ds = DatasetWithAxisInformation.createAxisDataSet(DatasetFactory.createRange(100, Dataset.INT), "Hello"); flattenAndUnflatten(ds); ds = DatasetWithAxisInformation.createAxisDataSet(DatasetFactory.createRange(100, Dataset.INT), "Hello", "Goodbye"); flattenAndUnflatten(ds); ds = DatasetWithAxisInformation.createAxisDataSet(DatasetFactory.createRange(100, Dataset.INT), "Hello", null); flattenAndUnflatten(ds); } @Test public void testAxisMapBean() { AxisMapBean amb = new AxisMapBean(); String[] ids = { AxisMapBean.XAXIS, AxisMapBean.YAXIS }; amb.setAxisID(ids); String[] names = { AxisMapBean.XAXIS, AxisMapBean.YAXIS }; amb.setAxisNames(names); flattenAndUnflatten(amb); amb.setAxisNames(null); flattenAndUnflatten(amb); } @Test public void testException() { // Exceptions are always unflattened as AnalysisRpcRemoteException type, // with original type information pre-pended to the message Exception[] npe_in = new Exception[] {new NullPointerException("Exceptional null happened")}; AnalysisRpcRemoteException[] npe_out = new AnalysisRpcRemoteException[] {new AnalysisRpcRemoteException("Exceptional null happened")}; // Make sure the stack traces are the same npe_out[0].setStackTrace(npe_in[0].getStackTrace()); flattenAndUnflatten(npe_in, npe_out); } @Test public void testGuiParameters() { // test one explicitly flattenAndUnflatten(GuiParameters.PLOTMODE); // test all the parameters // NOTE If the test fails here it is probably because of a mismatch between the Java and Python GuiParameters. // see GuiParameters.java and pybeans.py for (GuiParameters param : GuiParameters.values()) { flattenAndUnflatten(param); } } @Test public void testGuiPlotMode() { // test one explicitly flattenAndUnflatten(GuiPlotMode.EMPTY); // test all the modes for (GuiPlotMode param : GuiPlotMode.values()) { flattenAndUnflatten(param); } } @Test public void testUUID() { flattenAndUnflatten(UUID.fromString("93dfd804-85ba-4074-afce-d621f7f2aac6")); flattenAndUnflatten(UUID.fromString("dd09fd5c-bb75-4c8b-854b-7f3bb2c9c399")); flattenAndUnflatten(UUID.fromString("00000000-0000-0000-0000-000000000000")); flattenAndUnflatten(UUID.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff")); flattenAndUnflatten(UUID.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")); for (int i = 0; i < 100; i++) { // There is a reproducibility danger in using random UUIDs in this // test in that if one fails to match it cannot simply be re-run to // reproduce. The failing UUID should be extracted from the error message // stack trace and added to the list above of explicit values. // If it fails, the message will look something like: // junit.framework.AssertionFailedError: expected:<93dfd804-85ba-4074-afce-d621f7f2aac6> but // was:<dd09fd5c-bb75-4c8b-854b-7f3bb2c9c399> // ... flattenAndUnflatten(UUID.randomUUID()); } } // Primitive arrays and arrays of boxed primitives unflatten as primitive arrays @Test public void testPrimitiveArrays() { int[] ints = { 1, 5, -7 }; flattenAndUnflatten(ints); flattenAndUnflatten(ArrayUtils.toObject(ints), ints); double[] doubles = { 1.4, 12.6, 0, handleDoubleSpecials ? Double.NaN : -1.5 }; flattenAndUnflatten(doubles); flattenAndUnflatten(ArrayUtils.toObject(doubles), doubles); boolean[] booleans = { true, false, false, true }; flattenAndUnflatten(booleans); flattenAndUnflatten(ArrayUtils.toObject(booleans), booleans); double[][] doubles2d = { { 1, 5, -7 }, { 1.4, 12.6, 0 } }; flattenAndUnflatten(doubles2d, new double[][] { doubles2d[0], doubles2d[1] }); flattenAndUnflatten(new double[][] { doubles2d[0], doubles2d[1] }); } }