Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Properly implement the remove() method in the MultiSetIterator class. The Mutlse

ID: 3592893 • Letter: P

Question

Properly implement the remove() method in the MultiSetIterator class. The MutlsetIterator is provided below:

Please also makesure that the code passes the tests given below:

package 110;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.*;

import java.lang.reflect.Field;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.junit.Before;
import org.junit.Test;

public class ArrayMultiSetIteratorTest {
@Test
public void checkNextStartNotEmpty() throws IllegalAccessException {
ArrayMultiSet<String> mss = new ArrayMultiSet<>();
mss.add("Hello world!");
Iterator<String> testee = mss.iterator();
long collVersion = getCollectionVersion(testee);
assertEquals("First call to next() should return the entry at index 0 in _store", "Hello world!", testee.next());
int cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 1, cursor);
long sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextMiddle() throws IllegalAccessException {
ArrayMultiSet<String> mss = new ArrayMultiSet<>();
mss.add("-");
mss.add("^");
mss.add("v");
mss.add("@");
mss.add("");
setModCount(mss, 5);
Iterator<String> testee = mss.iterator();
long collVersion = getCollectionVersion(testee);
setCursor(testee, 1);
assertEquals("Second call to next() should entry at _store[1]", "^", testee.next());
int cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 2, cursor);
long sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
assertEquals("Third call to next() should entry at _store[2]", "v", testee.next());
cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 3, cursor);
sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
assertEquals("Fourth call to next() should entry at _store[3]", "@", testee.next());
cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 4, cursor);
failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextLast() throws IllegalAccessException {
ArrayMultiSet<Number> msn = new ArrayMultiSet<>();
msn.add(0.1);
msn.add(23);
msn.add(-99);
Iterator<Number> testee = msn.iterator();
setCursor(testee, 2);
assertEquals("Should be able to return the last entry in _store from the iterator", -99, testee.next());
int cursor = getCursor(testee);
assertEquals("next() should ALWAYS advance the Iterator's cursor", 3, cursor);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextAfterLast() throws IllegalAccessException {
ArrayMultiSet<Number> msn = new ArrayMultiSet<>();
msn.add(0.1);
msn.add(23);
msn.add(-99);
setModCount(msn, 9);
Iterator<Number> testee = msn.iterator();
setCursor(testee, 3);
setCollectionVersion(testee, 9);
try {
testee.next();
fail(
"next() should throw a NoSuchElementException when called after the cursor has advanced past all the elements.");
} catch (NoSuchElementException e) {
// This is the correct behavior; nothing should be done.
} catch (Exception e) {
fail(
"next() should throw a NoSuchElementException when called after the cursor has advanced past all the elements. You threw: "
+ e.toString());
}
}

@Test
public void checkNextModWhileInCollectionMiddle() throws IllegalAccessException {
ArrayMultiSet<Integer> msi = new ArrayMultiSet<>();
msi.add(0xDEADBEEF);
msi.add(0xFEEDFACE);
msi.add(0xBADACE);
setModCount(msi, 3);
Iterator<Integer> testee = msi.iterator();
setCursor(testee, 1);
setCollectionVersion(testee, 9);
try {
testee.next();
fail(
"next() should throw a ConcurrentModificationException when called and _collectionVersion shows the MultiSet has changed.");
} catch (ConcurrentModificationException e) {
// This is the correct behavior; nothing should be done.
} catch (Exception e) {
fail(
"next() should throw a ConcurrentModificationException when called and versioning does not match. You threw: "
+ e.toString());
}
}

@Test
public void checkRemoveSuccessUpdatesModCount() throws IllegalAccessException {
ArrayMultiSet<Integer> msi = new ArrayMultiSet<>();
msi.add(0xDEADBEEF);
msi.add(0xFEEDFACE);
msi.add(0xBADACE);
msi.add(null);
setModCount(msi, 17);
msi.remove(0xDEADBEEF);
long modCount = getModCount(msi);
assertEquals("remove() should increase the value of _modCount when it is successful", 18, modCount);
msi.remove(0xBADACE);
modCount = getModCount(msi);
assertEquals("remove() should increase the value of _modCount when it is successful", 19, modCount);
msi.remove(null);
modCount = getModCount(msi);
assertEquals("remove() should increase the value of _modCount when it is successful", 20, modCount);
}

@Test
public void checkRemoveFailsModCountUnchanged() throws IllegalAccessException {
ArrayMultiSet<Integer> msi = new ArrayMultiSet<>();
msi.add(0xDEADBEEF);
msi.add(0xFEEDFACE);
msi.add(0xBADACE);
setModCount(msi, 17);
msi.remove(0xDEADBEED);
long modCount = getModCount(msi);
assertEquals("remove() should NOT change the value of _modCount when it could not find the element", 17, modCount);
msi.remove(null);
modCount = getModCount(msi);
assertEquals("remove() should NOT change the value of _modCount when it could not find the element", 17, modCount);
}

@Test
public void checkRemoveBeforeNextFails() throws IllegalAccessException {
ArrayMultiSet<Integer> msi = new ArrayMultiSet<>();
msi.add(0xDEADBEEF);
msi.add(0xFEEDFACE);
msi.add(0xBADACE);
setModCount(msi, 17);
Iterator<Integer> testee = msi.iterator();
try {
testee.remove();
fail("remove() should throw an IllegalStateException when called before next() has been called");
} catch (IllegalStateException ise) {
// Nothing to do -- this is expected.
} catch (Exception e) {
fail("remove() should throw an IllegalStateException when called before next(). You called: " + e.toString());
}

testee.hasNext();
try {
testee.remove();
fail("remove() should throw an IllegalStateException when called before next() has been called");
} catch (IllegalStateException ise) {
// Nothing to do -- this is expected.
} catch (Exception e) {
fail("remove() should throw an IllegalStateException when called before next(). You called: " + e.toString());
}
}

@Test
public void checkRemoveAfterNext() throws IllegalAccessException {
ArrayMultiSet<Integer> msi = new ArrayMultiSet<>();
msi.add(0xDEADBEEF);
msi.add(0xFEEDFACE);
msi.add(0xBADACE);
setModCount(msi, 17);
Iterator<Integer> testee = msi.iterator();
setCursor(testee, 1);
setFailRemove(testee, false);
testee.remove();
assertEquals("Calling remove() in Iterator (when legal) should call removeAtIndex() to remove the element", 2,
msi.size());
long modCount = getModCount(msi);
assertEquals("Calling remove() in Iterator (when legal) should call removeAtIndex() to remove the element", 18,
modCount);
boolean elemRemoved = msi.contains(0xDEADBEEF);
assertFalse("Calling remove() in Iterator (when legal) should call removeAtIndex() to remove the element",
elemRemoved);
boolean failRemove = getFailRemove(testee);
assertTrue("remove() in Iterator should not allow it to succeed until next() is called", failRemove);
long collVersion = getCollectionVersion(testee);
assertEquals("remove() in Iterator needs to update its expected version!", 18, collVersion);
}

private Field cursorField;
private Field collectionVersionField;
private Field modCountField;
private Field failRemoveField;

@Before
public final void checkFieldsUnchanged() {
ArrayMultiSet<?> ams = new ArrayMultiSet<>();
Class<?> amsClass = ams.getClass();
try {
modCountField = amsClass.getDeclaredField("_modCount");
modCountField.setAccessible(true);
} catch (Exception e) {
fail("Your ArrayMultiSet class should still define a field named "_modCount"");
}
Class<?> cIterator = ams.iterator().getClass();
Field[] fields = cIterator.getDeclaredFields();
assertEquals("You should not add any fields to the MultiSetIterator class. This class's field count:", 4,
fields.length);
try {
collectionVersionField = cIterator.getDeclaredField("_collectionVersion");
collectionVersionField.setAccessible(true);
} catch (Exception e) {
fail("Your MultiSetIterator class should still define a field named "_collectionVersion"");
}
try {
cursorField = cIterator.getDeclaredField("_cursor");
cursorField.setAccessible(true);
} catch (Exception e) {
fail("Your MultiSetIterator class should still define a field named "_cursor"");
}
try {
failRemoveField = cIterator.getDeclaredField("_failRemove");
failRemoveField.setAccessible(true);
} catch (Exception e) {
fail("Your MultiSetIterator class should still define a field named "failRemove"");
}
}

private long getModCount(ArrayMultiSet<?> testee) throws IllegalAccessException {
return modCountField.getLong(testee);
}

private void setModCount(ArrayMultiSet<?> testee, long newVersion) throws IllegalAccessException {
modCountField.setLong(testee, newVersion);
}

private long getCollectionVersion(Iterator<?> testee) throws IllegalAccessException {
return collectionVersionField.getLong(testee);
}

private void setCollectionVersion(Iterator<?> testee, long newVersion) throws IllegalAccessException {
collectionVersionField.setLong(testee, newVersion);
}

private boolean getFailRemove(Iterator<?> testee) throws IllegalAccessException {
return failRemoveField.getBoolean(testee);
}

private void setFailRemove(Iterator<?> testee, boolean shouldFail) throws IllegalAccessException {
failRemoveField.setBoolean(testee, shouldFail);
}

private int getCursor(Iterator<?> testee) throws IllegalAccessException {
return cursorField.getInt(testee);
}

private void setCursor(Iterator<?> testee, int newSize) throws IllegalAccessException {
cursorField.setInt(testee, newSize);
}
}

