Skip to content

Commit

Permalink
documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
CoolSpy3 committed Jun 8, 2024
1 parent 17d3747 commit bae4599
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 4 deletions.
101 changes: 101 additions & 0 deletions src/test/java/org/team199/wpiws/devices/DevicesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.function.Function;
import java.util.function.Supplier;

import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -205,6 +206,37 @@ public static Object[] getTestCases() {
c -> c::callback)};
}

/**
* Uses the given information to construct the necessary parameters to run a test.
*
* @param <SimType> the type of sim device being tested
* @param <VarType> the type of variable being tested
* @param <CallbackType> the type of callbacks being used in the test
* @param typeName the WS type name of the device being tested
* @param valueName the WS name of the value being tested
* @param constructor a function that can be used to construct an instance of the sim device
* type being tested
* @param callbackRegistrationFunction a function that can be used to register a callback on
* the variable being tested
* @param callbackCancellationFunction a function that can be used to cancel the callback
* returned by the {@code callbackRegistrationFunction}
* @param getterFunction a function that can be used to get the value of the value being
* tested
* @param setterFunction a function that can be used to set the value of the value being
* tested. If the value cannot be set through the API, {@code null} may be used,
* however, this will prevent the {@code testSimSetter} test from being run.
* @param defaultValue the default value of the variable being tested before it has been set
* by the robot or the simulator
* @param alternateValue an alternative example of this value type that can be used for
* testing
* @param serializer a function that can convert the example values into their
* JSON-object-serialized form
* @param callbackConverter a function that can be used to convert the generalized callbacks
* used by the tests into the specific callback types necessary for the supplied
* functions. In most cases, passing {@code c => c::callback} will allow Java to
* figure it out.
* @return an Object array containing the parameters necessary to run the test case
*/
private static <SimType, VarType, CallbackType> Object[] createTestCase(
String typeName, String valueName,
Function<String, SimType> constructor,
Expand All @@ -225,6 +257,37 @@ private static <SimType, VarType, CallbackType> Object[] createTestCase(
typeName, valueName};
}

/**
* A variation of
* {@link #createTestCase(String, String, BiFunction, Consumer, Supplier, Consumer, Object, Object, Function, Function)}
* that is targeted towards test cases that analyze a static variable (one which does not
* require a sim device instance)
*
* @param <VarType> the type of variable being tested
* @param <CallbackType> the type of callbacks being used in the test
* @param typeName the WS type name of the device being tested
* @param valueName the WS name of the value being tested
* @param callbackRegistrationFunction a function that can be used to register a callback on
* the variable being tested
* @param callbackCancellationFunction a function that can be used to cancel the callback
* returned by the {@code callbackRegistrationFunction}
* @param getterFunction a function that can be used to get the value of the value being
* tested
* @param setterFunction a function that can be used to set the value of the value being
* tested. If the value cannot be set through the API, {@code null} may be used,
* however, this will prevent the {@code testSimSetter} test from being run.
* @param defaultValue the default value of the variable being tested before it has been set
* by the robot or the simulator
* @param alternateValue an alternative example of this value type that can be used for
* testing
* @param serializer a function that can convert the example values into their
* JSON-object-serialized form
* @param callbackConverter a function that can be used to convert the generalized callbacks
* used by the tests into the specific callback types necessary for the supplied
* functions. In most cases, passing {@code c => c::callback} will allow Java to
* figure it out.
* @return an Object array containing the parameters necessary to run the test case
*/
private static <VarType, CallbackType> Object[] createTestCase(
String typeName, String valueName,
BiFunction<CallbackType, Boolean, CallbackType> callbackRegistrationFunction,
Expand Down Expand Up @@ -332,6 +395,16 @@ public void testCallback() {
}
}

