mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-24 01:31:46 +00:00
Add fluent builders for more flexibly adding data to Shuffleboard (#1022)
This commit is contained in:
committed by
Peter Johnson
parent
ac7dfa5042
commit
175c6c1f01
@@ -0,0 +1,26 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import edu.wpi.first.wpilibj.SendableBase;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
|
||||
|
||||
/**
|
||||
* A mock sendable that marks itself as an actuator.
|
||||
*/
|
||||
public class MockActuatorSendable extends SendableBase {
|
||||
public MockActuatorSendable(String name) {
|
||||
super(false);
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setActuator(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
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 class ShuffleboardInstanceTest {
|
||||
private NetworkTableInstance m_ntInstance;
|
||||
private ShuffleboardInstance m_shuffleboardInstance;
|
||||
|
||||
@BeforeEach
|
||||
void setupInstance() {
|
||||
m_ntInstance = NetworkTableInstance.create();
|
||||
m_shuffleboardInstance = new ShuffleboardInstance(m_ntInstance);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDownInstance() {
|
||||
m_ntInstance.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPathFluent() {
|
||||
NetworkTableEntry entry = m_shuffleboardInstance.getTab("Tab Title")
|
||||
.getLayout("List", "List Layout")
|
||||
.add("Data", "string")
|
||||
.withWidget("Text View")
|
||||
.getEntry();
|
||||
|
||||
assertAll(
|
||||
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
|
||||
() -> assertEquals("/Shuffleboard/Tab Title/List Layout/Data", entry.getName(),
|
||||
"Entry path generated incorrectly"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedLayoutsFluent() {
|
||||
NetworkTableEntry entry = m_shuffleboardInstance.getTab("Tab")
|
||||
.getLayout("List", "First")
|
||||
.getLayout("List", "Second")
|
||||
.getLayout("List", "Third")
|
||||
.getLayout("List", "Fourth")
|
||||
.add("Value", "string")
|
||||
.getEntry();
|
||||
|
||||
assertAll(
|
||||
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
|
||||
() -> assertEquals("/Shuffleboard/Tab/First/Second/Third/Fourth/Value", entry.getName(),
|
||||
"Entry path generated incorrectly"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedLayoutsOop() {
|
||||
ShuffleboardTab tab = m_shuffleboardInstance.getTab("Tab");
|
||||
ShuffleboardLayout first = tab.getLayout("List", "First");
|
||||
ShuffleboardLayout second = first.getLayout("List", "Second");
|
||||
ShuffleboardLayout third = second.getLayout("List", "Third");
|
||||
ShuffleboardLayout fourth = third.getLayout("List", "Fourth");
|
||||
SimpleWidget widget = fourth.add("Value", "string");
|
||||
NetworkTableEntry entry = widget.getEntry();
|
||||
|
||||
assertAll(
|
||||
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
|
||||
() -> assertEquals("/Shuffleboard/Tab/First/Second/Third/Fourth/Value", entry.getName(),
|
||||
"Entry path generated incorrectly"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLayoutTypeIsSet() {
|
||||
String layoutType = "Type";
|
||||
m_shuffleboardInstance.getTab("Tab")
|
||||
.getLayout(layoutType, "Title");
|
||||
m_shuffleboardInstance.update();
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry(
|
||||
"/Shuffleboard/.metadata/Tab/Title/PreferredComponent");
|
||||
assertEquals(layoutType, entry.getString("Not Set"), "Layout type not set");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedActuatorWidgetsAreDisabled() {
|
||||
m_shuffleboardInstance.getTab("Tab")
|
||||
.getLayout("Layout", "Title")
|
||||
.add(new MockActuatorSendable("Actuator"));
|
||||
NetworkTableEntry controllableEntry =
|
||||
m_ntInstance.getEntry("/Shuffleboard/Tab/Title/Actuator/.controllable");
|
||||
|
||||
m_shuffleboardInstance.update();
|
||||
|
||||
// Note: we use the unsafe `getBoolean()` method because if the value is NOT a boolean, or if it
|
||||
// is not present, then something has clearly gone very, very wrong
|
||||
boolean controllable = controllableEntry.getValue().getBoolean();
|
||||
|
||||
// Sanity check
|
||||
assertTrue(controllable, "The nested actuator widget should be enabled by default");
|
||||
m_shuffleboardInstance.disableActuatorWidgets();
|
||||
controllable = controllableEntry.getValue().getBoolean();
|
||||
assertFalse(controllable, "The nested actuator widget should have been disabled");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
import edu.wpi.first.wpilibj.command.InstantCommand;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@SuppressWarnings({"PMD.TooManyMethods"})
|
||||
public class ShuffleboardTabTest {
|
||||
private NetworkTableInstance m_ntInstance;
|
||||
private ShuffleboardTab m_tab;
|
||||
private ShuffleboardInstance m_instance;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
m_ntInstance = NetworkTableInstance.create();
|
||||
m_instance = new ShuffleboardInstance(m_ntInstance);
|
||||
m_tab = m_instance.getTab("Tab");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
m_ntInstance.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddDouble() {
|
||||
NetworkTableEntry entry = m_tab.add("Double", 1.0).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/Double", entry.getName()),
|
||||
() -> assertEquals(1.0, entry.getValue().getDouble()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddInteger() {
|
||||
NetworkTableEntry entry = m_tab.add("Int", 1).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/Int", entry.getName()),
|
||||
() -> assertEquals(1.0, entry.getValue().getDouble()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddLong() {
|
||||
NetworkTableEntry entry = m_tab.add("Long", 1L).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/Long", entry.getName()),
|
||||
() -> assertEquals(1.0, entry.getValue().getDouble()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testAddBoolean() {
|
||||
NetworkTableEntry entry = m_tab.add("Bool", false).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/Bool", entry.getName()),
|
||||
() -> assertFalse(entry.getValue().getBoolean()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddString() {
|
||||
NetworkTableEntry entry = m_tab.add("String", "foobar").getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/String", entry.getName()),
|
||||
() -> assertEquals("foobar", entry.getValue().getString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddNamedSendableWithProperties() {
|
||||
Sendable sendable = new InstantCommand("Command");
|
||||
String widgetType = "Command Widget";
|
||||
m_tab.add(sendable)
|
||||
.withWidget(widgetType)
|
||||
.withProperties(mapOf("foo", 1234, "bar", "baz"));
|
||||
|
||||
m_instance.update();
|
||||
String meta = "/Shuffleboard/.metadata/Tab/Command";
|
||||
|
||||
assertAll(
|
||||
() -> assertEquals(1234,
|
||||
m_ntInstance.getEntry(meta + "/Properties/foo").getDouble(-1),
|
||||
"Property 'foo' not set correctly"),
|
||||
() -> assertEquals("baz",
|
||||
m_ntInstance.getEntry(meta + "/Properties/bar").getString(null),
|
||||
"Property 'bar' not set correctly"),
|
||||
() -> assertEquals(widgetType,
|
||||
m_ntInstance.getEntry(meta + "/PreferredComponent").getString(null),
|
||||
"Preferred component not set correctly"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddNumberArray() {
|
||||
NetworkTableEntry entry = m_tab.add("DoubleArray", new double[]{1, 2, 3}).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/DoubleArray", entry.getName()),
|
||||
() -> assertArrayEquals(new double[]{1, 2, 3}, entry.getValue().getDoubleArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddBooleanArray() {
|
||||
NetworkTableEntry entry = m_tab.add("BoolArray", new boolean[]{true, false}).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/BoolArray", entry.getName()),
|
||||
() -> assertArrayEquals(new boolean[]{true, false}, entry.getValue().getBooleanArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddStringArray() {
|
||||
NetworkTableEntry entry = m_tab.add("StringArray", new String[]{"foo", "bar"}).getEntry();
|
||||
assertAll(
|
||||
() -> assertEquals("/Shuffleboard/Tab/StringArray", entry.getName()),
|
||||
() -> assertArrayEquals(new String[]{"foo", "bar"}, entry.getValue().getStringArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTitleDuplicates() {
|
||||
m_tab.add("foo", "bar");
|
||||
assertThrows(IllegalArgumentException.class, () -> m_tab.add("foo", "baz"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub for Java 9 {@code Map.of()}.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "PMD"})
|
||||
private static <K, V> Map<K, V> mapOf(Object... entries) {
|
||||
Map<K, V> map = new HashMap<>();
|
||||
for (int i = 0; i < entries.length; i += 2) {
|
||||
map.put((K) entries[i], (V) entries[i + 1]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import edu.wpi.first.wpilibj.UtilityClassTest;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
public class ShuffleboardTest extends UtilityClassTest {
|
||||
public ShuffleboardTest() {
|
||||
super(Shuffleboard.class);
|
||||
}
|
||||
|
||||
// Most relevant tests are in ShuffleboardTabTest
|
||||
|
||||
@Test
|
||||
void testTabObjectsCached() {
|
||||
ShuffleboardTab tab1 = Shuffleboard.getTab("testTabObjectsCached");
|
||||
ShuffleboardTab tab2 = Shuffleboard.getTab("testTabObjectsCached");
|
||||
assertSame(tab1, tab2, "Tab objects were not cached");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user