| /******************************************************************************* |
| * Copyright (c) 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| package org.eclipse.tracecompass.ctf.core.tests.util; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.NoSuchElementException; |
| import java.util.Objects; |
| import java.util.Optional; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.tracecompass.internal.ctf.core.utils.SparseList; |
| import org.junit.Test; |
| |
| /** |
| * Sparse list test |
| * |
| * @author Matthew Khouzam |
| */ |
| public class SparseListTest { |
| |
| /** |
| * Create a list |
| * |
| * @return the list |
| */ |
| protected List<String> createList() { |
| return new SparseList<>(); |
| } |
| |
| /** |
| * Create a list that copies the data |
| * |
| * @param reference |
| * the source list |
| * @return a list |
| */ |
| protected List<String> createList(List<String> reference) { |
| return new SparseList<>(reference); |
| } |
| |
| /** |
| * Test simple building |
| */ |
| @Test |
| public void testSimple() { |
| List<String> test = createList(); |
| test.add("Pomme"); |
| for (int i = 0; i < 99999; i++) { |
| test.add(null); |
| } |
| test.add("Peche"); |
| for (int i = 0; i < 99999; i++) { |
| test.add(null); |
| } |
| test.add("Poire"); |
| for (int i = 0; i < 99998; i++) { |
| test.add(null); |
| } |
| test.add("Banane"); |
| assertEquals(300000, test.size()); |
| } |
| |
| /** |
| * Test equality of list |
| */ |
| @Test |
| public void testEquality() { |
| List<String> test = createList(); |
| test.add("Pomme"); |
| test.add("Peche"); |
| test.add("Poire"); |
| test.add("Banane"); |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> badReference = Arrays.asList("Apple", "Peach", "Pear", "Banana"); |
| List<String> outOfOrderReference = Arrays.asList("Pomme", "Peche", "Banane", "Poire"); |
| assertEquals(reference, test); |
| assertNotEquals(badReference, test); |
| assertNotEquals(outOfOrderReference, test); |
| assertTrue(test.add(null)); |
| assertNotEquals(reference, test); |
| } |
| |
| /** |
| * Test a copy constructor |
| */ |
| @Test |
| public void testCopyConstructor() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(reference); |
| assertEquals(reference, test); |
| } |
| |
| /** |
| * Test a copy constructor |
| */ |
| @Test |
| public void testCopyConstructorWithNull() { |
| List<String> reference = new ArrayList<>(); |
| reference.add(null); |
| List<String> test = createList(reference); |
| assertEquals(reference, test); |
| } |
| |
| /** |
| * Test with hash collisions |
| */ |
| @Test |
| public void testHashCollision() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| SparseList<String> test = new SparseList<>(); |
| test.ensureSize(1000000); |
| test.set(242899, reference.get(0)); |
| test.set(583202, reference.get(1)); |
| test.set(703005, reference.get(2)); |
| test.set(962783, reference.get(3)); |
| assertArrayEquals(reference.toArray(), test.toArray()); |
| assertArrayEquals(reference.toArray(new String[4]), test.toArray(new String[4])); |
| } |
| |
| /** |
| * Test a copy copy copy copy constructor |
| */ |
| @Test |
| public void testRecursiveCopyConstructor() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(createList(createList(createList(reference)))); |
| assertEquals(reference, test); |
| } |
| |
| /** |
| * Test a constructor with nulls |
| */ |
| @Test |
| public void testCopyConstructorWithNulls() { |
| List<String> reference = Arrays.asList("Pomme", null, "Peche", null, "Poire", null, "Banane", null); |
| List<String> test = createList(reference); |
| assertEquals(reference, test); |
| } |
| |
| /** |
| * Test Streams and the spliterator |
| */ |
| @Test |
| public void testStreams() { |
| List<String> reference = Arrays.asList("Pomme", null, "Peche", null, "Poire", null, "Banane", null); |
| Optional<String> first = reference.stream().findFirst(); |
| assertTrue(first.isPresent()); |
| assertEquals("Pomme", first.get()); |
| Optional<String> firstNonNull = reference.stream().filter(Objects::nonNull).findFirst(); |
| assertTrue(firstNonNull.isPresent()); |
| assertEquals("Pomme", firstNonNull.get()); |
| assertEquals(4, reference.stream().filter(Objects::isNull).count()); |
| assertEquals(Arrays.asList("Pomme", null, "Peche", "Poire", "Banane"), reference.stream().distinct().collect(Collectors.toList())); |
| } |
| |
| /** |
| * Test clear... shouldn't work, but it was easy |
| */ |
| @Test |
| public void testClear() { |
| List<String> test = createList(); |
| List<String> reference = Arrays.asList("Pomme", "Peche", null, "Poire", "Banane"); |
| assertTrue(test.isEmpty()); |
| test.addAll(reference); |
| assertEquals(reference, test); |
| test.clear(); |
| assertTrue(test.isEmpty()); |
| } |
| |
| /** |
| * Test is empty |
| */ |
| @Test |
| public void testIsEmpty() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(); |
| assertTrue(test.isEmpty()); |
| test.addAll(test); |
| assertTrue(test.isEmpty()); |
| test.addAll(reference); |
| assertFalse(test.isEmpty()); |
| test = createList(); |
| assertTrue(test.isEmpty()); |
| test.add(null); |
| assertFalse(test.isEmpty()); |
| } |
| |
| /** |
| * Test contains with null and other |
| */ |
| @Test |
| public void testContains() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(reference); |
| assertTrue(test.contains("Pomme")); |
| assertFalse(test.contains(null)); |
| assertTrue(test.containsAll(Arrays.asList("Peche", "Pomme"))); |
| assertFalse(test.containsAll(Arrays.asList("Pomme", null, "Peche", null))); |
| // add a null and re-run |
| test.add(null); |
| assertTrue(test.contains("Pomme")); |
| assertTrue(test.contains(null)); |
| assertTrue(test.containsAll(Arrays.asList("Peche", "Pomme"))); |
| assertTrue(test.containsAll(Arrays.asList("Pomme", null, "Peche", null))); |
| } |
| |
| /** |
| * Test indexOfs |
| */ |
| @Test |
| public void testIndexOf() { |
| List<String> test = createList(); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("mushroom"); |
| test.add("mushroom"); |
| assertEquals(0, test.indexOf("badger")); |
| assertEquals(-1, test.indexOf("a snake")); |
| assertEquals(-1, test.indexOf(null)); |
| assertEquals(-1, test.lastIndexOf(null)); |
| assertEquals(11, test.lastIndexOf("badger")); |
| assertTrue(test.contains("badger")); |
| assertTrue(test.containsAll(Collections.singleton("badger"))); |
| assertTrue(test.containsAll(Arrays.asList("badger", "mushroom"))); |
| } |
| |
| /** |
| * Test streams |
| */ |
| @Test |
| public void testStream() { |
| List<String> test = createList(); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("badger"); |
| test.add("mushroom"); |
| test.add("mushroom"); |
| assertEquals(12, test.parallelStream().filter("badger"::equals).count()); |
| } |
| |
| /** |
| * Test toArray |
| */ |
| @Test |
| public void testToArray() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(reference); |
| assertArrayEquals(reference.toArray(), test.toArray()); |
| assertArrayEquals(reference.toArray(new String[4]), test.toArray(new String[4])); |
| List<String> referenceWithNulls = Arrays.asList("Pomme", "Peche", "Poire", null, "Banane"); |
| test = createList(referenceWithNulls); |
| assertArrayEquals(reference.toArray(), test.toArray()); |
| assertArrayEquals(reference.toArray(new String[4]), test.toArray(new String[4])); |
| assertArrayEquals(reference.toArray(new String[4]), test.toArray(new String[1])); |
| assertArrayEquals(reference.toArray(new String[5]), test.toArray(new String[5])); |
| try { |
| assertArrayEquals(reference.toArray(new String[4]), test.toArray(new Long[4])); |
| fail("Should not get here"); |
| } catch (ArrayStoreException e) { |
| // correct flow |
| } |
| } |
| |
| /** |
| * Test toString |
| */ |
| @Test |
| public void testToString() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", null, "Banane"); |
| List<String> test = createList(reference); |
| assertEquals("[0:Pomme, 1:Peche, 2:Poire, 4:Banane]", test.toString()); |
| } |
| |
| /** |
| * Test the set operation |
| */ |
| @Test |
| public void testSet() { |
| List<String> reference = Arrays.asList("Pomme", "Peche", "Poire", "Banane"); |
| List<String> test = createList(reference); |
| assertEquals(reference, test); |
| test.set(0, "pomme"); |
| assertNotEquals(reference, test); |
| try { |
| test.set(-1, "pomme"); |
| fail("Should not get here"); |
| } catch (IndexOutOfBoundsException e) { |
| // correct flow |
| } |
| try { |
| test.set(5, "pomme"); |
| fail("Should not get here"); |
| } catch (IndexOutOfBoundsException e) { |
| // correct flow |
| } |
| } |
| |
| /** |
| * Test the list iterator |
| */ |
| @Test |
| public void testListIterator() { |
| testListIterator(createList(Arrays.asList("Hola", "yo", "quiero", "un", "UNSUPPORTEDOPERATIONEXCEPTION!"))); |
| } |
| |
| /** |
| * Test the list iterator out of order |
| */ |
| @Test |
| public void testListIteratorOutOfOrder() { |
| SparseList<String> list = new SparseList<>(); |
| list.ensureSize(5); |
| list.set(4, "UNSUPPORTEDOPERATIONEXCEPTION!"); |
| list.set(2, "quiero"); |
| list.set(1, "yo"); |
| list.set(0, "Hola"); |
| list.set(3, "un"); |
| testListIterator(list); |
| } |
| |
| private static void testListIterator(List<String> test) { |
| ListIterator<String> iterator = test.listIterator(0); |
| assertTrue(iterator.hasNext()); |
| assertFalse(iterator.hasPrevious()); |
| try { |
| iterator.previous(); |
| fail("Should not get here"); |
| } catch (NoSuchElementException e) { |
| // correct flow |
| } |
| assertEquals("Hola", iterator.next()); |
| assertEquals("yo", iterator.next()); |
| assertEquals("yo", iterator.previous()); |
| assertEquals("Hola", iterator.previous()); |
| try { |
| iterator.previous(); |
| fail("Should not get here"); |
| } catch (NoSuchElementException e) { |
| // correct flow |
| } |
| assertEquals("Hola", iterator.next()); |
| assertEquals("yo", iterator.next()); |
| assertEquals("quiero", iterator.next()); |
| assertEquals("un", iterator.next()); |
| assertEquals("UNSUPPORTEDOPERATIONEXCEPTION!", iterator.next()); |
| try { |
| iterator.next(); |
| fail("Should not get here"); |
| } catch (NoSuchElementException e) { |
| // correct flow |
| } |
| assertEquals("UNSUPPORTEDOPERATIONEXCEPTION!", iterator.previous()); |
| assertEquals(3, iterator.previousIndex()); |
| assertEquals(4, iterator.nextIndex()); |
| try { |
| iterator.remove(); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| iterator.set("hej"); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| iterator.add("hi"); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| } |
| |
| /** |
| * Test a list iterator with nulls |
| */ |
| @Test |
| public void testListIteratorWithNull() { |
| List<String> list = createList(Arrays.asList("Hello", null, "world")); |
| ListIterator<String> iterator = list.listIterator(); |
| assertEquals("Hello", iterator.next()); |
| assertEquals(null, iterator.next()); |
| assertEquals("world", iterator.next()); |
| assertEquals("world", iterator.previous()); |
| assertEquals(null, iterator.previous()); |
| assertEquals("Hello", iterator.previous()); |
| iterator = list.listIterator(0); |
| assertEquals("Hello", iterator.next()); |
| assertEquals(null, iterator.next()); |
| assertEquals("world", iterator.next()); |
| assertEquals("world", iterator.previous()); |
| assertEquals(null, iterator.previous()); |
| assertEquals("Hello", iterator.previous()); |
| iterator = list.listIterator(1); |
| assertEquals("Hello", iterator.previous()); |
| assertEquals("Hello", iterator.next()); |
| assertEquals(null, iterator.next()); |
| assertEquals("world", iterator.next()); |
| assertEquals("world", iterator.previous()); |
| assertEquals(null, iterator.previous()); |
| assertEquals("Hello", iterator.previous()); |
| iterator = list.listIterator(2); |
| assertEquals(null, iterator.previous()); |
| assertEquals("Hello", iterator.previous()); |
| assertEquals("Hello", iterator.next()); |
| assertEquals(null, iterator.next()); |
| assertEquals("world", iterator.next()); |
| assertEquals("world", iterator.previous()); |
| assertEquals(null, iterator.previous()); |
| assertEquals("Hello", iterator.previous()); |
| } |
| |
| /** |
| * Test setting the values our of order |
| */ |
| @Test |
| public void testUnorderedSet() { |
| String value = "badger"; |
| List<String> test = createList(); |
| ((SparseList<String>) test).ensureSize(5); |
| test.set(4, value); |
| test.set(2, value); |
| assertEquals(2, test.indexOf(value)); |
| assertEquals(4, test.lastIndexOf(value)); |
| assertEquals(0, test.indexOf(null)); |
| assertEquals(3, test.lastIndexOf(null)); |
| assertEquals(-1, test.indexOf("mushroom")); |
| assertEquals(-1, test.lastIndexOf("mushroom")); |
| assertNull(test.get(0)); |
| assertNull(test.get(1)); |
| assertEquals(value, test.get(2)); |
| assertNull(test.get(3)); |
| assertEquals(value, test.get(4)); |
| test.set(0, value); |
| assertEquals(1, test.indexOf(null)); |
| } |
| |
| /** |
| * Reminds people to update tests if they add these features. |
| */ |
| @Test |
| public void testUnsupporteds() { |
| List<String> test = createList(); |
| try { |
| test.addAll(0, Collections.emptyList()); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.add(0, null); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.remove(0); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.subList(0, 0); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.remove("que?"); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.removeAll(Collections.singletonList("que?")); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.retainAll(Arrays.asList("que", "pasa?")); |
| fail("Should not get here"); |
| } catch (UnsupportedOperationException e) { |
| // correct flow |
| } |
| try { |
| test.get(-1); |
| fail("Should not get here"); |
| } catch (IndexOutOfBoundsException e) { |
| // correct flow |
| } |
| try { |
| test.get(test.size()); |
| fail("Should not get here"); |
| } catch (IndexOutOfBoundsException e) { |
| // correct flow |
| } |
| } |
| } |