/**
* Registers a callback for the variable being tested on a sim device instance
*
* @param sim the sim device to register the callback on
* @param callback the callback to register
* @param initialNotify whether the callback should be called immediately with the current
* value of the variable
* @return an object that can be passed to the {@link #callbackCancellationFunction} to
* cancel the callback
*/
private CallbackType registerCallback(SimType sim,
ObjectCallback<VarType> callback, boolean initialNotify) {
return callbackRegistrationFunction.apply(sim,
Expand Down Expand Up @@ -415,19 +488,40 @@ public void testSimSetter() {
}
}

/**
* A wrapper around {@link TestUtils#setValueFromRobot(String, String, String, Object)} that
* auto-fills some of the parameters from the members of this class.
*
* @param deviceName the name of the device to set the value on
* @param newValue the new value to set
*/
private void setValueFromRobot(String deviceName,
Pair<VarType, Object> newValue) {
TestUtils.setValueFromRobot(deviceName, typeName, valueName,
newValue.val2);
}

/**
* A variation of {@link Assert#assertEquals(Object, Object)} that uses
* {@link Objects#deepEquals(Object, Object)}
*
* @param expected the expected object
* @param actual the actual object
*/
private void assertDeepEquals(Object expected, Object actual) {
assertTrue(
"Expected: %s but got %s".formatted(formatObject(expected),
formatObject(actual)),
Objects.deepEquals(expected, actual));
}

/**
* A utility function used by {@link #assertDeepEquals} to stringify objects in the event of
* an error
*
* @param obj the object to stringify
* @return the stringified object
*/
private String formatObject(Object obj) {
if (obj == null)
return "<null>";
Expand Down Expand Up @@ -461,6 +555,13 @@ private String formatObject(Object obj) {
@Parameter(10)
public String valueName;

/**
* Creates a device name that will not conflict with devices from other tests. Devices names
* for the same test case will always be equal.
*
* @param testMethodName the name of the test being run
* @return a device name unique to the given test
*/
private String getDeviceName(String testMethodName) {
return "DevicesTest.DataTests.%s-%s".formatted(testMethodName,
testName);
Expand Down
38 changes: 38 additions & 0 deletions src/test/java/org/team199/wpiws/devices/SimDeviceSimTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ public void testValueCreatedCallback() {
}
}

/**
* Creates a device name that will not conflict with devices from other tests. Devices names for
* the same test case will always be equal.
*
* @param testMethodName the name of the test being run
* @return a device name unique to the given test
*/
private static String getDeviceName(String testMethodName) {
return "SimDeviceSimTest.%s".formatted(testMethodName);
}
Expand All @@ -238,6 +245,23 @@ public static Object[] testCases() {
.flatMap(Arrays::stream).toArray();
}

/**
* Uses the given information to construct the necessary parameters to run a test. This
* method creates three test cases that simulate values that are a a robot input, a robot
* output, and a bidirectional value, respectively.
*
* @param <VarType> the type of variable being tested
* @param valueName a name for the variable. This will be included in the test name. This is
* not a WS name.
* @param setterFunction the specific SimDeviceSim function to use to set the value of the
* variable
* @param defaultValue the "default" value of the variable. For SimDeviceSim, get() always
* returns `null` by default, but we still need a specific value for testing.
* Ensuring that this is "falsy" will prevent any conflicts.
* @param alternateValue an alternative example of this value type that can be used for
* testing
* @return an Object array containing the generated test cases
*/
private static <VarType> Object[][] createTestCase(String valueName,
TriConsumer<SimDeviceSim, String, VarType> setterFunction,
VarType defaultValue, VarType alternateValue) {
Expand Down Expand Up @@ -404,6 +428,13 @@ public void testSimSetter() {
}
}

/**
* A wrapper around {@link TestUtils#setValueFromRobot(String, String, String, Object)} that
* auto-fills some of the parameters from the members of this class.
*
* @param deviceName the name of the device to set the value on
* @param newValue the new value to set
*/
private void setValueFromRobot(String deviceName, VarType newValue) {
TestUtils.setValueFromRobot(deviceName, "SimDevice", wsValueName,
newValue);
Expand All @@ -423,6 +454,13 @@ private void setValueFromRobot(String deviceName, VarType newValue) {
public boolean bidirectional;
private String wsValueName;

/**
* Creates a device name that will not conflict with devices from other tests. Devices names
* for the same test case will always be equal.
*
* @param testMethodName the name of the test being run
* @return a device name unique to the given test
*/
private String getDeviceName(String testMethodName) {
return "SimDeviceSimTest.DataTests.%s-%s".formatted(testMethodName,
testName);
Expand Down
24 changes: 24 additions & 0 deletions src/test/java/org/team199/wpiws/interfaces/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,41 @@
import org.team199.wpiws.connection.MessageProcessor;
import org.team199.wpiws.connection.WSValue;

/**
* Provides various utility functions for other test classes
*/
public final class TestUtils {

/**
* Asserts that two arrays contain the same elements in any order. The arrays must not contain
* any duplicate elements.
*
* @param <T> the type of the arrays
* @param expected the expected array
* @param actual the actual array
*/
public static <T> void assertArrayEqualsIgnoringOrder(T[] expected,
T[] actual) {
assertTrue("Arrays may not contain duplicate elements",
Arrays.stream(expected).distinct().count() == expected.length);
assertTrue("Arrays may not contain duplicate elements",
Arrays.stream(actual).distinct().count() == actual.length);

String message = "Expected: %s but got %s"
.formatted(Arrays.toString(expected), Arrays.toString(actual));
assertEquals(message, expected.length, actual.length);
assertTrue(message,
Arrays.asList(actual).containsAll(Arrays.asList(expected)));
}

/**
* Simulates a WebSockets message from the robot setting a value on a device
*
* @param deviceName the name of the device to set the value on
* @param typeName the type of the device
* @param valueName the name of the value to set
* @param newValue the new value
*/
public static void setValueFromRobot(String deviceName, String typeName,
String valueName, Object newValue) {
MessageProcessor.process(deviceName, typeName,
Expand Down
18 changes: 16 additions & 2 deletions src/test/java/org/team199/wpiws/interfaces/TriConsumer.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
package org.team199.wpiws.interfaces;

/**
* Represents a function that accepts three arguments and does not return a value.
*
* @param <T> the type of the first argument
* @param <U> the type of the second argument
* @param <V> the type of the third argument
*/
@FunctionalInterface
public interface TriConsumer<T, U, R> {
public interface TriConsumer<T, U, V> {

public void accept(T t, U u, R r);
/**
* Calls the function
*
* @param t the first argument to pass to the function
* @param u the second argument to pass to the function
* @param v the third argument to pass to the function
*/
public void accept(T t, U u, V v);

}
21 changes: 19 additions & 2 deletions src/test/java/org/team199/wpiws/interfaces/TriFunction.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
package org.team199.wpiws.interfaces;

/**
* Represents a function that accepts three arguments and returns a value.
*
* @param <T> the type of the first argument
* @param <U> the type of the second argument
* @param <V> the type of the third argument
* @param <R> the type of the return value
*/
@FunctionalInterface
public interface TriFunction<T, U, R, S> {
public interface TriFunction<T, U, V, R> {

public S apply(T t, U u, R r);
/**
* Calls the function
*
* @param t the first argument to pass to the function
* @param u the second argument to pass to the function
* @param v the third argument to pass to the function
*
* @return the result of the function
*/
public R apply(T t, U u, V v);

}

0 comments on commit bae4599

Please sign in to comment.