Explanation / Answer

Please also makesure that the code passes the tests given below:

package 110;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.*;

import java.lang.reflect.Field;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.junit.Before;
import org.junit.Test;

public class ArrayMultiSetIteratorTest {
@Test
public void checkNextStartNotEmpty() throws IllegalAccessException {
ArrayMultiSet<String> mss = new ArrayMultiSet<>();
mss.add("Hello world!");
Iterator<String> testee = mss.iterator();
long collVersion = getCollectionVersion(testee);
assertEquals("First call to next() should return the entry at index 0 in _store", "Hello world!", testee.next());
int cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 1, cursor);
long sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextMiddle() throws IllegalAccessException {
ArrayMultiSet<String> mss = new ArrayMultiSet<>();
mss.add("-");
mss.add("^");
mss.add("v");
mss.add("@");
mss.add("");
setModCount(mss, 5);
Iterator<String> testee = mss.iterator();
long collVersion = getCollectionVersion(testee);
setCursor(testee, 1);
assertEquals("Second call to next() should entry at _store[1]", "^", testee.next());
int cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 2, cursor);
long sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
assertEquals("Third call to next() should entry at _store[2]", "v", testee.next());
cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 3, cursor);
sameVersion = getCollectionVersion(testee);
assertEquals("next() should not change the Iterator's collectionVersion", collVersion, sameVersion);
failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
assertEquals("Fourth call to next() should entry at _store[3]", "@", testee.next());
cursor = getCursor(testee);
assertEquals("next() should advance the Iterator's cursor", 4, cursor);
failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextLast() throws IllegalAccessException {
ArrayMultiSet<Number> msn = new ArrayMultiSet<>();
msn.add(0.1);
msn.add(23);
msn.add(-99);
Iterator<Number> testee = msn.iterator();
setCursor(testee, 2);
assertEquals("Should be able to return the last entry in _store from the iterator", -99, testee.next());
int cursor = getCursor(testee);
assertEquals("next() should ALWAYS advance the Iterator's cursor", 3, cursor);
boolean failRemove = getFailRemove(testee);
assertFalse("next() should allow remove() to succeed!", failRemove);
}

@Test
public void checkNextAfterLast() throws IllegalAccessException {
ArrayMultiSet<Number> msn = new ArrayMultiSet<>();
msn.add(0.1);
msn.add(23);
msn.add(-99);
setModCount(msn, 9);
Iterator<Number> testee = msn.iterator();
setCursor(testee, 3);
setCollectionVersion(testee, 9);
try {
testee.next();
fail(
"next() should throw a NoSuchElementException when called after the cursor has advanced past all the elements.");
} catch (NoSuchElementException e) {
// This is the correct behavior; nothing should be done.
} catch (Exception e) {
fail(
"next() should throw a NoSuchElementException when called after the cursor has advanced past all the elements. You threw: "
+ e.toString());
}
}