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

Initial Commit

parents
No related merge requests found
Pipeline #36403 canceled with stage
Showing with 2103 additions and 0 deletions
+2103 -0
package edu.caltech.cs2.interfaces;
/**
* This interface represents a stack - a data structure that can add elements remove elements from a single end.
* @param <E> Element type
*/
public interface IStack<E> extends Iterable<E> {
/**
* Adds an element to the top of the stack.
* @param e Element to add
* @return True if successful, false otherwise (i.e. fixed data structure is full)
*/
public boolean push(E e);
/**
* Removes and returns the element at the top of the stack. Returns null if stack is empty.
* @return Element at top of the stack, if one exists; null otherwise
*/
public E pop();
/**
* Returns (but does not remove) the element at the top of the stack. Returns null if stack is empty.
* @return Element at top of the stack, if one exists; null otherwise
*/
public E peek();
/**
* Calculates the size of the stack.
* @return Number of elements in the stack
*/
public int size();
}
package edu.caltech.cs2.project03;
import edu.caltech.cs2.datastructures.CircularArrayFixedSizeQueue;
import edu.caltech.cs2.interfaces.IQueue;
import java.util.Random;
public class CircularArrayFixedSizeQueueGuitarString {
public CircularArrayFixedSizeQueueGuitarString(double frequency) {
}
public int length() {
return -1;
}
public void pluck() {
}
public void tic() {
}
public double sample() {
return 0;
}
}
package edu.caltech.cs2.project03;
import edu.caltech.cs2.project03.libraries.StdAudio;
import edu.caltech.cs2.project03.libraries.StdDraw;
import edu.caltech.cs2.datastructures.*;
public class GuitarHero {
private static final String KEYBOARD = "q2we4r5ty7u8i9op-[=zxdcfvgbnjmk,.;/' ";
private static final double CONCERT_A = 440.0;
public static void main(String[] args) {
// Create three arrays of strings
CircularArrayFixedSizeQueueGuitarString[] strings = new CircularArrayFixedSizeQueueGuitarString[KEYBOARD.length()];
// Populate string arrays with respective string types
for (int i = 0; i < KEYBOARD.length(); i++) {
strings[i] = new CircularArrayFixedSizeQueueGuitarString(CONCERT_A * Math.pow(2, (i - 24.0) / 12.0));
}
while (true) {
// check if the user has typed a key; if so, process it
if (StdDraw.hasNextKeyTyped()) {
char key = StdDraw.nextKeyTyped();
int idx = KEYBOARD.indexOf(key);
if (idx != -1) {
strings[idx].pluck();
}
}
// compute the superposition of samples
double sample = 0.0;
for (int i = 0; i < strings.length; i++) {
sample += strings[i].sample();
}
// play the sample on standard audio
StdAudio.play(sample);
// advance the simulation of each guitar string by one step
for (int i = 0; i < strings.length; i++) {
strings[i].tic();
}
}
}
}
package edu.caltech.cs2.project03.libraries;
/******************************************************************************
* Compilation: javac StdAudio.java
* Execution: java StdAudio
* Dependencies: none
*
* Simple library for reading, writing, and manipulating .wav files.
*
*
* Limitations
* -----------
* - Does not seem to work properly when reading .wav files from a .jar file.
* - Assumes the audio is monaural, with sampling rate of 44,100.
*
******************************************************************************/
import javax.sound.sampled.Clip;
// for playing midi sound files on some older systems
import java.applet.Applet;
import java.applet.AudioClip;
import java.net.MalformedURLException;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
/**
* <i>Standard audio</i>. This class provides a basic capability for
* creating, reading, and saving audio.
* <p>
* The audio format uses a sampling rate of 44,100 (CD quality audio), 16-bit, monaural.
*
* <p>
* For additional documentation, see <a href="https://introcs.cs.princeton.edu/15inout">Section 1.5</a> of
* <i>Computer Science: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public final class StdAudio {
/**
* The sample rate - 44,100 Hz for CD quality audio.
*/
public static final int SAMPLE_RATE = 44100;
private static final int BYTES_PER_SAMPLE = 2; // 16-bit audio
private static final int BITS_PER_SAMPLE = 16; // 16-bit audio
private static final double MAX_16_BIT = Short.MAX_VALUE; // 32,767
private static final int SAMPLE_BUFFER_SIZE = 4096;
private static SourceDataLine line; // to play the sound
private static byte[] buffer; // our internal buffer
private static int bufferSize = 0; // number of samples currently in internal buffer
private StdAudio() {
// can not instantiate
}
// static initializer
static {
init();
}
// open up an audio stream
private static void init() {
try {
// 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian
AudioFormat format = new AudioFormat((float) SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE);
// the internal buffer is a fraction of the actual buffer size, this choice is arbitrary
// it gets divided because we can't expect the buffered data to line up exactly with when
// the sound card decides to push out its samples.
buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE/3];
}
catch (LineUnavailableException e) {
System.out.println(e.getMessage());
}
// no sound gets made before this call
line.start();
}
/**
* Closes standard audio.
*/
public static void close() {
line.drain();
line.stop();
}
/**
* Writes one sample (between -1.0 and +1.0) to standard audio.
* If the sample is outside the range, it will be clipped.
*
* @param sample the sample to play
* @throws IllegalArgumentException if the sample is {@code Double.NaN}
*/
public static void play(double sample) {
// clip if outside [-1, +1]
if (Double.isNaN(sample)) throw new IllegalArgumentException("sample is NaN");
if (sample < -1.0) sample = -1.0;
if (sample > +1.0) sample = +1.0;
// convert to bytes
short s = (short) (MAX_16_BIT * sample);
buffer[bufferSize++] = (byte) s;
buffer[bufferSize++] = (byte) (s >> 8); // little Endian
// send to sound card if buffer is full
if (bufferSize >= buffer.length) {
line.write(buffer, 0, buffer.length);
bufferSize = 0;
}
}
/**
* Writes the array of samples (between -1.0 and +1.0) to standard audio.
* If a sample is outside the range, it will be clipped.
*
* @param samples the array of samples to play
* @throws IllegalArgumentException if any sample is {@code Double.NaN}
* @throws IllegalArgumentException if {@code samples} is {@code null}
*/
public static void play(double[] samples) {
if (samples == null) throw new IllegalArgumentException("argument to play() is null");
for (int i = 0; i < samples.length; i++) {
play(samples[i]);
}
}
/**
* Reads audio samples from a file (in .wav or .au format) and returns
* them as a double array with values between -1.0 and +1.0.
*
* @param filename the name of the audio file
* @return the array of samples
*/
public static double[] read(String filename) {
byte[] data = readByte(filename);
int n = data.length;
double[] d = new double[n/2];
for (int i = 0; i < n/2; i++) {
d[i] = ((short) (((data[2*i+1] & 0xFF) << 8) + (data[2*i] & 0xFF))) / ((double) MAX_16_BIT);
}
return d;
}
// return data as a byte array
private static byte[] readByte(String filename) {
byte[] data = null;
AudioInputStream ais = null;
try {
// try to read from file
File file = new File(filename);
if (file.exists()) {
ais = AudioSystem.getAudioInputStream(file);
int bytesToRead = ais.available();
data = new byte[bytesToRead];
int bytesRead = ais.read(data);
if (bytesToRead != bytesRead)
throw new IllegalStateException("read only " + bytesRead + " of " + bytesToRead + " bytes");
}
// try to read from URL
else {
URL url = StdAudio.class.getResource(filename);
ais = AudioSystem.getAudioInputStream(url);
int bytesToRead = ais.available();
data = new byte[bytesToRead];
int bytesRead = ais.read(data);
if (bytesToRead != bytesRead)
throw new IllegalStateException("read only " + bytesRead + " of " + bytesToRead + " bytes");
}
}
catch (IOException e) {
throw new IllegalArgumentException("could not read '" + filename + "'", e);
}
catch (UnsupportedAudioFileException e) {
throw new IllegalArgumentException("unsupported audio format: '" + filename + "'", e);
}
return data;
}
/**
* Saves the double array as an audio file (using .wav or .au format).
*
* @param filename the name of the audio file
* @param samples the array of samples
* @throws IllegalArgumentException if unable to save {@code filename}
* @throws IllegalArgumentException if {@code samples} is {@code null}
*/
public static void save(String filename, double[] samples) {
if (samples == null) {
throw new IllegalArgumentException("samples[] is null");
}
// assumes 44,100 samples per second
// use 16-bit audio, mono, signed PCM, little Endian
AudioFormat format = new AudioFormat(SAMPLE_RATE, 16, 1, true, false);
byte[] data = new byte[2 * samples.length];
for (int i = 0; i < samples.length; i++) {
int temp = (short) (samples[i] * MAX_16_BIT);
data[2*i + 0] = (byte) temp;
data[2*i + 1] = (byte) (temp >> 8);
}
// now save the file
try {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
AudioInputStream ais = new AudioInputStream(bais, format, samples.length);
if (filename.endsWith(".wav") || filename.endsWith(".WAV")) {
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename));
}
else if (filename.endsWith(".au") || filename.endsWith(".AU")) {
AudioSystem.write(ais, AudioFileFormat.Type.AU, new File(filename));
}
else {
throw new IllegalArgumentException("unsupported audio format: '" + filename + "'");
}
}
catch (IOException ioe) {
throw new IllegalArgumentException("unable to save file '" + filename + "'", ioe);
}
}
/**
* Plays an audio file (in .wav, .mid, or .au format) in a background thread.
*
* @param filename the name of the audio file
* @throws IllegalArgumentException if unable to play {@code filename}
* @throws IllegalArgumentException if {@code filename} is {@code null}
*/
public static synchronized void play(final String filename) {
if (filename == null) throw new IllegalArgumentException();
InputStream is = StdAudio.class.getResourceAsStream(filename);
if (is == null) {
throw new IllegalArgumentException("could not read '" + filename + "'");
}
// code adapted from: http://stackoverflow.com/questions/26305/how-can-i-play-sound-in-java
try {
// check if file format is supported
// (if not, will throw an UnsupportedAudioFileException)
AudioSystem.getAudioInputStream(is);
new Thread(new Runnable() {
@Override
public void run() {
stream(filename);
}
}).start();
}
// let's try Applet.newAudioClip() instead
catch (UnsupportedAudioFileException e) {
playApplet(filename);
return;
}
// something else went wrong
catch (IOException ioe) {
throw new IllegalArgumentException("could not play '" + filename + "'", ioe);
}
}
// play sound file using Applet.newAudioClip();
@SuppressWarnings("deprecation")
private static void playApplet(String filename) {
URL url = null;
try {
File file = new File(filename);
if (file.canRead()) url = file.toURI().toURL();
}
catch (MalformedURLException e) {
throw new IllegalArgumentException("could not play '" + filename + "'", e);
}
// URL url = StdAudio.class.getResource(filename);
if (url == null) {
throw new IllegalArgumentException("could not play '" + filename + "'");
}
AudioClip clip = Applet.newAudioClip(url);
clip.play();
}
// https://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
// play a wav or aif file
// javax.sound.sampled.Clip fails for long clips (on some systems)
private static void stream(String filename) {
SourceDataLine line = null;
int BUFFER_SIZE = 4096; // 4K buffer
try {
InputStream is = StdAudio.class.getResourceAsStream(filename);
AudioInputStream ais = AudioSystem.getAudioInputStream(is);
AudioFormat audioFormat = ais.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
byte[] samples = new byte[BUFFER_SIZE];
int count = 0;
while ((count = ais.read(samples, 0, BUFFER_SIZE)) != -1) {
line.write(samples, 0, count);
}
}
catch (IOException e) {
e.printStackTrace();
}
catch (UnsupportedAudioFileException e) {
e.printStackTrace();
}
catch (LineUnavailableException e) {
e.printStackTrace();
}
finally {
if (line != null) {
line.drain();
line.close();
}
}
}
/**
* Loops an audio file (in .wav, .mid, or .au format) in a background thread.
*
* @param filename the name of the audio file
* @throws IllegalArgumentException if {@code filename} is {@code null}
*/
public static synchronized void loop(String filename) {
if (filename == null) throw new IllegalArgumentException();
// code adapted from: http://stackoverflow.com/questions/26305/how-can-i-play-sound-in-java
try {
Clip clip = AudioSystem.getClip();
InputStream is = StdAudio.class.getResourceAsStream(filename);
AudioInputStream ais = AudioSystem.getAudioInputStream(is);
clip.open(ais);
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
catch (UnsupportedAudioFileException e) {
throw new IllegalArgumentException("unsupported audio format: '" + filename + "'", e);
}
catch (LineUnavailableException e) {
throw new IllegalArgumentException("could not play '" + filename + "'", e);
}
catch (IOException e) {
throw new IllegalArgumentException("could not play '" + filename + "'", e);
}
}
/***************************************************************************
* Unit tests {@code StdAudio}.
***************************************************************************/
// create a note (sine wave) of the given frequency (Hz), for the given
// duration (seconds) scaled to the given volume (amplitude)
private static double[] note(double hz, double duration, double amplitude) {
int n = (int) (StdAudio.SAMPLE_RATE * duration);
double[] a = new double[n+1];
for (int i = 0; i <= n; i++)
a[i] = amplitude * Math.sin(2 * Math.PI * i * hz / StdAudio.SAMPLE_RATE);
return a;
}
/**
* Test client - play an A major scale to standard audio.
*
* @param args the command-line arguments
*/
/**
* Test client - play an A major scale to standard audio.
*
* @param args the command-line arguments
*/
public static void main(String[] args) {
// 440 Hz for 1 sec
double freq = 440.0;
for (int i = 0; i <= StdAudio.SAMPLE_RATE; i++) {
StdAudio.play(0.5 * Math.sin(2*Math.PI * freq * i / StdAudio.SAMPLE_RATE));
}
// scale increments
int[] steps = { 0, 2, 4, 5, 7, 9, 11, 12 };
for (int i = 0; i < steps.length; i++) {
double hz = 440.0 * Math.pow(2, steps[i] / 12.0);
StdAudio.play(note(hz, 1.0, 0.5));
}
// need to call this in non-interactive stuff so the program doesn't terminate
// until all the sound leaves the speaker.
StdAudio.close();
}
}
This diff is collapsed.
0.5
0.5
0.5
0.5
0.5
0.498
0.498
0.498
0.497004
0.496008
0.496008
0.496008
0.495511992
0.494519976
0.494023968
0.494023968
0.49377695601599997
0.49303592006400004
0.492294884112
0.492047872128
0.49192486015996795
0.49143281228784
0.490694740479648
0.49020269260752
0.490018420679408
0.48971212087900834
0.489099521278209
0.4884869216774097
0.4881501144168901
0.4879058096960913
0.4874481977942942
0.4868380485918981
0.4863652439749613
0.4860758502082647
0.485726295730212
0.4851945507003238
0.484655239698296
0.4842756649032465
0.4839574686773614
0.48351858152240684
0.48298519561851266
0.4825275904915682
0.48218010052314275
0.4818030729994846
0.4813188810161779
0.48082536748282023
0.4804244301253261
0.4800636204142685
0.4796347330998
0.4791478357525011
0.4787023992088569
0.4783230491687181
0.4779297800500061
0.47747371928844595
0.4770094170107563
0.4765986732920323
0.4762139089509247
0.4757909426705491
0.4753326018770027
0.4748968289707887
0.4745006659569926
0.474098416107494
0.47365952518468085
0.4732142565622001
0.47279995247403506
0.4724023428681143
0.47198345476350306
0.47154314330994673
0.4711150761000451
0.47071074308039035
0.47030412722054543
0.46987624584057797
0.4694437932661759
0.46902925795185685
0.468625405409866
0.4682098257844394
0.4677813794751634
0.46735957950658036
0.46695202235413796
0.4665439451347641
0.4661236202192822
0.46570019757290837
0.4652871777266377
0.46488099180947323
0.4644684475463151
0.4640482612605109
0.463631712899174
0.46322374842898323
0.4628160207991826
0.46240132098579934
0.46198462713152305
0.4615740197414223
0.4611678050756266
0.460758236208921
0.46034420216242655
0.4599322061427268
0.45952542875889035
0.4591191685597047
0.4587090143089311
0.45829765133596634
0.45788990218100534
\ No newline at end of file
0.3
0.2
0.1
0
-0.1
-0.2
0.14940000000000003
0.049800000000000004
-0.049800000000000004
-0.14940000000000003
0.024401999999999993
0.1984032
0.09920160000000001
0.0
-0.09920160000000001
-0.06224900400000002
0.11095698959999999
0.1482071904
0.049402396800000005
-0.049402396800000005
-0.080402400792
0.024256576828799985
0.12906376164
0.0984095744256
0.0
-0.064642789200816
-0.027960620333673608
0.07635352855746239
0.1132817213606688
0.0490079680639488
-0.032192109022006365
-0.04611649794817582
0.02409966829544681
0.09443835445922934
0.08082026533345957
0.00837429780288733
-0.03899768627115073
-0.010964381167059048
0.05903193533182872
0.08727879265675909
0.044418892441900754
-0.015250447457195174
-0.02488110958422847
0.023937641974055294
0.07286274253831672
0.0655854471791326
0.014525885602383378
-0.019985515406628972
-4.6984686986624154E-4
0.04820659148716126
0.06894719847928976
0.03989544372519496
-0.002718895642514306
-0.010186770413694616
0.02377289881941292
0.05834258740329261
0.05420363581783339
0.018513920945174966
-0.006427021695992043
0.006765891946047715
0.04089351213890736
0.05604801916412075
0.03621334326797816
0.006019275826093095
1.6875738452772472E-4
0.023734383234307627
0.04827688258890799
0.04594615849118526
0.021031844308847487
0.0030816405388891686
0.011903764028180004
0.035861610379961384
0.04692307445788644
0.033355045394416305
0.012008515454172855
0.007462731474400449
0.02378715645525441
0.04122677304924821
0.039978503686446766
0.022591053302597402
0.009696680970429505
0.01556244418896812
0.0323769368932423
0.0404402278143761
0.031159639380543995
0.0160792916679674
0.012579044329380019
0.02387381177894079
0.03626294802439396
0.03565673386307021
0.023524987662158676
0.014271851326679016
0.018153522341943763
0.029948106382060705
0.03581600157995716
0.029472497319563983
0.01882282581644117
\ No newline at end of file
0.7825462456
-0.4561245625
0.3245324556
-0.9712345674
-0.5027592834
-0.1673752768
0.2364378668
0.8743574274
-0.7452743574
-0.0655328692362
-0.3220576516764
-0.7340489376984
-0.33372701097959995
0.03439316982000001
0.5531760565116
0.06428336885999998
-0.2901927468896676
0.048318514215904794
-0.1930200794144748
-0.5259410815086503
-0.5317524224416439
-0.14906825289748077
0.29260947471313675
0.30749479383505673
-0.11250287025877449
-0.12045336787153388
-0.07206137946888785
-0.35804265813971625
-0.5267313649672465
-0.33904869631888407
0.07148352846419669
0.2988519257370003
0.09710597794098856
-0.11601220658889357
-0.09587234417553002
-0.21419181072908483
-0.44061746350726744
-0.43115847052049305
-0.1332474535916343
0.1844270561921961
0.19718703603163845
-0.009415301866656692
-0.10551850628068295
-0.1544119491424982
-0.3260950185697034
-0.4341444151458247
-0.2810741502078394
0.02548744209507977
0.19004381792746963
0.09351032361416092
-0.05723703645737514
-0.12944536680074423
-0.23929246992067638
-0.37859923799033296
-0.35617884554612467
-0.12728218064015429
0.1073345674912296
0.14120996248773202
0.018064097004079318
-0.09296783682254343
-0.18363144268726744
-0.30771007053968263
-0.36591948560115595
-0.24076359104076692
-0.00993391134816449
0.12377517592952289
0.07931848162692205
-0.03730206242959513
-0.13774644119588583
-0.24468807358702113
-0.3354675189581376
-0.3021281721676776
-0.12484735618968784
0.05669294976151648
0.10114064146310957
0.02092417676026881
-0.08717415480548953
-0.19045238836188766
-0.28891748508748905
-0.31752265418065595
-0.212633813121968
-0.03394089440122934
0.07860112842986376
0.06078827947524243
-0.032992489066519914
-0.13825801849735384
-0.2387261969777896
-0.3020071893555362
-0.26401792071670677
-0.12279420434655226
0.02224079654625994
0.06941592513674287
0.013842303623543812
-0.08528275276680913
-0.18773813930662142
-0.26928522639399627
-0.281880504815977
-0.19263243828150298
-0.05007559708454557
0.0456450473981354
\ No newline at end of file
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.helpers.Inspection;
import edu.caltech.cs2.helpers.Reflection;
import edu.caltech.cs2.helpers.RuntimeInstrumentation;
import edu.caltech.cs2.interfaces.ICollection;
import edu.caltech.cs2.interfaces.IQueue;
import edu.caltech.cs2.interfaces.IDeque;
import edu.caltech.cs2.interfaces.IStack;
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.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Tag("C")
public class ArrayDequeTests implements DequeTests, StackTests, QueueTests {
private static String ARRAY_DEQUE_SOURCE ="src/edu/caltech/cs2/datastructures/ArrayDeque.java";
private Constructor arrayDequeConstructor = Reflection.getConstructor(ArrayDeque.class);
public ICollection<Object> newCollection() {
return Reflection.newInstance(arrayDequeConstructor);
}
public IDeque<Object> newDeque() {
return Reflection.newInstance(arrayDequeConstructor);
}
public IStack<Object> newStack() {
return Reflection.newInstance(arrayDequeConstructor);
}
public IQueue<Object> newQueue() {
return Reflection.newInstance(arrayDequeConstructor);
}
public IQueue<Object> newQueue(int size) {
return newQueue();
}
// ARRAYDEQUE-SPECIFIC TESTS ----------------------------------------
@Order(classSpecificTestLevel)
@DisplayName("Does not use or import disallowed classes")
@Test
public void testForInvalidClasses() {
List<String> regexps = List.of("java\\.util\\.(?!Iterator)", "java\\.lang\\.reflect", "java\\.io");
Inspection.assertNoImportsOf(ARRAY_DEQUE_SOURCE, regexps);
Inspection.assertNoUsageOf(ARRAY_DEQUE_SOURCE, regexps);
}
@Order(classSpecificTestLevel)
@DisplayName("There is an integer default capacity static field and an integer default grow factor static field")
@Test
public void testConstantFields() {
Reflection.assertFieldsEqualTo(ArrayDeque.class, "static", 2);
Stream<Field> fields = Reflection.getFields(ArrayDeque.class);
fields.filter(Reflection.hasModifier("static")).forEach((field) -> {
Reflection.checkFieldModifiers(field, List.of("private", "static", "final"));
assertEquals(field.getType(), int.class, "static fields must be of type int");
});
}
@Order(classSpecificTestLevel)
@DisplayName("The overall number of fields is small")
@Test
public void testSmallNumberOfFields() {
Reflection.assertFieldsLessThan(ArrayDeque.class, "private", 5);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no public fields")
@Test
public void testNoPublicFields() {
Reflection.assertNoPublicFields(ArrayDeque.class);
}
@Order(classSpecificTestLevel)
@DisplayName("The public interface is correct")
@Test
public void testPublicInterface() {
Reflection.assertPublicInterface(ArrayDeque.class, List.of(
"addFront",
"addBack",
"removeFront",
"removeBack",
"enqueue",
"dequeue",
"push",
"pop",
"peek",
"peekFront",
"peekBack",
"iterator",
"size",
"toString"
));
}
@Order(classSpecificTestLevel)
@DisplayName("Uses this(...) notation in all but one constructor")
@Test
public void testForThisConstructors() {
Inspection.assertConstructorHygiene(ARRAY_DEQUE_SOURCE);
}
// TOSTRING TESTS ---------------------------------------------------
@Order(toStringTestLevel)
@DisplayName("toString is correctly overridden")
@Test
public void testToStringOverride() {
Reflection.assertMethodCorrectlyOverridden(ArrayDeque.class, "toString");
}
@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"
})
public void testToString(String inputs) {
java.util.ArrayDeque<String> reference = new java.util.ArrayDeque<String>();
edu.caltech.cs2.datastructures.ArrayDeque<String> me = new edu.caltech.cs2.datastructures.ArrayDeque<>();
for (String value : inputs.trim().split(", ")) {
assertEquals(reference.toString(), me.toString(), "toString outputs should be the same");
reference.addLast(value);
me.addBack(value);
}
}
// TIME COMPLEXITY TESTS ------------------------------------------------
@Order(complexityTestLevel)
@DisplayName("addFront() and removeFront() take linear time")
@Test()
public void testFrontDequeOperationComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.addFront(i);
}
return q;
};
Consumer<IDeque<Integer>> addFront = (IDeque<Integer> q) -> q.addFront(0);
Consumer<IDeque<Integer>> removeFront = (IDeque<Integer> q) -> q.removeFront();
RuntimeInstrumentation.assertAtMost("addFront", RuntimeInstrumentation.ComplexityType.LINEAR, provide, addFront, 8);
RuntimeInstrumentation.assertAtMost("removeFront", RuntimeInstrumentation.ComplexityType.LINEAR, provide, removeFront, 8);
}
@Order(complexityTestLevel)
@DisplayName("addBack() and removeBack() take linear time")
@Test
public void testBackDequeOperationComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.addBack(i);
}
return q;
};
Consumer<IDeque<Integer>> addBack = (IDeque<Integer> q) -> q.addBack(0);
Consumer<IDeque<Integer>> removeBack = (IDeque<Integer> q) -> q.removeBack();
RuntimeInstrumentation.assertAtMost("addBack", RuntimeInstrumentation.ComplexityType.LINEAR, provide, addBack, 8);
RuntimeInstrumentation.assertAtMost("removeBack", RuntimeInstrumentation.ComplexityType.LINEAR, provide, removeBack, 8);
}
@Order(complexityTestLevel)
@DisplayName("enqueue() and dequeue() take linear time")
@Test
public void testQueueOperationComplexity() {
Function<Integer, IQueue<Integer>> provide = (Integer numElements) -> {
IQueue<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.enqueue(i);
}
return q;
};
Consumer<IQueue<Integer>> enqueue = (IQueue<Integer> q) -> q.enqueue(0);
Consumer<IQueue<Integer>> dequeue = (IQueue<Integer> q) -> q.dequeue();
RuntimeInstrumentation.assertAtMost("enqueue", RuntimeInstrumentation.ComplexityType.LINEAR, provide, enqueue, 8);
RuntimeInstrumentation.assertAtMost("dequeue", RuntimeInstrumentation.ComplexityType.LINEAR, provide, dequeue, 8);
}
@Order(complexityTestLevel)
@DisplayName("push() and pop() take constant time")
@Test
public void testStackOperationComplexity() {
Function<Integer, IStack<Integer>> provide = (Integer numElements) -> {
IStack<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.push(i);
}
return q;
};
Consumer<IStack<Integer>> push = (IStack<Integer> q) -> q.push(0);
Consumer<IStack<Integer>> pop = (IStack<Integer> q) -> q.pop();
RuntimeInstrumentation.assertAtMost("push", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, push, 8);
RuntimeInstrumentation.assertAtMost("pop", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, pop, 8);
}
@Order(complexityTestLevel)
@DisplayName("peek() takes constant time")
@Test
public void testPeekComplexity() {
Function<Integer, IStack<Integer>> provide = (Integer numElements) -> {
IStack<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.push(i);
}
return q;
};
Consumer<IStack<Integer>> peek = (IStack<Integer> q) -> q.peek();
RuntimeInstrumentation.assertAtMost("peek", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peek, 8);
}
@Order(complexityTestLevel)
@DisplayName("peekFront() takes constant time")
@Test()
public void testPeekFrontComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.addFront(i);
}
return q;
};
Consumer<IDeque<Integer>> peekFront = (IDeque<Integer> q) -> q.peekFront();
RuntimeInstrumentation.assertAtMost("peekFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekFront, 8);
}
@Order(complexityTestLevel)
@DisplayName("peekBack() takes constant time")
@Test
public void testPeekBackComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new ArrayDeque<>();
for (int i = 0; i < numElements; i++) {
q.addBack(i);
}
return q;
};
Consumer<IDeque<Integer>> peekBack = (IDeque<Integer> q) -> q.peekBack();
RuntimeInstrumentation.assertAtMost("peekBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekBack, 8);
}
}
\ No newline at end of file
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.helpers.Inspection;
import edu.caltech.cs2.helpers.Reflection;
import edu.caltech.cs2.helpers.RuntimeInstrumentation;
import edu.caltech.cs2.interfaces.IFixedSizeQueue;
import edu.caltech.cs2.interfaces.IQueue;
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.lang.reflect.Constructor;
import java.util.*;
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;
@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 Constructor circFixedSizeQueueConstructor = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class);
private int DEFAULT_CAPACITY = 10;
public IQueue<Object> newQueue() {
return Reflection.newInstance(circFixedSizeQueueConstructor, DEFAULT_CAPACITY);
}
public IQueue<Object> newQueue(int capacity) {
return Reflection.newInstance(circFixedSizeQueueConstructor, capacity);
}
public IFixedSizeQueue<Object> newFixedSizeQueue(int capacity) {
return Reflection.newInstance(circFixedSizeQueueConstructor, capacity);
}
// FIXED QUEUE-SPECIFIC TESTS ----------------------------------------
@Order(classSpecificTestLevel)
@DisplayName("Does not use or import disallowed classes")
@Test
public void testForInvalidClasses() {
List<String> regexps = List.of("java\\.util\\.(?!Iterator)", "java\\.lang\\.reflect", "java\\.io");
Inspection.assertNoImportsOf(FIXED_QUEUE_SOURCE, regexps);
Inspection.assertNoUsageOf(FIXED_QUEUE_SOURCE, regexps);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no static fields")
@Test
public void testConstantFields() {
Reflection.assertFieldsEqualTo(CircularArrayFixedSizeQueue.class, "static", 0);
}
@Order(classSpecificTestLevel)
@DisplayName("The overall number of fields is small")
@Test
public void testSmallNumberOfFields() {
Reflection.assertFieldsLessThan(CircularArrayFixedSizeQueue.class, "private", 4);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no public fields")
@Test
public void testNoPublicFields() {
Reflection.assertNoPublicFields(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"
));
}
@Order(classSpecificTestLevel)
@DisplayName("Uses this(...) notation in all but one constructor")
@Test
public void testForThisConstructors() {
Inspection.assertConstructorHygiene(FIXED_QUEUE_SOURCE);
}
// TOSTRING TESTS ---------------------------------------------------
@Order(toStringTestLevel)
@DisplayName("toString is correctly overridden")
@Test
public void testToStringOverride() {
Reflection.assertMethodCorrectlyOverridden(ArrayDeque.class, "toString");
}
@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"
})
public void testToString(String inputs) {
java.util.ArrayDeque<String> reference = new java.util.ArrayDeque<String>();
Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class);
IFixedSizeQueue<String> me = Reflection.newInstance(c, inputs.length());
for (String value : inputs.trim().split(", ")) {
assertEquals(reference.toString(), me.toString(), "toString outputs should be the same");
reference.addLast(value);
me.enqueue(value);
}
}
// TIME COMPLEXITY TESTS ------------------------------------------------
@Order(complexityTestLevel)
@DisplayName("enqueue() and dequeue() take constant time")
@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);
for (int i = 0; i < numElements; i++) {
q.enqueue(i);
}
return q;
};
Consumer<IFixedSizeQueue<Integer>> enqueue = (IFixedSizeQueue<Integer> q) -> q.enqueue(0);
Consumer<IFixedSizeQueue<Integer>> dequeue = (IFixedSizeQueue<Integer> q) -> q.dequeue();
RuntimeInstrumentation.assertAtMost("enqueue", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, enqueue, 8);
RuntimeInstrumentation.assertAtMost("dequeue", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, dequeue, 8);
}
@Order(complexityTestLevel)
@DisplayName("peek() takes constant time")
@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);
for (int i = 0; i < numElements; i++) {
q.enqueue(i);
}
return q;
};
Consumer<IFixedSizeQueue<Integer>> peek = (IFixedSizeQueue<Integer> q) -> q.peek();
RuntimeInstrumentation.assertAtMost("peek", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peek, 8);
}
}
\ No newline at end of file
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.interfaces.ICollection;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public interface CollectionTests {
ICollection<Object> newCollection();
@Order(collectionTestLevel)
@DisplayName("Simple tests of various ICollection functions")
@ParameterizedTest(name = "Test add(), size(), isEmpty(), contains(), and clear() on [{arguments}]")
@ValueSource(strings = {
"",
"1",
"0, 1, 2, 3",
"5, 4, 3, 2, 1",
"8, 3, 5, 7, 4, 3, 12, 12, 1"
})
default void testCollectionFunctions(String inputs) {
ICollection<Object> impl = newCollection();
List<Object> reference = new java.util.ArrayList<>();
// Check that collection is empty
assertTrue(impl.isEmpty(), "collection should be empty");
// Check that values are not in collection
for (Object value : inputs.trim().split(", ")) {
assertFalse(impl.contains(value), "value should not be contained");
}
// Add all values to collection
for (Object value : inputs.trim().split(", ")) {
impl.add(value);
reference.add(value);
}
// Check that size() and isEmpty() is correct
assertEquals(reference.size(), impl.size(), "sizes should be equal");
assertFalse(impl.isEmpty(), "collection should not be empty");
// Check that values are in collection
for (Object value : inputs.trim().split(", ")) {
assertTrue(impl.contains(value), "value should be contained");
}
// Clear and make sure size() and isEmpty() match
impl.clear();
assertEquals(0, impl.size(), "size should be 0");
assertTrue(impl.isEmpty(), "collection should be empty");
// Check that values are not in collection
for (Object value : inputs.trim().split(", ")) {
assertFalse(impl.contains(value), "value should not be contained");
}
}
@Order(collectionTestLevel)
@Test
@DisplayName("Test repeated emptying and filling of ICollection with single element")
default void testFillEmptyCollection() {
ICollection<Object> impl = newCollection();
for (int i = 0; i < 10; i ++) {
impl.add("a");
assertEquals(impl.size(), 1, "collection should have 1 element");
impl.clear();
assertTrue(impl.isEmpty());
}
}
@Order(collectionTestLevel)
@DisplayName("Stress test for add(...)")
@ParameterizedTest(name = "Test add()ing {1} random numbers with seed = {0}")
@CsvSource({
"100, 3000", "42, 1000"
})
default void stressTestAdd(int seed, int size) {
Random r = new Random(seed);
List<Integer> reference = new java.util.ArrayList<>();
ICollection<Object> impl = newCollection();
// Test adding values updates size and displays contained correctly
for (int i = 0; i < size; i++) {
int num = r.nextInt();
reference.add(num);
impl.add(num);
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.contains(num), impl.contains(num), "value should be contained");
}
// Test that values not in collection are not contained
for (int i = 0; i < size; i++) {
int num = r.nextInt();
assertEquals(reference.contains(num), impl.contains(num), "contained values do not match");
}
}
@Order(collectionTestLevel)
@DisplayName("Stress test for contains(...)")
@ParameterizedTest(name = "Test contains() with {1} random numbers and seed = {0}")
@CsvSource({
"100, 3000", "42, 1000"
})
default void stressTestContains(int seed, int size) {
Random r = new Random(seed);
List<Integer> nums = new java.util.ArrayList<>();
ICollection<Object> impl = newCollection();
// Add values to both the list of nums and test collection
for (int i = 0; i < size; i++) {
int num = r.nextInt();
nums.add(num);
impl.add(num);
}
// Shuffle order of nums and check that all are contained in the collection
Collections.shuffle(nums);
for (int num : nums) {
assertEquals(true, impl.contains(num), "value should be contained");
}
// Test that values not in collection are not contained
for (int i = 0; i < size; i++) {
int num = r.nextInt();
assertEquals(nums.contains(num), impl.contains(num), "contained values do not match");
}
}
}
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.interfaces.ICollection;
import edu.caltech.cs2.interfaces.IDeque;
import org.hamcrest.MatcherAssert;
import org.hamcrest.collection.IsEmptyIterable;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.hamcrest.collection.IsIterableContainingInOrder;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Random;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static org.junit.jupiter.api.Assertions.*;
public interface DequeTests extends CollectionTests {
IDeque<Object> newDeque();
@Order(dequeTestLevel)
@DisplayName("Test Deque Iterator")
@ParameterizedTest(name = "Test deque iterator on [{arguments}]")
@ValueSource(strings = {
"",
"1",
"0, 1, 2, 3",
"5, 4, 3, 2, 1",
"8, 3, 5, 7, 4, 3, 12, 12, 1"
})
default void testIterator(String inputs) {
ArrayDeque<Object> ref = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (Object value : inputs.trim().split(", ")) {
impl.addBack(value);
ref.addLast(value);
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
}
for (Object value : inputs.trim().split(", ")) {
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
impl.removeBack();
ref.removeLast();
}
MatcherAssert.assertThat(impl, IsEmptyIterable.emptyIterable());
}
@Test
@Order(dequeTestLevel)
@DisplayName("Test Deque addFront / removeFront edge cases")
default void testRepeatedAddFrontRemoveFront() {
ArrayDeque<Object> ref = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (int i = 0; i < 10; i ++) {
for (int j = 0; j < 5; j ++) {
impl.addFront(i);
ref.addFirst(i);
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
}
for (int j = 0; j < 5; j ++) {
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
impl.removeFront();
ref.removeFirst();
}
assertTrue(impl.isEmpty());
MatcherAssert.assertThat(impl, IsEmptyIterable.emptyIterable());
}
}
@Test
@Order(dequeTestLevel)
@DisplayName("Test Deque addFront / removeBack edge cases")
default void testRepeatedAddFrontRemoveBack() {
ArrayDeque<Object> ref = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (int i = 0; i < 10; i ++) {
for (int j = 0; j < 5; j ++) {
impl.addFront(i);
ref.addFirst(i);
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
}
for (int j = 0; j < 5; j ++) {
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
impl.removeBack();
ref.removeLast();
}
assertTrue(impl.isEmpty());
MatcherAssert.assertThat(impl, IsEmptyIterable.emptyIterable());
}
}
@Test
@Order(dequeTestLevel)
@DisplayName("Test Deque addBack / removeFront edge cases")
default void testRepeatedAddBackRemoveFront() {
ArrayDeque<Object> ref = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (int i = 0; i < 10; i ++) {
for (int j = 0; j < 5; j ++) {
impl.addBack(i);
ref.addLast(i);
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
}
for (int j = 0; j < 5; j ++) {
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
impl.removeFront();
ref.removeFirst();
}
assertTrue(impl.isEmpty());
MatcherAssert.assertThat(impl, IsEmptyIterable.emptyIterable());
}
}
@Test
@Order(dequeTestLevel)
@DisplayName("Test Deque addBack / removeBack edge cases")
default void testRepeatedAddBackRemoveBack() {
ArrayDeque<Object> ref = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (int i = 0; i < 10; i ++) {
for (int j = 0; j < 5; j ++) {
impl.addBack(i);
ref.addLast(i);
MatcherAssert.assertThat(impl, IsIterableContainingInOrder.contains(ref.toArray()));
}
for (int j = 0; j < 5; j ++) {
impl.removeBack();
ref.removeLast();
}
assertTrue(impl.isEmpty());
MatcherAssert.assertThat(impl, IsEmptyIterable.emptyIterable());
}
}
@Order(dequeTestLevel)
@DisplayName("Stress test for addFront(...) and peekFront(...)")
@ParameterizedTest(name = "Test addFront()ing {1} random numbers with seed = {0}")
@CsvSource({
"100, 300", "42, 500"
})
default void stressTestAddFront(int seed, int size) {
Random r = new Random(seed);
Deque<Object> reference = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
// 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();
reference.addFirst(num);
impl.addFront(num);
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.peekFirst(), impl.peekFront(), "peeks should be the same");
assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal");
}
}
@Order(dequeTestLevel)
@DisplayName("Stress test for addBack(...) and peekBack(...)")
@ParameterizedTest(name = "Test addBack()ing {1} random numbers with seed = {0}")
@CsvSource({
"100, 300", "42, 500"
})
default void stressTestAddBack(int seed, int size) {
Random r = new Random(seed);
Deque<Object> reference = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
// Test that first peek is null
assertNull(impl.peekBack(), "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();
reference.addLast(num);
impl.addBack(num);
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.peekLast(), impl.peekBack(), "peeks should be the same");
assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal");
}
}
@Order(dequeTestLevel)
@DisplayName("Stress test for removeFront(...)")
@ParameterizedTest(name = "Test removeFront()ing {1} random numbers with seed = {0}")
@CsvSource({
"101, 300", "45, 500"
})
default void stressTestRemoveFront(int seed, int size) {
Random r = new Random(seed);
Deque<Object> reference = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
// Test that first removeFront is null
assertNull(impl.removeFront(), "empty removeFront should return null");
for (int i = 0; i < size; i++) {
int num = r.nextInt();
reference.addFirst(num);
impl.addFront(num);
assertEquals(reference.peekFirst(), impl.peekFront(),"return values of peekFront()s are not equal");
if (r.nextBoolean()) {
assertEquals(reference.removeFirst(), impl.removeFront(),"return values of removeFront()s are not equal");
assertEquals(reference.peekFirst(), impl.peekFront(),"return values of peekFront()s are not equal");
}
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal");
}
}
@Order(dequeTestLevel)
@DisplayName("Stress test for removeBack(...)")
@ParameterizedTest(name = "Test removeBack()ing {1} random numbers with seed = {0}")
@CsvSource({
"101, 300", "45, 500"
})
default void stressTestRemoveBack(int seed, int size) {
Random r = new Random(seed);
Deque<Object> reference = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
// Test that first removeBack is null
assertNull(impl.removeBack(), "empty removeBack should return null");
for (int i = 0; i < size; i++) {
int num = r.nextInt();
reference.addLast(num);
impl.addBack(num);
assertEquals(reference.peekLast(), impl.peekBack(),"return values of peekBack()s are not equal");
if (r.nextBoolean()) {
assertEquals(reference.removeLast(), impl.removeBack(),"return values of removeBack()s are not equal");
assertEquals(reference.peekLast(), impl.peekBack(),"return values of peekBack()s are not equal");
}
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal");
}
}
@Order(dequeTestLevel)
@DisplayName("Stress test full IDeque")
@ParameterizedTest(name = "Test all IDeque methods {1} random numbers with seed = {0}")
@CsvSource({
"102, 300", "52, 500"
})
default void stressTestFullDeque(int seed, int size) {
Random r = new Random(seed);
Deque<Object> reference = new ArrayDeque<>();
IDeque<Object> impl = newDeque();
for (int i = 0; i < size; i++) {
int num = r.nextInt();
// Add to either front or back
if (r.nextBoolean()) {
reference.addFirst(num);
impl.addFront(num);
}
else {
reference.addLast(num);
impl.addBack(num);
}
// Test that peeks are correct
assertEquals(reference.peekFirst(), impl.peekFront(),"return values of peekFront()s are not equal");
assertEquals(reference.peekLast(), impl.peekBack(),"return values of peekBacks()s are not equal");
// If true, remove an element
if (r.nextBoolean()) {
// If true, remove from front, else remove from back
if (r.nextBoolean()) {
assertEquals(reference.removeFirst(), impl.removeFront(),"return values of removeFront()s are not equal");
}
else {
assertEquals(reference.removeLast(), impl.removeBack(),"return values of removeBack()s are not equal");
}
assertEquals(reference.peekFirst(), impl.peekFront(),"return values of peekFront()s are not equal");
assertEquals(reference.peekLast(), impl.peekBack(),"return values of peekBacks()s are not equal");
}
assertEquals(reference.size(), impl.size(), "size()s are not equal");
assertEquals(reference.toString(), impl.toString(), "toStrings()s are not equal");
}
}
@Order(dequeTestLevel)
@DisplayName("Test for addAll(...)")
@ParameterizedTest(name = "Test addAll with {1} random numbers and seed = {0}")
@CsvSource({
"99, 300", "48, 500"
})
default void testAddAll(int seed, int size) {
Random r = new Random(seed);
ICollection<Object> coll = newDeque();
IDeque<Object> impl = newDeque();
for (int i = 0; i < size; i++) {
int num = r.nextInt();
coll.add(num);
}
impl.addAll(coll);
for (Object num : coll) {
assertTrue(impl.contains(num), "value should be contained in Deque");
}
}
}
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.helpers.Reflection;
import edu.caltech.cs2.interfaces.IFixedSizeQueue;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import java.lang.reflect.Constructor;
import java.util.Queue;
import java.util.Random;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public interface FixedSizeQueueTests extends QueueTests {
IFixedSizeQueue<Object> newFixedSizeQueue(int capacity);
@Order(fixedSizeQueueLevel)
@DisplayName("Overflow test for enqueue(...)")
@ParameterizedTest(name = "Test randomly enqueue()ing/dequeue()ing {1} random numbers with seed = {0} and fixed array size = {2}")
@CsvSource({
"97, 3000, 100", "38, 5000, 10"
})
default void overflowTestEnqueue(int seed, int numVals, int queueSize) {
Random r = new Random(seed);
Constructor c = Reflection.getConstructor(CircularArrayFixedSizeQueue.class, int.class);
IFixedSizeQueue<Object> me = newFixedSizeQueue(queueSize);
Queue<Object> reference = new java.util.ArrayDeque<>();
assertEquals(queueSize, me.capacity(), "capacity does not match expected value");
int count = 0;
for (int i = 0; i < numVals; i++) {
int num = r.nextInt();
// Check that we get the expected value from enqueue when it has a risk of overflowing
if (count < queueSize) {
assertEquals(false, me.isFull(), "queue should not be full");
assertEquals(true, me.enqueue(num), "enqueue should be successful");
reference.add(num);
count++;
}
else {
assertEquals(true, me.isFull(), "queue should be full");
assertEquals(false, me.enqueue(num), "enqueue should have failed");
}
// Standard checks to make sure peeks() and dequeues() match up
assertEquals(reference.peek(), me.peek(),"return values of peek()s are not equal");
if (r.nextBoolean()) {
assertEquals(reference.remove(), me.dequeue(),"return values of dequeue()s are not equal");
assertEquals(reference.peek(), me.peek(),"return values of peek()s are not equal");
count--;
}
assertEquals(reference.size(), me.size(), "size()s are not equal");
assertEquals(queueSize, me.capacity(), "capacity does not match expected value");
}
}
}
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.helpers.Inspection;
import edu.caltech.cs2.helpers.Reflection;
import edu.caltech.cs2.helpers.RuntimeInstrumentation;
import edu.caltech.cs2.interfaces.ICollection;
import edu.caltech.cs2.interfaces.IDeque;
import edu.caltech.cs2.interfaces.IQueue;
import edu.caltech.cs2.interfaces.IStack;
import edu.caltech.cs2.project03.Project03TestOrdering.*;
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.lang.reflect.Constructor;
import java.util.*;
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;
@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 Constructor linkedDequeConstructor = Reflection.getConstructor(LinkedDeque.class);
public ICollection<Object> newCollection() {
return Reflection.newInstance(linkedDequeConstructor);
}
public IDeque<Object> newDeque() {
return Reflection.newInstance(linkedDequeConstructor);
}
public IStack<Object> newStack() {
return Reflection.newInstance(linkedDequeConstructor);
}
public IQueue<Object> newQueue() {
return Reflection.newInstance(linkedDequeConstructor);
}
public IQueue<Object> newQueue(int size) {
return newQueue();
}
// LINKEDDEQUE-SPECIFIC TESTS ----------------------------------------
@Order(classSpecificTestLevel)
@DisplayName("Does not use or import disallowed classes")
@Test
public void testForInvalidClasses() {
List<String> regexps = List.of("java\\.util\\.(?!Iterator)", "java\\.lang\\.reflect", "java\\.io");
Inspection.assertNoImportsOf(LINKED_DEQUE_SOURCE, regexps);
Inspection.assertNoUsageOf(LINKED_DEQUE_SOURCE, regexps);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no static fields")
@Test
public void testConstantFields() {
Reflection.assertFieldsEqualTo(LinkedDeque.class, "static", 0);
}
@Order(classSpecificTestLevel)
@DisplayName("The overall number of fields is small")
@Test
public void testSmallNumberOfFields() {
Reflection.assertFieldsLessThan(LinkedDeque.class, "private", 4);
}
@Order(classSpecificTestLevel)
@DisplayName("There are no public fields")
@Test
public void testNoPublicFields() {
Reflection.assertNoPublicFields(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"
));
}
@Order(classSpecificTestLevel)
@DisplayName("Uses this(...) notation in all but one constructor")
@Test
public void testForThisConstructors() {
Inspection.assertConstructorHygiene(LINKED_DEQUE_SOURCE);
}
// TOSTRING TESTS ---------------------------------------------------
@Order(toStringTestLevel)
@DisplayName("toString is correctly overridden")
@Test
public void testToStringOverride() {
Reflection.assertMethodCorrectlyOverridden(LinkedDeque.class, "toString");
}
@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"
})
public void testToString(String inputs) {
java.util.ArrayDeque<String> reference = new java.util.ArrayDeque<String>();
LinkedDeque<String> me = new LinkedDeque<>();
for (String value : inputs.trim().split(", ")) {
assertEquals(reference.toString(), me.toString(), "toString outputs should be the same");
reference.addLast(value);
me.addBack(value);
}
}
// TIME COMPLEXITY TESTS ------------------------------------------------
@Order(complexityTestLevel)
@DisplayName("addFront() and removeFront() take constant time")
@Test
public void testFrontDequeOperationComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.addFront(i);
}
return q;
};
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);
}
@Order(complexityTestLevel)
@DisplayName("addBack() and removeBack() take constant time")
@Test
public void testBackDequeOperationComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.addBack(i);
}
return q;
};
Consumer<IDeque<Integer>> addBack = (IDeque<Integer> q) -> q.addBack(0);
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);
}
@Order(complexityTestLevel)
@DisplayName("enqueue() and dequeue() take constant time")
@Test
public void testQueueOperationComplexity() {
Function<Integer, IQueue<Integer>> provide = (Integer numElements) -> {
IQueue<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.enqueue(i);
}
return q;
};
Consumer<IQueue<Integer>> enqueue = (IQueue<Integer> q) -> q.enqueue(0);
Consumer<IQueue<Integer>> dequeue = (IQueue<Integer> q) -> q.dequeue();
RuntimeInstrumentation.assertAtMost("enqueue", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, enqueue, 8);
RuntimeInstrumentation.assertAtMost("dequeue", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, dequeue, 8);
}
@Order(complexityTestLevel)
@DisplayName("push() and pop() take constant time")
@Test
public void testStackOperationComplexity() {
Function<Integer, IStack<Integer>> provide = (Integer numElements) -> {
IStack<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.push(i);
}
return q;
};
Consumer<IStack<Integer>> push = (IStack<Integer> q) -> q.push(0);
Consumer<IStack<Integer>> pop = (IStack<Integer> q) -> q.pop();
RuntimeInstrumentation.assertAtMost("push", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, push, 8);
RuntimeInstrumentation.assertAtMost("pop", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, pop, 8);
}
@Order(complexityTestLevel)
@DisplayName("peek() takes constant time")
@Test
public void testPeekComplexity() {
Function<Integer, IStack<Integer>> provide = (Integer numElements) -> {
IStack<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.push(i);
}
return q;
};
Consumer<IStack<Integer>> peek = (IStack<Integer> q) -> q.peek();
RuntimeInstrumentation.assertAtMost("peek", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peek, 8);
}
@Order(complexityTestLevel)
@DisplayName("peekFront() takes constant time")
@Test
public void testPeekFrontComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.addFront(i);
}
return q;
};
Consumer<IDeque<Integer>> peekFront = (IDeque<Integer> q) -> q.peekFront();
RuntimeInstrumentation.assertAtMost("peekFront", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekFront, 8);
}
@Order(complexityTestLevel)
@DisplayName("peekBack() takes constant time")
@Test
public void testPeekBackComplexity() {
Function<Integer, IDeque<Integer>> provide = (Integer numElements) -> {
IDeque<Integer> q = new LinkedDeque<>();
for (int i = 0; i < numElements; i++) {
q.addBack(i);
}
return q;
};
Consumer<IDeque<Integer>> peekBack = (IDeque<Integer> q) -> q.peekBack();
RuntimeInstrumentation.assertAtMost("peekBack", RuntimeInstrumentation.ComplexityType.CONSTANT, provide, peekBack, 8);
}
}
\ No newline at end of file
package edu.caltech.cs2.datastructures;
import edu.caltech.cs2.interfaces.IQueue;
import edu.caltech.cs2.interfaces.IStack;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import java.util.Queue;
import java.util.Random;
import static edu.caltech.cs2.project03.Project03TestOrdering.*;
import static org.junit.jupiter.api.Assertions.*;
public interface QueueTests {
IQueue<Object> newQueue();
IQueue<Object> newQueue(int size);
@Order(queueTestLevel)
@DisplayName("Stress test for enqueue(...) and peek(...)")
@ParameterizedTest(name = "Test enqueue()ing {1} random numbers with seed = {0}")
@CsvSource({
"97, 3000", "38, 5000"
})
default void stressTestEnqueue(int seed, int size) {
Random r = new Random(seed);
Queue<Object> reference = new java.util.ArrayDeque<>();
IQueue<Object> me = newQueue(size);
// Test that first peek is null
assertNull(me.peek(), "empty peek should return null");
// Test adding values updates size and peek correctly
for (int i = 0; i < size; i++) {
int num = r.nextInt();
reference.add(num);
assertTrue(me.enqueue(num), "enqueue should be successful");
assertEquals(reference.size(), me.size(), "size()s are not equal");
assertEquals(reference.peek(), me.peek(), "peeks should be the same");
}
}
@Order(queueTestLevel)
@DisplayName("Stress test for dequeue(...)")
@ParameterizedTest(name = "Test dequeue()ing {1} random numbers with seed = {0}")
@CsvSource({
"98, 3000", "39, 5000"
})
default void stressTestDequeue(int seed, int size) {
Random r = new Random(seed);
Queue<Object> reference = new java.util.ArrayDeque<>();
IQueue<Object> me = newQueue(size);
// Test that first dequeue is null
assertNull(me.dequeue(), "empty dequeue should return null");
for (int i = 0; i < size; i++) {
int num = r.nextInt();
reference.add(num);
assertTrue(me.enqueue(num), "enqueue should be successful");
assertEquals(reference.peek(), me.peek(),"return values of peek()s are not equal");
if (r.nextBoolean()) {
assertEquals(reference.remove(), me.dequeue(),"return values of dequeue()s are not equal");
assertEquals(reference.peek(), me.peek(),"return values of peek()s are not equal");
}
assertEquals(reference.size(), me.size(), "size()s are not equal");
}
}
}
This diff is collapsed.
This diff is collapsed.
package edu.caltech.cs2.helpers;
import org.junit.jupiter.params.provider.ArgumentsSource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(FileSourceProvider.class)
public @interface FileSource {
String[] inputs();
String[] outputFiles();
}
This diff is collapsed.
This diff is collapsed.
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