From c93aab88c794aadf6b19e4b8754505ca88284f6d Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Wed, 3 Jan 2024 14:45:25 -0600 Subject: [PATCH] Support standalone executable in gz-msgs11 (#357) Signed-off-by: Michael Carroll --- .github/ci/packages.apt | 1 + CMakeLists.txt | 5 +- core/CMakeLists.txt | 15 +- core/cmd/CMakeLists.txt | 37 +++++ core/cmd/cmdmsgs.rb.in | 49 +++++++ core/{src => }/cmd/msgs.bash_completion.sh | 3 +- core/cmd/msgs_main.cc | 134 +++++++++++++++++ core/include/gz/msgs/gz.hh | 35 ----- core/src/cmd/CMakeLists.txt | 58 -------- core/src/cmd/cmdmsgs.rb.in | 161 --------------------- core/src/gz.cc | 85 ----------- test/integration/CMakeLists.txt | 10 +- test/integration/Factory_TEST.cc | 8 + test/integration/gz_TEST.cc | 114 ++++++++------- 14 files changed, 301 insertions(+), 414 deletions(-) create mode 100644 core/cmd/CMakeLists.txt create mode 100644 core/cmd/cmdmsgs.rb.in rename core/{src => }/cmd/msgs.bash_completion.sh (97%) create mode 100644 core/cmd/msgs_main.cc delete mode 100644 core/include/gz/msgs/gz.hh delete mode 100644 core/src/cmd/CMakeLists.txt delete mode 100644 core/src/cmd/cmdmsgs.rb.in delete mode 100644 core/src/gz.cc diff --git a/.github/ci/packages.apt b/.github/ci/packages.apt index 83df8470..4dbc2d38 100644 --- a/.github/ci/packages.apt +++ b/.github/ci/packages.apt @@ -1,6 +1,7 @@ libgz-cmake4-dev libgz-math8-dev libgz-tools2-dev +libgz-utils3-cli-dev libprotobuf-dev libprotoc-dev libtinyxml2-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index f3d71a89..a4ec6da4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ gz_find_package(GzProtobuf #-------------------------------------- # Find gz-utils -gz_find_package(gz-utils3 REQUIRED) +gz_find_package(gz-utils3 REQUIRED COMPONENTS cli) set(GZ_UTILS_VER ${gz-utils3_VERSION_MAJOR}) #-------------------------------------- @@ -96,7 +96,7 @@ set(GZ_TOOLS_VER 1) #-------------------------------------- # Find Tinyxml2 -gz_find_package(TINYXML2 REQUIRED PRIVATE PRETTY tinyxml2) +gz_find_package(TINYXML2 REQUIRED PRETTY tinyxml2) #-------------------------------------- # Find DL if doing relocatable installation @@ -172,7 +172,6 @@ install( configure_file(${CMAKE_SOURCE_DIR}/api.md.in ${CMAKE_BINARY_DIR}/api.md) configure_file(${CMAKE_SOURCE_DIR}/tutorials.md.in ${CMAKE_BINARY_DIR}/tutorials.md) - gz_create_docs( API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 2bbe9114..75ae6e56 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -87,7 +87,6 @@ install(FILES ${msgs_python} DESTINATION ${GZ_PYTHON_INSTALL_PATH}/gz/msgs${PROJ gz_get_libsources_and_unittests(sources gtest_sources) gz_create_core_library(SOURCES - src/gz.cc src/Factory.cc src/MessageFactory.cc src/DynamicFactory.cc @@ -121,17 +120,5 @@ target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} target_include_directories(${PROJECT_LIBRARY_TARGET_NAME} SYSTEM PUBLIC $) -################################################## -# Build unit tests -# Build the unit tests. -gz_build_tests(TYPE UNIT - SOURCES - ${gtest_sources} - LIB_DEPS - TINYXML2::TINYXML2 -) - add_subdirectory(include/gz/msgs) -if(NOT WIN32) - add_subdirectory(src/cmd) -endif() +add_subdirectory(cmd) diff --git a/core/cmd/CMakeLists.txt b/core/cmd/CMakeLists.txt new file mode 100644 index 00000000..6e1230e1 --- /dev/null +++ b/core/cmd/CMakeLists.txt @@ -0,0 +1,37 @@ +set(msgs_executable gz-msgs) +add_executable(${msgs_executable} msgs_main.cc) +target_link_libraries(${msgs_executable} + ${PROJECT_LIBRARY_TARGET_NAME} + gz-utils${GZ_UTILS_VER}::cli +) + +set(EXE_INSTALL_DIR ${CMAKE_INSTALL_LIBEXECDIR}/gz/${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}/) +install(TARGETS ${msgs_executable} DESTINATION ${EXE_INSTALL_DIR}) +set(executable_location "../../../${EXE_INSTALL_DIR}/$") + +set(cmd_script_generated "${CMAKE_CURRENT_BINARY_DIR}/cmd${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}.rb") +set(cmd_script_configured "${cmd_script_generated}.configured") + +configure_file( + "cmd${GZ_DESIGNATION}.rb.in" + "${cmd_script_configured}" + @ONLY) + +file(GENERATE + OUTPUT "${cmd_script_generated}" + INPUT "${cmd_script_configured}") + +install(FILES ${cmd_script_generated} DESTINATION lib/ruby/gz) + +#=============================================================================== +# Bash completion + +# Tack version onto and install the bash completion script +configure_file( + "msgs.bash_completion.sh" + "${CMAKE_CURRENT_BINARY_DIR}/msgs${PROJECT_VERSION_MAJOR}.bash_completion.sh" @ONLY) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/msgs${PROJECT_VERSION_MAJOR}.bash_completion.sh + DESTINATION + ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${GZ_TOOLS_VER}.completion.d) diff --git a/core/cmd/cmdmsgs.rb.in b/core/cmd/cmdmsgs.rb.in new file mode 100644 index 00000000..b30f804e --- /dev/null +++ b/core/cmd/cmdmsgs.rb.in @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby + +# Copyright (C) 2016 Open Source Robotics Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'open3' +require 'pathname' + +COMMANDS = { + 'msg' => '@executable_location@' +}.freeze + +# Class for the Gazebo msgs command line tools. +# +class Cmd + def execute(args) + exe_name = COMMANDS[args[0]] + + unless Pathname.new(exe_name).absolute? + # We're assuming that the library path is relative to the current + # location of this script. + exe_name = File.expand_path(File.join(File.dirname(__FILE__), LIBRARY_NAME)) + end + + # Drop command from list of arguments + Open3.popen2e(exe_name, *args[1..1]) do |_in, out_err, wait_thr| + begin + out_err.each do |line| + print line + end + exit(wait_thr.value.exitstatus) + rescue Interrupt => e + print e.message + exit(-1) + end + end + end +end diff --git a/core/src/cmd/msgs.bash_completion.sh b/core/cmd/msgs.bash_completion.sh similarity index 97% rename from core/src/cmd/msgs.bash_completion.sh rename to core/cmd/msgs.bash_completion.sh index 85dcc9e9..f4348b39 100644 --- a/core/src/cmd/msgs.bash_completion.sh +++ b/core/cmd/msgs.bash_completion.sh @@ -24,8 +24,7 @@ GZ_MSGS_COMPLETION_LIST=" -i --info -l --list -h --help - --force-version - --versions + --version " function _gz_msg diff --git a/core/cmd/msgs_main.cc b/core/cmd/msgs_main.cc new file mode 100644 index 00000000..709f1a23 --- /dev/null +++ b/core/cmd/msgs_main.cc @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +////////////////////////////////////////////////// +/// \brief Enumeration of available commands +enum class MsgCommand +{ + kNone, + kMsgInfo, + kMsgList, +}; + +////////////////////////////////////////////////// +/// \brief Structure to hold all available message options +struct MsgOptions +{ + /// \brief Command to execute + MsgCommand command {MsgCommand::kNone}; + + /// \brief List of messages for message info command + std::vector msgNames; +}; + +////////////////////////////////////////////////// +void runMsgInfo(const MsgOptions &_opt) +{ + for (const auto &msgName: _opt.msgNames) + { + auto msg = gz::msgs::Factory::New(msgName); + if (msg) + { + auto descriptor = msg->GetDescriptor(); + auto fileDescriptor = descriptor->file(); + std::cout << "Name: " << descriptor->full_name() << std::endl; + std::cout << "File: " << fileDescriptor->name() << std::endl << std::endl; + std::cout << descriptor->DebugString() << std::endl; + } + else + { + std::cerr << "Unable to create message of type[" << msgName << "]\n"; + } + } +} + +////////////////////////////////////////////////// +void runMsgList(const MsgOptions &/*_opt*/) +{ + std::vector types; + gz::msgs::Factory::Types(types); + + for (auto const &type : types) + std::cout << type << std::endl; +} + +////////////////////////////////////////////////// +void runMsgCommand(const MsgOptions &_opt) +{ + switch(_opt.command) + { + case MsgCommand::kMsgInfo: + runMsgInfo(_opt); + break; + case MsgCommand::kMsgList: + runMsgList(_opt); + break; + case MsgCommand::kNone: + default: + // In the event that there is no command, display help + throw CLI::CallForHelp(); + break; + } +} + +////////////////////////////////////////////////// +void addMsgFlags(CLI::App &_app) +{ + auto opt = std::make_shared(); + + auto listOpt = _app.add_flag_callback("-l,--list", + [opt](){ + opt->command = MsgCommand::kMsgList; + }, "List all message types."); + + auto infoOpt = _app.add_option("-i,--info", + opt->msgNames, "Get info about the specified message type.") + ->excludes(listOpt); + + _app.callback([opt, infoOpt](){ + if(infoOpt->count() > 0) { + opt->command = MsgCommand::kMsgInfo; + } + runMsgCommand(*opt); + }); +} + +////////////////////////////////////////////////// +int main(int argc, char** argv) +{ + CLI::App app{"Print information about Gazebo messages"}; + + app.add_flag_callback("-v,--version", [](){ + std::cout << GZ_MSGS_VERSION_FULL << std::endl; + throw CLI::Success(); + }); + + addMsgFlags(app); + app.formatter(std::make_shared(&app)); + CLI11_PARSE(app, argc, argv); +} diff --git a/core/include/gz/msgs/gz.hh b/core/include/gz/msgs/gz.hh deleted file mode 100644 index f5c51852..00000000 --- a/core/include/gz/msgs/gz.hh +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -*/ - -#ifndef GZ_MSGS_GZ_HH_ -#define GZ_MSGS_GZ_HH_ - -#include -#include "gz/msgs/Export.hh" - -/// \brief External hook to execute 'gz msg -i' from the command line. -/// \param[in] _msg Message type name. -extern "C" GZ_MSGS_VISIBLE void cmdMsgInfo(const char *_msg); - -/// \brief External hook to execute 'gz msg -l' from the command line. -extern "C" GZ_MSGS_VISIBLE void cmdMsgList(); - -/// \brief External hook to read the library version. -/// \return C-string representing the version. Ex.: 0.1.2 -extern "C" GZ_MSGS_VISIBLE const char *gzMsgsVersion(); - -#endif diff --git a/core/src/cmd/CMakeLists.txt b/core/src/cmd/CMakeLists.txt deleted file mode 100644 index 3a746eb0..00000000 --- a/core/src/cmd/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -#=============================================================================== -# Generate the ruby script for internal testing. -# Note that the major version of the library is included in the name. -# Ex: cmdtransport0.rb -set(cmd_script_generated_test "${CMAKE_BINARY_DIR}/test/lib/ruby/gz/cmd${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}.rb") -set(cmd_script_configured_test "${cmd_script_generated_test}.configured") - -# Set the library_location variable to the full path of the library file within -# the build directory. -set(library_location "$") - -configure_file( - "cmd${GZ_DESIGNATION}.rb.in" - "${cmd_script_configured_test}" - @ONLY) - -file(GENERATE - OUTPUT "${cmd_script_generated_test}" - INPUT "${cmd_script_configured_test}") - - -#=============================================================================== -# Used for the installed version. -# Generate the ruby script that gets installed. -# Note that the major version of the library is included in the name. -# Ex: cmdtransport0.rb -set(cmd_script_generated "${CMAKE_CURRENT_BINARY_DIR}/cmd${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}.rb") -set(cmd_script_configured "${cmd_script_generated}.configured") - -# Set the library_location variable to the relative path to the library file -# within the install directory structure. -set(library_location "../../../${CMAKE_INSTALL_LIBDIR}/$") - -configure_file( - "cmd${GZ_DESIGNATION}.rb.in" - "${cmd_script_configured}" - @ONLY) - -file(GENERATE - OUTPUT "${cmd_script_generated}" - INPUT "${cmd_script_configured}") - -# Install the ruby command line library in an unversioned location. -install(FILES ${cmd_script_generated} DESTINATION lib/ruby/gz) - - -#=============================================================================== -# Bash completion - -# Tack version onto and install the bash completion script -configure_file( - "msgs.bash_completion.sh" - "${CMAKE_CURRENT_BINARY_DIR}/msgs${PROJECT_VERSION_MAJOR}.bash_completion.sh" @ONLY) -install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/msgs${PROJECT_VERSION_MAJOR}.bash_completion.sh - DESTINATION - ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gz/gz${GZ_TOOLS_VER}.completion.d) diff --git a/core/src/cmd/cmdmsgs.rb.in b/core/src/cmd/cmdmsgs.rb.in deleted file mode 100644 index ffb9829c..00000000 --- a/core/src/cmd/cmdmsgs.rb.in +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/ruby - -# Copyright (C) 2016 Open Source Robotics Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# We use 'dl' for Ruby <= 1.9.x and 'fiddle' for Ruby >= 2.0.x -if RUBY_VERSION.split('.')[0] < '2' - require 'dl' - require 'dl/import' - include DL -else - require 'fiddle' - require 'fiddle/import' - include Fiddle -end - -require 'optparse' - -# Constants. -LIBRARY_NAME = '@library_location@' -LIBRARY_VERSION = '@PROJECT_VERSION_FULL@' -COMMON_OPTIONS = - " -h [ --help ] Print this help message.\n"\ - " --force-version Use a specific library version.\n"\ - ' --versions Show the available versions.' -COMMANDS = { 'msg' => - "Print information about Gazebo messages.\n\n" + - " gz msg [options]\n\n" + - "Options:\n\n" + - " -i [ --info ] arg " + - "Get info about the specified message type.\n" + - " -l [ --list ] List all message types.\n" + - COMMON_OPTIONS -} - -# -# Class for the Gazebo msgs command line tools. -# -class Cmd - # - # Return a structure describing the options. - # - def parse(args) - options = {} - - usage = COMMANDS[args[0]] - - # Read the command line arguments. - opt_parser = OptionParser.new do |opts| - opts.banner = usage - - opts.on('-h', '--help', 'Print this help message') do - puts usage - exit(0) - end - - opts.on('-l', '--list', 'Print all message types') do |l| - options['list'] = l - end - - opts.on('-i msg', '--info', String, - 'Print information about a message') do |t| - options['info'] = t - end - end - begin - opt_parser.parse!(args) - rescue - puts usage - exit(-1) - end - - # Check that there is at least one command and there is a plugin that knows - # how to handle it. - if ARGV.empty? || !COMMANDS.key?(ARGV[0]) || - options.empty? - puts usage - exit(-1) - end - - options['command'] = ARGV[0] - - options - end # parse() - - def execute(args) - options = parse(args) - - # puts 'Parsed:' - # puts options - - # Read the plugin that handles the command. - if LIBRARY_NAME[0] == '/' - # If the first character is a slash, we'll assume that we've been given an - # absolute path to the library. This is only used during test mode. - plugin = LIBRARY_NAME - else - # We're assuming that the library path is relative to the current - # location of this script. - plugin = File.expand_path(File.join(File.dirname(__FILE__), LIBRARY_NAME)) - end - conf_version = LIBRARY_VERSION - - begin - Importer.dlload plugin - rescue DLError - puts "Library error: [#{plugin}] not found." - exit(-1) - end - - # Read the library version. - Importer.extern 'const char* gzMsgsVersion()' - begin - plugin_version = Importer.gzMsgsVersion.to_s - rescue DLError - puts "Library error: Problem running 'gzMsgsVersion()' from #{plugin}." - exit(-1) - end - - # Sanity check: Verify that the version of the yaml file matches the version - # of the library that we are using. - unless plugin_version.eql? conf_version - puts "Error: Version mismatch. Your configuration file version is - [#{conf_version}] but #{plugin} version is [#{plugin_version}]." - exit(-1) - end - - begin - case options['command'] - when 'msg' - if options.key?('list') - Importer.extern 'void cmdMsgList()' - Importer.cmdMsgList - elsif options.key?('info') - Importer.extern 'void cmdMsgInfo(const char *)' - Importer.cmdMsgInfo(options['info']) - else - puts 'Command error: I do not have an implementation '\ - 'for this command.' - end - else - puts 'Command error: I do not have an implementation for '\ - "command [gz #{options['command']}]." - end - rescue - puts "Library error: Problem running [#{options['command']}]() "\ - "from #{plugin}." - end - end -end diff --git a/core/src/gz.cc b/core/src/gz.cc deleted file mode 100644 index 4088b2d8..00000000 --- a/core/src/gz.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2016 Open Source Robotics Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -*/ - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4251) -#endif - -#include - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# pragma warning(disable: 4503) -#endif - -using namespace gz; -using namespace msgs; - -////////////////////////////////////////////////// -extern "C" GZ_MSGS_VISIBLE -void cmdMsgInfo(const char *_msg) -{ - if (_msg) - { - auto msg = Factory::New(_msg); - if (msg) - { - auto descriptor = msg->GetDescriptor(); - auto fileDescriptor = descriptor->file(); - std::cout << "Name: " << descriptor->full_name() << std::endl; - std::cout << "File: " << fileDescriptor->name() << std::endl << std::endl; - - std::cout << descriptor->DebugString() << std::endl; - } - else - std::cerr << "Unable to create message of type[" << _msg << "]\n"; - } - else - { - std::cerr << "Message type is null\n"; - } -} - -////////////////////////////////////////////////// -extern "C" GZ_MSGS_VISIBLE -void cmdMsgList() -{ - std::vector types; - Factory::Types(types); - - for (auto const &type : types) - std::cout << type << std::endl; -} - -////////////////////////////////////////////////// -extern "C" GZ_MSGS_VISIBLE -const char *gzMsgsVersion() -{ - return GZ_MSGS_VERSION_FULL; -} diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 817c9a2a..b0baa6b3 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -6,11 +6,13 @@ endif() gz_build_tests(TYPE INTEGRATION SOURCES ${tests} TEST_LIST test_targets) -foreach(test ${test_targets}) - target_link_libraries(${test} ${PROJECT_LIBRARY_TARGET_NAME}) -endforeach() +if(TARGET INTEGRATION_gz_TEST) + target_compile_definitions(INTEGRATION_gz_TEST PRIVATE + "GZ_MSGS_EXECUTABLE_PATH=\"$\"" + "GZ_MSGS_COMPLETION_SCRIPT_PATH=\"${PROJECT_SOURCE_DIR}/core/cmd/msgs.bash_completion.sh\"") +endif() if(TARGET INTEGRATION_Factory_TEST) target_compile_definitions(INTEGRATION_Factory_TEST PRIVATE - "-DGZ_MSGS_TEST_PATH=\"${PROJECT_SOURCE_DIR}/test\"") + "GZ_MSGS_TEST_PATH=\"${PROJECT_SOURCE_DIR}/test\"") endif() diff --git a/test/integration/Factory_TEST.cc b/test/integration/Factory_TEST.cc index 7f8a08fe..37e7e2ca 100644 --- a/test/integration/Factory_TEST.cc +++ b/test/integration/Factory_TEST.cc @@ -21,6 +21,7 @@ #include #include +#include "gz/msgs/MessageTypes.hh" #include "gz/msgs/vector3d.pb.h" #include "gz/msgs/serialized_map.pb.h" #include "gz/msgs/Factory.hh" @@ -215,3 +216,10 @@ TEST(FactoryTest, MultipleMessagesInAProto) EXPECT_EQ(nullptr, ptr); } } + +///////////////////////////////////////////////// +int main(int _argc, char **_argv) +{ + testing::InitGoogleTest(&_argc, _argv); + return RUN_ALL_TESTS(); +} diff --git a/test/integration/gz_TEST.cc b/test/integration/gz_TEST.cc index 0d7af541..7d5e2fc2 100644 --- a/test/integration/gz_TEST.cc +++ b/test/integration/gz_TEST.cc @@ -20,19 +20,27 @@ #include #include #include -#include "test_config.hh" #ifdef _MSC_VER # define popen _popen # define pclose _pclose #endif -static const std::string g_version(std::string(GZ_MSGS_VERSION_FULL)); +// Set from preprocessor defines +static constexpr const char * kMsgsVersion = GZ_MSGS_VERSION_FULL; +static constexpr const char * kExecutablePath = GZ_MSGS_EXECUTABLE_PATH; +static constexpr const char * kCompletionScriptPath = + GZ_MSGS_COMPLETION_SCRIPT_PATH; + +///////////////////////////////////////////////// +std::string make_exec_string(const std::string &_args) +{ + return std::string(kExecutablePath) + " " + _args; +} ///////////////////////////////////////////////// std::string custom_exec_str(std::string _cmd) { - _cmd += " 2>&1"; FILE *pipe = popen(_cmd.c_str(), "r"); if (!pipe) @@ -52,59 +60,83 @@ std::string custom_exec_str(std::string _cmd) } ///////////////////////////////////////////////// -TEST(CmdLine, Versions) +TEST(CmdLine, Version) { - auto outputDebug = custom_exec_str("gz"); - auto output = custom_exec_str("gz msg --versions"); - EXPECT_NE(std::string::npos, output.find(g_version)); + auto output = custom_exec_str(make_exec_string("--version")); + EXPECT_NE(std::string::npos, output.find(kMsgsVersion)); } ///////////////////////////////////////////////// TEST(CmdLine, Help) { - auto output = - custom_exec_str("gz msg --force-version " + g_version + " --help"); - EXPECT_NE(std::string::npos, output.find("list")); + { + // Full argument + auto output = custom_exec_str(make_exec_string("--help")); + EXPECT_NE(std::string::npos, output.find("list")); + EXPECT_NE(std::string::npos, output.find("info")); + } - output = custom_exec_str("gz msg --force-version " + g_version + " -h"); - EXPECT_NE(std::string::npos, output.find("list")); + { + // Short flag + auto output = custom_exec_str(make_exec_string("-h")); + EXPECT_NE(std::string::npos, output.find("list")); + EXPECT_NE(std::string::npos, output.find("info")); + } - output = custom_exec_str("gz msg --force-version " + g_version); - EXPECT_NE(std::string::npos, output.find("list")); + { + // Print help with no other args + auto output = custom_exec_str(make_exec_string("")); + EXPECT_NE(std::string::npos, output.find("list")); + EXPECT_NE(std::string::npos, output.find("info")); + } } ///////////////////////////////////////////////// TEST(CmdLine, MsgList) { - auto output = custom_exec_str("gz msg --list --force-version " + - g_version); - EXPECT_NE(std::string::npos, output.find("gz.msgs.Boolean")) - << output; + auto output = custom_exec_str(make_exec_string("--list")); + EXPECT_NE(std::string::npos, output.find("gz.msgs.WorldControl")); } ///////////////////////////////////////////////// TEST(CmdLine, MsgInfo) { - auto output = custom_exec_str("gz msg --info gz_msgs.Boolean" - " --force-version " + g_version); - EXPECT_NE(std::string::npos, output.find("message Boolean {")) - << output; + // Underscore separated + { + auto output = + custom_exec_str(make_exec_string("--info gz_msgs.WorldControl")); + EXPECT_NE(std::string::npos, output.find("message WorldControl {")) + << output; + } + + // Period separated + { + auto output = + custom_exec_str(make_exec_string("--info gz.msgs.WorldControl")); + EXPECT_NE(std::string::npos, output.find("message WorldControl {")) + << output; + } + + // Multiple arguments + { + auto output = custom_exec_str(make_exec_string( + "--info gz.msgs.WorldControl gz.msgs.Wrench")); + EXPECT_NE(std::string::npos, output.find("message WorldControl {")); + EXPECT_NE(std::string::npos, output.find("message Wrench {")); + } } ///////////////////////////////////////////////// TEST(CmdLine, MsgHelpVsCompletionFlags) { // Flags in help message - auto helpOutput = custom_exec_str("gz msg --help --force-version " - + g_version); - - // Call the output function in the bash completion script - std::filesystem::path scriptPath = PROJECT_SOURCE_PATH; - scriptPath = scriptPath / "core" / "src" / "cmd" / "msgs.bash_completion.sh"; + auto helpOutput = custom_exec_str(make_exec_string("--help")); // Equivalent to: // sh -c "bash -c \". /path/to/msgs.bash_completion.sh; _gz_msgs_flags\"" - std::string cmd = "bash -c \". " + scriptPath.string() + "; _gz_msgs_flags\""; + std::string cmd = "bash -c \". " + + std::string(kCompletionScriptPath) + + "; _gz_msgs_flags\""; std::string scriptOutput = custom_exec_str(cmd); // Tokenize script output @@ -115,30 +147,8 @@ TEST(CmdLine, MsgHelpVsCompletionFlags) EXPECT_GT(flags.size(), 0u); // Match each flag in script output with help message - for (std::string flag : flags) + for (const auto &flag : flags) { EXPECT_NE(std::string::npos, helpOutput.find(flag)) << helpOutput; } } - -///////////////////////////////////////////////// -/// Main -int main(int argc, char **argv) -{ - // Set GZ_CONFIG_PATH to the directory where the .yaml configuration files - // is located. - setenv("GZ_CONFIG_PATH", GZ_CONFIG_PATH, 1); - - // Make sure that we load the library recently built and not the one installed - // in your system. - // Add the directory where Gazebo msgs has been built. - std::string value = std::string(GZ_TEST_LIBRARY_PATH); - // Save the current value of LD_LIBRARY_PATH. - auto cvalue = std::getenv("LD_LIBRARY_PATH"); - if (cvalue) - value += ":" + std::string(cvalue); - setenv("LD_LIBRARY_PATH", value.c_str(), 1); - - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}