JAL-1684 removed reflection from ViewStyle (to Junit), and removed
[jalview.git] / test / jalview / viewmodel / styles / ViewStyleTest.java
diff --git a/test/jalview/viewmodel/styles/ViewStyleTest.java b/test/jalview/viewmodel/styles/ViewStyleTest.java
new file mode 100644 (file)
index 0000000..9a0820f
--- /dev/null
@@ -0,0 +1,174 @@
+package jalview.viewmodel.styles;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.lang.reflect.Field;
+import java.util.Random;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class ViewStyleTest
+{
+
+  Random r = new Random();
+
+  /**
+   * This test uses reflection to set all fields on a ViewStyle, make a copy of
+   * it, and verify all fields match. This test should fail if a getter/setter
+   * pair are added to the class but missing in the copy constructor. Using
+   * reflection in the copy constructor itself is broken by obfuscation when the
+   * applet is built.
+   * 
+   * To prove this test works, simply comment out a line in the ViewStyle copy
+   * constructor, or add a new member field to ViewStyle.
+   * 
+   * @throws IllegalAccessException
+   * @throws IllegalArgumentException
+   */
+  @Test
+  public void testCopyConstructor() throws IllegalArgumentException,
+          IllegalAccessException
+  {
+    ViewStyle vs1 = new ViewStyle();
+    Field[] fields = ViewStyle.class.getDeclaredFields();
+    for (Field field : fields)
+    {
+      field.setAccessible(true);
+      changeValue(vs1, field);
+    }
+
+    ViewStyle vs2 = new ViewStyle(vs1);
+
+    for (Field field1 : fields) {
+      final Object value1 = field1.get(vs1);
+      final Object value2 = field1.get(vs2);
+      String msg = "Mismatch in " + field1.getName() + "(" + value1 + "/"
+              + value2 + ") - not set in copy constructor?";
+      assertEquals(msg, value1, value2);
+    }
+  }
+
+  /**
+   * Change the value of one field in a ViewStyle object
+   * 
+   * @param vs
+   * @param field
+   * @throws IllegalAccessException
+   */
+  protected void changeValue(ViewStyle vs, Field field)
+          throws IllegalAccessException
+  {
+    Class<?> type = field.getType();
+    final int numValue = 1 + r.nextInt(100);
+
+    if (type.equals(boolean.class) || type.equals(Boolean.class))
+    {
+      boolean value = (Boolean) field.get(vs);
+      // System.out.println("Setting " + field.getName() + " to " + !value);
+      field.set(vs, !value);
+    }
+    else if (type.equals(short.class) || type.equals(int.class)
+            || type.equals(long.class) || type.equals(float.class)
+            || type.equals(double.class))
+    {
+      final int value = (int) (1 + field.getDouble(vs));
+      // System.out.println("Setting " + field.getName() + " to " + value);
+      field.set(vs, value);
+    }
+    else if (type.equals(Integer.class))
+    {
+      field.set(vs, (int) (1 + getNumberValue(field, vs)));
+    }
+    else if (type.equals(Float.class))
+    {
+      field.set(vs, (float) (1f + getNumberValue(field, vs)));
+    }
+    else if (type.equals(Long.class))
+    {
+      field.set(vs, (long) (1L + getNumberValue(field, vs)));
+    }
+    else if (type.equals(Double.class))
+    {
+      field.set(vs, 1d + getNumberValue(field, vs));
+    }
+    else if (type.equals(Short.class))
+    {
+      field.set(vs, (short) (1 + getNumberValue(field, vs)));
+    }
+    else if (type.equals(Byte.class))
+    {
+      field.set(vs, (byte) (1 + getNumberValue(field, vs)));
+    }
+    else if (type.equals(Character.class))
+    {
+      field.set(vs, (char) (1 + getNumberValue(field, vs)));
+    }
+    else if (type.equals(String.class))
+    {
+      field.set(vs, "Joe" + field.get(vs));
+    }
+    else if (type.equals(Color.class))
+    {
+      field.set(vs, Color.RED.equals(field.get(vs)) ? Color.BLACK
+              : Color.RED);
+    }
+    else
+    {
+      Assert.fail("Unhandled field type (add to test): " + field.getName()
+              + ":" + type);
+    }
+  }
+
+  private double getNumberValue(Field field, ViewStyle vs)
+          throws IllegalArgumentException, IllegalAccessException
+  {
+    if (field.get(vs) == null)
+    {
+      return 0d;
+    }
+    return ((Number) field.get(vs)).doubleValue();
+  }
+
+  /**
+   * Test that the equals method compares every field by changing them one by
+   * one in a cloned ViewStyle.
+   * 
+   * This test will fail if a new field is added to ViewStyle but not to the
+   * comparisons in ViewStyle.equals().
+   * 
+   * To confirm that this test works, temporarily comment out one of the field
+   * comparisons in ViewStyle.equals()
+   * 
+   * @throws IllegalAccessException
+   * @throws IllegalArgumentException
+   */
+  @Test
+  public void testEquals() throws IllegalArgumentException,
+          IllegalAccessException
+  {
+    ViewStyle vs1 = new ViewStyle();
+    ViewStyle vs2 = new ViewStyle(vs1);
+
+    assertFalse(vs1.equals(null));
+    assertFalse(vs1.equals(this));
+    assertTrue(vs1.equals(vs2));
+    assertTrue(vs2.equals(vs1));
+
+    Field[] fields = ViewStyle.class.getDeclaredFields();
+    for (Field field : fields)
+    {
+      field.setAccessible(true);
+      Object oldValue = field.get(vs2);
+      changeValue(vs2, field);
+      assertFalse("equals method ignores " + field.getName(),
+              vs1.equals(vs2));
+      // restore original value before testing the next field
+      field.set(vs2, oldValue);
+    }
+  }
+}