mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-26 01:51:41 +00:00
SCRIPT Move java files
This commit is contained in:
committed by
Peter Johnson
parent
7ca1be9bae
commit
c350c5f112
24
wpiutil/src/test/java/org/wpilib/util/ErrorMessagesTest.java
Normal file
24
wpiutil/src/test/java/org/wpilib/util/ErrorMessagesTest.java
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ErrorMessagesTest {
|
||||
@Test
|
||||
void requireNonNullParamNullTest() {
|
||||
assertThrows(
|
||||
NullPointerException.class, () -> requireNonNullParam(null, "testParam", "testMethod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void requireNonNullParamNotNullTest() {
|
||||
assertDoesNotThrow(() -> requireNonNullParam("null", "testParam", "testMethod"));
|
||||
}
|
||||
}
|
||||
26
wpiutil/src/test/java/org/wpilib/util/WPIUtilJNITest.java
Normal file
26
wpiutil/src/test/java/org/wpilib/util/WPIUtilJNITest.java
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class WPIUtilJNITest {
|
||||
@Test
|
||||
public void testEnableMockTime() {
|
||||
assertDoesNotThrow(WPIUtilJNI::enableMockTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetMockTime() {
|
||||
assertDoesNotThrow(() -> WPIUtilJNI.setMockTime(0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNow() {
|
||||
assertDoesNotThrow(WPIUtilJNI::now);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.cleanup;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CleanupPoolTest {
|
||||
static class AutoCloseableObject implements AutoCloseable {
|
||||
public boolean m_closed;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static class AutoCloseableObjectWithCallback implements AutoCloseable {
|
||||
private final Runnable m_cb;
|
||||
|
||||
AutoCloseableObjectWithCallback(Runnable cb) {
|
||||
m_cb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_cb.run();
|
||||
}
|
||||
}
|
||||
|
||||
static class FailingAutoCloseableObject implements AutoCloseable {
|
||||
public static final String message = "This is an expected failure";
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
void cleanupStackWithExceptionNotInCloseWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
String message = "This is a known failure";
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
throw new Exception(message);
|
||||
} catch (Exception e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackWithExceptionInCloseWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(new FailingAutoCloseableObject());
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackRemovalWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
|
||||
pool.remove(objects.get(0));
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
if (idx == 0) {
|
||||
assertFalse(autoCloseableObject.m_closed);
|
||||
} else {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackIsLifo() {
|
||||
List<AutoCloseableObjectWithCallback> objects = new ArrayList<>();
|
||||
List<Integer> order = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(0)));
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(1)));
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(2)));
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseable autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(order.size(), 3);
|
||||
assertEquals(order.get(0), 2);
|
||||
assertEquals(order.get(1), 1);
|
||||
assertEquals(order.get(2), 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.cleanup;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ReflectionCleanupTest {
|
||||
static class CleanupClass implements AutoCloseable {
|
||||
public boolean m_closed;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.TestClassWithoutTestCases")
|
||||
static class CleanupTest implements ReflectionCleanup {
|
||||
public CleanupClass m_class1 = new CleanupClass();
|
||||
public CleanupClass m_class2 = new CleanupClass();
|
||||
public Object m_nonCleanupObject = new Object();
|
||||
public Object m_nullCleanupObject;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
reflectionCleanup(CleanupTest.class);
|
||||
}
|
||||
}
|
||||
|
||||
static class CleanupTest2 extends CleanupTest {
|
||||
@SkipCleanup public CleanupClass m_class3 = new CleanupClass();
|
||||
public CleanupClass m_class4 = new CleanupClass();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
reflectionCleanup(CleanupTest2.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupClosesAllFields() {
|
||||
CleanupTest test = new CleanupTest();
|
||||
test.close();
|
||||
assertTrue(test.m_class1.m_closed);
|
||||
assertTrue(test.m_class2.m_closed);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupOnlyClosesExplicitClassAndSkipWorks() {
|
||||
CleanupTest2 test = new CleanupTest2();
|
||||
test.close();
|
||||
assertFalse(test.m_class1.m_closed);
|
||||
assertFalse(test.m_class2.m_closed);
|
||||
assertFalse(test.m_class3.m_closed);
|
||||
assertTrue(test.m_class4.m_closed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CircularBufferTest {
|
||||
private final double[] m_values = {
|
||||
751.848, 766.366, 342.657, 234.252, 716.126, 132.344, 445.697, 22.727, 421.125, 799.913
|
||||
};
|
||||
private final double[] m_addFirstOut = {
|
||||
799.913, 421.125, 22.727, 445.697, 132.344, 716.126, 234.252, 342.657
|
||||
};
|
||||
private final double[] m_addLastOut = {
|
||||
342.657, 234.252, 716.126, 132.344, 445.697, 22.727, 421.125, 799.913
|
||||
};
|
||||
|
||||
@Test
|
||||
void addFirstTest() {
|
||||
var queue = new CircularBuffer<Double>(8);
|
||||
|
||||
for (double value : m_values) {
|
||||
queue.addFirst(value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_addFirstOut.length; i++) {
|
||||
assertEquals(m_addFirstOut[i], queue.get(i), 0.00005);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addLastTest() {
|
||||
var queue = new CircularBuffer<Double>(8);
|
||||
|
||||
for (double value : m_values) {
|
||||
queue.addLast(value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_addLastOut.length; i++) {
|
||||
assertEquals(m_addLastOut[i], queue.get(i), 0.00005);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pushPopTest() {
|
||||
var queue = new CircularBuffer<Double>(3);
|
||||
|
||||
// Insert three elements into the buffer
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
assertEquals(3.0, queue.get(2), 0.00005);
|
||||
|
||||
/*
|
||||
* The buffer is full now, so pushing subsequent elements will overwrite the
|
||||
* front-most elements.
|
||||
*/
|
||||
|
||||
queue.addLast(4.0); // Overwrite 1 with 4
|
||||
|
||||
// The buffer now contains 2, 3, and 4
|
||||
assertEquals(2.0, queue.get(0), 0.00005);
|
||||
assertEquals(3.0, queue.get(1), 0.00005);
|
||||
assertEquals(4.0, queue.get(2), 0.00005);
|
||||
|
||||
queue.addLast(5.0); // Overwrite 2 with 5
|
||||
|
||||
// The buffer now contains 3, 4, and 5
|
||||
assertEquals(3.0, queue.get(0), 0.00005);
|
||||
assertEquals(4.0, queue.get(1), 0.00005);
|
||||
assertEquals(5.0, queue.get(2), 0.00005);
|
||||
|
||||
assertEquals(5.0, queue.removeLast(), 0.00005); // 5 is removed
|
||||
|
||||
// The buffer now contains 3 and 4
|
||||
assertEquals(3.0, queue.get(0), 0.00005);
|
||||
assertEquals(4.0, queue.get(1), 0.00005);
|
||||
|
||||
assertEquals(3.0, queue.removeFirst(), 0.00005); // 3 is removed
|
||||
|
||||
// Leaving only one element with value == 4
|
||||
assertEquals(4.0, queue.get(0), 0.00005);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetTest() {
|
||||
var queue = new CircularBuffer<Double>(5);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
queue.addLast((double) i);
|
||||
}
|
||||
|
||||
queue.clear();
|
||||
|
||||
assertEquals(0, queue.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resizeTest() {
|
||||
var queue = new CircularBuffer<Double>(5);
|
||||
|
||||
/* Buffer contains {1, 2, 3, _, _}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {_, 1, 2, 3, _}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.removeFirst();
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {_, _, 1, 2, 3}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.removeFirst();
|
||||
queue.removeFirst();
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {3, _, _, 1, 2}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(3.0);
|
||||
queue.addFirst(2.0);
|
||||
queue.addFirst(1.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {2, 3, _, _, 1}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.addFirst(1.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
// Test addLast() after resize
|
||||
queue.addLast(3.0);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
assertEquals(3.0, queue.get(2), 0.00005);
|
||||
|
||||
// Test addFirst() after resize
|
||||
queue.addFirst(4.0);
|
||||
assertEquals(4.0, queue.get(0), 0.00005);
|
||||
assertEquals(1.0, queue.get(1), 0.00005);
|
||||
assertEquals(2.0, queue.get(2), 0.00005);
|
||||
assertEquals(3.0, queue.get(3), 0.00005);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DoubleCircularBufferTest {
|
||||
private final double[] m_values = {
|
||||
751.848, 766.366, 342.657, 234.252, 716.126, 132.344, 445.697, 22.727, 421.125, 799.913
|
||||
};
|
||||
private final double[] m_addFirstOut = {
|
||||
799.913, 421.125, 22.727, 445.697, 132.344, 716.126, 234.252, 342.657
|
||||
};
|
||||
private final double[] m_addLastOut = {
|
||||
342.657, 234.252, 716.126, 132.344, 445.697, 22.727, 421.125, 799.913
|
||||
};
|
||||
|
||||
@Test
|
||||
void addFirstTest() {
|
||||
var queue = new DoubleCircularBuffer(8);
|
||||
|
||||
for (double value : m_values) {
|
||||
queue.addFirst(value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_addFirstOut.length; i++) {
|
||||
assertEquals(m_addFirstOut[i], queue.get(i), 0.00005);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addLastTest() {
|
||||
var queue = new DoubleCircularBuffer(8);
|
||||
|
||||
for (double value : m_values) {
|
||||
queue.addLast(value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_addLastOut.length; i++) {
|
||||
assertEquals(m_addLastOut[i], queue.get(i), 0.00005);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void pushPopTest() {
|
||||
var queue = new DoubleCircularBuffer(3);
|
||||
|
||||
// Insert three elements into the buffer
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
assertEquals(3.0, queue.get(2), 0.00005);
|
||||
|
||||
/*
|
||||
* The buffer is full now, so pushing subsequent elements will overwrite the
|
||||
* front-most elements.
|
||||
*/
|
||||
|
||||
queue.addLast(4.0); // Overwrite 1 with 4
|
||||
|
||||
// The buffer now contains 2, 3, and 4
|
||||
assertEquals(2.0, queue.get(0), 0.00005);
|
||||
assertEquals(3.0, queue.get(1), 0.00005);
|
||||
assertEquals(4.0, queue.get(2), 0.00005);
|
||||
|
||||
queue.addLast(5.0); // Overwrite 2 with 5
|
||||
|
||||
// The buffer now contains 3, 4, and 5
|
||||
assertEquals(3.0, queue.get(0), 0.00005);
|
||||
assertEquals(4.0, queue.get(1), 0.00005);
|
||||
assertEquals(5.0, queue.get(2), 0.00005);
|
||||
|
||||
assertEquals(5.0, queue.removeLast(), 0.00005); // 5 is removed
|
||||
|
||||
// The buffer now contains 3 and 4
|
||||
assertEquals(3.0, queue.get(0), 0.00005);
|
||||
assertEquals(4.0, queue.get(1), 0.00005);
|
||||
|
||||
assertEquals(3.0, queue.removeFirst(), 0.00005); // 3 is removed
|
||||
|
||||
// Leaving only one element with value == 4
|
||||
assertEquals(4.0, queue.get(0), 0.00005);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resetTest() {
|
||||
var queue = new DoubleCircularBuffer(5);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
queue.addLast(i);
|
||||
}
|
||||
|
||||
queue.clear();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertEquals(0.0, queue.get(i), 0.00005);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void resizeTest() {
|
||||
var queue = new DoubleCircularBuffer(5);
|
||||
|
||||
/* Buffer contains {1, 2, 3, _, _}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {_, 1, 2, 3, _}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.removeFirst();
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {_, _, 1, 2, 3}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(0.0);
|
||||
queue.addLast(1.0);
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.removeFirst();
|
||||
queue.removeFirst();
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {3, _, _, 1, 2}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(3.0);
|
||||
queue.addFirst(2.0);
|
||||
queue.addFirst(1.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.clear();
|
||||
|
||||
/* Buffer contains {2, 3, _, _, 1}
|
||||
* ^ front
|
||||
*/
|
||||
queue.addLast(2.0);
|
||||
queue.addLast(3.0);
|
||||
queue.addFirst(1.0);
|
||||
|
||||
queue.resize(2);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
queue.resize(5);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
|
||||
// Test addLast() after resize
|
||||
queue.addLast(3.0);
|
||||
assertEquals(1.0, queue.get(0), 0.00005);
|
||||
assertEquals(2.0, queue.get(1), 0.00005);
|
||||
assertEquals(3.0, queue.get(2), 0.00005);
|
||||
|
||||
// Test addFirst() after resize
|
||||
queue.addFirst(4.0);
|
||||
assertEquals(4.0, queue.get(0), 0.00005);
|
||||
assertEquals(1.0, queue.get(1), 0.00005);
|
||||
assertEquals(2.0, queue.get(2), 0.00005);
|
||||
assertEquals(3.0, queue.get(3), 0.00005);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.struct;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
@SuppressWarnings("AvoidEscapedUnicodeCharacters")
|
||||
class DynamicStructTest {
|
||||
@SuppressWarnings("MemberName")
|
||||
private StructDescriptorDatabase db;
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
db = new StructDescriptorDatabase();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmpty() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", ""));
|
||||
assertEquals(desc.getName(), "test");
|
||||
assertEquals(desc.getSchema(), "");
|
||||
assertTrue(desc.getFields().isEmpty());
|
||||
assertTrue(desc.isValid());
|
||||
assertEquals(desc.getSize(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedStruct() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int32 a"));
|
||||
assertTrue(desc.isValid());
|
||||
var desc2 = assertDoesNotThrow(() -> db.add("test2", "test a"));
|
||||
assertTrue(desc2.isValid());
|
||||
assertEquals(desc2.getSize(), 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDelayedValid() {
|
||||
final var desc = assertDoesNotThrow(() -> db.add("test", "foo a"));
|
||||
assertFalse(desc.isValid());
|
||||
var desc2 = assertDoesNotThrow(() -> db.add("test2", "foo a; foo b;"));
|
||||
assertFalse(desc2.isValid());
|
||||
var desc3 = assertDoesNotThrow(() -> db.add("test3", "foo a[2]"));
|
||||
assertFalse(desc3.isValid());
|
||||
var desc4 = assertDoesNotThrow(() -> db.add("foo", "int32 a"));
|
||||
assertTrue(desc4.isValid());
|
||||
assertTrue(desc.isValid());
|
||||
assertEquals(desc.getSize(), 4);
|
||||
assertTrue(desc2.isValid());
|
||||
assertEquals(desc2.getSize(), 8);
|
||||
assertTrue(desc3.isValid());
|
||||
assertEquals(desc3.getSize(), 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReuseNestedStructDelayed() {
|
||||
var desc2 = assertDoesNotThrow(() -> db.add("test2", "test a;test b;"));
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int32 a; uint16 b; int16 c;"));
|
||||
assertTrue(desc.isValid());
|
||||
assertTrue(desc2.isValid());
|
||||
assertEquals(desc2.getSize(), 16);
|
||||
var fields = desc2.getFields();
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getName(), "a");
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getOffset(), 8);
|
||||
assertEquals(field.getName(), "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidBitfield() {
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "float a:1"),
|
||||
"field a: type float cannot be bitfield");
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "double a:1"),
|
||||
"field a: type double cannot be bitfield");
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "foo a:1"),
|
||||
"field a: type foo cannot be bitfield");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCircularStructReference() {
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "test a"),
|
||||
"field a: recursive struct reference");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedCircularStructRef() {
|
||||
assertDoesNotThrow(() -> db.add("test", "foo a"));
|
||||
assertDoesNotThrow(() -> db.add("foo", "bar a"));
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("bar", "test a"),
|
||||
"circular struct reference: bar <- foo <- test");
|
||||
|
||||
// ok
|
||||
var desc = assertDoesNotThrow(() -> db.add("baz", "bar a"));
|
||||
assertFalse(desc.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedCircularStructRef2() {
|
||||
assertDoesNotThrow(() -> db.add("test", "foo a"));
|
||||
assertDoesNotThrow(() -> db.add("bar", "test a"));
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("foo", "bar a"),
|
||||
"circular struct reference: foo <- test <- bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBasic() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int32 a:2; uint32 b:30"));
|
||||
assertEquals(desc.getSize(), 4);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 2);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x3);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 4);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 30);
|
||||
assertEquals(field.getBitShift(), 2);
|
||||
assertEquals(field.getBitMask(), 0x3fffffff);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldDiffType() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int32 a:2; int16 b:2"));
|
||||
assertEquals(desc.getSize(), 6);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 2);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x3);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 4);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 2);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x3);
|
||||
assertEquals(field.getOffset(), 4);
|
||||
assertEquals(field.getSize(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldOverflow() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int8 a:4; int8 b:5"));
|
||||
assertEquals(desc.getSize(), 2);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 4);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0xf);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 1);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 5);
|
||||
assertEquals(field.getBitMask(), 0x1f);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getOffset(), 1);
|
||||
assertEquals(field.getSize(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolBegin8() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "bool a:1; int8 b:5"));
|
||||
assertEquals(desc.getSize(), 1);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 1);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 5);
|
||||
assertEquals(field.getBitMask(), 0x1f);
|
||||
assertEquals(field.getBitShift(), 1);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolBegin16() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "bool a:1; int16 b:5"));
|
||||
assertEquals(desc.getSize(), 3);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 1);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 5);
|
||||
assertEquals(field.getBitMask(), 0x1f);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getOffset(), 1);
|
||||
assertEquals(field.getSize(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolMid() {
|
||||
var desc =
|
||||
assertDoesNotThrow(() -> db.add("test", "int16 a:2; bool b:1; bool c:1; uint16 d:5"));
|
||||
assertEquals(desc.getSize(), 2);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 4);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 2);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x3);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getBitShift(), 2);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
field = fields.get(2);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getBitShift(), 3);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
field = fields.get(3);
|
||||
assertEquals(field.getBitWidth(), 5);
|
||||
assertEquals(field.getBitMask(), 0x1f);
|
||||
assertEquals(field.getBitShift(), 4);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolEnd() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int16 a:15; bool b:1"));
|
||||
assertEquals(desc.getSize(), 2);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 15);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0x7fff);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getBitShift(), 15);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolEnd2() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "int16 a:16; bool b:1"));
|
||||
assertEquals(desc.getSize(), 3);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 2);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getBitWidth(), 16);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getBitMask(), 0xffff);
|
||||
assertEquals(field.getOffset(), 0);
|
||||
assertEquals(field.getSize(), 2);
|
||||
field = fields.get(1);
|
||||
assertEquals(field.getBitWidth(), 1);
|
||||
assertEquals(field.getBitMask(), 0x1);
|
||||
assertEquals(field.getBitShift(), 0);
|
||||
assertEquals(field.getOffset(), 2);
|
||||
assertEquals(field.getSize(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldBoolWrongSize() {
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "bool a:2"),
|
||||
"field a: bit width must be 1 for bool type");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldTooBig() {
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "int16 a:17"),
|
||||
"field a: bit width 17 exceeds type size");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDuplicateFieldName() {
|
||||
assertThrows(
|
||||
BadSchemaException.class,
|
||||
() -> db.add("test", "int16 a; int8 a"),
|
||||
"field a: duplicate field name");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> provideSimpleTestParams() {
|
||||
return Stream.of(
|
||||
Arguments.of("bool a", 1, StructFieldType.kBool, false, false, 8, 0xff, 0, 0),
|
||||
Arguments.of("char a", 1, StructFieldType.kChar, false, false, 8, 0xff, 0, 0),
|
||||
Arguments.of("int8 a", 1, StructFieldType.kInt8, true, false, 8, 0xff, -128, 127),
|
||||
Arguments.of("int16 a", 2, StructFieldType.kInt16, true, false, 16, 0xffff, -32768, 32767),
|
||||
Arguments.of(
|
||||
"int32 a",
|
||||
4,
|
||||
StructFieldType.kInt32,
|
||||
true,
|
||||
false,
|
||||
32,
|
||||
0xffffffffL,
|
||||
-2147483648,
|
||||
2147483647),
|
||||
Arguments.of(
|
||||
"int64 a",
|
||||
8,
|
||||
StructFieldType.kInt64,
|
||||
true,
|
||||
false,
|
||||
64,
|
||||
-1,
|
||||
-9223372036854775808L,
|
||||
9223372036854775807L),
|
||||
Arguments.of("uint8 a", 1, StructFieldType.kUint8, false, true, 8, 0xff, 0, 255),
|
||||
Arguments.of("uint16 a", 2, StructFieldType.kUint16, false, true, 16, 0xffff, 0, 65535),
|
||||
Arguments.of(
|
||||
"uint32 a", 4, StructFieldType.kUint32, false, true, 32, 0xffffffffL, 0, 4294967295L),
|
||||
Arguments.of("uint64 a", 8, StructFieldType.kUint64, false, true, 64, -1, 0, 0),
|
||||
Arguments.of("float a", 4, StructFieldType.kFloat, false, false, 32, 0xffffffffL, 0, 0),
|
||||
Arguments.of("float32 a", 4, StructFieldType.kFloat, false, false, 32, 0xffffffffL, 0, 0),
|
||||
Arguments.of("double a", 8, StructFieldType.kDouble, false, false, 64, -1, 0, 0),
|
||||
Arguments.of("float64 a", 8, StructFieldType.kDouble, false, false, 64, -1, 0, 0),
|
||||
Arguments.of("foo a", 0, StructFieldType.kStruct, false, false, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideSimpleTestParams")
|
||||
void testStandardCheck(
|
||||
String schema,
|
||||
int size,
|
||||
StructFieldType type,
|
||||
boolean isInt,
|
||||
boolean isUint,
|
||||
int bitWidth,
|
||||
long bitMask) {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", schema));
|
||||
assertEquals(desc.getName(), "test");
|
||||
assertEquals(desc.getSchema(), schema);
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 1);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getParent(), desc);
|
||||
assertEquals(field.getName(), "a");
|
||||
assertEquals(field.isInt(), isInt);
|
||||
assertEquals(field.isUint(), isUint);
|
||||
assertFalse(field.isArray());
|
||||
if (type != StructFieldType.kStruct) {
|
||||
assertTrue(desc.isValid());
|
||||
assertEquals(desc.getSize(), size);
|
||||
assertEquals(field.getSize(), size);
|
||||
assertEquals(field.getBitWidth(), bitWidth);
|
||||
assertEquals(field.getBitMask(), bitMask);
|
||||
} else {
|
||||
assertFalse(desc.isValid());
|
||||
assertNotNull(field.getStruct());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideSimpleTestParams")
|
||||
void testStandardArray(
|
||||
String schema,
|
||||
int size,
|
||||
StructFieldType type,
|
||||
boolean isInt,
|
||||
boolean isUint,
|
||||
int bitWidth,
|
||||
long bitMask) {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", schema + "[2]"));
|
||||
assertEquals(desc.getName(), "test");
|
||||
assertEquals(desc.getSchema(), schema + "[2]");
|
||||
var fields = desc.getFields();
|
||||
assertEquals(fields.size(), 1);
|
||||
var field = fields.get(0);
|
||||
assertEquals(field.getParent(), desc);
|
||||
assertEquals(field.getName(), "a");
|
||||
assertEquals(field.isInt(), isInt);
|
||||
assertEquals(field.isUint(), isUint);
|
||||
assertTrue(field.isArray());
|
||||
assertEquals(field.getArraySize(), 2);
|
||||
if (type != StructFieldType.kStruct) {
|
||||
assertTrue(desc.isValid());
|
||||
assertEquals(desc.getSize(), size * 2);
|
||||
} else {
|
||||
assertFalse(desc.isValid());
|
||||
assertNotNull(field.getStruct());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideSimpleTestParams")
|
||||
void testIntRoundTrip(
|
||||
String schema,
|
||||
int size,
|
||||
StructFieldType type,
|
||||
boolean isInt,
|
||||
boolean isUint,
|
||||
int bitWidth,
|
||||
long bitMask,
|
||||
long minVal,
|
||||
long maxVal) {
|
||||
if (type == StructFieldType.kStruct) {
|
||||
return;
|
||||
}
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", schema));
|
||||
assertTrue(desc.isValid());
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertNotNull(field);
|
||||
if ((isInt || isUint) && type != StructFieldType.kUint64) {
|
||||
// Java can't represent uint64 max
|
||||
dynamic.setIntField(field, minVal);
|
||||
assertEquals(minVal, dynamic.getIntField(field));
|
||||
dynamic.setIntField(field, maxVal);
|
||||
assertEquals(maxVal, dynamic.getIntField(field));
|
||||
} else if (type == StructFieldType.kBool) {
|
||||
dynamic.setBoolField(field, false);
|
||||
assertFalse(dynamic.getBoolField(field));
|
||||
dynamic.setBoolField(field, true);
|
||||
assertTrue(dynamic.getBoolField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringAllZeros() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[32]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertEquals("", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTrip() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[32]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertTrue(dynamic.setStringField(field, "abc"));
|
||||
assertEquals("abc", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripEmbeddedNull() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[32]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertTrue(dynamic.setStringField(field, "ab\0c"));
|
||||
assertEquals("ab\0c", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripStringTooLong() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[2]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "abc"));
|
||||
assertEquals("ab", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial2ByteUtf8() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[2]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\u0234"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTrip2ByteUtf8() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[3]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertTrue(dynamic.setStringField(field, "a\u0234"));
|
||||
assertEquals("a\u0234", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial3ByteUtf8FirstByte() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[2]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\u1234"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial3ByteUtf8SecondByte() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[3]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\u1234"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTrip3ByteUtf8() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[4]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertTrue(dynamic.setStringField(field, "a\u1234"));
|
||||
assertEquals("a\u1234", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial4ByteUtf8FirstByte() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[2]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\uD83D\uDC00"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial4ByteUtf8SecondByte() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[3]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\uD83D\uDC00"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTripPartial4ByteUtf8ThirdByte() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[4]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertFalse(dynamic.setStringField(field, "a\uD83D\uDC00"));
|
||||
assertEquals("a", dynamic.getStringField(field));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringRoundTrip4ByteUtf8() {
|
||||
var desc = assertDoesNotThrow(() -> db.add("test", "char a[5]"));
|
||||
var dynamic = DynamicStruct.allocate(desc);
|
||||
var field = desc.findFieldByName("a");
|
||||
assertTrue(dynamic.setStringField(field, "a\uD83D\uDC00"));
|
||||
assertEquals("a\uD83D\uDC00", dynamic.getStringField(field));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.struct;
|
||||
|
||||
import static edu.wpi.first.util.struct.StructGenerator.genEnum;
|
||||
import static edu.wpi.first.util.struct.StructGenerator.genRecord;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class StructGeneratorTest {
|
||||
public record CustomRecord(int int32, boolean bool, double float64, char character, short int16)
|
||||
implements StructSerializable {
|
||||
public static CustomRecord create() {
|
||||
return new CustomRecord(42, true, Math.PI, 'a', (short) 16);
|
||||
}
|
||||
|
||||
public static final Struct<CustomRecord> struct = genRecord(CustomRecord.class);
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object arg) {
|
||||
return arg == this
|
||||
|| arg instanceof CustomRecord other
|
||||
&& int32 == other.int32
|
||||
&& bool == other.bool
|
||||
&& float64 == other.float64
|
||||
&& character == other.character
|
||||
&& int16 == other.int16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Integer.hashCode(int32)
|
||||
+ Boolean.hashCode(bool)
|
||||
+ Double.hashCode(float64)
|
||||
+ Character.hashCode(character)
|
||||
+ Short.hashCode(int16);
|
||||
}
|
||||
}
|
||||
|
||||
public enum CustomEnum implements StructSerializable {
|
||||
A(8),
|
||||
B(16),
|
||||
C(32),
|
||||
D(64);
|
||||
|
||||
public final int value;
|
||||
|
||||
CustomEnum(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static final Struct<CustomEnum> struct = genEnum(CustomEnum.class);
|
||||
}
|
||||
|
||||
public enum AnimalEnum implements StructSerializable {
|
||||
Dog,
|
||||
Cat;
|
||||
|
||||
public static final Struct<AnimalEnum> struct = genEnum(AnimalEnum.class);
|
||||
}
|
||||
|
||||
public record HigherOrderRecord(
|
||||
CustomRecord procRecord, CustomEnum procEnum, AnimalEnum animal, long i64, byte uint8)
|
||||
implements StructSerializable {
|
||||
public static HigherOrderRecord create() {
|
||||
return new HigherOrderRecord(
|
||||
CustomRecord.create(), CustomEnum.A, AnimalEnum.Dog, 1234567890123456789L, (byte) 100);
|
||||
}
|
||||
|
||||
public static final Struct<HigherOrderRecord> struct = genRecord(HigherOrderRecord.class);
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object arg) {
|
||||
return arg == this
|
||||
|| arg instanceof HigherOrderRecord other
|
||||
&& procRecord.equals(other.procRecord)
|
||||
&& procEnum == other.procEnum
|
||||
&& i64 == other.i64
|
||||
&& uint8 == other.uint8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return procRecord.hashCode()
|
||||
+ procEnum.hashCode()
|
||||
+ Long.hashCode(i64)
|
||||
+ Byte.hashCode(uint8);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends StructSerializable> void testStructRoundTrip(S value) {
|
||||
Struct<S> struct = StructFetcher.fetchStruct((Class<S>) value.getClass()).get();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(struct.getSize());
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
struct.pack(buffer, value);
|
||||
buffer.rewind();
|
||||
|
||||
final S deser = struct.unpack(buffer);
|
||||
assertEquals(value, deser);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends StructSerializable> void testStructDoublePack(S value) {
|
||||
Struct<S> struct = StructFetcher.fetchStruct((Class<S>) value.getClass()).get();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(struct.getSize());
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
struct.pack(buffer, value);
|
||||
buffer.rewind();
|
||||
struct.pack(buffer, value);
|
||||
buffer.rewind();
|
||||
|
||||
final S deser = struct.unpack(buffer);
|
||||
assertEquals(value, deser);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends StructSerializable> void testStructDoubleUnpack(S value) {
|
||||
Struct<S> struct = StructFetcher.fetchStruct((Class<S>) value.getClass()).get();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(struct.getSize());
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
struct.pack(buffer, value);
|
||||
buffer.rewind();
|
||||
|
||||
final S deser = struct.unpack(buffer);
|
||||
assertEquals(value, deser);
|
||||
buffer.rewind();
|
||||
|
||||
final S deser2 = struct.unpack(buffer);
|
||||
assertEquals(value, deser2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomRecordRoundTrip() {
|
||||
testStructRoundTrip(CustomRecord.create());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomRecordDoublePack() {
|
||||
testStructDoublePack(CustomRecord.create());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomRecordDoubleUnpack() {
|
||||
testStructDoubleUnpack(CustomRecord.create());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEnumRoundTrip() {
|
||||
testStructRoundTrip(CustomEnum.A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEnumDoublePack() {
|
||||
testStructDoublePack(CustomEnum.A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomEnumDoubleUnpack() {
|
||||
testStructDoubleUnpack(CustomEnum.A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHigherOrderRecordRoundTrip() {
|
||||
testStructRoundTrip(HigherOrderRecord.create());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHigherOrderRecordDoublePack() {
|
||||
testStructDoublePack(HigherOrderRecord.create());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHigherOrderRecordDoubleUnpack() {
|
||||
testStructDoubleUnpack(HigherOrderRecord.create());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.struct.parser;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ParserTest {
|
||||
@Test
|
||||
void testEmpty() {
|
||||
Parser p = new Parser("");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertTrue(schema.declarations.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptySemicolon() {
|
||||
Parser p = new Parser(";");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertTrue(schema.declarations.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimple() {
|
||||
Parser p = new Parser("int32 a");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.arraySize, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSimpleTrailingSemi() {
|
||||
Parser p = new Parser("int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testArray() {
|
||||
Parser p = new Parser("int32 a[2]");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.arraySize, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testArrayTrailingSemi() {
|
||||
Parser p = new Parser("int32 a[2];");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfield() {
|
||||
Parser p = new Parser("int32 a:2");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.bitWidth, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBitfieldTrailingSemi() {
|
||||
Parser p = new Parser("int32 a:2;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnumKeyword() {
|
||||
Parser p = new Parser("enum {x=1} int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.enumValues.size(), 1);
|
||||
assertEquals(decl.enumValues.get("x"), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnumNoKeyword() {
|
||||
Parser p = new Parser("{x=1} int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.enumValues.size(), 1);
|
||||
assertEquals(decl.enumValues.get("x"), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnumNoValues() {
|
||||
Parser p = new Parser("{} int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertTrue(decl.enumValues.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnumMultipleValues() {
|
||||
Parser p = new Parser("{x=1,y=-2} int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.enumValues.size(), 2);
|
||||
assertEquals(decl.enumValues.get("x"), 1);
|
||||
assertEquals(decl.enumValues.get("y"), -2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnumTrailingComma() {
|
||||
Parser p = new Parser("{x=1,y=2,} int32 a;");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 1);
|
||||
var decl = schema.declarations.get(0);
|
||||
assertEquals(decl.typeString, "int32");
|
||||
assertEquals(decl.name, "a");
|
||||
assertEquals(decl.enumValues.size(), 2);
|
||||
assertEquals(decl.enumValues.get("x"), 1);
|
||||
assertEquals(decl.enumValues.get("y"), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMultipleNoTrailingSemi() {
|
||||
Parser p = new Parser("int32 a; int16 b");
|
||||
ParsedSchema schema = assertDoesNotThrow(p::parse);
|
||||
assertEquals(schema.declarations.size(), 2);
|
||||
assertEquals(schema.declarations.get(0).typeString, "int32");
|
||||
assertEquals(schema.declarations.get(0).name, "a");
|
||||
assertEquals(schema.declarations.get(1).typeString, "int16");
|
||||
assertEquals(schema.declarations.get(1).name, "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrBitfieldArray() {
|
||||
Parser p = new Parser("int32 a[1]:2");
|
||||
assertThrows(ParseException.class, p::parse, "10: expected ';', got ':'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrNoArrayValue() {
|
||||
Parser p = new Parser("int32 a[]");
|
||||
assertThrows(ParseException.class, p::parse, "8: expected integer, got ']'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrNoBitfieldValue() {
|
||||
Parser p = new Parser("int32 a:");
|
||||
assertThrows(ParseException.class, p::parse, "8: expected integer, got ''");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrNoNameArray() {
|
||||
Parser p = new Parser("int32 [2]");
|
||||
assertThrows(ParseException.class, p::parse, "6: expected identifier, got '['");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrNoNameBitField() {
|
||||
Parser p = new Parser("int32 :2");
|
||||
assertThrows(ParseException.class, p::parse, "6: expected identifier, got ':'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNegativeBitField() {
|
||||
Parser p = new Parser("int32 a:-1");
|
||||
assertThrows(
|
||||
ParseException.class, p::parse, "8: bitfield width '-1' is not a positive integer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNegativeArraySize() {
|
||||
Parser p = new Parser("int32 a[-1]");
|
||||
assertThrows(ParseException.class, p::parse, "8: array size '-1' is not a positive integer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZeroBitField() {
|
||||
Parser p = new Parser("int32 a:0");
|
||||
assertThrows(ParseException.class, p::parse, "8: bitfield width '0' is not a positive integer");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZeroArraySize() {
|
||||
Parser p = new Parser("int32 a[0]");
|
||||
assertThrows(ParseException.class, p::parse, "8: array size '0' is not a positive integer");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user