1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package edu.caltech.cs2.project03;
import edu.caltech.cs2.datastructures.CircularArrayFixedSizeQueue;
import edu.caltech.cs2.helpers.Inspection;
import edu.caltech.cs2.helpers.Reflection;
import edu.caltech.cs2.interfaces.IFixedSizeQueue;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.stream.Stream;
import java.util.function.Function;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static java.lang.Math.abs;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Tag("A")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class GuitarStringTests {
private static String STRING_SOURCE = "src/edu/caltech/cs2/project03/CircularArrayFixedSizeQueueGuitarString.java";
public static CircularArrayFixedSizeQueueGuitarString constructGuitarString(double frequency) {
Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueueGuitarString.class, double.class);
return Reflection.newInstance(c, frequency);
}
public static IFixedSizeQueue<Double> getQueueFromString(CircularArrayFixedSizeQueueGuitarString string) {
String queueName = Reflection.getFieldByType(CircularArrayFixedSizeQueueGuitarString.class, IFixedSizeQueue.class)
.getName();
return Reflection.getFieldValue(CircularArrayFixedSizeQueueGuitarString.class, queueName, string);
}
@Order(classSpecificTestLevel)
@DisplayName("Does not use or import disallowed classes")
@Test
public void testForInvalidClasses() {
List<String> regexps = List.of("java\\.util\\.(?!Random|function.Function)", "java\\.lang\\.reflect", "java\\.io");
Inspection.assertNoImportsOf(STRING_SOURCE, regexps);
Inspection.assertNoUsageOf(STRING_SOURCE, regexps);
}
@Order(classSpecificTestLevel)
@DisplayName("Uses this(...) notation in all but one constructor")
@Test
public void testForThisConstructors() {
Inspection.assertConstructorHygiene(STRING_SOURCE);
}
@Order(classSpecificTestLevel)
@DisplayName("There are three static fields: the two double constants and a random value generator")
@Test
public void testStaticFields() {
Reflection.assertFieldsEqualTo(CircularArrayFixedSizeQueueGuitarString.class, "static", 3);
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");
});
}
@Order(classSpecificTestLevel)
@DisplayName("The overall number of fields is small")
@Test
public void testSmallNumberOfFields() {
Reflection.assertFieldsLessThan(CircularArrayFixedSizeQueueGuitarString.class, "private", 5);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no public fields")
@Test
public void testNoPublicFields() {
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"));
}
@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" })
public void testConstructor(double frequency, int expectedSize) {
CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency);
IFixedSizeQueue<Double> queue = getQueueFromString(string);
assertEquals(expectedSize, queue.size(), "Queue size is not equal to expected size");
for (double val : queue) {
assertEquals(0, val, "All values in queue should be equal to 0");
}
}
@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" })
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) {
assertEquals(0, val, "initial values must be 0");
}
string.pluck();
queue = getQueueFromString(string);
double sum = 0;
double absSum = 0;
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");
}
@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" })
public void testTic(double frequency, String filename) {
// Set up scanner
String filepath = "tests/data/" + filename + ".txt";
Scanner in;
try {
in = new Scanner(new File(filepath));
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(filepath + " is not a valid trace file.");
}
// Set up class and retrieve queue
CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency);
IFixedSizeQueue<Double> queue = getQueueFromString(string);
// Reinitialize queue with new data
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++) {
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");
}
}
@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" })
public void testLength(double frequency, int expectedLength, int iterations) {
// Set up class and retrieve queue
CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency);
IFixedSizeQueue<Double> queue = getQueueFromString(string);
// Pluck and make sure length doesn't change
int initSize = queue.size();
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
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");
}
}
@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" })
public void testSample(double frequency, int iterations) {
// Set up class and retrieve queue
CircularArrayFixedSizeQueueGuitarString string = constructGuitarString(frequency);
IFixedSizeQueue<Double> queue = getQueueFromString(string);
// Pluck and make sure initial samples are correct
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");
}
}
}