1 package jalview.datamodel; 2 3 import static org.testng.Assert.assertEquals; 4 import static org.testng.Assert.assertNotSame; 5 import static org.testng.Assert.fail; 6 7 import java.util.ArrayList; 8 import java.util.ConcurrentModificationException; 9 import java.util.List; 10 11 import org.testng.annotations.BeforeMethod; 12 import org.testng.annotations.Test; 13 14 /** 15 * Not a test of code specific to Jalview, but some tests to verify Java 16 * behaviour under certain scenarios of concurrent modification of iterated 17 * lists or arrays 18 */ 19 public class ConcurrentModificationTest 20 { 21 static int MAX = 10; 22 23 int[] intArray; 24 25 List<Integer> intList; 26 27 /** 28 * Setup: populate array and list with values 0,...,9 29 */ 30 @BeforeMethod() setUp()31 public void setUp() 32 { 33 intArray = new int[MAX]; 34 intList = new ArrayList<Integer>(); 35 for (int i = 0; i < MAX; i++) 36 { 37 intArray[i] = i; 38 intList.add(i); 39 } 40 } 41 42 /** 43 * Sanity check of values if no 'interference' 44 */ 45 @Test test_nullCase()46 public void test_nullCase() 47 { 48 /* 49 * array iteration 50 */ 51 int j = 0; 52 for (int i : intArray) 53 { 54 assertEquals(i, j); 55 j++; 56 } 57 58 /* 59 * list iteration 60 */ 61 j = 0; 62 for (int i : intList) 63 { 64 assertEquals(i, j); 65 j++; 66 } 67 } 68 69 /** 70 * Test for the case where the array is reallocated and enlarged during the 71 * iteration. The for loop iteration is not affected. 72 */ 73 @Test testEnhancedForLoop_arrayExtended()74 public void testEnhancedForLoop_arrayExtended() 75 { 76 int j = 0; 77 for (int i : intArray) 78 { 79 if (j == 5) 80 { 81 intArray = new int[MAX + 1]; 82 } 83 assertEquals(i, j); 84 j++; 85 } 86 assertEquals(j, MAX); 87 } 88 89 /** 90 * Test for the case where the array is nulled during the iteration. The for 91 * loop iteration is not affected. 92 */ 93 @Test testEnhancedForLoop_arrayNulled()94 public void testEnhancedForLoop_arrayNulled() 95 { 96 int j = 0; 97 for (int i : intArray) 98 { 99 if (j == 5) 100 { 101 intArray = null; 102 } 103 assertEquals(i, j); 104 j++; 105 } 106 assertEquals(j, MAX); 107 } 108 109 /** 110 * Test for the case where a value is changed before the iteration reaches it. 111 * The iteration reads the new value. 112 * <p> 113 * This is analagous to Jalview's consensus thread modifying entries in the 114 * AlignmentAnnotation.annotations array of Annotation[] while it is being 115 * read. 116 */ 117 @Test testEnhancedForLoop_arrayModified()118 public void testEnhancedForLoop_arrayModified() 119 { 120 int j = 0; 121 for (int i : intArray) 122 { 123 if (j == 5) 124 { 125 intArray[5] = -1; 126 intArray[6] = -2; 127 } 128 /* 129 * the value 'just read' by the for loop is not affected; 130 * the next value read is affected 131 */ 132 int expected = j == 6 ? -2 : j; 133 assertEquals(i, expected); 134 j++; 135 } 136 assertEquals(j, MAX); 137 } 138 139 /** 140 * Test for the case where a list entry is added during the iteration. 141 */ 142 @Test testEnhancedForLoop_listExtended()143 public void testEnhancedForLoop_listExtended() 144 { 145 int j = 0; 146 try 147 { 148 for (int i : intList) 149 { 150 if (j == 5) 151 { 152 intList.add(MAX + 1); 153 } 154 assertEquals(i, j); 155 j++; 156 } 157 } catch (ConcurrentModificationException e) 158 { 159 /* 160 * exception occurs on next loop iteration after 'concurrent' 161 * modification 162 */ 163 assertEquals(j, 6); 164 return; 165 } 166 fail("Expected exception"); 167 } 168 169 /** 170 * Test for the case where a list entry is modified during the iteration. No 171 * exception occurs. 172 */ 173 @Test testEnhancedForLoop_listModified()174 public void testEnhancedForLoop_listModified() 175 { 176 int j = 0; 177 for (int i : intList) 178 { 179 if (j == 5) 180 { 181 intList.set(5, -1); 182 intList.set(6, -2); 183 } 184 185 /* 186 * the value 'just read' is not affected, the next value 187 * is read as modified, no exception 188 */ 189 int expected = j == 6 ? -2 : j; 190 assertEquals(i, expected); 191 j++; 192 } 193 assertEquals(j, MAX); 194 } 195 196 /** 197 * Test for the case where the list is recreated during the iteration. 198 */ 199 @Test testEnhancedForLoop_listRenewed()200 public void testEnhancedForLoop_listRenewed() 201 { 202 Object theList = intList; 203 int j = 0; 204 for (int i : intList) 205 { 206 if (j == 5) 207 { 208 /* 209 * recreate a new List object 210 */ 211 setUp(); 212 assertNotSame(theList, intList); 213 } 214 assertEquals(i, j); 215 j++; 216 } 217 218 /* 219 * no exception in the for loop; changing the object intList refers to 220 * does not affect the loop's iteration over the original object 221 */ 222 assertEquals(j, MAX); 223 } 224 } 225