Commit 39cdbef5 authored by Ethan Ordentlich's avatar Ethan Ordentlich
Browse files

Merge branch 'tests' into 'master'

Review Tests for Project 3

Closes #1, #2, #3, #5, #6, #7, and #9

See merge request !1
1 merge request!1Review Tests for Project 3
Pipeline #36478 canceled with stage
Showing with 628 additions and 160 deletions
+628 -160
......@@ -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);
}
/**
......
......@@ -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
......@@ -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");
}
}
}
......@@ -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());
}
......
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
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");
}
}
......@@ -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.");
}
}
}
......@@ -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");
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment