Skip to content

Commit

Permalink
unit test setup
Browse files Browse the repository at this point in the history
  • Loading branch information
voidSevenSevenSix committed Jan 18, 2024
1 parent 0821b43 commit b4e5ad6
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 1 deletion.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ dependencies {
nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
simulationRelease wpi.sim.enableRelease()

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'

}



test {
useJUnitPlatform()
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
Expand Down
124 changes: 124 additions & 0 deletions src/main/java/frc/robot/utils/RingBuffer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package frc.robot.utils;
import java.util.NoSuchElementException;

public class RingBuffer<T> {

private Object[] backingArray;
private int firstIdx = 0; // Index of the first elements
private int nextIdx = 0; // Index of the slot into which we would insert an element on addLast
// If nextIdx == (firstIdx - 1) % array_size, then insertion requires resizing the array.
// If nextIdx == firstIdx, then the buffer is empty.

public RingBuffer() {
backingArray = new Object[2];
}

synchronized private void doubleBackingArraySize() {
int newSize = backingArray.length * 2;
Object[] newArray = new Object[newSize];
int oldSize;

if (nextIdx < firstIdx) {
int numElementsToEndOfArray = backingArray.length - firstIdx;
System.arraycopy(backingArray, firstIdx, newArray, 0, numElementsToEndOfArray);
System.arraycopy(backingArray, 0, newArray, numElementsToEndOfArray, nextIdx);
oldSize = numElementsToEndOfArray + nextIdx;
} else {
// This will happen if firstIdx == 0
System.arraycopy(backingArray, firstIdx, newArray, 0, nextIdx - firstIdx);
oldSize = nextIdx - firstIdx;
}

backingArray = newArray;
// Update our indices into that array.
firstIdx = 0;
nextIdx = oldSize;
}

/**
* Returns the number of elements that the array backing this can hold.
* This is NOT necessarily the number of elements presently in the buffer.
* Useful for testing that the implementation works correctly, and for figuring out if an add{First, Last} will
* cause a re-allocation.
*/
public int capacity() {
return backingArray.length - 1;
}

/**
* The number of elements currently held in the buffer.
*/
public int size() {
if (firstIdx <= nextIdx) {
return nextIdx - firstIdx;
} else {
return (backingArray.length - firstIdx + nextIdx);
}
}

public void addLast(T x) {
if ((nextIdx + 1) % backingArray.length == firstIdx) {
doubleBackingArraySize();
}

backingArray[nextIdx] = x;
nextIdx +=1;
nextIdx %= backingArray.length;
}

public void addFirst(T x) {
if ((nextIdx + 1) % backingArray.length == firstIdx) {
doubleBackingArraySize();
}

firstIdx -= 1;
// Note: in Java -1 % n == -1
if (firstIdx < 0) {
firstIdx += backingArray.length;
}
backingArray[firstIdx] = x;
}

public void removeFirst() {
if (size() == 0) {
throw new NoSuchElementException();
} else {
firstIdx += 1;
firstIdx %= backingArray.length;
}
}

public void removeLast() {
if (size() == 0) {
throw new NoSuchElementException();
} else {
nextIdx -= 1;
if (nextIdx < 0) {
nextIdx += backingArray.length;
}
}
}

public T getFromFirst(int i) {
if (i < 0 || i >= size()) {
throw new NoSuchElementException();
} else {
//noinspection unchecked
return (T)backingArray[(firstIdx + i) % backingArray.length];
}
}

public T getFromLast(int i) {
if (i < 0 || i >= size()) {
throw new NoSuchElementException();
} else {
int idx = nextIdx - 1 - i;
if (idx < 0) {
idx += backingArray.length;
}
//noinspection unchecked
return (T)backingArray[idx];
}
}

}
145 changes: 145 additions & 0 deletions src/test/java/RingBufferTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import static org.junit.Assert.*;
import org.junit.jupiter.api.Test;


import frc.robot.utils.RingBuffer;

import java.util.NoSuchElementException;

public class RingBufferTests {

@Test
public void populateAndRandomAccess() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addLast(5); // [5]
buffer.addLast(6); // [5, 6]
buffer.addLast(7); // [5, 6, 7]

Assert.assertEquals(5, (int)buffer.getFromFirst(0));
Assert.assertEquals(6, (int)buffer.getFromFirst(1));
Assert.assertEquals(7, (int)buffer.getFromFirst(2));
}

@Test
public void populateAndRandomAccessFromLast() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addLast(5); // [5];
buffer.addLast(6); // [5, 6]
buffer.addLast(7); // [5, 6, 7]

Assert.assertEquals(7, (int)buffer.getFromLast(0));
Assert.assertEquals(6, (int)buffer.getFromLast(1));
Assert.assertEquals(5, (int)buffer.getFromLast(2));
}

