package net.sf.openrocket.rocketcomponent; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.lang.reflect.Method; import java.util.Iterator; import java.util.regex.Pattern; import net.sf.openrocket.util.BugException; public class ComponentCompare { private static final Pattern GETTER_PATTERN = Pattern.compile("^(is|get)[A-Z].*+"); private static final String[] IGNORED_METHODS = { "getClass", "getChildCount", "getChildren", "getNextComponent", "getID", "getPreviousComponent", "getParent", "getRocket", "getRoot", "getStage", "getStageNumber", "getComponentName", "getStageSeparationConfiguration", "getMotorConfiguration", "getIgnitionConfiguration", // Rocket specific methods: "getModID", "getMassModID", "getAerodynamicModID", "getTreeModID", "getFunctionalModID", "getFlightConfigurationIDs", "getDefaultConfiguration", "getMotorMounts" }; /** * Check whether the two components are <em>equal</em>. Two components are considered * equal if they are of the same type and all of their getXXX() and isXXX() methods * return equal values. * * @param c1 the first component to compare. * @param c2 the second component to compare. */ public static void assertEquality(RocketComponent c1, RocketComponent c2) { assertEquals(c1.getClass(), c2.getClass()); // Same class + similar == equal assertSimilarity(c1, c2); } public static void assertDeepEquality(RocketComponent c1, RocketComponent c2) { assertEquality(c1, c2); Iterator<RocketComponent> i1 = c1.getChildren().iterator(); Iterator<RocketComponent> i2 = c2.getChildren().iterator(); while (i1.hasNext()) { assertTrue("iterator continues", i2.hasNext()); RocketComponent comp1 = i1.next(); RocketComponent comp2 = i2.next(); assertDeepEquality(comp1, comp2); } assertFalse("iterator end", i2.hasNext()); } public static void assertDeepSimilarity(RocketComponent c1, RocketComponent c2, boolean allowNameDifference) { assertSimilarity(c1, c2, allowNameDifference); Iterator<RocketComponent> i1 = c1.getChildren().iterator(); Iterator<RocketComponent> i2 = c2.getChildren().iterator(); while (i1.hasNext()) { assertTrue("iterator continues", i2.hasNext()); RocketComponent comp1 = i1.next(); RocketComponent comp2 = i2.next(); assertDeepSimilarity(comp1, comp2, allowNameDifference); } assertFalse("iterator end", i2.hasNext()); } /** * Check whether the two components are <em>similar</em>. Two components are similar * if each of the getXXX and isXXX methods that both object types have return * equal values. This does not check whether the two components are of the same type. * * @param c1 the first component. * @param c2 the second component. */ public static void assertSimilarity(RocketComponent c1, RocketComponent c2) { assertSimilarity(c1, c2, false); } /** * Check whether the two components are <em>similar</em>, allowing a name difference. * * @param c1 the first component. * @param c2 the second component. * @param allowNameDifference whether to allow the components to have different names. */ public static void assertSimilarity(RocketComponent c1, RocketComponent c2, boolean allowNameDifference) { Class<? extends RocketComponent> class1 = c1.getClass(); Class<? extends RocketComponent> class2 = c2.getClass(); mainloop: for (Method m1 : class1.getMethods()) { // Check for getter method String name = m1.getName(); if (!GETTER_PATTERN.matcher(name).matches()) continue; // Ignore methods that take parameters if (m1.getParameterTypes().length != 0) continue; // Ignore specific getters for (String ignore : IGNORED_METHODS) { if (name.equals(ignore)) continue mainloop; } if (allowNameDifference && name.equals("getName")) continue; // Check for method in other class Method m2; try { m2 = class2.getMethod(name); } catch (NoSuchMethodException e) { continue; } // System.out.println("Testing results of method " + name); // Run the methods Object result1, result2; try { result1 = m1.invoke(c1); result2 = m2.invoke(c2); } catch (Exception e) { throw new BugException("Error executing method " + name, e); } if (result1 != null && result2 != null && result1.getClass().isArray() && result2.getClass().isArray()) { assertArrayEquals("Comparing result of method " + name, (Object[]) result1, (Object[]) result2); } else { assertEquals("Comparing result of method " + name, result1, result2); } } } }