diff --git a/src/edu/caltech/cs2/interfaces/IDeque.java b/src/edu/caltech/cs2/interfaces/IDeque.java index e0db44669a21b9c6e7744bdd29259207f76c62f2..6bfbcb1e0e963aa3b57943a75e7865840ab12b4b 100644 --- a/src/edu/caltech/cs2/interfaces/IDeque.java +++ b/src/edu/caltech/cs2/interfaces/IDeque.java @@ -23,7 +23,7 @@ public interface IDeque<E> extends ICollection<E> { * @param e Element to add */ default public void add(E e){ - this.addFront(e); + this.addBack(e); } /** diff --git a/tests/edu/caltech/cs2/datastructures/ArrayDequeTests.java b/tests/edu/caltech/cs2/datastructures/ArrayDequeTests.java index 3ee197f116d237e56a5a164e9c417243cc751988..93534150154c78e18648ebae639f180bdfa0d88f 100644 --- a/tests/edu/caltech/cs2/datastructures/ArrayDequeTests.java +++ b/tests/edu/caltech/cs2/datastructures/ArrayDequeTests.java @@ -15,11 +15,13 @@ import org.junit.jupiter.params.provider.ValueSource; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; import static edu.caltech.cs2.project03.Project03TestOrdering.*; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -86,6 +88,20 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { Reflection.assertNoPublicFields(ArrayDeque.class); } + @Order(classSpecificTestLevel) + @DisplayName("There are no protected fields") + @Test + public void testNoProtectedFields() { + Reflection.assertNoProtectedFields(ArrayDeque.class); + } + + @Order(classSpecificTestLevel) + @DisplayName("All fields in ArrayDeque have modifiers") + @Test + public void testFieldModifiers() { + Reflection.assertFieldModifiers(ArrayDeque.class); + } + @Order(classSpecificTestLevel) @DisplayName("The public interface is correct") @Test @@ -145,6 +161,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("addFront() and removeFront() take linear time") + @Timeout(value = 20, unit = SECONDS) @Test() public void testFrontDequeOperationComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -163,6 +180,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("addBack() and removeBack() take linear time") + @Timeout(value = 20, unit = SECONDS) @Test public void testBackDequeOperationComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -181,6 +199,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("enqueue() and dequeue() take linear time") + @Timeout(value = 20, unit = SECONDS) @Test public void testQueueOperationComplexity() { Function<Integer, IQueue<Integer>> provide = (Integer numElements) -> { @@ -199,6 +218,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("push() and pop() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testStackOperationComplexity() { Function<Integer, IStack<Integer>> provide = (Integer numElements) -> { @@ -217,6 +237,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("peek() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testPeekComplexity() { Function<Integer, IStack<Integer>> provide = (Integer numElements) -> { @@ -233,6 +254,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("peekFront() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test() public void testPeekFrontComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -249,6 +271,7 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("peekBack() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testPeekBackComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -262,4 +285,5 @@ public class ArrayDequeTests implements DequeTests, StackTests, QueueTests { RuntimeInstrumentation.assertAtMost("peekBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekBack, 8); } + } \ No newline at end of file diff --git a/tests/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueueTests.java b/tests/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueueTests.java index 6123c3fa40341e258839864a79380f1e41c6f460..c1ca90d88c626ead24b918f843850fecec74af22 100644 --- a/tests/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueueTests.java +++ b/tests/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueueTests.java @@ -16,14 +16,16 @@ import java.util.function.Consumer; import java.util.function.Function; import static edu.caltech.cs2.project03.Project03TestOrdering.*; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.jupiter.api.Assertions.*; @Tag("B") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { - private static String FIXED_QUEUE_SOURCE ="src/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueue.java"; + private static String FIXED_QUEUE_SOURCE = "src/edu/caltech/cs2/datastructures/CircularArrayFixedSizeQueue.java"; - private Constructor circFixedSizeQueueConstructor = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class); + private Constructor circFixedSizeQueueConstructor = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, + int.class); private int DEFAULT_CAPACITY = 10; public IQueue<Object> newQueue() { @@ -70,20 +72,26 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { Reflection.assertNoPublicFields(CircularArrayFixedSizeQueue.class); } + @Order(classSpecificTestLevel) + @DisplayName("There are no protected fields") + @Test + public void testNoProtectedFields() { + Reflection.assertNoProtectedFields(CircularArrayFixedSizeQueue.class); + } + + @Order(classSpecificTestLevel) + @DisplayName("All fields in CircularArrayFixedSizeQueue have modifiers") + @Test + public void testFieldModifiers() { + Reflection.assertFieldModifiers(CircularArrayFixedSizeQueue.class); + } + @Order(classSpecificTestLevel) @DisplayName("The public interface is correct") @Test public void testPublicInterface() { - Reflection.assertPublicInterface(CircularArrayFixedSizeQueue.class, List.of( - "enqueue", - "dequeue", - "peek", - "iterator", - "size", - "isFull", - "capacity", - "toString" - )); + Reflection.assertPublicInterface(CircularArrayFixedSizeQueue.class, + List.of("enqueue", "dequeue", "peek", "iterator", "size", "isFull", "capacity", "toString")); } @Order(classSpecificTestLevel) @@ -93,7 +101,6 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { Inspection.assertConstructorHygiene(FIXED_QUEUE_SOURCE); } - // TOSTRING TESTS --------------------------------------------------- @Order(toStringTestLevel) @@ -106,9 +113,7 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { @Order(toStringTestLevel) @DisplayName("toString() matches java.util.ArrayDeque") @ParameterizedTest(name = "Test toString() on [{arguments}]") - @ValueSource(strings = { - "0, 1, 2, 3", "5, 4, 3, 2, 1", "8, 3, 5, 7, 4, 3, 12, 12, 1" - }) + @ValueSource(strings = { "0, 1, 2, 3", "5, 4, 3, 2, 1", "8, 3, 5, 7, 4, 3, 12, 12, 1" }) public void testToString(String inputs) { java.util.ArrayDeque<String> reference = new java.util.ArrayDeque<String>(); Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class); @@ -124,11 +129,12 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { @Order(complexityTestLevel) @DisplayName("enqueue() and dequeue() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test() public void testQueueOperationComplexity() { Function<Integer, IFixedSizeQueue<Integer>> provide = (Integer numElements) -> { Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class); - IFixedSizeQueue<Integer> q = Reflection.newInstance(c, numElements*2); + IFixedSizeQueue<Integer> q = Reflection.newInstance(c, numElements * 2); for (int i = 0; i < numElements; i++) { q.enqueue(i); } @@ -141,14 +147,14 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { RuntimeInstrumentation.assertAtMost("dequeue", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, dequeue, 8); } - @Order(complexityTestLevel) @DisplayName("peek() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test() public void testPeekComplexity() { Function<Integer, IFixedSizeQueue<Integer>> provide = (Integer numElements) -> { Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class); - IFixedSizeQueue<Integer> q = Reflection.newInstance(c, numElements*2); + IFixedSizeQueue<Integer> q = Reflection.newInstance(c, numElements * 2); for (int i = 0; i < numElements; i++) { q.enqueue(i); } @@ -158,4 +164,31 @@ public class CircularArrayFixedSizeQueueTests implements FixedSizeQueueTests { RuntimeInstrumentation.assertAtMost("peek", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peek, 8); } -} \ No newline at end of file + + @Order(fixedSizeQueueLevel) + @DisplayName("Test iterator matches reference for wraparound values") + @ParameterizedTest(name = "Test iterator and wraparound behavior with {1} random values with seed = {0} and fixed array size = {2}") + @CsvSource({ "69, 200, 20", "21, 300, 200" }) + public void testWrapAround(int seed, int numVals, int queueSize) { + Random r = new Random(seed); + IFixedSizeQueue<Object> me = newFixedSizeQueue(queueSize); + Queue<Object> reference = new java.util.ArrayDeque<>(); + assertEquals(queueSize, me.capacity(), "capacity does not match expected value"); + for (int i = 0; i < queueSize; i++) { + int num = r.nextInt(); + assertFalse(me.isFull(), "queue should not be full"); + assertTrue(me.enqueue(num), "enqueue should be successful"); + reference.add(num); + + } + for (int i = 0; i < numVals; i++) { + me.enqueue(me.dequeue()); + reference.add(reference.remove()); + assertEquals(reference.peek(), me.peek(), "return values of peek()s are not equal"); + assertEquals(reference.size(), me.size(), "size()s are not equal"); + assertEquals(queueSize, me.capacity(), "capacity of a fixed size queue should not change"); + assertIterableEquals(reference, me, "Reference and implemented queues are not equal"); + } + } + +} diff --git a/tests/edu/caltech/cs2/datastructures/CollectionTests.java b/tests/edu/caltech/cs2/datastructures/CollectionTests.java index b1b39af9ac161e5a8962b7649003bd2ff7fef6fa..bbc3b056679f4dd4a69699e0676d5bb4eaf206da 100644 --- a/tests/edu/caltech/cs2/datastructures/CollectionTests.java +++ b/tests/edu/caltech/cs2/datastructures/CollectionTests.java @@ -74,7 +74,7 @@ public interface CollectionTests { ICollection<Object> impl = newCollection(); for (int i = 0; i < 10; i ++) { impl.add("a"); - assertEquals(impl.size(), 1, "collection should have 1 element"); + assertEquals(1, impl.size(), "collection should have 1 element"); impl.clear(); assertTrue(impl.isEmpty()); } diff --git a/tests/edu/caltech/cs2/datastructures/LinkedDequeTests.java b/tests/edu/caltech/cs2/datastructures/LinkedDequeTests.java index ad7d4ee4507161c0cd533de63e035c82621c0e1d..40961504a967197edf47cd69a78d77dd7861366a 100644 --- a/tests/edu/caltech/cs2/datastructures/LinkedDequeTests.java +++ b/tests/edu/caltech/cs2/datastructures/LinkedDequeTests.java @@ -1,6 +1,7 @@ package edu.caltech.cs2.datastructures; import edu.caltech.cs2.helpers.Inspection; +import edu.caltech.cs2.helpers.NodeChecker; import edu.caltech.cs2.helpers.Reflection; import edu.caltech.cs2.helpers.RuntimeInstrumentation; import edu.caltech.cs2.interfaces.ICollection; @@ -15,16 +16,19 @@ import org.junit.jupiter.params.provider.ValueSource; import java.lang.reflect.Constructor; import java.util.*; +import java.util.ArrayDeque; import java.util.function.Consumer; import java.util.function.Function; import static edu.caltech.cs2.project03.Project03TestOrdering.*; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; @Tag("C") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { - private static String LINKED_DEQUE_SOURCE ="src/edu/caltech/cs2/datastructures/LinkedDeque.java"; + private static String LINKED_DEQUE_SOURCE = "src/edu/caltech/cs2/datastructures/LinkedDeque.java"; private Constructor linkedDequeConstructor = Reflection.getConstructor(LinkedDeque.class); @@ -80,26 +84,26 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { Reflection.assertNoPublicFields(LinkedDeque.class); } + @Order(classSpecificTestLevel) + @DisplayName("There are no protected fields") + @Test + public void testNoProtectedFields() { + Reflection.assertNoProtectedFields(LinkedDeque.class); + } + + @Order(classSpecificTestLevel) + @DisplayName("All fields in LinkedDeque have modifiers") + @Test + public void testFieldModifiers() { + Reflection.assertFieldModifiers(LinkedDeque.class); + } + @Order(classSpecificTestLevel) @DisplayName("The public interface is correct") @Test public void testPublicInterface() { - Reflection.assertPublicInterface(LinkedDeque.class, List.of( - "addFront", - "addBack", - "removeFront", - "removeBack", - "enqueue", - "dequeue", - "push", - "pop", - "peek", - "peekFront", - "peekBack", - "iterator", - "size", - "toString" - )); + Reflection.assertPublicInterface(LinkedDeque.class, List.of("addFront", "addBack", "removeFront", "removeBack", + "enqueue", "dequeue", "push", "pop", "peek", "peekFront", "peekBack", "iterator", "size", "toString")); } @Order(classSpecificTestLevel) @@ -109,6 +113,18 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { Inspection.assertConstructorHygiene(LINKED_DEQUE_SOURCE); } + @Order(classSpecificTestLevel) + @DisplayName("Check for linked node class") + @Test + public void testLinkedNode() { + Class[] classes = LinkedDeque.class.getDeclaredClasses(); + for (Class clazz : classes) { + if (Iterator.class.isAssignableFrom(clazz)) { + continue; + } + NodeChecker.isNode(clazz, true); + } + } // TOSTRING TESTS --------------------------------------------------- @@ -122,9 +138,7 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { @Order(toStringTestLevel) @DisplayName("toString() matches java.util.ArrayDeque") @ParameterizedTest(name = "Test toString() on [{arguments}]") - @ValueSource(strings = { - "0, 1, 2, 3", "5, 4, 3, 2, 1", "8, 3, 5, 7, 4, 3, 12, 12, 1" - }) + @ValueSource(strings = { "0, 1, 2, 3", "5, 4, 3, 2, 1", "8, 3, 5, 7, 4, 3, 12, 12, 1" }) public void testToString(String inputs) { java.util.ArrayDeque<String> reference = new java.util.ArrayDeque<String>(); LinkedDeque<String> me = new LinkedDeque<>(); @@ -139,6 +153,7 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("addFront() and removeFront() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testFrontDequeOperationComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -151,12 +166,15 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { Consumer<IDeque<Integer>> addFront = (IDeque<Integer> q) -> q.addFront(0); Consumer<IDeque<Integer>> removeFront = (IDeque<Integer> q) -> q.removeFront(); - RuntimeInstrumentation.assertAtMost("addFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, addFront, 8); - RuntimeInstrumentation.assertAtMost("removeFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, removeFront, 8); + RuntimeInstrumentation.assertAtMost("addFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, addFront, + 8); + RuntimeInstrumentation.assertAtMost("removeFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, + removeFront, 8); } @Order(complexityTestLevel) @DisplayName("addBack() and removeBack() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testBackDequeOperationComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -170,11 +188,13 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { Consumer<IDeque<Integer>> removeBack = (IDeque<Integer> q) -> q.removeBack(); RuntimeInstrumentation.assertAtMost("addBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, addBack, 8); - RuntimeInstrumentation.assertAtMost("removeBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, removeBack, 8); + RuntimeInstrumentation.assertAtMost("removeBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, + removeBack, 8); } @Order(complexityTestLevel) @DisplayName("enqueue() and dequeue() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testQueueOperationComplexity() { Function<Integer, IQueue<Integer>> provide = (Integer numElements) -> { @@ -193,6 +213,7 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("push() and pop() take constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testStackOperationComplexity() { Function<Integer, IStack<Integer>> provide = (Integer numElements) -> { @@ -211,6 +232,7 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("peek() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testPeekComplexity() { Function<Integer, IStack<Integer>> provide = (Integer numElements) -> { @@ -227,6 +249,7 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { @Order(complexityTestLevel) @DisplayName("peekFront() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testPeekFrontComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -238,11 +261,13 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { }; Consumer<IDeque<Integer>> peekFront = (IDeque<Integer> q) -> q.peekFront(); - RuntimeInstrumentation.assertAtMost("peekFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekFront, 8); + RuntimeInstrumentation.assertAtMost("peekFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekFront, + 8); } @Order(complexityTestLevel) @DisplayName("peekBack() takes constant time") + @Timeout(value = 10, unit = SECONDS) @Test public void testPeekBackComplexity() { Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> { @@ -254,7 +279,78 @@ public class LinkedDequeTests implements DequeTests, StackTests, QueueTests { }; Consumer<IDeque<Integer>> peekBack = (IDeque<Integer> q) -> q.peekBack(); - RuntimeInstrumentation.assertAtMost("peekBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekBack, 8); + RuntimeInstrumentation.assertAtMost("peekBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekBack, + 8); + } + + @Order(dequeTestLevel) + @DisplayName("Cycle detection for addFront(...), addBack(...), removeFront(...), and removeBack(...)") + @ParameterizedTest(name = "Test cycles - {1} random numbers with seed = {0}") + @CsvSource({ "69, 2000", "20, 3000" }) + public void checkForCycles(int seed, int size) { + Random r = new Random(seed); + Deque<Object> reference = new ArrayDeque<>(); + IDeque<Object> impl = new LinkedDeque<>(); + // Test that first peek is null + assertNull(impl.peekFront(), "empty peek should return null"); + // Test adding values updates size and displays contained correctly + for (int i = 0; i < size; i++) { + int num = r.nextInt(); + if (num % 2 == 0) { + reference.addLast(num); + impl.addBack(num); + } else { + reference.addFirst(num); + impl.addFront(num); + } + if (reference.size() > 1 && impl.size() > 1) { + if (num % 5 == 0) { + reference.removeFirst(); + impl.removeFront(); + } else if (num % 7 == 0) { + reference.removeLast(); + impl.removeBack(); + } + } + NodeChecker.cycleDetection(impl, true); + assertEquals(reference.size(), impl.size(), "size()s are not equal"); + assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal"); + } + } + + @Order(dequeTestLevel) + @DisplayName("Check reverses for addFront(...), addBack(...), removeFront(...), and removeBack(...)") + @ParameterizedTest(name = "Test reverse - {1} random numbers with seed = {0}") + @CsvSource({ "31, 2000", "64, 3000" }) + public void checkReverses(int seed, int size) { + Random r = new Random(seed); + Deque<Object> reference = new ArrayDeque<>(); + IDeque<Object> impl = new LinkedDeque<>(); + // Test that first peek is null + assertNull(impl.peekFront(), "empty peek should return null"); + // Test adding values updates size and displays contained correctly + for (int i = 0; i < size; i++) { + int num = r.nextInt(); + if (num % 2 == 0) { + reference.addLast(num); + impl.addBack(num); + } else { + reference.addFirst(num); + impl.addFront(num); + } + if (reference.size() > 1 && impl.size() > 1) { + if (num % 5 == 0) { + reference.removeFirst(); + impl.removeFront(); + } else if (num % 7 == 0) { + reference.removeLast(); + impl.removeBack(); + } + } + NodeChecker.checkReverse(impl); + assertEquals(reference.size(), impl.size(), "size()s are not equal"); + assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal"); + } } } \ No newline at end of file diff --git a/tests/edu/caltech/cs2/helpers/NodeChecker.java b/tests/edu/caltech/cs2/helpers/NodeChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..75e3ef4cd3abbe9acc557215d41700eaddae73f8 --- /dev/null +++ b/tests/edu/caltech/cs2/helpers/NodeChecker.java @@ -0,0 +1,318 @@ +package edu.caltech.cs2.helpers; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import org.hamcrest.collection.IsIterableContainingInOrder; + +import edu.caltech.cs2.interfaces.IDeque; + +/** + * @author Archie Shahidullah <archie@caltech.edu> + */ +public class NodeChecker { + + /** + * This method checks whether a given class is a linked node or not. + * + * @param clazz the class you want to check + * @param doublyLinked whether or not the list <em>can</em> be doubly linked + */ + public static void isNode(Class clazz, boolean doublyLinked) { + // Check if class is private + if (!Modifier.isPrivate(clazz.getModifiers())) { + fail("Class " + clazz.getTypeName() + " is not private"); + } + + // Check if class is static + if (!Modifier.isStatic(clazz.getModifiers())) { + fail("Class " + clazz.getTypeName() + " is not static"); + } + + // Get fields + SortedSet<String> fields = new TreeSet<>( + Stream.of(clazz.getDeclaredFields()).map(x -> x.getName()).collect(Collectors.toList())); + + boolean hasData = false; + boolean hasNode = false; + + // Check fields + for (String field : fields) { + Field f = null; + try { + f = clazz.getDeclaredField(field); + f.setAccessible(true); + } catch (NoSuchFieldException ex) { + ex.printStackTrace(); + fail(); + } + + if (f.getType().toString().equals("class " + clazz.getTypeName())) { + if (hasNode && !doublyLinked) { + // Returns false is the list is doubly linked + fail("Class " + clazz.getName() + " is a doubly linked node"); + return; + } + // Linked to another node + hasNode = true; + } else if (f.getType().toString().equals("class java.lang.Object")) { + if (!Modifier.isFinal(f.getModifiers())) { + fail("Field \"" + field + "\" in class " + clazz.getName() + " is not final"); + } + // Has a generic type to store data + if (hasData) { + // Checks for multiple data fields + fail("Class " + clazz.getName() + " has multiple generic fields: \"" + field + "\""); + return; + } + hasData = true; + } else { + fail("Field \"" + field + "\" is not a generic type in " + clazz.getTypeName()); + } + } + + // Get constructors + Constructor[] constructors = clazz.getConstructors(); + + // Checks arguments to the constructors + for (Constructor c : constructors) { + boolean hasConstructor = false; + for (Class type : c.getParameterTypes()) { + if (type.toString().equals("class java.lang.Object")) { + if (hasConstructor) { + // Checks for multiple arguments + fail("Constructor \"" + c.getName() + "\" has multiple generic arguments"); + return; + } + hasConstructor = true; + } else if (!type.toString().equals("class " + clazz.getTypeName())) { + // Check for invalid argument types + fail("Constructor \"" + c.getName() + "\" has an argument that is not a " + "generic type in class " + + clazz.getTypeName()); + } + } + } + } + + /** + * This method performs a node check on every internal class. + * + * @param clazz the class you want to check + * @param doublyLinked whether or not the list <em>can</em> be doubly linked + */ + public static void checkInternalClasses(Class clazz, boolean doublyLinked) { + Class[] classes = clazz.getDeclaredClasses(); + boolean node = false; + for (Class c : classes) { + String className = c.toString().replaceFirst("class ", ""); + try { + isNode(Class.forName(className), doublyLinked); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + fail(); + } catch (AssertionError e) { + continue; + } + node = true; + } + if (!node) { + fail("There are no valid node classes in " + clazz.getName()); + } + } + + /** + * This method gets a valid, internal node class from a given class. + * + * @param clazz the class you want to check + * @param doublyLinked whether or not the list <em>can</em> be doubly linked + * @return the node class + */ + public static Class getNodeClass(Class clazz, boolean doublyLinked) { + Class[] classes = clazz.getDeclaredClasses(); + for (Class c : classes) { + try { + isNode(c, doublyLinked); + } catch (AssertionError e) { + // Is not a node class so continue searching + continue; + } + return c; + } + fail("There are no valid node classes in " + clazz.getName()); + // Should never reach here + return null; + } + + /** + * This method gets fields of specified type from a given class. + * + * @param clazz the class you want to check + * @param type the type of field you want + * @return a list of fields matching the given type + */ + public static List<Field> getFields(Class clazz, Class type) { + Field[] fields = clazz.getDeclaredFields(); + List<Field> namedFields = new ArrayList<>(); + for (Field f : fields) { + f.setAccessible(true); + if (f.getType().toString().equals("class " + type.getTypeName())) { + namedFields.add(f); + } + } + return namedFields; + } + + /** + * This method checks whether a given pointer permutation in a deque contains a + * cycle. + * + * @param deque the deque you want to check + * @param nextField the field corresponding to the next pointer in a linked + * node + * @param dequeField the field corresponding to the head pointer in a linked + * deque + * @param <E> the generic type of the data field in a linked node + * @return an array containing the indices of the cyclic nodes + */ + public static <E> int[] checkCycle(IDeque<E> deque, Field nextField, Field dequeField) { + // Grab head of list + Object head = null; + try { + head = dequeField.get(deque); + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + fail(); + } + // Create array to store all nodes + Object[] nodes = new Object[deque.size() + 1]; + // Iterate through list + Object temp = head; + int i = 0; + while (temp != null) { + nodes[i] = temp; + for (int j = 0; j < i; j++) { + // Check if memory locations are equal + if (nodes[j] == nodes[i]) { + // Return indices of nodes that create a cycle + return new int[] { i, j }; + } + } + try { + // Next node + temp = nextField.get(temp); + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + fail(); + } + i++; + } + // No cycle + return new int[] { -1, -1 }; + } + + /** + * This method checks whether a given deque contains a cycle. + * + * @param deque the deque you want to check + * @param doublyLinked whether or not the list <em>can</em> be doubly linked + * @param <E> the generic type of the data field in a linked node + */ + public static <E> void cycleDetection(IDeque<E> deque, boolean doublyLinked) { + Class nodeClass = getNodeClass(deque.getClass(), doublyLinked); + // Can be either next or previous pointer + List<Field> nextFields = getFields(nodeClass, nodeClass); + // Can be either head or tail pointer + List<Field> dequeFields = getFields(deque.getClass(), nodeClass); + // Check all permutations of pointers + int[] nodes; + for (Field nextField : nextFields) { + for (Field dequeField : dequeFields) { + // Check for a cycle + nodes = checkCycle(deque, nextField, dequeField); + if (nodes[0] == -1 && nodes[1] == -1) { + // No cycle + continue; + } + if (nodes[0] == deque.size() && nodes[1] == 0) { + fail("The last node is connected to the first node in " + nodeClass.getName() + " object"); + } else { + fail("Node " + nodes[0] + " is connected to Node " + nodes[1] + " in " + nodeClass.getName() + + " object"); + } + } + } + } + + /** + * This method checks whether iterating through a list forwards and backwards + * returns the same values. + * + * @param deque the deque you want to check + * @param <E> the generic type of the data field in a linked node + */ + public static <E> void checkReverse(IDeque<E> deque) { + // Grab the linked node class and possible pointers to the head and tail + Class nodeClass = getNodeClass(deque.getClass(), true); + List<Field> dequePointers = getFields(deque.getClass(), nodeClass); + assertEquals(2, dequePointers.size(), "List does not have one head and tail pointer"); + // Try all permutations of pointers + try { + for (int i = 0; i < 2; i++) { + // Get trial head and tail pointers + Field headField = dequePointers.get(i); + Field tailField = dequePointers.get((i + 1) % 2); + Object head = headField.get(deque); + Object tail = tailField.get(deque); + // If deque size is one, tests will fail so check alternative + if (deque.size() == 1) { + assertEquals(head, tail, "Deque of size 1 does not have same head and tail"); + return; + } + // Grab possible next and previous pointers + List<Field> pointers = getFields(head.getClass(), nodeClass); + assertEquals(2, pointers.size(), "List is not doubly linked"); + for (int j = 0; j < 2; j++) { + // Get trial next and previous pointers + Field next = pointers.get(j); + Field prev = pointers.get((j + 1) % 2); + // Get data field + List<Field> dataFields = getFields(nodeClass, Object.class); + assertEquals(1, dataFields.size(), "Incorrect number of generic types in node class"); + Field data = dataFields.get(0); + // Iterate through linked list and construct value lists + List<E> forwardValues = new ArrayList<>(); + List<E> backwardValues = new ArrayList<>(); + Object temp = head; + while (temp != null) { + forwardValues.add((E) data.get(temp)); + temp = next.get(temp); + } + temp = tail; + while (temp != null) { + backwardValues.add((E) data.get(temp)); + temp = prev.get(temp); + } + Collections.reverse(backwardValues); + // Test the reverse of the backwards equals the forwards + if (IsIterableContainingInOrder.contains(forwardValues.toArray()).matches(backwardValues)) { + return; + } + } + } + } catch (IllegalAccessException ex) { + ex.printStackTrace(); + fail(); + } + // Exiting the loop indicates failure + fail("Forwards and backwards lists of values do not agree"); + } + +} diff --git a/tests/edu/caltech/cs2/helpers/Reflection.java b/tests/edu/caltech/cs2/helpers/Reflection.java index 8f776cefde5b336c6e99d5727f2ea01fa4394f6b..1f4b95089489a98defaad8131d895ee83095d7c8 100644 --- a/tests/edu/caltech/cs2/helpers/Reflection.java +++ b/tests/edu/caltech/cs2/helpers/Reflection.java @@ -5,6 +5,7 @@ import java.util.*; import java.util.function.*; import java.util.stream.*; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; public class Reflection { @@ -40,7 +41,9 @@ public class Reflection { c.setAccessible(true); } catch (NoSuchMethodException e) { e.printStackTrace(); - fail("Could not find constructor " + clazz.getName() + "(" + String.join(", ", (String[])Stream.of(params).map(x -> x.getName()).collect(Collectors.toList()).toArray()) + ")" + " in class " + clazz.getName()); + fail("Could not find constructor " + clazz.getName() + "(" + + String.join(", ", (String[]) Stream.of(params).map(x -> x.getName()).collect(Collectors.toList()).toArray()) + + ")" + " in class " + clazz.getName()); return null; } return c; @@ -56,7 +59,6 @@ public class Reflection { return result; } - public static <T> T invokeStatic(Method m, Object... args) { T result = null; try { @@ -83,12 +85,18 @@ public class Reflection { private static int stringToIntModifier(String modifier) { switch (modifier.toLowerCase()) { - case "private": return Modifier.PRIVATE; - case "public": return Modifier.PUBLIC; - case "protected": return Modifier.PROTECTED; - case "static": return Modifier.STATIC; - case "final": return Modifier.FINAL; - default: fail("Unknown modifier test."); + case "private": + return Modifier.PRIVATE; + case "public": + return Modifier.PUBLIC; + case "protected": + return Modifier.PROTECTED; + case "static": + return Modifier.STATIC; + case "final": + return Modifier.FINAL; + default: + fail("Unknown modifier test."); } /* Should never reach here... */ return -1; @@ -111,17 +119,21 @@ public class Reflection { } public static void assertFieldsLessThan(Class clazz, Class FieldType, int x) { - assertFieldsLessThan(clazz, null, FieldType, x ); + assertFieldsLessThan(clazz, null, FieldType, x); } + public static void assertFieldsLessThan(Class clazz, String modifier, int x) { assertFieldsLessThan(clazz, modifier, null, x); } + public static void assertFieldsLessThan(Class clazz, Stream<Field> fields, int x) { - assertFieldsLessThan(clazz, fields, null, null, x ); + assertFieldsLessThan(clazz, fields, null, null, x); } + public static void assertFieldsLessThan(Class clazz, String modifier, Class FieldType, int x) { assertFieldsLessThan(clazz, getFields(clazz), modifier, FieldType, x); } + public static void assertFieldsLessThan(Class clazz, Stream<Field> fields, String modifier, Class FieldType, int x) { if (modifier != null) { fields = fields.filter(hasModifier(modifier)).filter(doesNotHaveModifier("static")); @@ -131,27 +143,29 @@ public class Reflection { } if (fields.count() >= x) { - fail(clazz.getName() + " has too many fields" + - (modifier != null ? " with modifier " + modifier : "") + "" + - (FieldType != null ? " of type " + FieldType.getName() : "") - ); + fail(clazz.getName() + " has too many fields" + (modifier != null ? " with modifier " + modifier : "") + "" + + (FieldType != null ? " of type " + FieldType.getName() : "")); } } - public static void assertFieldsGreaterThan(Class clazz, Class FieldType, int x) { - assertFieldsGreaterThan(clazz, null, FieldType, x ); + assertFieldsGreaterThan(clazz, null, FieldType, x); } + public static void assertFieldsGreaterThan(Class clazz, String modifier, int x) { assertFieldsGreaterThan(clazz, modifier, null, x); } + public static void assertFieldsGreaterThan(Class clazz, Stream<Field> fields, int x) { - assertFieldsGreaterThan(clazz, fields, null, null, x ); + assertFieldsGreaterThan(clazz, fields, null, null, x); } + public static void assertFieldsGreaterThan(Class clazz, String modifier, Class FieldType, int x) { assertFieldsGreaterThan(clazz, getFields(clazz), modifier, FieldType, x); } - public static void assertFieldsGreaterThan(Class clazz, Stream<Field> fields, String modifier, Class FieldType, int x) { + + public static void assertFieldsGreaterThan(Class clazz, Stream<Field> fields, String modifier, Class FieldType, + int x) { if (modifier != null) { fields = fields.filter(hasModifier(modifier)); } @@ -160,26 +174,27 @@ public class Reflection { } if (fields.count() <= x) { - fail(clazz.getName() + " has too few fields" + - (modifier != null ? " with modifier " + modifier : "") + " " + - (FieldType != null ? " of type " + FieldType.getName() : "") - ); + fail(clazz.getName() + " has too few fields" + (modifier != null ? " with modifier " + modifier : "") + " " + + (FieldType != null ? " of type " + FieldType.getName() : "")); } } - public static void assertFieldsEqualTo(Class clazz, Class FieldType, int x) { - assertFieldsEqualTo(clazz, null, FieldType, x ); + assertFieldsEqualTo(clazz, null, FieldType, x); } + public static void assertFieldsEqualTo(Class clazz, String modifier, int x) { - assertFieldsEqualTo(clazz, modifier, null, x ); + assertFieldsEqualTo(clazz, modifier, null, x); } + public static void assertFieldsEqualTo(Class clazz, Stream<Field> fields, int x) { - assertFieldsEqualTo(clazz, fields, null, null, x ); + assertFieldsEqualTo(clazz, fields, null, null, x); } + public static void assertFieldsEqualTo(Class clazz, String modifier, Class FieldType, int x) { assertFieldsEqualTo(clazz, getFields(clazz), modifier, FieldType, x); } + public static void assertFieldsEqualTo(Class clazz, Stream<Field> fields, String modifier, Class FieldType, int x) { if (modifier != null) { fields = fields.filter(hasModifier(modifier)); @@ -189,16 +204,26 @@ public class Reflection { } if (fields.count() != x) { - fail(clazz.getName() + " has the wrong number of fields" + - (modifier != null ? " with modifier " + modifier : "") + " " + - (FieldType != null ? " of type " + FieldType.getName() : "") - ); + fail(clazz.getName() + " has the wrong number of fields" + (modifier != null ? " with modifier " + modifier : "") + + " " + (FieldType != null ? " of type " + FieldType.getName() : "")); } } public static void assertNoPublicFields(Class clazz) { - assertFieldsEqualTo(clazz, getFields(clazz).filter(doesNotHaveModifier("static")), - "public", null, 0); + assertFieldsEqualTo(clazz, getFields(clazz).filter(doesNotHaveModifier("static")), "public", null, 0); + } + + public static void assertNoProtectedFields(Class clazz) { + assertFieldsEqualTo(clazz, getFields(clazz).filter(doesNotHaveModifier("static")), "protected", null, 0); + } + + public static void assertFieldModifiers(Class clazz) { + List<Field> fields = getFields(clazz).collect(Collectors.toList()); + for (Field f : fields) { + int m = f.getModifiers(); + assertTrue(Modifier.isPrivate(m) || Modifier.isProtected(m) || Modifier.isPublic(m), + "Field \"" + f.getName() + "\" does not have one of {public, private, protected}"); + } } public static Field getFieldByName(Class clazz, String name) { @@ -215,20 +240,13 @@ public class Reflection { Stream<Field> fields = getFields(clazz).filter(hasType(FieldType)).filter(doesNotHaveModifier("static")); List<Field> fieldsList = fields.collect(Collectors.toList()); if (fieldsList.isEmpty()) { - fail(clazz.getName() + - " should have a field with the type '" + FieldType.getName() + - "', but does not." - ); + fail(clazz.getName() + " should have a field with the type '" + FieldType.getName() + "', but does not."); // Should not reach here! return null; } if (fieldsList.size() > 1) { - fail(clazz.getName() + - " should only have one field with the type '" + - FieldType.getName() + - "', but has more." - ); + fail(clazz.getName() + " should only have one field with the type '" + FieldType.getName() + "', but has more."); // Should not reach here return null; } @@ -240,20 +258,13 @@ public class Reflection { Stream<Field> fields = getFields(clazz).filter(hasType(FieldType)); List<Field> fieldsList = fields.collect(Collectors.toList()); if (fieldsList.isEmpty()) { - fail(clazz.getName() + - " should have a field with the type '" + FieldType.getName() + - "', but does not." - ); + fail(clazz.getName() + " should have a field with the type '" + FieldType.getName() + "', but does not."); // Should not reach here! return null; } if (fieldsList.size() > 1) { - fail(clazz.getName() + - " should only have one field with the type '" + - FieldType.getName() + - "', but has more." - ); + fail(clazz.getName() + " should only have one field with the type '" + FieldType.getName() + "', but has more."); // Should not reach here return null; } @@ -272,21 +283,15 @@ public class Reflection { } List<Field> fieldsList = fields.collect(Collectors.toList()); if (fieldsList.isEmpty()) { - fail(clazz.getName() + - " should have a field with the modifiers '" + - String.join(", ", modifiers) + - "', but does not." - ); + fail(clazz.getName() + " should have a field with the modifiers '" + String.join(", ", modifiers) + + "', but does not."); // Should not reach here! return null; } if (fieldsList.size() > 1) { - fail(clazz.getName() + - " should only have one field with the modifiers '" + - String.join(", ", modifiers) + - "', but has more." - ); + fail(clazz.getName() + " should only have one field with the modifiers '" + String.join(", ", modifiers) + + "', but has more."); // Should not reach here return null; } @@ -297,6 +302,7 @@ public class Reflection { public static void checkFieldModifiers(Field f, String modifier) { checkFieldModifiers(f, List.of(modifier)); } + public static void checkFieldModifiers(Field f, List<String> modifiers) { if (!modifiers.stream().allMatch(m -> hasModifier(m).test(f))) { fail(f.getName() + " is missing at least one of the modifiers: " + String.join(", ", modifiers)); @@ -305,10 +311,8 @@ public class Reflection { public static void assertPublicInterface(Class clazz, List<String> methods) { SortedSet<String> expected = new TreeSet<>(methods); - SortedSet<String> actual = new TreeSet<>(Stream.of(clazz.getDeclaredMethods()) - .filter(hasModifier("public")) - .map(x -> x.getName()) - .collect(Collectors.toList())); + SortedSet<String> actual = new TreeSet<>(Stream.of(clazz.getDeclaredMethods()).filter(hasModifier("public")) + .map(x -> x.getName()).collect(Collectors.toList())); if (!expected.equals(actual)) { String diff = "expected: " + expected + "\nactual: " + actual; fail("The public interface of " + clazz.getName() + " has incorrect functionality.\n" + diff); @@ -322,4 +326,5 @@ public class Reflection { fail("You should be overriding the " + method + "method, but your signature wasn't correct."); } } + } diff --git a/tests/edu/caltech/cs2/project03/GuitarStringTests.java b/tests/edu/caltech/cs2/project03/GuitarStringTests.java index 0586d8e051e6be53961893c6fce6a6ff1bbb127c..81fabe06152bac315ec51b37b2778c18d5464f64 100644 --- a/tests/edu/caltech/cs2/project03/GuitarStringTests.java +++ b/tests/edu/caltech/cs2/project03/GuitarStringTests.java @@ -35,7 +35,8 @@ public class GuitarStringTests { } public static IFixedSizeQueue<Double> getQueueFromString(CircularArrayFixedSizeQueueGuitarString string) { - String queueName = Reflection.getFieldByType(CircularArrayFixedSizeQueueGuitarString.class, IFixedSizeQueue.class).getName(); + String queueName = Reflection.getFieldByType(CircularArrayFixedSizeQueueGuitarString.class, IFixedSizeQueue.class) + .getName(); return Reflection.getFieldValue(CircularArrayFixedSizeQueueGuitarString.class, queueName, string); } @@ -63,7 +64,8 @@ public class GuitarStringTests { Stream<Field> fields = Reflection.getFields(CircularArrayFixedSizeQueueGuitarString.class); fields.filter(Reflection.hasModifier("static")).forEach((field) -> { Reflection.checkFieldModifiers(field, List.of("private", "static")); - assertTrue(Reflection.hasModifier("final").test(field) || field.getType().equals(Random.class), "non-final static class must be a random value generator"); + assertTrue(Reflection.hasModifier("final").test(field) || field.getType().equals(Random.class), + "non-final static class must be a random value generator"); }); } @@ -81,28 +83,32 @@ public class GuitarStringTests { Reflection.assertNoPublicFields(CircularArrayFixedSizeQueueGuitarString.class); } + @Order(classSpecificTestLevel) + @DisplayName("There are no protected fields") + @Test + public void testNoProtectedFields() { + Reflection.assertNoProtectedFields(CircularArrayFixedSizeQueueGuitarString.class); + } + + @Order(classSpecificTestLevel) + @DisplayName("All fields in CircularArrayFixedSizeQueueGuitarString have modifiers") + @Test + public void testFieldModifiers() { + Reflection.assertFieldModifiers(CircularArrayFixedSizeQueueGuitarString.class); + } + @Order(classSpecificTestLevel) @DisplayName("The public interface is correct") @Test public void testPublicInterface() { - Reflection.assertPublicInterface(CircularArrayFixedSizeQueueGuitarString.class, List.of( - "length", - "pluck", - "tic", - "sample" - )); + Reflection.assertPublicInterface(CircularArrayFixedSizeQueueGuitarString.class, + List.of("length", "pluck", "tic", "sample")); } @Order(classSpecificTestLevel) @DisplayName("The constructor correctly sets up the queue") @ParameterizedTest(name = "Test constructor with CircularArrayFixedSizeQueue and a frequency of {0} Hz; expected queue size is {1}") - @CsvSource({ - "110, 401", - "340, 130", - "512, 87", - "600.5, 74", - "880, 51" - }) + @CsvSource({ "110, 401", "340, 130", "512, 87", "600.5, 74", "880, 51" }) public void testConstructor(double frequency, int expectedSize) { CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency); IFixedSizeQueue<Double> queue = getQueueFromString(string); @@ -116,41 +122,32 @@ public class GuitarStringTests { @Order(guitarStringTestLevel) @DisplayName("The pluck() method randomizes the values in the queue") @ParameterizedTest(name = "Test pluck() with CircularArrayFixedSizeQueue and a frequency of {0} Hz") - @CsvSource({ - "100", - "50", - "10", - "8", - "5" - }) + @CsvSource({ "100", "50", "10", "8", "5" }) public void testPluck(double frequency) { final double DELTA = 0.05; // Set up class and retrieve queue CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency); IFixedSizeQueue<Double> queue = getQueueFromString(string); // Checks all values are initially 0 - for(double val : queue){ + for (double val : queue) { assertEquals(0, val, "initial values must be 0"); } string.pluck(); + queue = getQueueFromString(string); double sum = 0; double absSum = 0; - for(double val : queue){ + for (double val : queue) { sum += val; absSum += abs(val); } - assertEquals(0, sum/queue.size(), DELTA, "average value of uniform distribution should be near 0"); - assertEquals(0.25, absSum/queue.size(), DELTA, "average magnitude of uniform distribution should be near 0.25"); + assertEquals(0, sum / queue.size(), DELTA, "average value of uniform distribution should be near 0"); + assertEquals(0.25, absSum / queue.size(), DELTA, "average magnitude of uniform distribution should be near 0.25"); } @Order(guitarStringTestLevel) @DisplayName("The tic() method correctly applies the Karplus-Strong algorithm") @ParameterizedTest(name = "Test tic() with CircularArrayFixedSizeQueue and a frequency of {0} Hz; data file {1}.txt") - @CsvSource({ - "10000, ticStates1", - "8000, ticStates2", - "5000, ticStates3" - }) + @CsvSource({ "10000, ticStates1", "8000, ticStates2", "5000, ticStates3" }) public void testTic(double frequency, String filename) { // Set up scanner String filepath = "tests/data/" + filename + ".txt"; @@ -164,19 +161,21 @@ public class GuitarStringTests { CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency); IFixedSizeQueue<Double> queue = getQueueFromString(string); // Reinitialize queue with new data - for(int i = 0; i < queue.size(); i++){ + for (int i = 0; i < queue.size(); i++) { queue.dequeue(); queue.enqueue(in.nextDouble()); } int initSize = queue.size(); // Pass through the same number of tics as elements in the array - for(int i = 0; i < initSize; i++){ + for (int i = 0; i < initSize; i++) { string.tic(); + queue = getQueueFromString(string); assertEquals(initSize, queue.size(), "queue size must remain the same"); } // Compare peek() values with the expected values in the files while (in.hasNext()) { string.tic(); + queue = getQueueFromString(string); assertEquals(initSize, queue.size(), "queue size must remain the same"); assertEquals(in.nextDouble(), queue.peek(), "next expected value not at front of queue"); } @@ -185,13 +184,7 @@ public class GuitarStringTests { @Order(guitarStringTestLevel) @DisplayName("The length() method correctly gives the length of the queue") @ParameterizedTest(name = "Test length() with CircularArrayFixedSizeQueue and a frequency of {0} Hz; expected length = {1}; iterations = {2}") - @CsvSource({ - "110, 401, 1000", - "340, 130, 500", - "512, 87, 200", - "600.5, 74, 150", - "880, 51, 100" - }) + @CsvSource({ "110, 401, 1000", "340, 130, 500", "512, 87, 200", "600.5, 74, 150", "880, 51, 100" }) public void testLength(double frequency, int expectedLength, int iterations) { // Set up class and retrieve queue CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency); @@ -202,12 +195,15 @@ public class GuitarStringTests { assertEquals(expectedLength, string.length(), "Length should be same as expected"); assertEquals(queue.size(), string.length(), "Length should be same as queue size"); string.pluck(); + queue = getQueueFromString(string); assertEquals(initSize, string.length(), "Length should not have changed from beginning"); assertEquals(queue.size(), string.length(), "Length should be same as queue size"); - // Run through many iterations, making sure both the queue size and length are constant + // Run through many iterations, making sure both the queue size and length are + // constant for (int i = 0; i < iterations; i++) { string.tic(); + queue = getQueueFromString(string); assertEquals(initSize, string.length(), "Length should not have changed from beginning"); assertEquals(queue.size(), string.length(), "Length should be same as queue size"); } @@ -217,13 +213,7 @@ public class GuitarStringTests { @Order(guitarStringTestLevel) @DisplayName("The sample() method gives the same values as peek()ing the queue") @ParameterizedTest(name = "Test sample() with CircularArrayFixedSizeQueue and a frequency of {0} Hz") - @CsvSource({ - "110, 1000", - "340, 500", - "512, 200", - "600.5, 150", - "880, 100" - }) + @CsvSource({ "110, 1000", "340, 500", "512, 200", "600.5, 150", "880, 100" }) public void testSample(double frequency, int iterations) { // Set up class and retrieve queue CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency); @@ -233,11 +223,13 @@ public class GuitarStringTests { assertEquals(0, string.sample(), "Sample should return 0 before plucking"); assertEquals(queue.peek(), string.sample(), "Sample should same as peek()ing queue"); string.pluck(); + queue = getQueueFromString(string); assertEquals(queue.peek(), string.sample(), "Sample should same as peek()ing queue"); // Run through many iterations, making sure sample() matches peek() for (int i = 0; i < iterations; i++) { string.tic(); + queue = getQueueFromString(string); assertEquals(queue.peek(), string.sample(), "Sample should same as peek()ing queue"); }