View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.commons.collections;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  import static org.apache.juneau.junit.bct.BctAssertions.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import org.apache.juneau.*;
24  import org.junit.jupiter.api.*;
25  
26  class ControlledArrayList_Test extends TestBase {
27  
28  	@Nested
29  	class A_ConstructorTests extends TestBase {
30  
31  		@Test
32  		void a01_emptyModifiable() {
33  			var x = new ControlledArrayList<>(false);
34  			assertTrue(x.isModifiable());
35  			assertEmpty(x);
36  		}
37  
38  		@Test
39  		void a02_emptyUnmodifiable() {
40  			var x = new ControlledArrayList<>(true);
41  			assertFalse(x.isModifiable());
42  			assertEmpty(x);
43  		}
44  
45  		@Test
46  		void a03_withInitialListModifiable() {
47  			var x = new ControlledArrayList<>(false, l(1, 2, 3));
48  			assertTrue(x.isModifiable());
49  			assertList(x, 1, 2, 3);
50  		}
51  
52  		@Test
53  		void a04_withInitialListUnmodifiable() {
54  			var x = new ControlledArrayList<>(true, l(1, 2, 3));
55  			assertFalse(x.isModifiable());
56  			assertList(x, 1, 2, 3);
57  		}
58  
59  		@Test
60  		void a05_withEmptyList() {
61  			var x1 = new ControlledArrayList<>(false, l());
62  			var x2 = new ControlledArrayList<>(true, l());
63  			assertTrue(x1.isModifiable());
64  			assertFalse(x2.isModifiable());
65  			assertEmpty(x1);
66  			assertEmpty(x2);
67  		}
68  	}
69  
70  	@Nested
71  	class B_ModificationTests extends TestBase {
72  
73  		@Test
74  		void b01_set() {
75  			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
76  			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
77  
78  			assertEquals(2, x1.set(1, 99));
79  			assertThrows(UnsupportedOperationException.class, () -> x2.set(1, 99));
80  			x2.overrideSet(1, 99);
81  			assertList(x1, 1, 99, 3);
82  			assertList(x2, 1, 99, 3);
83  		}
84  
85  		@Test
86  		void b02_add() {
87  			var x1 = new ControlledArrayList<>(false, l(1, 2));
88  			var x2 = new ControlledArrayList<>(true, l(1, 2));
89  
90  			assertTrue(x1.add(3));
91  			assertThrows(UnsupportedOperationException.class, () -> x2.add(3));
92  			x2.overrideAdd(3);
93  			assertList(x1, 1, 2, 3);
94  			assertList(x2, 1, 2, 3);
95  		}
96  
97  		@Test
98  		void b03_addAtIndex() {
99  			var x1 = new ControlledArrayList<>(false, l(1, 3));
100 			var x2 = new ControlledArrayList<>(true, l(1, 3));
101 
102 			x1.add(1, 2);
103 			assertThrows(UnsupportedOperationException.class, () -> x2.add(1, 2));
104 			x2.overrideAdd(1, 2);
105 			assertList(x1, 1, 2, 3);
106 			assertList(x2, 1, 2, 3);
107 		}
108 
109 		@Test
110 		void b04_addAll() {
111 			var x1 = new ControlledArrayList<>(false, l(1));
112 			var x2 = new ControlledArrayList<>(true, l(1));
113 
114 			assertTrue(x1.addAll(l(2, 3)));
115 			assertThrows(UnsupportedOperationException.class, () -> x2.addAll(l(2, 3)));
116 			x2.overrideAddAll(l(2, 3));
117 			assertList(x1, 1, 2, 3);
118 			assertList(x2, 1, 2, 3);
119 		}
120 
121 		@Test
122 		void b05_addAllAtIndex() {
123 			var x1 = new ControlledArrayList<>(false, l(1, 4));
124 			var x2 = new ControlledArrayList<>(true, l(1, 4));
125 
126 			assertTrue(x1.addAll(1, l(2, 3)));
127 			assertThrows(UnsupportedOperationException.class, () -> x2.addAll(1, l(2, 3)));
128 			x2.overrideAddAll(1, l(2, 3));
129 			assertList(x1, 1, 2, 3, 4);
130 			assertList(x2, 1, 2, 3, 4);
131 		}
132 
133 		@Test
134 		void b06_removeByIndex() {
135 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
136 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
137 
138 			assertEquals(2, x1.remove(1));
139 			assertThrows(UnsupportedOperationException.class, () -> x2.remove(1));
140 			x2.overrideRemove(1);
141 			assertList(x1, 1, 3);
142 			assertList(x2, 1, 3);
143 		}
144 
145 		@Test
146 		void b07_removeByObject() {
147 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
148 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
149 
150 			assertTrue(x1.remove((Integer)2));
151 			assertThrows(UnsupportedOperationException.class, () -> x2.remove((Integer)2));
152 			x2.overrideRemove((Integer)2);
153 			assertList(x1, 1, 3);
154 			assertList(x2, 1, 3);
155 		}
156 
157 		@Test
158 		void b08_removeAll() {
159 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
160 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
161 
162 			assertTrue(x1.removeAll(l(2, 4)));
163 			assertThrows(UnsupportedOperationException.class, () -> x2.removeAll(l(2, 4)));
164 			x2.overrideRemoveAll(l(2, 4));
165 			assertList(x1, 1, 3);
166 			assertList(x2, 1, 3);
167 		}
168 
169 		@Test
170 		void b09_retainAll() {
171 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
172 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
173 
174 			assertTrue(x1.retainAll(l(2, 4)));
175 			assertThrows(UnsupportedOperationException.class, () -> x2.retainAll(l(2, 4)));
176 			x2.overrideRetainAll(l(2, 4));
177 			assertList(x1, 2, 4);
178 			assertList(x2, 2, 4);
179 		}
180 
181 		@Test
182 		void b10_clear() {
183 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
184 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
185 
186 			x1.clear();
187 			assertThrows(UnsupportedOperationException.class, x2::clear);
188 			x2.overrideClear();
189 			assertEmpty(x1);
190 			assertEmpty(x2);
191 		}
192 
193 		@Test
194 		void b11_replaceAll() {
195 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
196 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
197 
198 			x1.replaceAll(x -> x * 2);
199 			assertThrows(UnsupportedOperationException.class, () -> x2.replaceAll(x -> x * 2));
200 			x2.overrideReplaceAll(x -> x * 2);
201 			assertList(x1, 2, 4, 6);
202 			assertList(x2, 2, 4, 6);
203 		}
204 
205 		@Test
206 		void b12_removeIf() {
207 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
208 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
209 
210 			assertTrue(x1.removeIf(x -> x % 2 == 0));
211 			assertThrows(UnsupportedOperationException.class, () -> x2.removeIf(x -> x % 2 == 0));
212 			x2.overrideRemoveIf(x -> x % 2 == 0);
213 			assertList(x1, 1, 3);
214 			assertList(x2, 1, 3);
215 		}
216 
217 		@Test
218 		void b13_sort() {
219 			var x1 = new ControlledArrayList<>(false, l(3, 1, 4, 2));
220 			var x2 = new ControlledArrayList<>(true, l(3, 1, 4, 2));
221 
222 			x1.sort(null);
223 			assertThrows(UnsupportedOperationException.class, () -> x2.sort(null));
224 			x2.overrideSort(null);
225 			assertList(x1, 1, 2, 3, 4);
226 			assertList(x2, 1, 2, 3, 4);
227 		}
228 
229 		@Test
230 		void b14_sortWithComparator() {
231 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
232 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
233 
234 			x1.sort((a, b) -> b.compareTo(a));
235 			assertThrows(UnsupportedOperationException.class, () -> x2.sort((a, b) -> b.compareTo(a)));
236 			x2.overrideSort((a, b) -> b.compareTo(a));
237 			assertList(x1, 4, 3, 2, 1);
238 			assertList(x2, 4, 3, 2, 1);
239 		}
240 	}
241 
242 	@Nested
243 	class C_IteratorTests extends TestBase {
244 
245 		@Test
246 		void c01_modifiableIterator() {
247 			var x = new ControlledArrayList<>(false, l(1, 2, 3));
248 			var it = x.iterator();
249 
250 			assertTrue(it.hasNext());
251 			assertEquals(1, it.next());
252 			it.remove();
253 			assertList(x, 2, 3);
254 
255 			assertTrue(it.hasNext());
256 			assertEquals(2, it.next());
257 			assertTrue(it.hasNext());
258 			assertEquals(3, it.next());
259 			assertFalse(it.hasNext());
260 		}
261 
262 		@Test
263 		void c02_unmodifiableIterator() {
264 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
265 			var it = x.iterator();
266 
267 			assertTrue(it.hasNext());
268 			assertEquals(1, it.next());
269 			assertThrows(UnsupportedOperationException.class, it::remove);
270 
271 			assertTrue(it.hasNext());
272 			assertEquals(2, it.next());
273 			assertTrue(it.hasNext());
274 			assertEquals(3, it.next());
275 			assertFalse(it.hasNext());
276 		}
277 
278 		@Test
279 		void c03_iteratorForEachRemaining() {
280 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
281 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
282 			var list1 = new java.util.ArrayList<Integer>();
283 			var list2 = new java.util.ArrayList<Integer>();
284 
285 			x1.iterator().forEachRemaining(list1::add);
286 			x2.iterator().forEachRemaining(list2::add);
287 
288 			assertList(list1, 1, 2, 3);
289 			assertList(list2, 1, 2, 3);
290 		}
291 
292 		@Test
293 		void c04_overrideIterator() {
294 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
295 			var it = x.overrideIterator();
296 
297 			assertTrue(it.hasNext());
298 			assertEquals(1, it.next());
299 			// Note: overrideIterator() returns the underlying iterator, but iterator.remove()
300 			// still goes through the list's remove() method which checks modifiability.
301 			// So we can only test that it returns a readable iterator.
302 			var list = new java.util.ArrayList<Integer>();
303 			it.forEachRemaining(list::add);
304 			assertList(list, 2, 3);
305 		}
306 
307 		@Test
308 		void c05_emptyIterator() {
309 			var x1 = new ControlledArrayList<>(false);
310 			var x2 = new ControlledArrayList<>(true);
311 
312 			assertFalse(x1.iterator().hasNext());
313 			assertFalse(x2.iterator().hasNext());
314 		}
315 	}
316 
317 	@Nested
318 	class D_ListIteratorTests extends TestBase {
319 
320 		@Test
321 		void d01_modifiableListIterator() {
322 			var x = new ControlledArrayList<>(false, l(1, 2, 3));
323 			var it = x.listIterator();
324 
325 			assertTrue(it.hasNext());
326 			assertFalse(it.hasPrevious());
327 			assertEquals(0, it.nextIndex());
328 			assertEquals(-1, it.previousIndex());
329 
330 			assertEquals(1, it.next());
331 			assertTrue(it.hasPrevious());
332 			assertEquals(1, it.nextIndex());
333 			assertEquals(0, it.previousIndex());
334 
335 			it.set(99);
336 			assertList(x, 99, 2, 3);
337 
338 			it.add(100);
339 			assertList(x, 99, 100, 2, 3);
340 
341 			assertEquals(2, it.nextIndex());
342 			assertEquals(1, it.previousIndex());
343 		}
344 
345 		@Test
346 		void d02_unmodifiableListIterator() {
347 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
348 			var it = x.listIterator();
349 
350 			assertTrue(it.hasNext());
351 			assertFalse(it.hasPrevious());
352 			assertEquals(0, it.nextIndex());
353 			assertEquals(-1, it.previousIndex());
354 
355 			assertEquals(1, it.next());
356 			assertTrue(it.hasPrevious());
357 			assertEquals(1, it.nextIndex());
358 			assertEquals(0, it.previousIndex());
359 
360 			assertThrows(UnsupportedOperationException.class, () -> it.set(99));
361 			assertThrows(UnsupportedOperationException.class, () -> it.add(100));
362 			assertThrows(UnsupportedOperationException.class, it::remove);
363 		}
364 
365 		@Test
366 		void d03_listIteratorWithIndex() {
367 			var x = new ControlledArrayList<>(false, l(1, 2, 3, 4));
368 			var it = x.listIterator(2);
369 
370 			assertTrue(it.hasNext());
371 			assertTrue(it.hasPrevious());
372 			assertEquals(2, it.nextIndex());
373 			assertEquals(1, it.previousIndex());
374 
375 			assertEquals(3, it.next());
376 			assertEquals(2, it.previousIndex());
377 			assertEquals(3, it.previous());
378 			assertEquals(1, it.previousIndex());
379 		}
380 
381 		@Test
382 		void d04_listIteratorWithIndexUnmodifiable() {
383 			var x = new ControlledArrayList<>(true, l(1, 2, 3, 4));
384 			var it = x.listIterator(2);
385 
386 			assertTrue(it.hasNext());
387 			assertTrue(it.hasPrevious());
388 			assertEquals(2, it.nextIndex());
389 			assertEquals(1, it.previousIndex());
390 
391 			assertEquals(3, it.next());
392 			assertThrows(UnsupportedOperationException.class, () -> it.set(99));
393 			assertThrows(UnsupportedOperationException.class, () -> it.add(100));
394 			assertThrows(UnsupportedOperationException.class, it::remove);
395 		}
396 
397 		@Test
398 		void d05_listIteratorForEachRemaining() {
399 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
400 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
401 			var list1 = new java.util.ArrayList<Integer>();
402 			var list2 = new java.util.ArrayList<Integer>();
403 
404 			x1.listIterator().forEachRemaining(list1::add);
405 			x2.listIterator().forEachRemaining(list2::add);
406 
407 			assertList(list1, 1, 2, 3);
408 			assertList(list2, 1, 2, 3);
409 		}
410 
411 		@Test
412 		void d06_overrideListIterator() {
413 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
414 			var it = x.overrideListIterator(1);
415 
416 			assertTrue(it.hasNext());
417 			assertEquals(2, it.next());
418 			// Note: overrideListIterator() returns the underlying iterator, but iterator.set()
419 			// still goes through the list's set() method which checks modifiability.
420 			// So we can only test that it returns a readable iterator at the correct position.
421 			assertTrue(it.hasPrevious());
422 			assertEquals(1, it.previousIndex());
423 			assertEquals(2, it.nextIndex());
424 		}
425 
426 		@Test
427 		void d07_listIteratorBidirectional() {
428 			var x = new ControlledArrayList<>(false, l(1, 2, 3));
429 			var it = x.listIterator();
430 
431 			assertEquals(1, it.next());
432 			assertEquals(2, it.next());
433 			assertEquals(2, it.previous());
434 			assertEquals(1, it.previous());
435 			assertFalse(it.hasPrevious());
436 		}
437 
438 		@Test
439 		void d08_listIteratorWithIndex_previous() {
440 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
441 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
442 
443 			// Test modifiable list
444 			var it1 = x1.listIterator(2);
445 			assertTrue(it1.hasPrevious());
446 			assertEquals(1, it1.previousIndex());
447 			assertEquals(2, it1.previous()); // Should return element at index 1 (which is 2)
448 			assertEquals(0, it1.previousIndex());
449 			assertEquals(1, it1.previous()); // Should return element at index 0 (which is 1)
450 			assertFalse(it1.hasPrevious());
451 
452 			// Test unmodifiable list
453 			var it2 = x2.listIterator(2);
454 			assertTrue(it2.hasPrevious());
455 			assertEquals(1, it2.previousIndex());
456 			assertEquals(2, it2.previous()); // Should return element at index 1 (which is 2)
457 			assertEquals(0, it2.previousIndex());
458 			assertEquals(1, it2.previous()); // Should return element at index 0 (which is 1)
459 			assertFalse(it2.hasPrevious());
460 		}
461 
462 		@Test
463 		void d09_listIteratorWithIndex_previousFromEnd() {
464 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
465 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
466 
467 			// Test modifiable list - start at end
468 			var it1 = x1.listIterator(3);
469 			assertFalse(it1.hasNext());
470 			assertTrue(it1.hasPrevious());
471 			assertEquals(2, it1.previousIndex());
472 			assertEquals(3, it1.previous()); // Should return element at index 2 (which is 3)
473 			assertEquals(2, it1.previous()); // Should return element at index 1 (which is 2)
474 			assertEquals(1, it1.previous()); // Should return element at index 0 (which is 1)
475 			assertFalse(it1.hasPrevious());
476 
477 			// Test unmodifiable list - start at end
478 			var it2 = x2.listIterator(3);
479 			assertFalse(it2.hasNext());
480 			assertTrue(it2.hasPrevious());
481 			assertEquals(2, it2.previousIndex());
482 			assertEquals(3, it2.previous()); // Should return element at index 2 (which is 3)
483 			assertEquals(2, it2.previous()); // Should return element at index 1 (which is 2)
484 			assertEquals(1, it2.previous()); // Should return element at index 0 (which is 1)
485 			assertFalse(it2.hasPrevious());
486 		}
487 
488 		@Test
489 		void d10_listIteratorWithIndex_previousBidirectional() {
490 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3, 4));
491 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3, 4));
492 
493 			// Test modifiable list - bidirectional from middle
494 			var it1 = x1.listIterator(2);
495 			assertEquals(3, it1.next());
496 			assertEquals(3, it1.previous());
497 			assertEquals(2, it1.previous());
498 			assertEquals(2, it1.next());
499 			assertEquals(3, it1.next());
500 
501 			// Test unmodifiable list - bidirectional from middle
502 			var it2 = x2.listIterator(2);
503 			assertEquals(3, it2.next());
504 			assertEquals(3, it2.previous());
505 			assertEquals(2, it2.previous());
506 			assertEquals(2, it2.next());
507 			assertEquals(3, it2.next());
508 		}
509 	}
510 
511 	@Nested
512 	class E_SubListTests extends TestBase {
513 
514 		@Test
515 		void e01_subListModifiable() {
516 			var x = new ControlledArrayList<>(false, l(1, 2, 3, 4, 5));
517 			var sub = (ControlledArrayList<Integer>) x.subList(1, 4);
518 
519 			assertTrue(sub.isModifiable());
520 			assertList(sub, 2, 3, 4);
521 
522 			// Note: subList creates a copy, not a view (because the constructor copies elements)
523 			// So modifications to subList don't affect the original list
524 			sub.set(0, 99);
525 			assertEquals(99, sub.get(0));
526 			assertList(sub, 99, 3, 4);
527 			// Original list is unchanged
528 			assertList(x, 1, 2, 3, 4, 5);
529 		}
530 
531 		@Test
532 		void e02_subListUnmodifiable() {
533 			var x = new ControlledArrayList<>(true, l(1, 2, 3, 4, 5));
534 			var sub = (ControlledArrayList<Integer>) x.subList(1, 4);
535 
536 			assertFalse(sub.isModifiable());
537 			assertList(sub, 2, 3, 4);
538 
539 			assertThrows(UnsupportedOperationException.class, () -> sub.set(0, 99));
540 		}
541 
542 		@Test
543 		void e03_subListEmpty() {
544 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
545 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
546 
547 			var sub1 = (ControlledArrayList<Integer>) x1.subList(1, 1);
548 			var sub2 = (ControlledArrayList<Integer>) x2.subList(1, 1);
549 
550 			assertTrue(sub1.isModifiable());
551 			assertFalse(sub2.isModifiable());
552 			assertEmpty(sub1);
553 			assertEmpty(sub2);
554 		}
555 
556 		@Test
557 		void e04_subListFullRange() {
558 			var x1 = new ControlledArrayList<>(false, l(1, 2, 3));
559 			var x2 = new ControlledArrayList<>(true, l(1, 2, 3));
560 
561 			var sub1 = (ControlledArrayList<Integer>) x1.subList(0, 3);
562 			var sub2 = (ControlledArrayList<Integer>) x2.subList(0, 3);
563 
564 			assertTrue(sub1.isModifiable());
565 			assertFalse(sub2.isModifiable());
566 			assertList(sub1, 1, 2, 3);
567 			assertList(sub2, 1, 2, 3);
568 		}
569 	}
570 
571 	@Nested
572 	class F_SetUnmodifiableTests extends TestBase {
573 
574 		@Test
575 		void f01_setUnmodifiable() {
576 			var x = new ControlledArrayList<>(false, l(1, 2, 3));
577 
578 			assertTrue(x.isModifiable());
579 			x.set(0, 99); // Should work
580 
581 			var result = x.setUnmodifiable();
582 			assertSame(x, result); // Should return this
583 			assertFalse(x.isModifiable());
584 
585 			assertThrows(UnsupportedOperationException.class, () -> x.set(0, 100));
586 			assertThrows(UnsupportedOperationException.class, () -> x.add(4));
587 			assertThrows(UnsupportedOperationException.class, () -> x.remove(0));
588 		}
589 
590 		@Test
591 		void f02_setUnmodifiableAlreadyUnmodifiable() {
592 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
593 
594 			assertFalse(x.isModifiable());
595 			x.setUnmodifiable();
596 			assertFalse(x.isModifiable());
597 		}
598 	}
599 
600 	@Nested
601 	class G_EdgeCaseTests extends TestBase {
602 
603 		@Test
604 		void g01_emptyListOperations() {
605 			var x1 = new ControlledArrayList<>(false);
606 			var x2 = new ControlledArrayList<>(true);
607 
608 			assertFalse(x1.addAll(l()));
609 			assertThrows(UnsupportedOperationException.class, () -> x2.addAll(l()));
610 
611 			assertFalse(x1.removeAll(l()));
612 			assertThrows(UnsupportedOperationException.class, () -> x2.removeAll(l()));
613 
614 			assertFalse(x1.retainAll(l()));
615 			assertThrows(UnsupportedOperationException.class, () -> x2.retainAll(l()));
616 
617 			assertFalse(x1.remove((Integer)1));
618 			assertThrows(UnsupportedOperationException.class, () -> x2.remove((Integer)1));
619 		}
620 
621 		@Test
622 		void g02_singleElementList() {
623 			var x1 = new ControlledArrayList<>(false, l(42));
624 			var x2 = new ControlledArrayList<>(true, l(42));
625 
626 			assertEquals(42, x1.get(0));
627 			assertEquals(42, x2.get(0));
628 
629 			x1.set(0, 99);
630 			assertThrows(UnsupportedOperationException.class, () -> x2.set(0, 99));
631 			x2.overrideSet(0, 99);
632 
633 			assertEquals(99, x1.remove(0));
634 			assertThrows(UnsupportedOperationException.class, () -> x2.remove(0));
635 			x2.overrideRemove(0);
636 
637 			assertEmpty(x1);
638 			assertEmpty(x2);
639 		}
640 
641 		@Test
642 		void g03_overrideMethodsWorkWhenUnmodifiable() {
643 			var x = new ControlledArrayList<>(true, l(1, 2, 3));
644 
645 			x.overrideAdd(4);
646 			x.overrideAdd(0, 0);
647 			x.overrideSet(2, 99);
648 			x.overrideRemove(3);
649 			x.overrideRemove((Integer)1);
650 			x.overrideAddAll(l(5, 6));
651 			x.overrideAddAll(0, l(-1));
652 			x.overrideRemoveAll(l(0));
653 			x.overrideRetainAll(l(2, 99, 5, 6));
654 			x.overrideReplaceAll(a -> a * 2);
655 			x.overrideRemoveIf(a -> a == 4);
656 			x.overrideSort(null);
657 			x.overrideClear();
658 
659 			assertEmpty(x);
660 		}
661 
662 		@Test
663 		void g04_isModifiable() {
664 			var x1 = new ControlledArrayList<>(false);
665 			var x2 = new ControlledArrayList<>(true);
666 
667 			assertTrue(x1.isModifiable());
668 			assertFalse(x2.isModifiable());
669 
670 			x1.setUnmodifiable();
671 			assertFalse(x1.isModifiable());
672 		}
673 	}
674 }