From 38df0643f6499a93c8c9d08a911b95908af91611 Mon Sep 17 00:00:00 2001 From: Jenn Nguyen Date: Fri, 29 Jul 2022 17:21:01 -0700 Subject: [PATCH 1/3] fixed topic echo test Signed-off-by: Jenn Nguyen --- src/plugins/topic_echo/CMakeLists.txt | 3 +- src/plugins/topic_echo/TopicEcho.cc | 1 - src/plugins/topic_echo/TopicEcho.qml | 5 + src/plugins/topic_echo/TopicEcho_TEST.cc | 267 +++++++++++++---------- 4 files changed, 158 insertions(+), 118 deletions(-) diff --git a/src/plugins/topic_echo/CMakeLists.txt b/src/plugins/topic_echo/CMakeLists.txt index 2073e501a..8460b96dd 100644 --- a/src/plugins/topic_echo/CMakeLists.txt +++ b/src/plugins/topic_echo/CMakeLists.txt @@ -4,6 +4,5 @@ ign_gui_add_plugin(TopicEcho QT_HEADERS TopicEcho.hh TEST_SOURCES - # TopicEcho_TEST.cc + TopicEcho_TEST.cc ) - diff --git a/src/plugins/topic_echo/TopicEcho.cc b/src/plugins/topic_echo/TopicEcho.cc index 629e2955c..a149a6f69 100644 --- a/src/plugins/topic_echo/TopicEcho.cc +++ b/src/plugins/topic_echo/TopicEcho.cc @@ -180,4 +180,3 @@ void TopicEcho::SetPaused(const bool &_paused) // Register this plugin IGNITION_ADD_PLUGIN(ignition::gui::plugins::TopicEcho, ignition::gui::Plugin) - diff --git a/src/plugins/topic_echo/TopicEcho.qml b/src/plugins/topic_echo/TopicEcho.qml index aef2cd3a5..ceef81322 100644 --- a/src/plugins/topic_echo/TopicEcho.qml +++ b/src/plugins/topic_echo/TopicEcho.qml @@ -40,12 +40,14 @@ Rectangle { TextField { id: topicField + objectName: "topicField" text: TopicEcho.topic selectByMouse: true } } Switch { + objectName: "echoSwitch" text: qsTr("Echo") onToggled: { TopicEcho.topic = topicField.text @@ -64,6 +66,7 @@ Rectangle { SpinBox { id: bufferField + objectName: "bufferField" value: 10 onValueChanged: { TopicEcho.OnBuffer(value) @@ -71,6 +74,7 @@ Rectangle { } CheckBox { + objectName: "pauseCheck" text: qsTr("Pause") checked: TopicEcho.paused onClicked: { @@ -90,6 +94,7 @@ Rectangle { ListView { id: listView + objectName: "listView" clip: true anchors.fill: parent diff --git a/src/plugins/topic_echo/TopicEcho_TEST.cc b/src/plugins/topic_echo/TopicEcho_TEST.cc index dd28ebd6c..8a37635ef 100644 --- a/src/plugins/topic_echo/TopicEcho_TEST.cc +++ b/src/plugins/topic_echo/TopicEcho_TEST.cc @@ -16,224 +16,261 @@ */ #include +#include -#include +#ifdef _MSC_VER +#pragma warning(push, 0) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include #include +#include -#include "ignition/gui/Iface.hh" -#include "ignition/gui/Plugin.hh" +#include "ignition/gui/Application.hh" #include "ignition/gui/MainWindow.hh" +#include "ignition/gui/Plugin.hh" +#include "test_config.h" // NOLINT(build/include) +#include "TopicEcho.hh" + +int g_argc = 1; +char* g_argv[] = +{ + reinterpret_cast(const_cast("./TopicEcho_TEST")), +}; using namespace ignition; using namespace gui; ///////////////////////////////////////////////// -TEST(TopicEchoTest, Load) +TEST(TopicEchoTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(Load)) { - EXPECT_TRUE(initApp()); + common::Console::SetVerbosity(4); + + Application app(g_argc, g_argv); + app.AddPluginPath(std::string(PROJECT_BINARY_PATH) + "/lib"); + + // Load plugin + EXPECT_TRUE(app.LoadPlugin("TopicEcho")); + + // Get main window + auto win = app.findChild(); + ASSERT_NE(win, nullptr); + + // Get plugin + auto plugins = win->findChildren(); + EXPECT_EQ(plugins.size(), 1); - EXPECT_TRUE(loadPlugin("TopicEcho")); + auto plugin = plugins[0]; + EXPECT_EQ(plugin->Title(), "Topic echo"); - EXPECT_TRUE(stop()); + // Cleanup + plugins.clear(); } ///////////////////////////////////////////////// -TEST(TopicEchoTest, Echo) +TEST(TopicEchoTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(Echo)) { - setVerbosity(4); - EXPECT_TRUE(initApp()); + common::Console::SetVerbosity(4); + + Application app(g_argc, g_argv); + app.AddPluginPath(std::string(PROJECT_BINARY_PATH) + "/lib"); // Load plugin - EXPECT_TRUE(loadPlugin("TopicEcho")); + EXPECT_TRUE(app.LoadPlugin("TopicEcho")); - // Create main window - EXPECT_TRUE(createMainWindow()); - auto win = mainWindow(); - EXPECT_TRUE(win != nullptr); + // Get main window + auto win = app.findChild(); + ASSERT_NE(win, nullptr); // Get plugin - auto plugins = win->findChildren(); + auto plugins = win->findChildren(); EXPECT_EQ(plugins.size(), 1); + auto plugin = plugins[0]; EXPECT_EQ(plugin->Title(), "Topic echo"); // Widgets - auto echoButton = plugin->findChild("echoButton"); - EXPECT_TRUE(echoButton != nullptr); - EXPECT_EQ(echoButton->text(), "Echo"); - - auto topicEdit = plugin->findChild("topicEdit"); - EXPECT_TRUE(topicEdit != nullptr); - EXPECT_EQ(topicEdit->text(), "/echo"); - - auto msgList = plugin->findChild("msgList"); - EXPECT_TRUE(msgList != nullptr); - EXPECT_EQ(msgList->count(), 0); - - auto bufferSpin = plugin->findChild("bufferSpin"); - EXPECT_TRUE(bufferSpin != nullptr); - EXPECT_EQ(bufferSpin->value(), 10); - - auto pauseCheck = plugin->findChild("pauseCheck"); - EXPECT_TRUE(pauseCheck != nullptr); - EXPECT_FALSE(pauseCheck->isChecked()); + auto echoSwitch = plugin->PluginItem()->findChild("echoSwitch"); + ASSERT_NE(echoSwitch, nullptr); + QVariant objProp = echoSwitch->property("text"); + EXPECT_TRUE(objProp.isValid()); + EXPECT_EQ(objProp.toString().toStdString(), "Echo"); + + auto msgList = plugin->PluginItem()->findChild("listView"); + ASSERT_NE(msgList, nullptr); + objProp = msgList->property("model"); + EXPECT_TRUE(objProp.isValid()); + auto msgStringList = objProp.value(); + ASSERT_NE(msgStringList, nullptr); + EXPECT_EQ(msgStringList->rowCount(), 0); + + auto bufferField = plugin->PluginItem()->findChild("bufferField"); + ASSERT_NE(bufferField, nullptr); + auto bufferProp = bufferField->property("value"); + EXPECT_TRUE(bufferProp.isValid()); + EXPECT_EQ(bufferProp.toInt(), 10); + + auto pauseCheck = plugin->PluginItem()->findChild("pauseCheck"); + ASSERT_NE(pauseCheck, nullptr); + auto pauseProp = pauseCheck->property("checked"); + EXPECT_TRUE(pauseProp.isValid()); + EXPECT_FALSE(pauseProp.toBool()); + EXPECT_FALSE(plugin->Paused()); // Start echoing - echoButton->click(); - EXPECT_EQ(echoButton->text(), "Stop echoing"); + plugin->OnEcho(true); // Publish string transport::Node node; auto pub = node.Advertise("/echo"); - - { - msgs::StringMsg msg; - msg.set_data("example string"); - pub.Publish(msg); - } + msgs::StringMsg msg; + msg.set_data("example string"); + pub.Publish(msg); int sleep = 0; int maxSleep = 30; - while (msgList->count() == 0 && sleep < maxSleep) + while(msgStringList->rowCount() == 0 && sleep < maxSleep) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } // Check message was echoed - ASSERT_EQ(msgList->count(), 1); - EXPECT_EQ(msgList->item(0)->text(), QString("data: \"example string\"\n")) - << msgList->item(0)->text().toStdString(); + ASSERT_EQ(msgStringList->rowCount(), 1); + EXPECT_EQ(msgStringList->stringList()[0].toStdString(), + "data: \"example string\"\n"); // Publish more than buffer size (messages numbered 0 to 14) - for (auto i = 0; i < bufferSpin->value() + 5; ++i) + for (auto i = 0; i < bufferProp.toInt() + 5; ++i) { - msgs::StringMsg msg; + msg.Clear(); msg.set_data("many messages: " + std::to_string(i)); pub.Publish(msg); } + QRegExp regExp13("*13"); + regExp13.setPatternSyntax(QRegExp::Wildcard); + QRegExp regExp14("*14"); + regExp14.setPatternSyntax(QRegExp::Wildcard); + // Wait until all 15 messages are received // To avoid flakiness due to messages coming out of order, we check for both // 13 and 14. There's a chance a lower number comes afterwards, but that's // just bad luck. sleep = 0; - while (msgList->findItems(QString::number(13), Qt::MatchContains).count() == 0 - && msgList->findItems(QString::number(14), Qt::MatchContains).count() == 0 + while (msgStringList->stringList().filter(regExp13).count() == 0 + && msgStringList->stringList().filter(regExp14).count() == 0 && sleep < maxSleep) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } EXPECT_LT(sleep, maxSleep); // Check we have only 10 messages listed - ASSERT_EQ(msgList->count(), 10); + ASSERT_EQ(msgStringList->rowCount(), 10); // We can't guarantee the order of messages // We expect that out of the 10 messages last, at least 6 belong to the [5-14] // range + QRegExp regExp; + regExp.setPatternSyntax(QRegExp::Wildcard); unsigned int count = 0; for (auto i = 5; i < 15; ++i) { - if (msgList->findItems(QString::number(i), Qt::MatchContains).count() > 0) - count++; + regExp.setPattern("*" + QString::number(i)); + if (msgStringList->stringList().filter(regExp).count() > 0) + ++count; } EXPECT_GE(count, 6u); // Increase buffer - bufferSpin->setValue(20); + bufferField->setProperty("value", 20); + bufferProp = bufferField->property("value"); + EXPECT_TRUE(bufferProp.isValid()); + EXPECT_EQ(bufferProp.toInt(), 20); // Publish another message and now it fits - { - msgs::StringMsg msg; - msg.set_data("new message"); - pub.Publish(msg); - } + msg.Clear(); + msg.set_data("new message"); + pub.Publish(msg); sleep = 0; - while (msgList->count() < 11 && sleep < maxSleep) + while (msgStringList->rowCount() < 11 && sleep < maxSleep) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } // We have 11 messages - ASSERT_EQ(msgList->count(), 11); + ASSERT_EQ(msgStringList->rowCount(), 11); // The last one is guaranteed to be the new message - EXPECT_EQ(msgList->item(10)->text(), QString("data: \"new message\"\n")) - << msgList->item(10)->text().toStdString(); + EXPECT_EQ(msgStringList->stringList().last().toStdString(), + "data: \"new message\"\n") + << msgStringList->stringList().last().toStdString(); // Pause - pauseCheck->click(); + plugin->SetPaused(true); + pauseProp = pauseCheck->property("checked"); + EXPECT_TRUE(pauseProp.toBool()); - // Publish another message and it is not received - { - msgs::StringMsg msg; - msg.set_data("dropped message"); - pub.Publish(msg); - } + // Publish another message and check it is not received + msg.Clear(); + msg.set_data("dropped message"); + pub.Publish(msg); sleep = 0; - while (msgList->count() < 11 && sleep < maxSleep) + while (sleep < maxSleep) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } - - ASSERT_EQ(msgList->count(), 11); - EXPECT_EQ(msgList->item(10)->text(), QString("data: \"new message\"\n")) - << msgList->item(10)->text().toStdString(); + ASSERT_EQ(msgStringList->rowCount(), 11); + EXPECT_EQ(msgStringList->stringList().last().toStdString(), + "data: \"new message\"\n") + << msgStringList->stringList().last().toStdString(); // Decrease buffer - bufferSpin->setValue(5); - - // Check we have less messages - ASSERT_EQ(msgList->count(), 5); + bufferField->setProperty("value", 5); + bufferProp = bufferField->property("value"); + EXPECT_TRUE(bufferProp.isValid()); + EXPECT_EQ(bufferProp.toInt(), 5); - // The last message is still the new one - EXPECT_EQ(msgList->item(4)->text(), QString("data: \"new message\"\n")) - << msgList->item(4)->text().toStdString(); - - // Stop echoing - echoButton->click(); - EXPECT_EQ(echoButton->text(), "Echo"); - ASSERT_EQ(msgList->count(), 0); + // Publish another message to decrease message list + plugin->SetPaused(false); + msg.Clear(); + msg.set_data("new message 2"); + pub.Publish(msg); sleep = 0; - while (msgList->count() == 0 && sleep < maxSleep) + while (msgStringList->rowCount() != 5 && sleep < maxSleep) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); QCoreApplication::processEvents(); - sleep++; + ++sleep; } - ASSERT_EQ(msgList->count(), 0); - - // Start echoing again - echoButton->click(); - EXPECT_EQ(echoButton->text(), "Stop echoing"); - - // Stop echoing by editing topic - topicEdit->setText("/another_topic"); - EXPECT_EQ(echoButton->text(), "Echo"); - ASSERT_EQ(msgList->count(), 0); + // Check we have less messages + ASSERT_EQ(msgStringList->rowCount(), 5); - sleep = 0; - while (msgList->count() == 0 && sleep < maxSleep) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - QCoreApplication::processEvents(); - sleep++; - } + // The last message is still the new one + EXPECT_EQ(msgStringList->stringList().last().toStdString(), + "data: \"new message 2\"\n") + << msgStringList->stringList().last().toStdString(); - ASSERT_EQ(msgList->count(), 0); + // Stop echoing + plugin->OnEcho(false); + EXPECT_EQ(msgStringList->rowCount(), 0); - EXPECT_TRUE(stop()); + // Cleanup + plugins.clear(); } - From 118d4d5943ecf97a498ae4facd9a7091fb6e417b Mon Sep 17 00:00:00 2001 From: Jenn Nguyen Date: Mon, 1 Aug 2022 09:55:00 -0700 Subject: [PATCH 2/3] use common::joinPaths Signed-off-by: Jenn Nguyen --- src/plugins/topic_echo/TopicEcho_TEST.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/topic_echo/TopicEcho_TEST.cc b/src/plugins/topic_echo/TopicEcho_TEST.cc index 8a37635ef..c3cbbc8ff 100644 --- a/src/plugins/topic_echo/TopicEcho_TEST.cc +++ b/src/plugins/topic_echo/TopicEcho_TEST.cc @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -51,7 +52,8 @@ TEST(TopicEchoTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(Load)) common::Console::SetVerbosity(4); Application app(g_argc, g_argv); - app.AddPluginPath(std::string(PROJECT_BINARY_PATH) + "/lib"); + app.AddPluginPath( + common::joinPaths(std::string(PROJECT_BINARY_PATH), "lib")); // Load plugin EXPECT_TRUE(app.LoadPlugin("TopicEcho")); @@ -77,7 +79,8 @@ TEST(TopicEchoTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(Echo)) common::Console::SetVerbosity(4); Application app(g_argc, g_argv); - app.AddPluginPath(std::string(PROJECT_BINARY_PATH) + "/lib"); + app.AddPluginPath( + common::joinPaths(std::string(PROJECT_BINARY_PATH), "lib")); // Load plugin EXPECT_TRUE(app.LoadPlugin("TopicEcho")); From a1cfeae08abfba90e67b7c6fe545988ca410cd6c Mon Sep 17 00:00:00 2001 From: Jenn Nguyen Date: Mon, 1 Aug 2022 10:05:45 -0700 Subject: [PATCH 3/3] windows fix Signed-off-by: Jenn Nguyen --- src/plugins/topic_echo/TopicEcho.hh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/plugins/topic_echo/TopicEcho.hh b/src/plugins/topic_echo/TopicEcho.hh index 9a53638c0..e9fd62252 100644 --- a/src/plugins/topic_echo/TopicEcho.hh +++ b/src/plugins/topic_echo/TopicEcho.hh @@ -26,6 +26,16 @@ #pragma warning(pop) #endif +#ifndef _WIN32 +# define TopicEcho_EXPORTS_API +#else +# if (defined(TopicEcho_EXPORTS)) +# define TopicEcho_EXPORTS_API __declspec(dllexport) +# else +# define TopicEcho_EXPORTS_API __declspec(dllimport) +# endif +#endif + #include #include "ignition/gui/Plugin.hh" @@ -42,7 +52,7 @@ namespace plugins /// /// ## Configuration /// This plugin doesn't accept any custom configuration. - class TopicEcho : public Plugin + class TopicEcho_EXPORTS_API TopicEcho : public Plugin { Q_OBJECT