Commit d476add1 authored by Adam Blank's avatar Adam Blank
Browse files

Initial Commit

parents
Pipeline #36403 canceled with stage
Showing with 968 additions and 0 deletions
+968 -0
package edu.caltech.cs2.helpers;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.support.AnnotationConsumer;
import java.util.stream.Stream;
public class ImageFileSourceProvider implements ArgumentsProvider, AnnotationConsumer<ImageFileSource> {
private String[] inputs;
private String[] outputFiles;
@Override
public void accept(ImageFileSource source) {
this.inputs = source.inputs();
this.outputFiles = source.outputFiles();
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
Arguments[] args = new Arguments[this.outputFiles.length];
for (int i = 0; i < this.outputFiles.length; i++) {
String inputArgs = this.inputs[i];
args[i] = Arguments.arguments(inputArgs, Images.getImage("tests/data/" + this.outputFiles[i]));
}
return Stream.of(args);
}
}
package edu.caltech.cs2.helpers;
import org.junit.platform.commons.util.Preconditions;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class Images {
public static BufferedImage getImage(String resource) {
Preconditions.notBlank(resource, "Test file " + resource + " must not be null or blank");
try {
return ImageIO.read(new File(resource));
} catch (IOException e) {
fail("Test file " + resource + " does not exist");
}
return null;
}
private static boolean within(int a, int b, double threshold) {
System.err.println(a + ", " + b + ", " + Math.abs(a - b));
return Math.abs(a - b) <= threshold;
}
private static boolean rgbEqual(int p1, int p2, double t) {
int a1 = (p1 >> 24) & 0xff;
int r1 = (p1 >> 16) & 0xff;
int g1 = (p1 >> 8) & 0xff;
int b1 = (p1) & 0xff;
int a2 = (p2 >> 24) & 0xff;
int r2 = (p2 >> 16) & 0xff;
int g2 = (p2 >> 8) & 0xff;
int b2 = (p2) & 0xff;
return within(a1, a2, t) && within(r1, r2, t) && within(g1, g2, t) && within(b1, b2, t);
}
public static String rgb(int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
return "(" + alpha + ", " + red + ", " + green + ", " + blue + ")";
}
public static void assertImagesEqual(BufferedImage expected, BufferedImage image, double threshold) {
assertEquals(expected.getWidth(), image.getWidth(), "image widths are different");
assertEquals(expected.getHeight(), image.getHeight(), "image height are different");
int width = expected.getWidth();
int height = expected.getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (!rgbEqual(expected.getRGB(x, y), image.getRGB(x, y), threshold)){
fail("image is not the same as expected at (" + x + ", " + y + "): \nexpected: <" + rgb(expected.getRGB(x, y)) + ">\nactual: <" + rgb(image.getRGB(x, y)) + ">");
}
}
}
}
}
package edu.caltech.cs2.helpers;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.fail;
public class Inspection {
private static String getUsageOf(List<String> regexps, List<? extends Node> codeObjects) {
for (Node d : codeObjects) {
for (String regex : regexps) {
if (d.toString().replaceAll("\\R", "").matches(".*" + regex + ".*")) {
return regex;
}
}
}
return null;
}
public static void assertNoImportsOf(String filePath, List<String> regexps) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
String usage = getUsageOf(regexps, cu.getImports());
if (usage != null) {
fail("You may not import " + usage + " in " + Paths.get(filePath).getFileName() + ".");
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
private static class ConstructorCollector extends VoidVisitorAdapter<List<ConstructorDeclaration>> {
@Override
public void visit(ConstructorDeclaration md, List<ConstructorDeclaration> collector) {
super.visit(md, collector);
collector.add(md);
}
}
private static class MethodCollector extends VoidVisitorAdapter<List<MethodDeclaration>> {
@Override
public void visit(MethodDeclaration md, List<MethodDeclaration> collector) {
super.visit(md, collector);
collector.add(md);
}
}
private static MethodCollector METHOD_COLLECTOR = new MethodCollector();
private static ConstructorCollector CONSTRUCTOR_COLLECTOR = new ConstructorCollector();
public static void assertNoUsageOf(String filePath, List<String> regexps) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
List<ConstructorDeclaration> constructors = new ArrayList<>();
CONSTRUCTOR_COLLECTOR.visit(cu, constructors);
String usage = getUsageOf(regexps, constructors);
if (usage != null) {
fail("You may not use " + usage + " in " + Paths.get(filePath).getFileName() + ".");
}
List<MethodDeclaration> methods = new ArrayList<>();
METHOD_COLLECTOR.visit(cu, methods);
usage = getUsageOf(regexps, methods);
if (usage != null) {
fail("You may not use " + usage + " in " + Paths.get(filePath).getFileName() + ".");
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
public static void assertConstructorHygiene(String filePath) {
try {
CompilationUnit cu = JavaParser.parse(new File(filePath));
// Use a Map to restrict constructor verification to per class
Set<String> foundNonThisConstructors = new HashSet<>();
Set<String> failedConstructors = new HashSet<>();
List<ConstructorDeclaration> constructors = new ArrayList<>();
CONSTRUCTOR_COLLECTOR.visit(cu, constructors);
for (ConstructorDeclaration c : constructors) {
BlockStmt body = c.getBody();
List<Statement> statements = body.getStatements();
// Nontrivial constructor, or a constructor that doesn't pass to another constructor
if (statements.size() != 1 || !statements.get(0).toString().startsWith("this(")) {
// If we find it twice, it's bad
if (!foundNonThisConstructors.add(c.getNameAsString())) {
failedConstructors.add(c.getNameAsString());
}
}
if (! failedConstructors.isEmpty()) {
fail(failedConstructors.toString() + " do not have exactly one constructor using this(...) notation.");
}
}
} catch (FileNotFoundException e) {
fail("Missing Java file: " + Paths.get(filePath).getFileName());
}
}
}
package edu.caltech.cs2.helpers;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import static org.junit.jupiter.api.Assertions.fail;
public class Reflection {
public static <T> T getFieldValue(Class clazz, String name, Object o) {
T result = null;
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return (T) field.get(o);
} catch (NoSuchFieldException | IllegalAccessException e) {
fail("Could not find field " + name + " in class " + clazz.getName());
return null;
}
}
public static Method getMethod(Class clazz, String name, Class<?>... params) {
Method method = null;
try {
method = clazz.getDeclaredMethod(name, params);
method.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
fail("Could not find method " + name + " in class " + clazz.getName());
return null;
}
return method;
}
public static Constructor getConstructor(Class clazz, Class<?>... params) {
Constructor c = null;
try {
c = clazz.getDeclaredConstructor(params);
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());
return null;
}
return c;
}
public static <T> T invoke(Method m, Object... args) {
T result = null;
try {
result = (T) m.invoke(args[0], Arrays.copyOfRange(args, 1, args.length));
} catch (IllegalAccessException | InvocationTargetException e) {
fail(e.getCause());
}
return result;
}
public static <T> T invokeStatic(Method m, Object... args) {
T result = null;
try {
result = (T) m.invoke(null, args);
} catch (IllegalAccessException | InvocationTargetException e) {
fail(e.getCause());
}
return result;
}
public static <T> T newInstance(Constructor c, Object... args) {
T result = null;
try {
result = (T) c.newInstance(args);
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
fail(e.getCause());
}
return result;
}
public static Stream<Field> getFields(Class clazz) {
return Stream.of(clazz.getDeclaredFields());
}
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.");
}
/* Should never reach here... */
return -1;
}
public static Predicate<Member> hasModifier(String modifier) {
return (Member f) -> (f.getModifiers() & stringToIntModifier(modifier)) != 0;
}
public static Predicate<Member> doesNotHaveModifier(String modifier) {
return (Member f) -> (f.getModifiers() & stringToIntModifier(modifier)) == 0;
}
public static Predicate<Field> hasType(Class clazz) {
return (Field f) -> f.getType().equals(clazz);
}
public static Predicate<Field> doesNotHaveType(Class clazz) {
return (Field f) -> !f.getType().equals(clazz);
}
public static void assertFieldsLessThan(Class clazz, Class FieldType, int 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 );
}
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"));
}
if (FieldType != null) {
fields = fields.filter(hasType(FieldType));
}
if (fields.count() >= x) {
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 );
}
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 );
}
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) {
if (modifier != null) {
fields = fields.filter(hasModifier(modifier));
}
if (FieldType != null) {
fields = fields.filter(hasType(FieldType));
}
if (fields.count() <= x) {
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 );
}
public static void assertFieldsEqualTo(Class clazz, String modifier, int x) {
assertFieldsEqualTo(clazz, modifier, null, x );
}
public static void assertFieldsEqualTo(Class clazz, Stream<Field> fields, int 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));
}
if (FieldType != null) {
fields = fields.filter(hasType(FieldType));
}
if (fields.count() != x) {
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);
}
public static Field getFieldByName(Class clazz, String name) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
fail(clazz.getName() + " should have a field named '" + name + "', but does not.");
// Should not reach here!
return null;
}
}
public static Field getNonStaticFieldByType(Class clazz, Class FieldType) {
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."
);
// 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."
);
// Should not reach here
return null;
}
return fieldsList.get(0);
}
public static Field getFieldByType(Class clazz, Class FieldType) {
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."
);
// 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."
);
// Should not reach here
return null;
}
return fieldsList.get(0);
}
public static Field getFieldByModifiers(Class clazz, String modifier) {
return getFieldByModifiers(clazz, List.of(modifier));
}
public static Field getFieldByModifiers(Class clazz, List<String> modifiers) {
Stream<Field> fields = getFields(clazz);
for (String m : modifiers) {
fields = fields.filter(hasModifier(m));
}
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."
);
// 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."
);
// Should not reach here
return null;
}
return fieldsList.get(0);
}
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));
}
}
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()));
if (!expected.equals(actual)) {
String diff = "expected: " + expected + "\nactual: " + actual;
fail("The public interface of " + clazz.getName() + " has incorrect functionality.\n" + diff);
}
}
public static void assertMethodCorrectlyOverridden(Class clazz, String method, Class<?>... params) {
Method studentc = getMethod(clazz, method, params);
Method superc = getMethod(clazz.getSuperclass(), method, params);
if (!studentc.getReturnType().equals(superc.getReturnType())) {
fail("You should be overriding the " + method + "method, but your signature wasn't correct.");
}
}
}
package edu.caltech.cs2.helpers;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
public class RuntimeInstrumentation {
private static final int SKIP = 5;
private static final int ITERATIONS = 100;
public enum ComplexityType {
CONSTANT(0, "constant"),
LOGARITHMIC(1, "logarithmic"),
LINEAR(2, "linear"),
QUADRATIC(3, "quadratic"),
WORSE(4, "worse than quadratic");
private final String name;
private int size;
ComplexityType(int size, String name) {
this.size = size;
this.name = name;
}
public String toString() {
return this.name;
}
public boolean isSlowerThan(ComplexityType other) {
return this.size > other.size;
}
}
public static <DS> long timeFunction(DS ds, Consumer<DS> function) {
long startTime = System.nanoTime();
function.accept(ds);
long endTime = System.nanoTime();
return endTime - startTime;
}
public static <DS> ComplexityType getEmpiricalComplexity(Function<Integer, DS> provideDSOfSize, Consumer<DS> functionToTest, int numberOfDoubles) {
List<Long> times = new ArrayList<>();
int maxSize = (1 << (numberOfDoubles + SKIP));
for (int currentSize = 1; currentSize < maxSize; currentSize *= 2) {
long totalTime = 0;
for (int i = 0; i < ITERATIONS; i++) {
DS ds = provideDSOfSize.apply(currentSize);
// Bring ds into cache! Make sure we're only clocking
// the function, and not JVM operations on the heap / cache
timeFunction(ds, functionToTest);
totalTime += timeFunction(ds, functionToTest);
}
times.add(Math.round((double)totalTime / ITERATIONS));
}
for (int i = 0; i < SKIP; i++) {
times.remove(0);
}
if (isApproximately(ComplexityType.CONSTANT, times)) {
return ComplexityType.CONSTANT;
}
else if (isApproximately(ComplexityType.LOGARITHMIC, times)) {
return ComplexityType.LOGARITHMIC;
}
else if (isApproximately(ComplexityType.LINEAR, times)) {
return ComplexityType.LINEAR;
}
else if (isApproximately(ComplexityType.QUADRATIC, times)) {
return ComplexityType.QUADRATIC;
}
else {
return ComplexityType.WORSE;
}
}
private static boolean isApproximately(ComplexityType type, List<Long> times) {
List<Double> y = new ArrayList<>();
List<Double> x = new ArrayList<>();
for (int i = 0; i < times.size(); i++) {
int numElements = (1 << (i + SKIP));
x.add((double) numElements);
double d = 0.0;
switch (type) {
case CONSTANT:
d = times.get(i);
break;
case LOGARITHMIC:
d = times.get(i) / (Math.log10(numElements) / Math.log10(2));
break;
case LINEAR:
d = ((double)times.get(i)) / numElements;
break;
case QUADRATIC:
d = ((double)times.get(i)) / (numElements * numElements);
break;
default:
throw new RuntimeException("unimplemented isApproximately for " + type);
}
y.add(d);
}
// Store sums
double sumX = 0;
double sumY = 0;
for (int i = 0; i < x.size(); i ++) {
sumX += x.get(i);
sumY += y.get(i);
}
// Calc standard deviation of numElements
double std = 0;
for (int i = 0; i < x.size(); i ++) {
std += (Math.pow(x.get(i) - sumX / x.size(), 2));
}
std /= times.size();
double slope;
double inter;
// If constant, no slope - best fit is mean of times
if (type == ComplexityType.CONSTANT) {
slope = 0;
inter = sumY / y.size();
}
// Otherwise, do least squares regression to find the best
// linear fit for the transformed times
else {
double cov = 0;
for (int i = 0; i < y.size(); i ++) {
cov += (x.get(i) - sumX / y.size()) * (y.get(i) - sumY / y.size());
}
cov /= y.size() - 1;
slope = cov / std;
inter = sumY / y.size() - slope * sumX / y.size();
}
// Calculate mean squared error
double mse = 0;
for (int i = 0; i < y.size(); i ++) {
mse += Math.pow(y.get(i) - inter + slope * x.get(i), 2);
}
// Use R^2 measure to check fit
double rSq = 1 - mse / std;
// Tune depending on strictness - 0.95 accounts for variations
// *Should* actually be like 0.99, but sometimes weird heap operations
// happen and make certain runs take longer
return rSq >= 0.92;
}
public static <DS> void assertAtMost(String whatIsBeingTested, ComplexityType expected, Function<Integer, DS> provideDSOfSize, Consumer<DS> functionToTest, int numberOfDoubles) {
ComplexityType calculated = getEmpiricalComplexity(provideDSOfSize, functionToTest, numberOfDoubles);
if (calculated.isSlowerThan(expected)) {
fail(whatIsBeingTested + " is expected to be " + expected + " time or better. The actual calculated time is " + calculated + ".\nThis test is non-deterministic which means it might not always be correct. If you run it multiple times and it usually passes, that's probably fine.");
}
}
}
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("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();
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();
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();
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();
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();
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();
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();
assertEquals(queue.peek(), string.sample(), "Sample should same as peek()ing queue");
}
}
}
package edu.caltech.cs2.project03;
public final class Project03TestOrdering {
public Project03TestOrdering() {
throw new InstantiationError("Class is only for storing constant variables");
}
public static final int classSpecificTestLevel = 0;
public static final int collectionTestLevel = 1;
public static final int dequeTestLevel = 2;
public static final int stackTestLevel = 3;
public static final int queueTestLevel = 3;
public static final int fixedSizeQueueLevel = 3;
public static final int toStringTestLevel = 4;
public static final int complexityTestLevel = 5;
public static final int guitarStringTestLevel = 6;
}
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