/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.collections; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.rules.ExpectedException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Tests the {@link IndexedSet} class. */ public final class IndexedSetTest { private static class Pair { private int mInt; private long mLong; public Pair(int i, long l) { mInt = i; mLong = l; } public int intValue() { return mInt; } public long longValue() { return mLong; } } private IndexedSet<Pair> mSet; private IndexDefinition<Pair> mNonUniqueIntIndex; private IndexDefinition<Pair> mUniqueLongIndex; /** * Sets up the fields before running a test. */ @Before public void before() { mNonUniqueIntIndex = new IndexDefinition<Pair>(false) { @Override public Object getFieldValue(Pair o) { return o.intValue(); } }; mUniqueLongIndex = new IndexDefinition<Pair>(true) { @Override public Object getFieldValue(Pair o) { return o.longValue(); } }; mSet = new IndexedSet<>(mNonUniqueIntIndex, mUniqueLongIndex); long l = 0; for (int i = 0; i < 3; i++) { for (int k = 0; k < 3; k++) { mSet.add(new Pair(i, l++)); } } } /** * Tests the {@link IndexedSet#contains(IndexDefinition, Object) } method. */ @Test public void UniqueContains() { for (int i = 0; i < 3; i++) { Assert.assertTrue(mSet.contains(mNonUniqueIntIndex, i)); } Assert.assertFalse(mSet.contains(mNonUniqueIntIndex, 4)); } /** * Tests the {@link IndexedSet#contains(IndexDefinition, Object)} method. */ @Test public void NonUniqueContains() { for (long l = 0; l < 9; l++) { Assert.assertTrue(mSet.contains(mUniqueLongIndex, l)); } Assert.assertFalse(mSet.contains(mUniqueLongIndex, 9L)); } /** * Tests the {@link IndexedSet#getByField(IndexDefinition, Object)} method. */ @Test public void nonUniqueGet() { for (int i = 0; i < 3; i++) { Set<Pair> set = mSet.getByField(mNonUniqueIntIndex, i); Assert.assertEquals(3, set.size()); List<Long> longs = new ArrayList<>(set.size()); for (Pair o : set) { longs.add(o.longValue()); } Collections.sort(longs); for (int j = 0; j < 3; j++) { Assert.assertEquals(new Long(i * 3 + j), longs.get(j)); } } } /** * Tests the {@link IndexedSet#getByField(IndexDefinition, Object)} method. */ @Test public void uniqueGet() { for (int i = 0; i < 9; i++) { Set<Pair> set = mSet.getByField(mUniqueLongIndex, i); Assert.assertEquals(0, set.size()); // i is integer, must be in the same type set = mSet.getByField(mUniqueLongIndex, (long) i); Assert.assertEquals(1, set.size()); Assert.assertEquals(i / 3, set.iterator().next().intValue()); } } /** * Tests that {@link IndexedSet#remove(Object)} method and * {@link IndexedSet#contains(IndexDefinition, Object)} method work correctly when trying to * remove the data. */ @Test public void remove() { Pair toRemove = mSet.getFirstByField(mUniqueLongIndex, 1L); Assert.assertEquals(1, mSet.getByField(mUniqueLongIndex, toRemove.longValue()).size()); Assert.assertEquals(9, mSet.size()); Assert.assertTrue(mSet.remove(toRemove)); Assert.assertEquals(8, mSet.size()); Assert.assertEquals(2, mSet.getByField(mNonUniqueIntIndex, toRemove.intValue()).size()); Assert.assertTrue("Element should be in the NonUniqueIntIndex", mSet.contains(mNonUniqueIntIndex, toRemove.intValue())); Assert.assertEquals(0, mSet.getByField(mUniqueLongIndex, toRemove.longValue()).size()); Assert.assertFalse("Element should not be in the mUniqueLongIndex", mSet.contains(mUniqueLongIndex, toRemove.longValue())); toRemove = mSet.getFirstByField(mNonUniqueIntIndex, 2); Assert.assertTrue(mSet.remove(toRemove)); Assert.assertTrue("Element should be in the NonUniqueIntIndex", mSet.contains(mNonUniqueIntIndex, toRemove.intValue())); toRemove = mSet.getFirstByField(mNonUniqueIntIndex, 2); Assert.assertTrue(mSet.remove(toRemove)); Assert.assertTrue("Element should be in the NonUniqueIntIndex", mSet.contains(mNonUniqueIntIndex, toRemove.intValue())); toRemove = mSet.getFirstByField(mNonUniqueIntIndex, 2); Assert.assertTrue(mSet.remove(toRemove)); Assert.assertFalse("Element should not be in the NonUniqueIntIndex", mSet.contains(mNonUniqueIntIndex, toRemove.intValue())); Assert.assertFalse("Element should not be in the mNonUniqueIntIndex", mSet.contains(mNonUniqueIntIndex, toRemove.longValue())); toRemove = mSet.getFirstByField(mNonUniqueIntIndex, 2); Assert.assertTrue(toRemove == null); } /** * Tests the {@link IndexedSet#remove(Object)} method to work correctly when trying to remove a * non-existent item. */ @Test public void removeNonExist() { Assert.assertFalse(mSet.remove(new Pair(-1, -1))); Assert.assertEquals(0, mSet.removeByField(mNonUniqueIntIndex, -1)); Assert.assertEquals(0, mSet.removeByField(mUniqueLongIndex, -1L)); } /** * Tests the {@link IndexedSet#removeByField(IndexDefinition, Object)} method. */ @Test public void nonUniqueRemoveByField() { Assert.assertEquals(3, mSet.getByField(mNonUniqueIntIndex, 1).size()); Assert.assertEquals(9, mSet.size()); Assert.assertEquals(3, mSet.removeByField(mNonUniqueIntIndex, 1)); Assert.assertEquals(6, mSet.size()); Assert.assertEquals(0, mSet.getByField(mNonUniqueIntIndex, 1).size()); Assert.assertEquals(3, mSet.getByField(mNonUniqueIntIndex, 0).size()); Assert.assertEquals(3, mSet.getByField(mNonUniqueIntIndex, 2).size()); for (long l = 3; l < 6; l++) { Assert.assertEquals(0, mSet.getByField(mUniqueLongIndex, l).size()); } } /** * Tests the {@link IndexedSet#removeByField(IndexDefinition, Object)} method. */ @Test public void uniqueRemoveByField() { Assert.assertEquals(9, mSet.size()); Assert.assertEquals(1, mSet.removeByField(mUniqueLongIndex, 1L)); Assert.assertEquals(8, mSet.size()); Assert.assertEquals(0, mSet.removeByField(mUniqueLongIndex, 1L)); Assert.assertEquals(8, mSet.size()); Assert.assertEquals(0, mSet.getByField(mUniqueLongIndex, 1L).size()); Assert.assertEquals(1, mSet.getByField(mUniqueLongIndex, 0L).size()); Assert.assertEquals(1, mSet.getByField(mUniqueLongIndex, 2L).size()); Assert.assertEquals(2, mSet.getByField(mNonUniqueIntIndex, 0).size()); } /** * Tests that the {@link IndexedSet} works correctly when adding the same object multiple times. */ @Test public void addTheSameObjectMultipleTimes() { final ExpectedException exception = ExpectedException.none(); for (int i = 0; i < 3; i++) { Assert.assertEquals(9, mSet.size()); Assert.assertEquals(3, mSet.getByField(mNonUniqueIntIndex, i).size()); for (Pair p : mSet.getByField(mNonUniqueIntIndex, i)) { exception.expect(IllegalStateException.class); exception.expectMessage("Adding more than one value to a unique index."); mSet.add(p); } Assert.assertEquals(9, mSet.size()); Assert.assertEquals(3, mSet.getByField(mNonUniqueIntIndex, i).size()); } try { mSet.add(new Pair(1, 9L)); } catch (IllegalStateException e) { Assert.fail(); } Assert.assertEquals(10, mSet.size()); Assert.assertEquals(4, mSet.getByField(mNonUniqueIntIndex, 1).size()); } /** * Tests that the remove works correctly with the iterator gathered by * {@link IndexedSet#iterator()} method. */ @Test public void iteratorRemove() { Iterator<Pair> it = mSet.iterator(); Assert.assertTrue(it.hasNext()); final Pair first = it.next(); Set<Pair> valueSet = mSet.getByField(mNonUniqueIntIndex, first.intValue()); Assert.assertTrue("Element should be in the set", valueSet.contains(first)); valueSet = mSet.getByField(mUniqueLongIndex, first.longValue()); Assert.assertTrue("Element should be in the set", valueSet.contains(first)); it.remove(); valueSet = mSet.getByField(mNonUniqueIntIndex, first.intValue()); Assert.assertFalse("Element should not be in the set", valueSet.contains(first)); valueSet = mSet.getByField(mUniqueLongIndex, first.longValue()); Assert.assertFalse("Element should not be in the set", valueSet.contains(first)); } /** * Tests that foreach works correctly with the iterator gathered by * {@link IndexedSet#iterator()} method. */ @Test public void iteratorForeach() { long removed = 0; Iterator<Pair> it = mSet.iterator(); Assert.assertTrue(it.hasNext()); final Pair first = it.next(); it.remove(); removed++; while (it.hasNext()) { it.next(); it.remove(); removed++; } Assert.assertEquals(9L, removed); Assert.assertEquals(0, mSet.size()); for (Pair o : mSet) { Assert.fail(); } long l = 0; for (int i = 0; i < 3; i++) { Assert.assertFalse(mSet.contains(mNonUniqueIntIndex, i)); for (int k = 0; k < 3; k++) { Assert.assertFalse(mSet.contains(mUniqueLongIndex, l++)); } } } /** * Tests that next works correctly with the iterator gathered by {@link IndexedSet#iterator()} * method. */ @Test public void iteratorNext() { Iterator<Pair> it = mSet.iterator(); int intSum = 0; int expectedIntSum = 0; long longSum = 0; long expectedLongSum = 0; try { long l = 0; for (int i = 0; i < 3; i++) { for (int k = 0; k < 3; k++) { Pair pair = it.next(); intSum += pair.intValue(); longSum += pair.longValue(); expectedIntSum += i; expectedLongSum += l++; } } } catch (Exception e) { Assert.fail(); } Assert.assertEquals(expectedIntSum, intSum); Assert.assertEquals(expectedLongSum, longSum); Assert.assertFalse(it.hasNext()); } /** * Tests that hasNext works correctly with the iterator gathered by {@link IndexedSet#iterator()} * method. */ @Test public void iteratorhasNext() { Iterator<Pair> it = mSet.iterator(); long size = mSet.size(); try { for (int i = 0; i < size * 2; i++) { Assert.assertTrue(it.hasNext()); } for (int i = 0; i < 3; i++) { for (int k = 0; k < 3; k++) { it.next(); } } for (int i = 0; i < size; i++) { Assert.assertFalse(it.hasNext()); } } catch (Exception e) { Assert.fail(); } } }