32003c259b68138718e69715879b6840f7c2f5bc
[jalview.git] / test / jalview / viewmodel / styles / ViewStyleTest.java
1 package jalview.viewmodel.styles;
2
3 import static org.testng.AssertJUnit.assertEquals;
4 import static org.testng.AssertJUnit.assertFalse;
5 import static org.testng.AssertJUnit.assertTrue;
6 import org.testng.annotations.Test;
7 import org.testng.AssertJUnit;
8 import java.awt.Color;
9 import java.lang.reflect.Field;
10 import java.util.Random;
11
12
13 public class ViewStyleTest
14 {
15
16   Random r = new Random();
17
18   /**
19    * This test uses reflection to set all fields on a ViewStyle, make a copy of
20    * it, and verify all fields match. This test should fail if a getter/setter
21    * pair are added to the class but missing in the copy constructor. Using
22    * reflection in the copy constructor itself is broken by obfuscation when the
23    * applet is built.
24    * 
25    * To prove this test works, simply comment out a line in the ViewStyle copy
26    * constructor, or add a new member field to ViewStyle.
27    * 
28    * @throws IllegalAccessException
29    * @throws IllegalArgumentException
30    */
31   @Test
32   public void testCopyConstructor() throws IllegalArgumentException,
33           IllegalAccessException
34   {
35     ViewStyle vs1 = new ViewStyle();
36     Field[] fields = ViewStyle.class.getDeclaredFields();
37     for (Field field : fields)
38     {
39       field.setAccessible(true);
40       if (!copyConstructorIgnores(field.getName()))
41       {
42         changeValue(vs1, field);
43       }
44     }
45
46     ViewStyle vs2 = new ViewStyle(vs1);
47
48     for (Field field1 : fields) {
49       final Object value1 = field1.get(vs1);
50       final Object value2 = field1.get(vs2);
51       String msg = "Mismatch in " + field1.getName() + "(" + value1 + "/"
52               + value2 + ") - not set in copy constructor?";
53       assertEquals(msg, value1, value2);
54     }
55     assertEquals("Hashcode not equals", vs1.hashCode(), vs2.hashCode());
56   }
57
58   /**
59    * Add any field names in here that we expect to be ignored by the copy
60    * constructor
61    * 
62    * @param name
63    * @return
64    */
65   private boolean copyConstructorIgnores(String name)
66   {
67     /*
68      * currently none!
69      */
70     return false;
71   }
72
73   /**
74    * Change the value of one field in a ViewStyle object
75    * 
76    * @param vs
77    * @param field
78    * @throws IllegalAccessException
79    */
80   protected void changeValue(ViewStyle vs, Field field)
81           throws IllegalAccessException
82   {
83     Class<?> type = field.getType();
84
85     if (type.equals(boolean.class) || type.equals(Boolean.class))
86     {
87       boolean value = (Boolean) field.get(vs);
88       // System.out.println("Setting " + field.getName() + " to " + !value);
89       field.set(vs, !value);
90     }
91     else if (type.equals(short.class) || type.equals(int.class)
92             || type.equals(long.class) || type.equals(float.class)
93             || type.equals(double.class))
94     {
95       final int value = (int) (1 + field.getDouble(vs));
96       // System.out.println("Setting " + field.getName() + " to " + value);
97       field.set(vs, value);
98     }
99     else if (type.equals(Integer.class))
100     {
101       field.set(vs, (int) (1 + getNumberValue(field, vs)));
102     }
103     else if (type.equals(Float.class))
104     {
105       field.set(vs, (float) (1f + getNumberValue(field, vs)));
106     }
107     else if (type.equals(Long.class))
108     {
109       field.set(vs, (long) (1L + getNumberValue(field, vs)));
110     }
111     else if (type.equals(Double.class))
112     {
113       field.set(vs, 1d + getNumberValue(field, vs));
114     }
115     else if (type.equals(Short.class))
116     {
117       field.set(vs, (short) (1 + getNumberValue(field, vs)));
118     }
119     else if (type.equals(Byte.class))
120     {
121       field.set(vs, (byte) (1 + getNumberValue(field, vs)));
122     }
123     else if (type.equals(Character.class))
124     {
125       field.set(vs, (char) (1 + getNumberValue(field, vs)));
126     }
127     else if (type.equals(String.class))
128     {
129       field.set(vs, "Joe" + field.get(vs));
130     }
131     else if (type.equals(Color.class))
132     {
133       field.set(vs, Color.RED.equals(field.get(vs)) ? Color.BLACK
134               : Color.RED);
135     }
136     else
137     {
138       AssertJUnit.fail("Unhandled field type (add to test): " + field.getName()
139               + ":" + type);
140     }
141   }
142
143   private double getNumberValue(Field field, ViewStyle vs)
144           throws IllegalArgumentException, IllegalAccessException
145   {
146     if (field.get(vs) == null)
147     {
148       return 0d;
149     }
150     return ((Number) field.get(vs)).doubleValue();
151   }
152
153   /**
154    * Test that the equals method compares every field by changing them one by
155    * one in a cloned ViewStyle.
156    * 
157    * This test will fail if a new field is added to ViewStyle but not to the
158    * comparisons in ViewStyle.equals().
159    * 
160    * To confirm that this test works, temporarily comment out one of the field
161    * comparisons in ViewStyle.equals()
162    * 
163    * @throws IllegalAccessException
164    * @throws IllegalArgumentException
165    */
166   @Test
167   public void testEquals() throws IllegalArgumentException,
168           IllegalAccessException
169   {
170     ViewStyle vs1 = new ViewStyle();
171     ViewStyle vs2 = new ViewStyle(vs1);
172
173     assertFalse(vs1.equals(null));
174     assertFalse(vs1.equals(this));
175     assertTrue(vs1.equals(vs2));
176     assertTrue(vs2.equals(vs1));
177
178     Field[] fields = ViewStyle.class.getDeclaredFields();
179     for (Field field : fields)
180     {
181       field.setAccessible(true);
182       Object oldValue = field.get(vs2);
183       changeValue(vs2, field);
184       assertFalse("equals method ignores " + field.getName(),
185               vs1.equals(vs2));
186
187       if (vs1.hashCode() == vs2.hashCode())
188       {
189         // uncomment next line to see which fields hashCode ignores
190         // System.out.println("hashCode ignores " + field.getName());
191       }
192       // restore original value before testing the next field
193       field.set(vs2, oldValue);
194     }
195   }
196 }