mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-03 03:01:44 +00:00
Fix shuffleboard C++ tests, and run them on desktop (#1351)
This commit is contained in:
committed by
Peter Johnson
parent
7b471d8c62
commit
fd82153456
@@ -60,8 +60,8 @@ SimpleWidget& ShuffleboardContainer::Add(
|
||||
|
||||
auto widget = std::make_unique<SimpleWidget>(*this, title);
|
||||
auto ptr = widget.get();
|
||||
widget->GetEntry().SetDefaultValue(defaultValue);
|
||||
m_components.emplace_back(std::move(widget));
|
||||
ptr->GetEntry().SetDefaultValue(defaultValue);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,11 @@ SimpleWidget& ShuffleboardContainer::Add(const wpi::Twine& title,
|
||||
return Add(title, nt::Value::MakeString(defaultValue));
|
||||
}
|
||||
|
||||
SimpleWidget& ShuffleboardContainer::Add(const wpi::Twine& title,
|
||||
const char* defaultValue) {
|
||||
return Add(title, nt::Value::MakeString(defaultValue));
|
||||
}
|
||||
|
||||
SimpleWidget& ShuffleboardContainer::Add(const wpi::Twine& title,
|
||||
wpi::ArrayRef<bool> defaultValue) {
|
||||
return Add(title, nt::Value::MakeBooleanArray(defaultValue));
|
||||
|
||||
@@ -12,7 +12,7 @@ using namespace frc;
|
||||
ShuffleboardLayout::ShuffleboardLayout(ShuffleboardContainer& parent,
|
||||
const wpi::Twine& name,
|
||||
const wpi::Twine& type)
|
||||
: ShuffleboardValue(name),
|
||||
: ShuffleboardValue(type),
|
||||
ShuffleboardComponent(parent, type, name),
|
||||
ShuffleboardContainer(name) {
|
||||
m_isLayout = true;
|
||||
|
||||
@@ -15,12 +15,11 @@ using namespace frc;
|
||||
|
||||
SimpleWidget::SimpleWidget(ShuffleboardContainer& parent,
|
||||
const wpi::Twine& title)
|
||||
: ShuffleboardValue(title), ShuffleboardWidget(parent, title) {}
|
||||
: ShuffleboardValue(title), ShuffleboardWidget(parent, title), m_entry() {}
|
||||
|
||||
nt::NetworkTableEntry SimpleWidget::GetEntry() {
|
||||
if (!m_entryInitialized) {
|
||||
if (!m_entry) {
|
||||
ForceGenerate();
|
||||
m_entryInitialized = true;
|
||||
}
|
||||
return m_entry;
|
||||
}
|
||||
@@ -28,9 +27,8 @@ nt::NetworkTableEntry SimpleWidget::GetEntry() {
|
||||
void SimpleWidget::BuildInto(std::shared_ptr<nt::NetworkTable> parentTable,
|
||||
std::shared_ptr<nt::NetworkTable> metaTable) {
|
||||
BuildMetadata(metaTable);
|
||||
if (!m_entryInitialized) {
|
||||
if (!m_entry) {
|
||||
m_entry = parentTable->GetEntry(GetTitle());
|
||||
m_entryInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class ShuffleboardComponentBase : public virtual ShuffleboardValue {
|
||||
|
||||
protected:
|
||||
wpi::StringMap<std::shared_ptr<nt::Value>> m_properties;
|
||||
bool m_metadataDirty = false;
|
||||
bool m_metadataDirty = true;
|
||||
int m_column = -1;
|
||||
int m_row = -1;
|
||||
int m_width = -1;
|
||||
|
||||
@@ -139,6 +139,18 @@ class ShuffleboardContainer : public virtual ShuffleboardValue {
|
||||
*/
|
||||
SimpleWidget& Add(const wpi::Twine& title, const wpi::Twine& defaultValue);
|
||||
|
||||
/**
|
||||
* Adds a widget to this container to display the given data.
|
||||
*
|
||||
* @param title the title of the widget
|
||||
* @param defaultValue the default value of the widget
|
||||
* @return a widget to display the sendable data
|
||||
* @throws IllegalArgumentException if a widget already exists in this
|
||||
* container with the given title
|
||||
* @see #addPersistent(String, Object) add(String title, Object defaultValue)
|
||||
*/
|
||||
SimpleWidget& Add(const wpi::Twine& title, const char* defaultValue);
|
||||
|
||||
/**
|
||||
* Adds a widget to this container to display the given data.
|
||||
*
|
||||
|
||||
@@ -37,7 +37,6 @@ class SimpleWidget final : public ShuffleboardWidget<SimpleWidget> {
|
||||
|
||||
private:
|
||||
nt::NetworkTableEntry m_entry;
|
||||
bool m_entryInitialized = false;
|
||||
|
||||
void ForceGenerate();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "shuffleboard/MockActuatorSendable.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
MockActuatorSendable::MockActuatorSendable(wpi::StringRef name)
|
||||
: SendableBase(false) {
|
||||
SetName(name);
|
||||
}
|
||||
|
||||
void MockActuatorSendable::InitSendable(SendableBuilder& builder) {
|
||||
builder.SetActuator(true);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "frc/shuffleboard/ShuffleboardInstance.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <networktables/NetworkTableEntry.h>
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
|
||||
#include "frc/shuffleboard/ShuffleboardInstance.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "shuffleboard/MockActuatorSendable.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
class ShuffleboardInstanceTest : public testing::Test {
|
||||
void SetUp() override {
|
||||
m_ntInstance = nt::NetworkTableInstance::Create();
|
||||
m_shuffleboardInstance =
|
||||
std::make_unique<detail::ShuffleboardInstance>(m_ntInstance);
|
||||
}
|
||||
|
||||
protected:
|
||||
nt::NetworkTableInstance m_ntInstance;
|
||||
std::unique_ptr<detail::ShuffleboardInstance> m_shuffleboardInstance;
|
||||
};
|
||||
|
||||
TEST_F(ShuffleboardInstanceTest, PathFluent) {
|
||||
auto entry = m_shuffleboardInstance->GetTab("Tab Title")
|
||||
.GetLayout("List", "List Layout")
|
||||
.Add("Data", "string")
|
||||
.WithWidget("Text View")
|
||||
.GetEntry();
|
||||
|
||||
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
|
||||
EXPECT_EQ("/Shuffleboard/Tab Title/List Layout/Data", entry.GetName())
|
||||
<< "Entry path generated incorrectly";
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardInstanceTest, NestedLayoutsFluent) {
|
||||
auto entry = m_shuffleboardInstance->GetTab("Tab")
|
||||
.GetLayout("List", "First")
|
||||
.GetLayout("List", "Second")
|
||||
.GetLayout("List", "Third")
|
||||
.GetLayout("List", "Fourth")
|
||||
.Add("Value", "string")
|
||||
.GetEntry();
|
||||
|
||||
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
|
||||
EXPECT_EQ("/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
|
||||
entry.GetName())
|
||||
<< "Entry path generated incorrectly";
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardInstanceTest, NestedLayoutsOop) {
|
||||
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");
|
||||
auto entry = widget.GetEntry();
|
||||
|
||||
EXPECT_EQ("string", entry.GetString("")) << "Wrong entry value";
|
||||
EXPECT_EQ("/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
|
||||
entry.GetName())
|
||||
<< "Entry path generated incorrectly";
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardInstanceTest, LayoutTypeIsSet) {
|
||||
std::string layoutType = "Type";
|
||||
m_shuffleboardInstance->GetTab("Tab").GetLayout(layoutType, "Title");
|
||||
m_shuffleboardInstance->Update();
|
||||
nt::NetworkTableEntry entry = m_ntInstance.GetEntry(
|
||||
"/Shuffleboard/.metadata/Tab/Title/PreferredComponent");
|
||||
EXPECT_EQ(layoutType, entry.GetString("Not Set")) << "Layout type not set";
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardInstanceTest, NestedActuatoWidgetsAreDisabled) {
|
||||
MockActuatorSendable sendable("Actuator");
|
||||
m_shuffleboardInstance->GetTab("Tab")
|
||||
.GetLayout("Layout", "Title")
|
||||
.Add(sendable);
|
||||
auto 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
|
||||
bool controllable = controllableEntry.GetValue()->GetBoolean();
|
||||
// Sanity check
|
||||
EXPECT_TRUE(controllable)
|
||||
<< "The nested actuator widget should be enabled by default";
|
||||
m_shuffleboardInstance->DisableActuatorWidgets();
|
||||
controllable = controllableEntry.GetValue()->GetBoolean();
|
||||
EXPECT_FALSE(controllable)
|
||||
<< "The nested actuator widget should have been disabled";
|
||||
}
|
||||
115
wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardTabTest.cpp
Normal file
115
wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardTabTest.cpp
Normal file
@@ -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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <networktables/NetworkTableEntry.h>
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
|
||||
#include "frc/commands/InstantCommand.h"
|
||||
#include "frc/shuffleboard/ShuffleboardInstance.h"
|
||||
#include "frc/shuffleboard/ShuffleboardTab.h"
|
||||
#include "frc/smartdashboard/Sendable.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
class ShuffleboardTabTest : public testing::Test {
|
||||
void SetUp() override {
|
||||
m_ntInstance = nt::NetworkTableInstance::Create();
|
||||
m_instance = std::make_unique<detail::ShuffleboardInstance>(m_ntInstance);
|
||||
m_tab = &(m_instance->GetTab("Tab"));
|
||||
}
|
||||
|
||||
protected:
|
||||
nt::NetworkTableInstance m_ntInstance;
|
||||
ShuffleboardTab* m_tab;
|
||||
std::unique_ptr<detail::ShuffleboardInstance> m_instance;
|
||||
};
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddDouble) {
|
||||
auto entry = m_tab->Add("Double", 1.0).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/Double", entry.GetName());
|
||||
EXPECT_FLOAT_EQ(1.0, entry.GetValue()->GetDouble());
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddInteger) {
|
||||
auto entry = m_tab->Add("Int", 1).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/Int", entry.GetName());
|
||||
EXPECT_FLOAT_EQ(1.0, entry.GetValue()->GetDouble());
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddBoolean) {
|
||||
auto entry = m_tab->Add("Bool", false).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/Bool", entry.GetName());
|
||||
EXPECT_FALSE(entry.GetValue()->GetBoolean());
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddString) {
|
||||
auto entry = m_tab->Add("String", "foobar").GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/String", entry.GetName());
|
||||
EXPECT_EQ("foobar", entry.GetValue()->GetString());
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddNamedSendableWithProperties) {
|
||||
InstantCommand sendable("Command");
|
||||
std::string widgetType = "Command Widget";
|
||||
wpi::StringMap<std::shared_ptr<nt::Value>> map;
|
||||
map.try_emplace("foo", nt::Value::MakeDouble(1234));
|
||||
map.try_emplace("bar", nt::Value::MakeString("baz"));
|
||||
m_tab->Add(sendable).WithWidget(widgetType).WithProperties(map);
|
||||
|
||||
m_instance->Update();
|
||||
std::string meta = "/Shuffleboard/.metadata/Tab/Command";
|
||||
|
||||
EXPECT_EQ(1234, m_ntInstance.GetEntry(meta + "/Properties/foo").GetDouble(-1))
|
||||
<< "Property 'foo' not set correctly";
|
||||
EXPECT_EQ("baz",
|
||||
m_ntInstance.GetEntry(meta + "/Properties/bar").GetString(""))
|
||||
<< "Property 'bar' not set correctly";
|
||||
EXPECT_EQ(widgetType,
|
||||
m_ntInstance.GetEntry(meta + "/PreferredComponent").GetString(""))
|
||||
<< "Preferred component not set correctly";
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddNumberArray) {
|
||||
std::array<double, 3> expect = {{1.0, 2.0, 3.0}};
|
||||
auto entry = m_tab->Add("DoubleArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/DoubleArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetDoubleArray();
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_FLOAT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddBooleanArray) {
|
||||
std::array<bool, 2> expect = {{true, false}};
|
||||
auto entry = m_tab->Add("BoolArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/BoolArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetBooleanArray();
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddStringArray) {
|
||||
std::array<std::string, 2> expect = {{"foo", "bar"}};
|
||||
auto entry = m_tab->Add("StringArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/StringArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetStringArray();
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "frc/shuffleboard/Shuffleboard.h"
|
||||
#include "frc/shuffleboard/ShuffleboardTab.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
class ShuffleboardTest : public testing::Test {};
|
||||
|
||||
TEST_F(ShuffleboardTest, TabObjectsCached) {
|
||||
ShuffleboardTab& tab1 = Shuffleboard::GetTab("testTabObjectsCached");
|
||||
ShuffleboardTab& tab2 = Shuffleboard::GetTab("testTabObjectsCached");
|
||||
EXPECT_EQ(&tab1, &tab2) << "Tab objects were not cached";
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wpi/StringRef.h>
|
||||
|
||||
#include "frc/smartdashboard/SendableBase.h"
|
||||
#include "frc/smartdashboard/SendableBuilder.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
* A mock sendable that marks itself as an actuator.
|
||||
*/
|
||||
class MockActuatorSendable : public SendableBase {
|
||||
public:
|
||||
explicit MockActuatorSendable(wpi::StringRef name);
|
||||
|
||||
void InitSendable(SendableBuilder& builder) override;
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
@@ -79,37 +79,37 @@ TEST_F(ShuffleboardTabTest, AddNamedSendableWithProperties) {
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddNumberArray) {
|
||||
std::array<double, 3> expect = {1.0, 2.0, 3.0};
|
||||
std::array<double, 3> expect = {{1.0, 2.0, 3.0}};
|
||||
auto entry = m_tab->Add("DoubleArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/DoubleArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetDoubleArray();
|
||||
EXPECT_EQ(sizeof(expect), sizeof(actual));
|
||||
for (size_t i = 0; i < sizeof(expect); i++) {
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_FLOAT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddBooleanArray) {
|
||||
std::array<bool, 2> expect = {true, false};
|
||||
std::array<bool, 2> expect = {{true, false}};
|
||||
auto entry = m_tab->Add("BoolArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/BoolArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetBooleanArray();
|
||||
EXPECT_EQ(sizeof(expect), sizeof(actual));
|
||||
for (size_t i = 0; i < sizeof(expect); i++) {
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ShuffleboardTabTest, AddStringArray) {
|
||||
std::array<std::string, 2> expect = {"foo", "bar"};
|
||||
std::array<std::string, 2> expect = {{"foo", "bar"}};
|
||||
auto entry = m_tab->Add("StringArray", expect).GetEntry();
|
||||
EXPECT_EQ("/Shuffleboard/Tab/StringArray", entry.GetName());
|
||||
|
||||
auto actual = entry.GetValue()->GetStringArray();
|
||||
EXPECT_EQ(sizeof(expect), sizeof(actual));
|
||||
for (size_t i = 0; i < sizeof(expect); i++) {
|
||||
EXPECT_EQ(expect.size(), actual.size());
|
||||
for (size_t i = 0; i < expect.size(); i++) {
|
||||
EXPECT_EQ(expect[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user