@Test
public void populateFromFirst() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addFirst(5); // [5]
buffer.addFirst(6); // [6, 5]
buffer.addFirst(7); // [7, 6, 5]

Assert.assertEquals(5, (int)buffer.getFromLast(0));
Assert.assertEquals(6, (int)buffer.getFromLast(1));
Assert.assertEquals(7, (int)buffer.getFromLast(2));

Assert.assertEquals(7, (int)buffer.getFromFirst(0));
Assert.assertEquals(6, (int)buffer.getFromFirst(1));
Assert.assertEquals(5, (int)buffer.getFromFirst(2));
}

@Test
public void populateFromBothEnds() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addFirst(6); // [6]
buffer.addFirst(5); // [5, 6]
buffer.addLast(7); // [5, 6, 7]
buffer.addLast(8); // [5, 6, 7, 8]

Assert.assertEquals(8, (int)buffer.getFromLast(0));
Assert.assertEquals(7, (int)buffer.getFromLast(1));
Assert.assertEquals(6, (int)buffer.getFromLast(2));
Assert.assertEquals(5, (int)buffer.getFromLast(3));

Assert.assertEquals(5, (int)buffer.getFromFirst(0));
Assert.assertEquals(6, (int)buffer.getFromFirst(1));
Assert.assertEquals(7, (int)buffer.getFromFirst(2));
Assert.assertEquals(8, (int)buffer.getFromFirst(3));
}

@Test
public void outOfBoundsAccessThrows() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addLast(5); // [5]
buffer.addLast(6); // [5, 6]
buffer.addLast(7); // [5, 6, 7]

Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromFirst(3));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromFirst(4));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromFirst(5));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromLast(3));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromLast(4));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromLast(5));

Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromFirst(-1));
Assert.assertThrows(NoSuchElementException.class, () -> buffer.getFromLast(-1));
}

@Test
public void removingWhenEmptyThrows() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addLast(5); // [5]
buffer.addLast(6); // [5, 6]
buffer.addLast(7); // [5, 6, 7]

buffer.removeFirst();
buffer.removeFirst();
buffer.removeFirst();

Assert.assertThrows(NoSuchElementException.class, buffer::removeFirst);
Assert.assertThrows(NoSuchElementException.class, buffer::removeLast);
}

@Test
public void populateAndRemove() {
RingBuffer<Integer> buffer = new RingBuffer<>();
buffer.addLast(5); // [5]
buffer.addLast(6); // [5, 6]
buffer.addLast(7); // [5, 6, 7]

buffer.removeFirst(); // Should remove the 5

Assert.assertEquals(6, (int)buffer.getFromFirst(0));
Assert.assertEquals(7, (int)buffer.getFromFirst(1));

Assert.assertEquals(6, (int)buffer.getFromLast(1));
Assert.assertEquals(7, (int)buffer.getFromLast(0));
}

@Test
public void populateAndRemoveManyTimes() {
RingBuffer<Integer> buffer = new RingBuffer<>();

// This should result in the buffer always containing between 3 and 5 elements.
buffer.addLast(-1);
buffer.addLast(-1);
buffer.addLast(-1);
for (int i=0; i < 100; i+=2) {
buffer.addLast(i);
buffer.addLast(i+1);
buffer.removeFirst();
buffer.removeFirst();
}

// Check that the buffer has only 3 elements
Assert.assertEquals(3, buffer.size());
// Check that these elements are [97, 98, 99]
Assert.assertEquals(97, (int)buffer.getFromFirst(0));
Assert.assertEquals(98, (int)buffer.getFromFirst(1));
Assert.assertEquals(99, (int)buffer.getFromFirst(2));

// Check that the buffer has not grown in capacity to some absurd size
// Will use 8 since my implementation will probably grow by doubling the backing array size.
Assert.assertTrue(buffer.capacity() <= 8);
}
}
8 changes: 8 additions & 0 deletions src/test/java/TestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import org.junit.jupiter.api.Test;

public class TestTest {
@Test
void test(){
assert true;
}
}
10 changes: 10 additions & 0 deletions src/test/java/frc/robot/TestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package frc.robot;

import org.junit.jupiter.api.Test;

public class TestTest {
@Test
public static void test(){
assert false;
}
}

0 comments on commit b4e5ad6

Please sign in to comment.