diff --git a/.clang-tidy b/.clang-tidy index 6b4c31f3..15aa6d02 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -34,6 +34,7 @@ Checks: > -readability-function-size, -readability-identifier-length, -readability-magic-numbers, + -readability-math-missing-parentheses, -readability-uppercase-literal-suffix, modernize-*, -modernize-use-trailing-return-type, @@ -70,3 +71,5 @@ CheckOptions: value: google - key: readability-braces-around-statements.ShortStatementLines value: "1" + - key: misc-include-cleaner.IgnoreHeaders + value: "asm-generic/.*;bits/.*" diff --git a/.github/workflows/gcc.yaml b/.github/workflows/gcc.yaml index d1200508..25a8b7ce 100644 --- a/.github/workflows/gcc.yaml +++ b/.github/workflows/gcc.yaml @@ -36,7 +36,7 @@ jobs: version: "7" name: Linux GCC-${{ matrix.toolchain.version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 continue-on-error: true # Use the container for this specific version of gcc @@ -96,7 +96,7 @@ jobs: run: ctest --output-on-failure -E "dsl/UDP" - name: Upload Traces - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: traces-gcc-${{ matrix.toolchain.version }} diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml index bacca550..7ece21ef 100644 --- a/.github/workflows/linting.yaml +++ b/.github/workflows/linting.yaml @@ -20,19 +20,19 @@ concurrency: jobs: linux-clang-tidy: name: Linux Clang-Tidy - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout Code uses: actions/checkout@v4 - - name: Install clang-tidy-15 + - name: Install clang-tidy run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee /etc/apt/sources.list.d/llvm-15 - echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" | sudo tee -a /etc/apt/sources.list.d/llvm-15 + echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee /etc/apt/sources.list.d/llvm-19.list + echo "deb-src http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" | sudo tee -a /etc/apt/sources.list.d/llvm-19.list sudo apt-get update - sudo apt-get install -y clang-tidy-15 + sudo apt-get install -y clang-tidy-19 # Download and install cmake - name: Install CMake @@ -62,7 +62,7 @@ jobs: mkdir -p ${{ github.workspace }}/.ctcache - echo CTCACHE_CLANG_TIDY='/usr/bin/clang-tidy-15' >> "$GITHUB_ENV" + echo CTCACHE_CLANG_TIDY='/usr/bin/clang-tidy-19' >> "$GITHUB_ENV" echo CTCACHE_LOCAL=1 >> "$GITHUB_ENV" echo CTCACHE_SAVE_OUTPUT=1 >> "$GITHUB_ENV" echo CTCACHE_DIR='${{github.workspace}}/.ctcache' >> "$GITHUB_ENV" diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index cc949da1..0e7d4728 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -64,7 +64,7 @@ jobs: run: ctest --output-on-failure - name: Upload Traces - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: traces-macos diff --git a/.github/workflows/sonarcloud.yaml b/.github/workflows/sonarcloud.yaml index 009255ea..69f0b0ec 100644 --- a/.github/workflows/sonarcloud.yaml +++ b/.github/workflows/sonarcloud.yaml @@ -67,11 +67,11 @@ jobs: run: ctest --output-on-failure - name: Collect coverage into one XML report - if: always() + if: ${{ !cancelled() }} run: gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --exclude-unreachable-branches --exclude-noncode-lines --sonarqube > coverage.xml - name: Upload coverage report - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: coverage-sonar @@ -80,7 +80,7 @@ jobs: overwrite: true - name: Run sonar-scanner - if: always() + if: ${{ !cancelled() }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -90,7 +90,7 @@ jobs: --define sonar.coverageReportPaths=coverage.xml - name: Upload Traces - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: traces-sonar diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index 2163cc35..380ef47c 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -85,7 +85,7 @@ jobs: run: ctest --output-on-failure - name: Upload Traces - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@v4 with: name: traces-windows-${{ matrix.toolchain.name }} diff --git a/.gitignore b/.gitignore index 8ae53a55..7deac2fd 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ tags docs/doxygen docs/doxygen_sqlite3.db *.sublime-workspace +.DS_Store diff --git a/cmake/ClangTidy.cmake b/cmake/ClangTidy.cmake index e1d6f051..ac29995d 100644 --- a/cmake/ClangTidy.cmake +++ b/cmake/ClangTidy.cmake @@ -1,10 +1,10 @@ # Default not to run the clang-tidy checks, default to whatever our CI_BUILD is option(ENABLE_CLANG_TIDY "Enable building with clang-tidy checks.") if(ENABLE_CLANG_TIDY) - # Search for clang-tidy-15 first as this is the version installed in CI - find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy-15 clang-tidy) + # Search for the same version of clang-tidy as is used in CI first + find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy-19 clang-tidy) if(NOT CLANG_TIDY_EXECUTABLE) - message(FATAL_ERROR "clang-tidy-15 not found.") + message(FATAL_ERROR "clang-tidy not found.") endif() # Report clang-tidy executable details diff --git a/src/Configuration.hpp b/src/Configuration.hpp index c31ef042..f65eb9f9 100644 --- a/src/Configuration.hpp +++ b/src/Configuration.hpp @@ -23,7 +23,6 @@ #ifndef NUCLEAR_CONFIGURATION_HPP #define NUCLEAR_CONFIGURATION_HPP -#include #include namespace NUClear { diff --git a/src/Environment.hpp b/src/Environment.hpp index 2122fea2..3f723bcb 100644 --- a/src/Environment.hpp +++ b/src/Environment.hpp @@ -24,8 +24,8 @@ #define NUCLEAR_ENVIRONMENT_HPP #include +#include -#include "LogLevel.hpp" namespace NUClear { diff --git a/src/LogLevel.hpp b/src/LogLevel.hpp index 6801d06f..3c9d6f04 100644 --- a/src/LogLevel.hpp +++ b/src/LogLevel.hpp @@ -23,7 +23,9 @@ #ifndef NUCLEAR_LOGLEVEL_HPP #define NUCLEAR_LOGLEVEL_HPP -#include +#include +#include +#include // Why do we need to include platform.hpp here? // Because windows defines a bunch of things for legacy reasons, one of which is a #define for ERROR as blank diff --git a/src/PowerPlant.cpp b/src/PowerPlant.cpp index deabde45..790eb89b 100644 --- a/src/PowerPlant.cpp +++ b/src/PowerPlant.cpp @@ -22,19 +22,18 @@ #include "PowerPlant.hpp" -#include -#include +#include +#include +#include "Configuration.hpp" #include "Reactor.hpp" #include "dsl/store/DataStore.hpp" #include "dsl/word/Shutdown.hpp" #include "dsl/word/Startup.hpp" #include "dsl/word/emit/Inline.hpp" -#include "extension/ChronoController.hpp" -#include "extension/IOController.hpp" -#include "extension/NetworkController.hpp" +#include "id.hpp" #include "message/CommandLineArguments.hpp" -#include "message/LogMessage.hpp" +#include "threading/Reaction.hpp" #include "threading/ReactionTask.hpp" namespace NUClear { diff --git a/src/PowerPlant.hpp b/src/PowerPlant.hpp index 98fae22f..f0601f41 100644 --- a/src/PowerPlant.hpp +++ b/src/PowerPlant.hpp @@ -23,18 +23,18 @@ #ifndef NUCLEAR_POWER_PLANT_HPP #define NUCLEAR_POWER_PLANT_HPP -#include -#include #include -#include +#include +#include #include #include // Utilities -#include "Configuration.hpp" +#include "Configuration.hpp" // IWYU pragma: export #include "Environment.hpp" #include "LogLevel.hpp" #include "id.hpp" +#include "threading/Reaction.hpp" #include "threading/ReactionTask.hpp" #include "threading/scheduler/Scheduler.hpp" #include "util/FunctionFusion.hpp" diff --git a/src/Reactor.cpp b/src/Reactor.cpp index 1b3c5214..dcc5425b 100644 --- a/src/Reactor.cpp +++ b/src/Reactor.cpp @@ -22,6 +22,8 @@ #include "Reactor.hpp" +#include "LogLevel.hpp" + namespace NUClear { constexpr LogLevel Reactor::TRACE; diff --git a/src/Reactor.hpp b/src/Reactor.hpp index 8e758167..42095e90 100644 --- a/src/Reactor.hpp +++ b/src/Reactor.hpp @@ -24,18 +24,22 @@ #define NUCLEAR_REACTOR_HPP #include -#include +#include +#include #include #include -#include +#include +#include #include -#include "Environment.hpp" -#include "LogLevel.hpp" +#include "Environment.hpp" // IWYU pragma: export +#include "LogLevel.hpp" // IWYU pragma: export +#include "clock.hpp" // IWYU pragma: export #include "dsl/Parse.hpp" -#include "threading/Reaction.hpp" -#include "threading/ReactionHandle.hpp" -#include "threading/ReactionIdentifiers.hpp" +#include "id.hpp" // IWYU pragma: export +#include "threading/Reaction.hpp" // IWYU pragma: export +#include "threading/ReactionHandle.hpp" // IWYU pragma: export +#include "threading/ReactionIdentifiers.hpp" // IWYU pragma: export #include "util/CallbackGenerator.hpp" #include "util/Sequence.hpp" #include "util/demangle.hpp" diff --git a/src/dsl/fusion/BindFusion.hpp b/src/dsl/fusion/BindFusion.hpp index 35969fb4..cfdc635d 100644 --- a/src/dsl/fusion/BindFusion.hpp +++ b/src/dsl/fusion/BindFusion.hpp @@ -79,13 +79,13 @@ namespace dsl { reaction, std::forward(args)...))>::value, NoReturn, - Return>::template call(reaction, std::forward(args)...)) { + Return>::call(reaction, std::forward(args)...)) { return std::conditional_t< std::is_void(reaction, std::forward(args)...))>::value, NoReturn, - Return>::template call(reaction, std::forward(args)...); + Return>::call(reaction, std::forward(args)...); } }; diff --git a/src/dsl/operation/CacheGet.hpp b/src/dsl/operation/CacheGet.hpp index 818945b4..689159fd 100644 --- a/src/dsl/operation/CacheGet.hpp +++ b/src/dsl/operation/CacheGet.hpp @@ -27,6 +27,9 @@ #include "../store/ThreadStore.hpp" namespace NUClear { +namespace threading { + class ReactionTask; // Forward declare ReactionTask +} // namespace threading namespace dsl { namespace operation { @@ -41,6 +44,7 @@ namespace dsl { */ template struct CacheGet { + CacheGet() = delete; // Ensure that DSL words are not instantiated template static std::shared_ptr get(const threading::ReactionTask& /*task*/) { diff --git a/src/dsl/operation/ChronoTask.hpp b/src/dsl/operation/ChronoTask.hpp index 0c2343e7..60fe87aa 100644 --- a/src/dsl/operation/ChronoTask.hpp +++ b/src/dsl/operation/ChronoTask.hpp @@ -23,6 +23,8 @@ #ifndef NUCLEAR_DSL_OPERATION_CHRONO_TASK_HPP #define NUCLEAR_DSL_OPERATION_CHRONO_TASK_HPP +#include + #include "../../clock.hpp" #include "../../id.hpp" diff --git a/src/dsl/operation/TypeBind.hpp b/src/dsl/operation/TypeBind.hpp index fa76696f..72b6b89c 100644 --- a/src/dsl/operation/TypeBind.hpp +++ b/src/dsl/operation/TypeBind.hpp @@ -23,6 +23,8 @@ #ifndef NUCLEAR_DSL_OPERATION_TYPE_BIND_HPP #define NUCLEAR_DSL_OPERATION_TYPE_BIND_HPP +#include + #include "../store/TypeCallbackStore.hpp" namespace NUClear { @@ -56,6 +58,7 @@ namespace dsl { */ template struct TypeBind { + TypeBind() = delete; // Ensure that DSL words are not instantiated template static void bind(const std::shared_ptr& reaction) { diff --git a/src/dsl/word/Idle.hpp b/src/dsl/word/Idle.hpp index fb95620b..b2b9d564 100644 --- a/src/dsl/word/Idle.hpp +++ b/src/dsl/word/Idle.hpp @@ -71,7 +71,12 @@ namespace dsl { static void bind(const std::shared_ptr& reaction) { // Make a fake task to use for finding an appropriate descriptor - threading::ReactionTask task(reaction, false, DSL::priority, DSL::run_inline, DSL::pool, DSL::group); + const threading::ReactionTask task(reaction, + false, + DSL::priority, + DSL::run_inline, + DSL::pool, + DSL::group); bind_idle(reaction, PoolType::template pool(task)); } }; diff --git a/src/dsl/word/Shutdown.hpp b/src/dsl/word/Shutdown.hpp index 20ea2c16..a840bb45 100644 --- a/src/dsl/word/Shutdown.hpp +++ b/src/dsl/word/Shutdown.hpp @@ -52,11 +52,19 @@ namespace dsl { * @par Implements * Bind */ - struct Shutdown - : operation::TypeBind - , Priority::IDLE {}; + struct Shutdown {}; } // namespace word + + namespace operation { + + template <> + struct DSLProxy + : operation::TypeBind + , word::Priority::IDLE {}; + + } // namespace operation + } // namespace dsl } // namespace NUClear diff --git a/src/dsl/word/Startup.hpp b/src/dsl/word/Startup.hpp index 97baa24d..132cd563 100644 --- a/src/dsl/word/Startup.hpp +++ b/src/dsl/word/Startup.hpp @@ -39,9 +39,17 @@ namespace dsl { * @par Implements * Bind */ - struct Startup : operation::TypeBind {}; + struct Startup {}; } // namespace word + + namespace operation { + + template <> + struct DSLProxy : operation::TypeBind {}; + + } // namespace operation + } // namespace dsl } // namespace NUClear diff --git a/src/dsl/word/TaskScope.hpp b/src/dsl/word/TaskScope.hpp index 18f2e0a3..927a4d3e 100644 --- a/src/dsl/word/TaskScope.hpp +++ b/src/dsl/word/TaskScope.hpp @@ -21,7 +21,6 @@ */ #ifndef NUCLEAR_DSL_WORD_TASK_SCOPE_HPP #define NUCLEAR_DSL_WORD_TASK_SCOPE_HPP -#include #include "../../id.hpp" #include "../../threading/ReactionTask.hpp" @@ -76,7 +75,7 @@ namespace dsl { template static Lock scope(const threading::ReactionTask& task) { // Store the old task id - NUClear::id_t old_id = current_task_id; + const NUClear::id_t old_id = current_task_id; // Set the current task id to the word current_task_id = task.id; // Return a lock that will restore the old task id diff --git a/src/dsl/word/UDP.hpp b/src/dsl/word/UDP.hpp index f0762102..ef2e12a5 100644 --- a/src/dsl/word/UDP.hpp +++ b/src/dsl/word/UDP.hpp @@ -367,7 +367,7 @@ namespace dsl { mh.msg_iovlen = 1; // Receive our message - ssize_t received = recvmsg(event.fd, &mh, MSG_DONTWAIT); + const ssize_t received = recvmsg(event.fd, &mh, MSG_DONTWAIT); if (received < 0) { return {}; } diff --git a/src/dsl/word/emit/Delay.hpp b/src/dsl/word/emit/Delay.hpp index 96394487..b1a97050 100644 --- a/src/dsl/word/emit/Delay.hpp +++ b/src/dsl/word/emit/Delay.hpp @@ -47,7 +47,7 @@ namespace dsl { struct Delay { static void emit(PowerPlant& powerplant, - std::shared_ptr data, + const std::shared_ptr& data, NUClear::clock::duration delay) { // Our chrono task is just to do a normal emit in the amount of time @@ -67,7 +67,7 @@ namespace dsl { } static void emit(PowerPlant& powerplant, - std::shared_ptr data, + const std::shared_ptr& data, NUClear::clock::time_point at_time) { // Our chrono task is just to do a normal emit in the amount of time diff --git a/src/dsl/word/emit/Initialise.hpp b/src/dsl/word/emit/Initialise.hpp index cd013fdd..73abdfb6 100644 --- a/src/dsl/word/emit/Initialise.hpp +++ b/src/dsl/word/emit/Initialise.hpp @@ -53,7 +53,7 @@ namespace dsl { template struct Initialise { - static void emit(PowerPlant& powerplant, std::shared_ptr data) { + static void emit(PowerPlant& powerplant, const std::shared_ptr& data) { // Make a floating reaction task to submit which will emit this data auto emitter = std::make_unique( diff --git a/src/dsl/word/emit/Network.hpp b/src/dsl/word/emit/Network.hpp index 84d17997..292f7167 100644 --- a/src/dsl/word/emit/Network.hpp +++ b/src/dsl/word/emit/Network.hpp @@ -24,6 +24,7 @@ #define NUCLEAR_DSL_WORD_EMIT_NETWORK_HPP #include +#include #include "../../../util/serialise/Serialise.hpp" @@ -79,7 +80,7 @@ namespace dsl { struct Network { static void emit(PowerPlant& powerplant, - std::shared_ptr data, + const std::shared_ptr& data, std::string target = "", bool reliable = false) { @@ -93,7 +94,7 @@ namespace dsl { powerplant.emit(e); } - static void emit(PowerPlant& powerplant, std::shared_ptr data, bool reliable) { + static void emit(PowerPlant& powerplant, const std::shared_ptr& data, bool reliable) { emit(powerplant, data, "", reliable); } }; diff --git a/src/dsl/word/emit/UDP.hpp b/src/dsl/word/emit/UDP.hpp index 3ed6e812..ee2b33e5 100644 --- a/src/dsl/word/emit/UDP.hpp +++ b/src/dsl/word/emit/UDP.hpp @@ -60,7 +60,7 @@ namespace dsl { struct UDP { static void emit(const PowerPlant& /*powerplant*/, - std::shared_ptr data, + const std::shared_ptr& data, const std::string& to_addr, in_port_t to_port, const std::string& from_addr = "", diff --git a/src/extension/ChronoController.cpp b/src/extension/ChronoController.cpp index 2866e25d..5b035831 100644 --- a/src/extension/ChronoController.cpp +++ b/src/extension/ChronoController.cpp @@ -22,8 +22,16 @@ #include "ChronoController.hpp" +#include #include - +#include +#include +#include +#include + +#include "../Reactor.hpp" +#include "../dsl/operation/Unbind.hpp" +#include "../message/TimeTravel.hpp" #include "../util/precise_sleep.hpp" namespace NUClear { diff --git a/src/extension/NetworkController.cpp b/src/extension/NetworkController.cpp index 429cd9bc..250a6f84 100644 --- a/src/extension/NetworkController.cpp +++ b/src/extension/NetworkController.cpp @@ -22,7 +22,22 @@ #include "NetworkController.hpp" +#include +#include +#include +#include +#include +#include +#include + +#include "../Reactor.hpp" +#include "../dsl/operation/Unbind.hpp" +#include "../dsl/store/ThreadStore.hpp" +#include "../dsl/word/Network.hpp" +#include "../dsl/word/emit/Network.hpp" +#include "../message/NetworkConfiguration.hpp" #include "../message/NetworkEvent.hpp" +#include "../util/get_hostname.hpp" namespace NUClear { namespace extension { diff --git a/src/extension/TraceController.cpp b/src/extension/TraceController.cpp index b2a40608..15c5002f 100644 --- a/src/extension/TraceController.cpp +++ b/src/extension/TraceController.cpp @@ -22,9 +22,17 @@ #include "TraceController.hpp" +#include #include +#include +#include +#include #include +#include +#include +#include +#include "../Reactor.hpp" #include "../message/LogMessage.hpp" #include "../message/ReactionStatistics.hpp" #include "../message/Trace.hpp" @@ -39,44 +47,60 @@ namespace extension { using message::ReactionEvent; using message::ReactionStatistics; - /// Use a constant sequence id as there will only be one writer, 0 is invalid so 1 is the first valid id - constexpr uint32_t trusted_packet_sequence_id = 1; - - // Extracted from the chromium trace format - enum SequenceFlags : int32_t { SEQ_NEEDS_INCREMENTAL_STATE = 2, SEQ_INCREMENTAL_STATE_CLEARED = 1 }; - enum TrackDescriptorType : int32_t { TYPE_SLICE_BEGIN = 1, TYPE_SLICE_END = 2, TYPE_INSTANT = 3 }; - enum BuiltinCounterType : int32_t { COUNTER_THREAD_TIME_NS = 1 }; - enum LogMessagePriority : int32_t { - PRIO_UNSPECIFIED = 0, - PRIO_UNUSED = 1, - PRIO_VERBOSE = 2, - PRIO_DEBUG = 3, - PRIO_INFO = 4, - PRIO_WARN = 5, - PRIO_ERROR = 6, - PRIO_FATAL = 7, - }; - - template - std::chrono::nanoseconds ts(const T& timestamp) { - return std::chrono::duration_cast(timestamp.time_since_epoch()); - } - - void TraceController::write_trace_packet(const std::vector& packet) { - // Write the packet to the file - trace_file.write(packet.data(), ssize_t(packet.size())); - } + namespace { // Anonymous namespace for internal linkage + + /// Use a constant sequence id as there will only be one writer, 0 is invalid so 1 is the first valid id + constexpr uint32_t trusted_packet_sequence_id = 1; + + // Extracted from the chromium trace format + enum SequenceFlags : int8_t { SEQ_NEEDS_INCREMENTAL_STATE = 2, SEQ_INCREMENTAL_STATE_CLEARED = 1 }; + enum TrackDescriptorType : int8_t { TYPE_SLICE_BEGIN = 1, TYPE_SLICE_END = 2, TYPE_INSTANT = 3 }; + enum BuiltinCounterType : int8_t { COUNTER_THREAD_TIME_NS = 1 }; + enum LogMessagePriority : int8_t { + PRIO_UNSPECIFIED = 0, + PRIO_UNUSED = 1, + PRIO_VERBOSE = 2, + PRIO_DEBUG = 3, + PRIO_INFO = 4, + PRIO_WARN = 5, + PRIO_ERROR = 6, + PRIO_FATAL = 7, + }; + + template + std::chrono::nanoseconds ts(const T& timestamp) { + return std::chrono::duration_cast(timestamp.time_since_epoch()); + } - std::string name_for_id(const std::shared_ptr& ids) { - if (ids == nullptr) { - // With no identifiers we can't do anything - return ""; + std::string name_for_id(const std::shared_ptr& ids) { + if (ids == nullptr) { + // With no identifiers we can't do anything + return ""; + } + if (ids->name.empty()) { + // Remove the namespace from the DSL with a regex + return std::regex_replace(ids->dsl, std::regex("[A-Za-z_][A-Za-z0-9_]+::"), ""); + } + return ids->name; } - if (ids->name.empty()) { - // Remove the namespace from the DSL with a regex - return std::regex_replace(ids->dsl, std::regex("[A-Za-z_][A-Za-z0-9_]+::"), ""); + + const ReactionStatistics::Event& relevant_event(const ReactionEvent& event) { + const auto& statistics = *event.statistics; + switch (event.type) { + case ReactionEvent::BLOCKED: + case ReactionEvent::MISSING_DATA: + case ReactionEvent::CREATED: return statistics.created; + case ReactionEvent::STARTED: return statistics.started; + case ReactionEvent::FINISHED: return statistics.finished; + default: throw std::invalid_argument("Unknown event type"); + } } - return ids->name; + + } // namespace + + void TraceController::write_trace_packet(const std::vector& packet) { + // Write the packet to the file + trace_file.write(packet.data(), std::streamsize(packet.size())); } uint64_t TraceController::process() { @@ -143,18 +167,6 @@ namespace extension { return uuid; } - const ReactionStatistics::Event& relevant_event(const ReactionEvent& event) { - const auto& statistics = *event.statistics; - switch (event.type) { - case ReactionEvent::BLOCKED: - case ReactionEvent::MISSING_DATA: - case ReactionEvent::CREATED: return statistics.created; - case ReactionEvent::STARTED: return statistics.started; - case ReactionEvent::FINISHED: return statistics.finished; - default: throw std::invalid_argument("Unknown event type"); - } - } - void TraceController::encode_event(const ReactionEvent& event) { const auto& relevant = relevant_event(event); diff --git a/src/extension/network/NUClearNetwork.cpp b/src/extension/network/NUClearNetwork.cpp index 74ba0e82..11839da9 100644 --- a/src/extension/network/NUClearNetwork.cpp +++ b/src/extension/network/NUClearNetwork.cpp @@ -23,52 +23,66 @@ #include "NUClearNetwork.hpp" #include +#include +#include +#include +#include #include +#include #include -#include +#include +#include #include +#include #include #include +#include #include "../../util/network/if_number_from_address.hpp" #include "../../util/network/resolve.hpp" +#include "../../util/network/sock_t.hpp" #include "../../util/platform.hpp" +#include "wire_protocol.hpp" namespace NUClear { namespace extension { namespace network { - /** - * Read a single packet from the given udp file descriptor. - * - * @param fd The file descriptor to read from - * - * @return The data and who it was sent from - */ - std::pair> read_socket(fd_t fd) { - - // Allocate a vector that can hold a datagram - std::vector payload(1500); - iovec iov{}; - iov.iov_base = reinterpret_cast(payload.data()); - iov.iov_len = static_cast(payload.size()); - - // Who we are receiving from - util::network::sock_t from{}; - - // Setup our message header to receive - msghdr mh{}; - mh.msg_name = &from.sock; - mh.msg_namelen = sizeof(from); - mh.msg_iov = &iov; - mh.msg_iovlen = 1; - - // Now read the data for real - const ssize_t received = recvmsg(fd, &mh, 0); - payload.resize(received); - - return {from, std::move(payload)}; - } + namespace { // Anonymous namespace for internal linkage + + /** + * Read a single packet from the given udp file descriptor. + * + * @param fd The file descriptor to read from + * + * @return The data and who it was sent from + */ + std::pair> read_socket(fd_t fd) { + + // Allocate a vector that can hold a datagram + std::vector payload(1500); + iovec iov{}; + iov.iov_base = reinterpret_cast(payload.data()); + iov.iov_len = static_cast(payload.size()); + + // Who we are receiving from + util::network::sock_t from{}; + + // Setup our message header to receive + msghdr mh{}; + mh.msg_name = &from.sock; + mh.msg_namelen = sizeof(from); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + // Now read the data for real + const ssize_t received = recvmsg(fd, &mh, 0); + payload.resize(received); + + return {from, std::move(payload)}; + } + + } // namespace NUClearNetwork::PacketQueue::PacketTarget::PacketTarget(std::weak_ptr target, std::vector acked) diff --git a/src/extension/trace/protobuf.cpp b/src/extension/trace/protobuf.cpp index 7489ccae..017b54ea 100644 --- a/src/extension/trace/protobuf.cpp +++ b/src/extension/trace/protobuf.cpp @@ -22,8 +22,10 @@ #include "protobuf.hpp" +#include #include #include +#include #include #include @@ -32,71 +34,84 @@ namespace extension { namespace trace { namespace protobuf { - namespace encode { - template ::value, int> = 0> - OutputIterator redundant_varint(const T& value, const size_t& n_bytes, OutputIterator out) { - // Encode the value as a varint - uint32_t v = value; - for (unsigned i = 0; i < n_bytes - 1; i++) { - *out++ = (v & 0x7F) | 0x80; - v >>= 7; + namespace { // Everything here has internal linkage + + namespace encode { + template ::value, int> = 0> + OutputIterator redundant_varint(const T& value, const size_t& n_bytes, OutputIterator out) { + // Encode the value as a varint + uint32_t v = value; + for (unsigned i = 0; i < n_bytes - 1; i++) { + *out++ = (v & 0x7F) | 0x80; + v >>= 7; + } + *out++ = v & 0x7F; + return out; } - *out++ = v & 0x7F; - return out; - } - - template ::value, int> = 0> - OutputIterator varint(const T& value, OutputIterator out) { - // Cast the value down to its unsigned type and encode it as a varint - std::make_unsigned_t v(value); - while (v >= 0x80) { - *out++ = (v & 0x7F) | 0x80; - v >>= 7; + + template ::value, int> = 0> + OutputIterator varint(const T& value, OutputIterator out) { + // Cast the value down to its unsigned type and encode it as a varint + std::make_unsigned_t v(value); + while (v >= 0x80) { + *out++ = (v & 0x7F) | 0x80; + v >>= 7; + } + *out++ = v & 0x7F; + return out; + } + + template ::value, int> = 0> + OutputIterator fixed(const T& value, OutputIterator out) { + // Cast the value down to its unsigned type and encode it as fixed + const std::make_unsigned_t v(value); + for (size_t i = 0; i < sizeof(T); ++i) { + *out++ = (v >> (i * 8)) & 0xFF; + } + return out; } - *out++ = v & 0x7F; - return out; - } - - template ::value, int> = 0> - OutputIterator fixed(const T& value, OutputIterator out) { - // Cast the value down to its unsigned type and encode it as fixed - const std::make_unsigned_t v(value); - for (size_t i = 0; i < sizeof(T); ++i) { - *out++ = (v >> (i * 8)) & 0xFF; + + template + OutputIterator length_delimited(Iterator begin, Iterator end, OutputIterator out) { + // Encode the value as a varint length and then the string + out = varint(uint32_t(std::distance(begin, end)), out); + out = std::copy(begin, end, out); + return out; + } + + } // namespace encode + + namespace field { + template + OutputIterator varint(const uint32_t& id, const T& value, OutputIterator out) { + out = encode::varint(uint32_t(id << 3 | 0), out); + return encode::varint(value, out); } - return out; - } - - template - OutputIterator length_delimited(Iterator begin, Iterator end, OutputIterator out) { - // Encode the value as a varint length and then the string - out = varint(uint32_t(std::distance(begin, end)), out); - out = std::copy(begin, end, out); - return out; - } - - } // namespace encode - - namespace field { - template - OutputIterator varint(const uint32_t& id, const T& value, OutputIterator out) { - out = encode::varint(uint32_t(id << 3 | 0), out); - return encode::varint(value, out); - } - - template - OutputIterator fixed(const uint32_t& id, const T& value, OutputIterator out) { - out = encode::varint(uint32_t(id << 3 | 1), out); - return encode::fixed(value, out); - } - - template - OutputIterator length_delimited(const uint32_t& id, Iterator begin, Iterator end, OutputIterator out) { - out = encode::varint(uint32_t(id << 3 | 2), out); - return encode::length_delimited(begin, end, out); - } - - } // namespace field + + template + OutputIterator fixed(const uint32_t& id, const T& value, OutputIterator out) { + out = encode::varint(uint32_t(id << 3 | 1), out); + return encode::fixed(value, out); + } + + template + OutputIterator length_delimited(const uint32_t& id, + Iterator begin, + Iterator end, + OutputIterator out) { + out = encode::varint(uint32_t(id << 3 | 2), out); + return encode::length_delimited(begin, end, out); + } + + } // namespace field + + } // namespace void uint64(const uint32_t& id, const uint64_t& value, std::vector& data) { field::varint(id, value, std::back_inserter(data)); diff --git a/src/id.hpp b/src/id.hpp index 453832fb..2e3e79c0 100644 --- a/src/id.hpp +++ b/src/id.hpp @@ -23,7 +23,7 @@ #ifndef NUCLEAR_UTIL_ID_HPP #define NUCLEAR_UTIL_ID_HPP -#include +#include namespace NUClear { diff --git a/src/message/LogMessage.hpp b/src/message/LogMessage.hpp index 29f44fa9..3deeab74 100644 --- a/src/message/LogMessage.hpp +++ b/src/message/LogMessage.hpp @@ -58,10 +58,10 @@ namespace message { , statistics(std::move(statistics)) {} /// The logging level of the log - LogLevel level{}; + LogLevel level; /// The logging level of the reactor that made the log (the level to display at) - LogLevel display_level{}; + LogLevel display_level; /// The string contents of the message std::string message; diff --git a/src/message/ReactionStatistics.cpp b/src/message/ReactionStatistics.cpp index f3121d56..ea43dea8 100644 --- a/src/message/ReactionStatistics.cpp +++ b/src/message/ReactionStatistics.cpp @@ -22,7 +22,16 @@ #include "ReactionStatistics.hpp" +#include +#include +#include +#include +#include + +#include "../clock.hpp" +#include "../id.hpp" #include "../threading/scheduler/Pool.hpp" +#include "../util/usage_clock.hpp" namespace NUClear { namespace message { diff --git a/src/nuclear.in b/src/nuclear.in index 80342fa8..eb630cb7 100644 --- a/src/nuclear.in +++ b/src/nuclear.in @@ -23,9 +23,17 @@ #ifndef NUCLEAR #define NUCLEAR +// IWYU pragma: begin_exports + // Main classes #include "${nuclear_include_base_directory}PowerPlant.hpp" #include "${nuclear_include_base_directory}Reactor.hpp" +#include "${nuclear_include_base_directory}threading/Reaction.hpp" +#include "${nuclear_include_base_directory}threading/ReactionTask.hpp" + +// Base types +#include "${nuclear_include_base_directory}clock.hpp" +#include "${nuclear_include_base_directory}id.hpp" // Message types #include "${nuclear_include_base_directory}message/CommandLineArguments.hpp" @@ -42,4 +50,10 @@ #include "${nuclear_include_base_directory}extension/NetworkController.hpp" #include "${nuclear_include_base_directory}extension/TraceController.hpp" +// Publicly available utilities +#include "${nuclear_include_base_directory}dsl/operation/ChronoTask.hpp" +#include "${nuclear_include_base_directory}util/demangle.hpp" + +// IWYU pragma: end_exports + #endif // NUCLEAR diff --git a/src/threading/Reaction.cpp b/src/threading/Reaction.cpp index 31892dd0..75e6ba2c 100644 --- a/src/threading/Reaction.cpp +++ b/src/threading/Reaction.cpp @@ -22,6 +22,7 @@ #include "Reaction.hpp" +#include #include #include diff --git a/src/threading/ReactionTask.cpp b/src/threading/ReactionTask.cpp index 1c8ae543..151d604e 100644 --- a/src/threading/ReactionTask.cpp +++ b/src/threading/ReactionTask.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "../id.hpp" diff --git a/src/threading/scheduler/Group.cpp b/src/threading/scheduler/Group.cpp index 883180c3..c24522be 100644 --- a/src/threading/scheduler/Group.cpp +++ b/src/threading/scheduler/Group.cpp @@ -25,9 +25,12 @@ #include #include #include +#include #include #include "../../id.hpp" +#include "../../util/GroupDescriptor.hpp" +#include "Lock.hpp" namespace NUClear { namespace threading { diff --git a/src/threading/scheduler/Pool.cpp b/src/threading/scheduler/Pool.cpp index a9b6cb97..08a2140f 100644 --- a/src/threading/scheduler/Pool.cpp +++ b/src/threading/scheduler/Pool.cpp @@ -22,13 +22,22 @@ #include "Pool.hpp" #include +#include +#include +#include +#include +#include +#include +#include #include "../../dsl/word/MainThread.hpp" #include "../../dsl/word/Pool.hpp" +#include "../../id.hpp" #include "../../message/ReactionStatistics.hpp" +#include "../../threading/Reaction.hpp" #include "../../util/Inline.hpp" +#include "../../util/platform.hpp" #include "../ReactionTask.hpp" -#include "CombinedLock.hpp" #include "CountingLock.hpp" #include "Scheduler.hpp" @@ -179,9 +188,9 @@ namespace threading { } } catch (const ShutdownThreadException&) { - // This throw is here for when the pool is stopped + Pool::current_pool = nullptr; + return; } - Pool::current_pool = nullptr; } Pool::Task Pool::get_task() { diff --git a/src/threading/scheduler/Scheduler.cpp b/src/threading/scheduler/Scheduler.cpp index cf1c4e00..23ef8aa5 100644 --- a/src/threading/scheduler/Scheduler.cpp +++ b/src/threading/scheduler/Scheduler.cpp @@ -22,11 +22,22 @@ #include "Scheduler.hpp" #include +#include +#include +#include +#include #include +#include +#include #include "../../dsl/word/MainThread.hpp" -#include "../../dsl/word/Pool.hpp" +#include "../../id.hpp" +#include "../../threading/Reaction.hpp" +#include "../../threading/ReactionTask.hpp" #include "CombinedLock.hpp" +#include "Group.hpp" +#include "Lock.hpp" +#include "Pool.hpp" namespace NUClear { namespace threading { diff --git a/src/util/FileDescriptor.cpp b/src/util/FileDescriptor.cpp index 2c0e691b..7e16acb3 100644 --- a/src/util/FileDescriptor.cpp +++ b/src/util/FileDescriptor.cpp @@ -22,6 +22,7 @@ #include "FileDescriptor.hpp" +#include #include #include diff --git a/src/util/FunctionFusion.hpp b/src/util/FunctionFusion.hpp index b86e6038..3dffc635 100644 --- a/src/util/FunctionFusion.hpp +++ b/src/util/FunctionFusion.hpp @@ -177,7 +177,11 @@ namespace util { NextStep::call(std::forward(args)...))) { // Call each on a separate line to preserve order of execution - auto current = tuplify(call_one(CurrentRange(), std::forward(args)...)); + // TODO(thouliston) this is a legitimate bug, fix it in a future PR and add a test to ensure it doesn't + // regress + // NOLINTNEXTLINE(bugprone-use-after-move) + auto current = tuplify(call_one(CurrentRange(), std::forward(args)...)); + // NOLINTNEXTLINE(bugprone-use-after-move) auto remainder = NextStep::call(std::forward(args)...); return std::tuple_cat(std::move(current), std::move(remainder)); @@ -200,8 +204,8 @@ namespace util { using no = std::false_type; template - static auto test(int) -> decltype(apply_function_fusion_call(std::declval()), - yes()); + static auto test(int) + -> decltype(apply_function_fusion_call(std::declval()), yes()); template static no test(...); @@ -211,8 +215,7 @@ namespace util { template - class FunctionWrapper, + template class FunctionWrapper, typename WrapperArgs, int Shared = 0, int Start = Shared, @@ -248,8 +251,7 @@ namespace util { template - class FunctionWrapper, + template class FunctionWrapper, typename... WrapperArgs, int Shared, int Start, @@ -332,8 +334,7 @@ namespace util { * Otherwise it will be a false_type to indicate its failure. */ template - class FunctionWrapper, + template class FunctionWrapper, typename... WrapperArgs, int Shared, int Start, diff --git a/src/util/Logger.cpp b/src/util/Logger.cpp index 21bbc703..5fc1fd53 100644 --- a/src/util/Logger.cpp +++ b/src/util/Logger.cpp @@ -1,5 +1,30 @@ +/* + * MIT License + * + * Copyright (c) 2024 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + #include "Logger.hpp" +#include +#include + #include "../Reactor.hpp" #include "../dsl/word/emit/Inline.hpp" #include "../message/LogMessage.hpp" @@ -8,21 +33,27 @@ namespace NUClear { namespace util { - /** - * Get the current reactor that is running based on the passed in reactor, or the current task if not in a reactor. - * - * @param calling_reactor The reactor that is calling this function or nullptr if not called from a reactor - * - * @return The current reactor or nullptr if not in a reactor - */ - const Reactor* get_current_reactor(const Reactor* calling_reactor) { - if (calling_reactor != nullptr) { - return calling_reactor; + namespace { // Anonymous namespace for internal linkage + + /** + * Get the current reactor that is running based on the passed in reactor, or the current task if not in a + * reactor. + * + * @param calling_reactor The reactor that is calling this function or nullptr if not called from a reactor + * + * @return The current reactor or nullptr if not in a reactor + */ + const Reactor* get_current_reactor(const Reactor* calling_reactor) { + if (calling_reactor != nullptr) { + return calling_reactor; + } + // Get the current task + const auto* const current_task = threading::ReactionTask::get_current_task(); + return current_task != nullptr && current_task->parent != nullptr ? ¤t_task->parent->reactor + : nullptr; } - // Get the current task - const auto* const current_task = threading::ReactionTask::get_current_task(); - return current_task != nullptr && current_task->parent != nullptr ? ¤t_task->parent->reactor : nullptr; - } + + } // namespace Logger::LogLevels Logger::get_current_log_levels(const Reactor* calling_reactor) { // Get the current reactor either from the passed in reactor or the current task diff --git a/src/util/Logger.hpp b/src/util/Logger.hpp index 9fae6377..ca240dea 100644 --- a/src/util/Logger.hpp +++ b/src/util/Logger.hpp @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2013 NUClear Contributors + * Copyright (c) 2024 NUClear Contributors * * This file is part of the NUClear codebase. * See https://github.com/Fastcode/NUClear for further info. diff --git a/src/util/TypeMap.hpp b/src/util/TypeMap.hpp index 4ba0d4d1..43e4b609 100644 --- a/src/util/TypeMap.hpp +++ b/src/util/TypeMap.hpp @@ -80,7 +80,7 @@ namespace util { * * @param d A pointer to the data to be stored (the map takes ownership) */ - static void set(std::shared_ptr d) { + static void set(const std::shared_ptr& d) { const std::lock_guard lock(data_mutex); data = d; } diff --git a/src/util/platform.hpp b/src/util/platform.hpp index b67b992e..a151deaf 100644 --- a/src/util/platform.hpp +++ b/src/util/platform.hpp @@ -181,6 +181,8 @@ struct WSAHolder { #else // Include real networking stuff + // export with IWYU as this is the header that should be used for these functions + // IWYU pragma: begin_exports #include #include #include @@ -192,6 +194,7 @@ struct WSAHolder { #include #include #include + // IWYU pragma: end_exports #include diff --git a/src/util/precise_sleep.cpp b/src/util/precise_sleep.cpp index 37b53617..83d9957a 100644 --- a/src/util/precise_sleep.cpp +++ b/src/util/precise_sleep.cpp @@ -22,9 +22,13 @@ #include "precise_sleep.hpp" +#include // NOLINT(modernize-deprecated-headers) Technically nanosleep lives in time.h not ctime + +#include +#include + #if defined(_WIN32) - #include #include #include @@ -61,8 +65,6 @@ namespace util { #else #include - #include - #include namespace NUClear { namespace util { diff --git a/src/util/serialise/Serialise.hpp b/src/util/serialise/Serialise.hpp index 32f4247e..f3516896 100644 --- a/src/util/serialise/Serialise.hpp +++ b/src/util/serialise/Serialise.hpp @@ -115,7 +115,7 @@ namespace util { static uint64_t hash() { // Serialise based on the demangled class name - std::string type_name = demangle(typeid(T).name()); + const std::string type_name = demangle(typeid(T).name()); return xxhash64(type_name.c_str(), type_name.size(), 0x4e55436c); } }; diff --git a/src/util/usage_clock.cpp b/src/util/usage_clock.cpp index fd132277..32b36551 100644 --- a/src/util/usage_clock.cpp +++ b/src/util/usage_clock.cpp @@ -1,6 +1,9 @@ #include "usage_clock.hpp" +#include // NOLINT(modernize-deprecated-headers) Technically clock_gettime lives in time.h not ctime + #include +#include // Windows #if defined(_WIN32) @@ -27,14 +30,15 @@ namespace util { } // namespace NUClear #else - #include namespace NUClear { namespace util { cpu_clock::time_point cpu_clock::now() noexcept { ::timespec ts{}; - ::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); + if (::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) { + return time_point{}; // Error, return a default time point + } return time_point(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5f01f998..9520419b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,12 +42,12 @@ set_target_properties(${catch2_target} PROPERTIES CMAKE_CXX_FLAGS "") # Create a test_util library that is used by all tests file(GLOB_RECURSE test_util_src "test_util/*.cpp") add_library(test_util OBJECT ${test_util_src}) +# This is linking WHOLE_ARCHIVE as otherwise the linker will remove the WSAHolder from the final binary +# As a result the WSA initialisation code won't run and the network tests will fail target_link_libraries(test_util INTERFACE "$") target_link_libraries(test_util PUBLIC Catch2::Catch2) +target_include_directories(test_util PUBLIC ${PROJECT_BINARY_DIR}/include ${PROJECT_SOURCE_DIR}/src) target_include_directories(test_util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories( - test_util SYSTEM PUBLIC ${CATCH_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/include "${PROJECT_SOURCE_DIR}/src" -) # Create a test binary for each test file file(GLOB_RECURSE test_sources "tests/*.cpp") diff --git a/tests/networktest.cpp b/tests/networktest.cpp index d96a3c25..581a712a 100644 --- a/tests/networktest.cpp +++ b/tests/networktest.cpp @@ -20,11 +20,18 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include #include +#include #include #include -#include +#include +#include +#include +#include +#include + +#include "nuclear" struct PerformEmits {}; diff --git a/tests/test_util/TestBase.hpp b/tests/test_util/TestBase.hpp index 8b18a15a..f2ae2151 100644 --- a/tests/test_util/TestBase.hpp +++ b/tests/test_util/TestBase.hpp @@ -28,7 +28,7 @@ #include #include "nuclear" -#include "test_util/diff_string.hpp" +#include "test_util/diff_string.hpp" // IWYU pragma: export namespace test_util { @@ -54,6 +54,7 @@ class TestBase : public NUClear::Reactor { std::string message; }; +private: explicit TestBase(std::unique_ptr environment, const bool& shutdown_on_idle = true, const std::chrono::milliseconds& timeout = std::chrono::milliseconds(1000)) @@ -93,10 +94,15 @@ class TestBase : public NUClear::Reactor { }); } -private: + /// Mutex to wait on for the test timeout std::mutex timeout_mutex; + /// Condition variable to wait on for the test timeout std::condition_variable timeout_cv; + /// If the shutdown was clean bool clean_shutdown = false; + + // CRTP subclass is a friend of the base class so it can access the constructor + friend BaseClass; }; } // namespace test_util diff --git a/tests/test_util/common.hpp b/tests/test_util/common.hpp index fc80e51c..f302829e 100644 --- a/tests/test_util/common.hpp +++ b/tests/test_util/common.hpp @@ -23,9 +23,8 @@ #ifndef TEST_UTIL_COMMON_HPP #define TEST_UTIL_COMMON_HPP -#include - #include "executable_path.hpp" +#include "nuclear" namespace test_util { diff --git a/tests/test_util/diff_string.cpp b/tests/test_util/diff_string.cpp index 078d24e8..709a7ebf 100644 --- a/tests/test_util/diff_string.cpp +++ b/tests/test_util/diff_string.cpp @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include "lcs.hpp" diff --git a/tests/test_util/executable_path.cpp b/tests/test_util/executable_path.cpp index 365f7367..70a2567d 100644 --- a/tests/test_util/executable_path.cpp +++ b/tests/test_util/executable_path.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -59,6 +59,8 @@ std::string get_executable_path() { } // namespace test_util #elif defined(__linux__) + #include + #include #include namespace test_util { diff --git a/tests/test_util/has_ipv6.cpp b/tests/test_util/has_ipv6.cpp index ed5afa8e..88aa82ab 100644 --- a/tests/test_util/has_ipv6.cpp +++ b/tests/test_util/has_ipv6.cpp @@ -22,7 +22,10 @@ #include "has_ipv6.hpp" -#include +#include + +#include "util/network/get_interfaces.hpp" +#include "util/platform.hpp" namespace test_util { diff --git a/tests/test_util/lcs.hpp b/tests/test_util/lcs.hpp index 46e36e76..0b95f925 100644 --- a/tests/test_util/lcs.hpp +++ b/tests/test_util/lcs.hpp @@ -74,7 +74,7 @@ std::pair, std::vector> lcs(const std::vector& a, con a[x] == b[y] ? (x == 0 ? (y + 1) * insert_weight : last_weights[x - 1]) : 0x7FFFFFFF; // Find the smallest weight - const int min_weight = std::min(std::min(weight_from_left, weight_from_top), weight_from_diagonal); + const int min_weight = std::min({weight_from_left, weight_from_top, weight_from_diagonal}); curr_weights[x] = min_weight; const int direction = (min_weight == weight_from_diagonal ? 0x01 : 0x0) // diff --git a/tests/tests/api/LogLevel.cpp b/tests/tests/api/LogLevel.cpp index 1db06fb6..733c9c16 100644 --- a/tests/tests/api/LogLevel.cpp +++ b/tests/tests/api/LogLevel.cpp @@ -1,11 +1,31 @@ -#define CATCH_CONFIG_MAIN +/* + * MIT License + * + * Copyright (c) 2024 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + #include "LogLevel.hpp" #include #include -#include -#include #include +#include #include SCENARIO("LogLevel smart enum values can be constructed and converted appropriately") { diff --git a/tests/tests/api/ReactionHandle.cpp b/tests/tests/api/ReactionHandle.cpp index 427ecf01..0dc567a7 100644 --- a/tests/tests/api/ReactionHandle.cpp +++ b/tests/tests/api/ReactionHandle.cpp @@ -20,12 +20,18 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" +namespace { // Make everything in this file have internal linkage class TestReactor : public test_util::TestBase { public: @@ -66,6 +72,7 @@ class TestReactor : public test_util::TestBase { std::vector events; }; +} // namespace TEST_CASE("Testing reaction handle functionality", "[api][reactionhandle]") { NUClear::Configuration config; diff --git a/tests/tests/api/ReactionStatistics.cpp b/tests/tests/api/ReactionStatistics.cpp index 9d8d412d..ed3360c9 100644 --- a/tests/tests/api/ReactionStatistics.cpp +++ b/tests/tests/api/ReactionStatistics.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/api/ReactionStatisticsTiming.cpp b/tests/tests/api/ReactionStatisticsTiming.cpp index f0ee9904..ce642929 100644 --- a/tests/tests/api/ReactionStatisticsTiming.cpp +++ b/tests/tests/api/ReactionStatisticsTiming.cpp @@ -20,43 +20,42 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" #include "util/precise_sleep.hpp" -using TimeUnit = test_util::TimeUnit; - -/// Events that occur during the test and the time they occur -/// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -std::vector> code_events; -/// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -std::vector> stat_events; - -struct Usage { - std::map real; - std::map cpu; -}; - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -Usage usage; - -struct DoTest {}; -struct HeavyTask {}; -struct LightTask {}; - -const std::string heavy_name = "Heavy"; // NOLINT(cert-err58-cpp) -const std::string light_name = "Light"; // NOLINT(cert-err58-cpp) -const std::string initial_name = "Initial"; // NOLINT(cert-err58-cpp) -constexpr int scale = 5; // Number of time units to sleep/wait for - using NUClear::message::ReactionEvent; +using test_util::TimeUnit; class TestReactor : public test_util::TestBase { public: + struct Usage { + std::map real; + std::map cpu; + }; + + struct DoTest {}; + struct HeavyTask {}; + struct LightTask {}; + + const std::string heavy_name = "Heavy"; // NOLINT(cert-err58-cpp) + const std::string light_name = "Light"; // NOLINT(cert-err58-cpp) + const std::string initial_name = "Initial"; // NOLINT(cert-err58-cpp) + static constexpr int scale = 5; // Number of time units to sleep/wait for + TestReactor(std::unique_ptr environment) : TestBase(std::move(environment), true, std::chrono::seconds(2)) { @@ -66,7 +65,7 @@ class TestReactor : public test_util::TestBase { emit(std::make_unique()); code_events.emplace_back("Finished " + initial_name + ":" + heavy_name, NUClear::clock::now()); }); - on>().then(heavy_name, [] { + on>().then(heavy_name, [this] { code_events.emplace_back("Started " + heavy_name, NUClear::clock::now()); auto start = NUClear::clock::now(); while (NUClear::clock::now() - start < TimeUnit(scale)) { @@ -80,13 +79,13 @@ class TestReactor : public test_util::TestBase { emit(std::make_unique()); code_events.emplace_back("Finished " + initial_name + ":" + light_name, NUClear::clock::now()); }); - on>().then(light_name, [] { + on>().then(light_name, [this] { code_events.emplace_back("Started " + light_name, NUClear::clock::now()); NUClear::util::precise_sleep(TimeUnit(scale)); code_events.emplace_back("Finished " + light_name, NUClear::clock::now()); }); - on>().then([](const ReactionEvent& event) { + on>().then([this](const ReactionEvent& event) { const auto& stats = *event.statistics; // Check the name ends with light_name or heavy_name if (stats.identifiers->name.substr(stats.identifiers->name.size() - light_name.size()) == light_name @@ -116,7 +115,16 @@ class TestReactor : public test_util::TestBase { emit(std::make_unique>()); }); } + + /// Code events that occur during the test and the time they occur + std::vector> code_events; + /// Statistic events that occur during the test and the time they occur + std::vector> stat_events; + /// Usage statistics for the heavy and light tasks + Usage usage; }; +// Needed because until c++17 this value will cause a linker error if it is not defined in a cpp file +constexpr int TestReactor::scale; TEST_CASE("Testing reaction statistics timing", "[api][reactionstatistics][timing]") { @@ -125,16 +133,24 @@ TEST_CASE("Testing reaction statistics timing", "[api][reactionstatistics][timin config.default_pool_concurrency = 1; NUClear::PowerPlant plant(config); test_util::add_tracing(plant); - plant.install(); + auto& reactor = plant.install(); plant.start(); + // Extract variables + const auto& code_events = reactor.code_events; + auto& stat_events = reactor.stat_events; + const auto& usage = reactor.usage; + constexpr int scale = TestReactor::scale; + const auto& heavy_name = reactor.heavy_name; + const auto& light_name = reactor.light_name; + // Sort the stats events by timestamp as they are not always going to be in order due to how stats are processed std::stable_sort(stat_events.begin(), stat_events.end(), [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }); - auto make_delta = [](const std::vector>& events) { + auto make_delta = [&](const std::vector>& events) { std::vector delta_events; auto first = events.front().second; for (const auto& event : events) { @@ -175,8 +191,8 @@ TEST_CASE("Testing reaction statistics timing", "[api][reactionstatistics][timin } // Most of heavy real time should be cpu time - REQUIRE(usage.cpu[heavy_name] > usage.real[heavy_name] / 2); + REQUIRE(usage.cpu.at(heavy_name) > usage.real.at(heavy_name) / 2); // Most of light real time should be sleeping - REQUIRE(usage.cpu[light_name] < usage.real[light_name] / 2); + REQUIRE(usage.cpu.at(light_name) < usage.real.at(light_name) / 2); } diff --git a/tests/tests/api/ReactorArgs.cpp b/tests/tests/api/ReactorArgs.cpp index 0c9c3f79..53b3e879 100644 --- a/tests/tests/api/ReactorArgs.cpp +++ b/tests/tests/api/ReactorArgs.cpp @@ -21,7 +21,12 @@ */ #include -#include +#include +#include +#include +#include + +#include "nuclear" class TestReactorNoArgs : public NUClear::Reactor { public: diff --git a/tests/tests/api/TimeTravel.cpp b/tests/tests/api/TimeTravel.cpp index bf1c128a..834fada2 100644 --- a/tests/tests/api/TimeTravel.cpp +++ b/tests/tests/api/TimeTravel.cpp @@ -1,7 +1,37 @@ +/* + * MIT License + * + * Copyright (c) 2024 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/api/TimeTravelFrozen.cpp b/tests/tests/api/TimeTravelFrozen.cpp index bad45e46..3aca9066 100644 --- a/tests/tests/api/TimeTravelFrozen.cpp +++ b/tests/tests/api/TimeTravelFrozen.cpp @@ -1,8 +1,36 @@ +/* + * MIT License + * + * Copyright (c) 2024 NUClear Contributors + * + * This file is part of the NUClear codebase. + * See https://github.com/Fastcode/NUClear for further info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include #include #include -#include -#include - +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" #include "util/precise_sleep.hpp" diff --git a/tests/tests/dsl/Always.cpp b/tests/tests/dsl/Always.cpp index 841173b6..3dd10851 100644 --- a/tests/tests/dsl/Always.cpp +++ b/tests/tests/dsl/Always.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" @@ -62,6 +67,7 @@ TEST_CASE("The Always DSL keyword runs continuously when it can", "[api][always] NUClear::Configuration config; config.default_pool_concurrency = 1; NUClear::PowerPlant plant(config); + test_util::add_tracing(plant); auto& reactor = plant.install(); plant.start(); diff --git a/tests/tests/dsl/ArgumentFission.cpp b/tests/tests/dsl/ArgumentFission.cpp index cb8c2b0c..4fe4aff1 100644 --- a/tests/tests/dsl/ArgumentFission.cpp +++ b/tests/tests/dsl/ArgumentFission.cpp @@ -20,13 +20,21 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include #include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" +namespace { // Make everything in this file have internal linkage + /// Events that occur during the test std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -84,6 +92,7 @@ class TestReactor : public test_util::TestBase { } }; +} // namespace TEST_CASE("Testing distributing arguments to multiple bind functions (NUClear Fission)", "[api][dsl][fission]") { diff --git a/tests/tests/dsl/BlockNoData.cpp b/tests/tests/dsl/BlockNoData.cpp index 702728ac..ca98bce9 100644 --- a/tests/tests/dsl/BlockNoData.cpp +++ b/tests/tests/dsl/BlockNoData.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Buffer.cpp b/tests/tests/dsl/Buffer.cpp index 5e465ef0..53dfc669 100644 --- a/tests/tests/dsl/Buffer.cpp +++ b/tests/tests/dsl/Buffer.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/CommandLineArguments.cpp b/tests/tests/dsl/CommandLineArguments.cpp index 0acaea5f..977b643c 100644 --- a/tests/tests/dsl/CommandLineArguments.cpp +++ b/tests/tests/dsl/CommandLineArguments.cpp @@ -20,10 +20,15 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include #include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/CustomGet.cpp b/tests/tests/dsl/CustomGet.cpp index 6439379f..31c3967e 100644 --- a/tests/tests/dsl/CustomGet.cpp +++ b/tests/tests/dsl/CustomGet.cpp @@ -20,13 +20,24 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "dsl/operation/TypeBind.hpp" +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" -struct CustomGet : NUClear::dsl::operation::TypeBind { +struct CustomGet { + + template + static void bind(const std::shared_ptr& reaction) { + NUClear::dsl::operation::TypeBind::template bind(reaction); + } template static std::shared_ptr get(const NUClear::threading::ReactionTask& /*task*/) { diff --git a/tests/tests/dsl/DSLOrdering.cpp b/tests/tests/dsl/DSLOrdering.cpp index 7deea04f..f870a2c4 100644 --- a/tests/tests/dsl/DSLOrdering.cpp +++ b/tests/tests/dsl/DSLOrdering.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/DSLProxy.cpp b/tests/tests/dsl/DSLProxy.cpp index 7aec106e..767ae423 100644 --- a/tests/tests/dsl/DSLProxy.cpp +++ b/tests/tests/dsl/DSLProxy.cpp @@ -20,9 +20,18 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include +#include "dsl/operation/DSLProxy.hpp" +#include +#include +#include +#include +#include +#include + +#include "dsl/operation/CacheGet.hpp" +#include "dsl/operation/TypeBind.hpp" +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Every.cpp b/tests/tests/dsl/Every.cpp index 02c987f1..ca6b00df 100644 --- a/tests/tests/dsl/Every.cpp +++ b/tests/tests/dsl/Every.cpp @@ -20,10 +20,19 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" @@ -49,6 +58,8 @@ class TestReactor : public test_util::TestBase { std::vector dynamic_times; }; +namespace { + void test_results(const std::vector& times) { // Build up our difference vector @@ -73,6 +84,7 @@ void test_results(const std::vector& times) { REQUIRE(std::abs(mean + stddev * 2) < 0.008); } +} // namespace TEST_CASE("Testing the Every<> DSL word", "[api][every][per]") { diff --git a/tests/tests/dsl/FlagMessage.cpp b/tests/tests/dsl/FlagMessage.cpp index 33b81b19..269acced 100644 --- a/tests/tests/dsl/FlagMessage.cpp +++ b/tests/tests/dsl/FlagMessage.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/FusionInOrder.cpp b/tests/tests/dsl/FusionInOrder.cpp index 2679b53b..9313c743 100644 --- a/tests/tests/dsl/FusionInOrder.cpp +++ b/tests/tests/dsl/FusionInOrder.cpp @@ -21,7 +21,13 @@ */ #include -#include +#include +#include +#include + +#include "nuclear" + +namespace { // Make everything here internal linkage std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,-warnings-as-errors) @@ -36,11 +42,11 @@ struct Extension { class TestReactor : public NUClear::Reactor { public: TestReactor(std::unique_ptr environment) : Reactor(std::move(environment)) { - on, Extension<1>, Extension<2>, Extension<3>, Extension<4>>().then([] {}); } }; +} // namespace TEST_CASE("Testing that the bind functions of extensions are executed in order", "[api][extension][bind]") { diff --git a/tests/tests/dsl/GroupPool.cpp b/tests/tests/dsl/GroupPool.cpp index df6a1794..d11be152 100644 --- a/tests/tests/dsl/GroupPool.cpp +++ b/tests/tests/dsl/GroupPool.cpp @@ -20,11 +20,17 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" +#include "util/Sequence.hpp" class TestReactor : public test_util::TestBase { public: diff --git a/tests/tests/dsl/IO.cpp b/tests/tests/dsl/IO.cpp index ac9493ca..0d4aee9f 100644 --- a/tests/tests/dsl/IO.cpp +++ b/tests/tests/dsl/IO.cpp @@ -20,18 +20,24 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include - -#include "test_util/TestBase.hpp" -#include "test_util/common.hpp" - // Windows can't do this test as it doesn't have file descriptors #ifndef _WIN32 + #include + #include #include - #include + #include + #include + #include + #include + #include + #include + #include + + #include "nuclear" + #include "test_util/TestBase.hpp" + #include "test_util/common.hpp" class TestReactor : public test_util::TestBase { public: @@ -137,6 +143,8 @@ TEST_CASE("Testing the IO extension", "[api][io]") { #else + #include + #include TEST_CASE("Testing the IO extension", "[api][io]") { SUCCEED("This test is not supported on Windows"); diff --git a/tests/tests/dsl/Idle.cpp b/tests/tests/dsl/Idle.cpp index 8b3f9cd7..5e4026f3 100644 --- a/tests/tests/dsl/Idle.cpp +++ b/tests/tests/dsl/Idle.cpp @@ -20,9 +20,17 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/IdleCrossPool.cpp b/tests/tests/dsl/IdleCrossPool.cpp index cc710770..80a79a98 100644 --- a/tests/tests/dsl/IdleCrossPool.cpp +++ b/tests/tests/dsl/IdleCrossPool.cpp @@ -20,9 +20,15 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/IdleGlobal.cpp b/tests/tests/dsl/IdleGlobal.cpp index 47d280ff..e22b72fe 100644 --- a/tests/tests/dsl/IdleGlobal.cpp +++ b/tests/tests/dsl/IdleGlobal.cpp @@ -20,9 +20,12 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/IdleSingle.cpp b/tests/tests/dsl/IdleSingle.cpp index 27459cf4..61d05ea8 100644 --- a/tests/tests/dsl/IdleSingle.cpp +++ b/tests/tests/dsl/IdleSingle.cpp @@ -20,11 +20,19 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" -#include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" #include "util/precise_sleep.hpp" diff --git a/tests/tests/dsl/IdleSingleGlobal.cpp b/tests/tests/dsl/IdleSingleGlobal.cpp index 2d399434..76c044c2 100644 --- a/tests/tests/dsl/IdleSingleGlobal.cpp +++ b/tests/tests/dsl/IdleSingleGlobal.cpp @@ -20,11 +20,19 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" -#include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" namespace Catch { diff --git a/tests/tests/dsl/IdleSync.cpp b/tests/tests/dsl/IdleSync.cpp index dde936d1..1cb648a2 100644 --- a/tests/tests/dsl/IdleSync.cpp +++ b/tests/tests/dsl/IdleSync.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Inline.cpp b/tests/tests/dsl/Inline.cpp index ea0cfd4b..84445227 100644 --- a/tests/tests/dsl/Inline.cpp +++ b/tests/tests/dsl/Inline.cpp @@ -20,12 +20,21 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" +#include "threading/scheduler/Pool.hpp" #include "util/precise_sleep.hpp" class TestReactor : public test_util::TestBase { diff --git a/tests/tests/dsl/Last.cpp b/tests/tests/dsl/Last.cpp index da05d4f0..7c1300a8 100644 --- a/tests/tests/dsl/Last.cpp +++ b/tests/tests/dsl/Last.cpp @@ -20,9 +20,16 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/MainThread.cpp b/tests/tests/dsl/MainThread.cpp index 99f931c8..3eb0dca9 100644 --- a/tests/tests/dsl/MainThread.cpp +++ b/tests/tests/dsl/MainThread.cpp @@ -20,9 +20,15 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/MissingArguments.cpp b/tests/tests/dsl/MissingArguments.cpp index 479f311c..b984ae04 100644 --- a/tests/tests/dsl/MissingArguments.cpp +++ b/tests/tests/dsl/MissingArguments.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Once.cpp b/tests/tests/dsl/Once.cpp index d8bff7e4..fc277fa9 100644 --- a/tests/tests/dsl/Once.cpp +++ b/tests/tests/dsl/Once.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Optional.cpp b/tests/tests/dsl/Optional.cpp index 8a09e68b..27891576 100644 --- a/tests/tests/dsl/Optional.cpp +++ b/tests/tests/dsl/Optional.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Priority.cpp b/tests/tests/dsl/Priority.cpp index ae650f73..e160f01b 100644 --- a/tests/tests/dsl/Priority.cpp +++ b/tests/tests/dsl/Priority.cpp @@ -20,10 +20,17 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include #include -#include +#include #include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Raw.cpp b/tests/tests/dsl/Raw.cpp index e28712b9..1c8ea6b2 100644 --- a/tests/tests/dsl/Raw.cpp +++ b/tests/tests/dsl/Raw.cpp @@ -21,8 +21,11 @@ */ #include -#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/RawFunction.cpp b/tests/tests/dsl/RawFunction.cpp index b7d7c7dd..277cac73 100644 --- a/tests/tests/dsl/RawFunction.cpp +++ b/tests/tests/dsl/RawFunction.cpp @@ -20,12 +20,19 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" +namespace { // Anonymous namespace to ensure internal linkage + /// Events that occur during the test std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -79,6 +86,8 @@ void raw_function_test_both_args(const Message& msg, const Data& data) { events.push_back("Raw function both args: " + msg.data + " " + data.data); } +} // namespace + class TestReactor : public test_util::TestBase { public: TestReactor(std::unique_ptr environment) : TestBase(std::move(environment)) { diff --git a/tests/tests/dsl/Shutdown.cpp b/tests/tests/dsl/Shutdown.cpp index 9f644217..a4e9f6e0 100644 --- a/tests/tests/dsl/Shutdown.cpp +++ b/tests/tests/dsl/Shutdown.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Startup.cpp b/tests/tests/dsl/Startup.cpp index f4b72d07..727a4d12 100644 --- a/tests/tests/dsl/Startup.cpp +++ b/tests/tests/dsl/Startup.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Sync.cpp b/tests/tests/dsl/Sync.cpp index 2d95c4c0..fb0182e4 100644 --- a/tests/tests/dsl/Sync.cpp +++ b/tests/tests/dsl/Sync.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/SyncMulti.cpp b/tests/tests/dsl/SyncMulti.cpp index b0e69b6e..9177534f 100644 --- a/tests/tests/dsl/SyncMulti.cpp +++ b/tests/tests/dsl/SyncMulti.cpp @@ -20,9 +20,15 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/SyncOrder.cpp b/tests/tests/dsl/SyncOrder.cpp index ee3f47ba..a9caa2c7 100644 --- a/tests/tests/dsl/SyncOrder.cpp +++ b/tests/tests/dsl/SyncOrder.cpp @@ -21,11 +21,11 @@ */ #include -#include -#include -#include +#include +#include #include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/TCP.cpp b/tests/tests/dsl/TCP.cpp index da049bba..db872e63 100644 --- a/tests/tests/dsl/TCP.cpp +++ b/tests/tests/dsl/TCP.cpp @@ -20,15 +20,25 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" #include "test_util/has_ipv6.hpp" - -/// Events that occur during the test -std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +#include "util/FileDescriptor.hpp" +#include "util/network/resolve.hpp" +#include "util/network/sock_t.hpp" +#include "util/platform.hpp" enum TestPorts : in_port_t { KNOWN_V4_PORT = 40010, @@ -41,23 +51,19 @@ enum TestType : uint8_t { V6_KNOWN, V6_EPHEMERAL, }; -std::vector active_tests; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -in_port_t v4_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -in_port_t v6_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -struct TestConnection { - TestConnection(std::string name, std::string address, in_port_t port) - : name(std::move(name)), address(std::move(address)), port(port) {} - std::string name; - std::string address; - in_port_t port; -}; - -struct Finished {}; class TestReactor : public test_util::TestBase { public: + struct TestConnection { + TestConnection(std::string name, std::string address, in_port_t port) + : name(std::move(name)), address(std::move(address)), port(port) {} + std::string name; + std::string address; + in_port_t port; + }; + + struct Finished {}; + void handle_data(const std::string& name, const IO::Event& event) { // We have data to read if ((event.events & IO::READ) != 0) { @@ -77,8 +83,8 @@ class TestReactor : public test_util::TestBase { } } - TestReactor(std::unique_ptr environment) - : TestBase(std::move(environment), false, std::chrono::seconds(2)) { + TestReactor(std::unique_ptr environment, const std::vector& active_tests_) + : TestBase(std::move(environment), false, std::chrono::seconds(2)), active_tests(active_tests_) { for (const auto& t : active_tests) { switch (t) { @@ -122,7 +128,7 @@ class TestReactor : public test_util::TestBase { } // Send a test message to the known port - on, Sync>().then([](const TestConnection& target) { + on, Sync>().then([this](const TestConnection& target) { // Resolve the target address const NUClear::util::network::sock_t address = NUClear::util::network::resolve(target.address, target.port); @@ -193,7 +199,18 @@ class TestReactor : public test_util::TestBase { }); } + /// Events that occur during the test + std::vector events; + private: + /// The active tests to run + std::vector active_tests; + + /// The bound ephemeral port for IPv4 + in_port_t v4_port = 0; + /// The bound ephemeral port for IPv6 + in_port_t v6_port = 0; + size_t test_no = 0; NUClear::util::FileDescriptor known_port_fd; NUClear::util::FileDescriptor ephemeral_port_fd; @@ -203,6 +220,7 @@ class TestReactor : public test_util::TestBase { TEST_CASE("Testing listening for TCP connections and receiving data messages", "[api][network][tcp]") { // First work out what tests will be active + std::vector active_tests; active_tests.push_back(V4_KNOWN); active_tests.push_back(V4_EPHEMERAL); if (test_util::has_ipv6()) { @@ -215,7 +233,7 @@ TEST_CASE("Testing listening for TCP connections and receiving data messages", " NUClear::PowerPlant plant(config); test_util::add_tracing(plant); plant.install(); - plant.install(); + auto& reactor = plant.install(active_tests); plant.start(); // Get the results for the tests we expect @@ -251,8 +269,8 @@ TEST_CASE("Testing listening for TCP connections and receiving data messages", " expected.push_back("Finishing Test"); // Make an info print the diff in an easy to read way if we fail - INFO(test_util::diff_string(expected, events)); + INFO(test_util::diff_string(expected, reactor.events)); // Check the events fired in order and only those events - REQUIRE(events == expected); + REQUIRE(reactor.events == expected); } diff --git a/tests/tests/dsl/TaskScope.cpp b/tests/tests/dsl/TaskScope.cpp index eb192a5a..66e94b2c 100644 --- a/tests/tests/dsl/TaskScope.cpp +++ b/tests/tests/dsl/TaskScope.cpp @@ -20,10 +20,18 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include #include -#include +#include +#include +#include #include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" @@ -122,7 +130,7 @@ TEST_CASE("Test that Trigger statements get the correct data", "[api][trigger]") NUClear::Configuration config; config.default_pool_concurrency = 1; NUClear::PowerPlant plant(config); - // test_util::add_tracing(plant); + test_util::add_tracing(plant); const auto& reactor = plant.install(); plant.start(); diff --git a/tests/tests/dsl/Transient.cpp b/tests/tests/dsl/Transient.cpp index dd957406..88a1e8ef 100644 --- a/tests/tests/dsl/Transient.cpp +++ b/tests/tests/dsl/Transient.cpp @@ -20,9 +20,18 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include - +#include +#include +#include +#include +#include + +#include "dsl/operation/CacheGet.hpp" +#include "dsl/operation/TypeBind.hpp" +#include "dsl/trait/is_transient.hpp" +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/Trigger.cpp b/tests/tests/dsl/Trigger.cpp index cf70e85a..fffc5f65 100644 --- a/tests/tests/dsl/Trigger.cpp +++ b/tests/tests/dsl/Trigger.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/UDP.cpp b/tests/tests/dsl/UDP.cpp index 6d14ce4b..38ede417 100644 --- a/tests/tests/dsl/UDP.cpp +++ b/tests/tests/dsl/UDP.cpp @@ -20,15 +20,26 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include + +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" #include "test_util/has_ipv6.hpp" +#include "util/network/get_interfaces.hpp" +#include "util/platform.hpp" -/// Events that occur during the test -std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +namespace { // Anonymous namespace to ensure internal linkage enum TestPorts : in_port_t { UNICAST_V4 = 40000, @@ -51,13 +62,6 @@ const std::string IPV6_BIND = "::1"; // NOLINT(cert-err58-cpp) const std::string IPV6_BIND = "::"; // NOLINT(cert-err58-cpp) #endif -// Ephemeral ports that we will use -in_port_t uni_v4_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -in_port_t uni_v6_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -in_port_t broad_v4_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -in_port_t multi_v4_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -in_port_t multi_v6_port = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - enum TestType : uint8_t { UNICAST_V4_KNOWN, UNICAST_V4_EPHEMERAL, @@ -70,9 +74,8 @@ enum TestType : uint8_t { MULTICAST_V6_KNOWN, MULTICAST_V6_EPHEMERAL, }; -std::vector active_tests; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -inline std::string get_broadcast_addr() { +std::string get_broadcast_addr() { static std::string addr; if (!addr.empty()) { @@ -96,73 +99,77 @@ inline std::string get_broadcast_addr() { return addr; } -struct SendTarget { - std::string data; - struct Target { - std::string address; - in_port_t port = 0; +} // namespace + +class TestReactor : public test_util::TestBase { +public: + struct Finished { + Finished(std::string name) : name(std::move(name)) {} + std::string name; }; - Target to{}; - Target from{}; -}; -std::vector send_targets(const std::string& type, in_port_t port) { - std::vector results; - // Loop through the active tests and add the send targets - // Make sure that the type we are actually after is sent last - for (const auto& t : active_tests) { - switch (t) { - case UNICAST_V4_KNOWN: - case UNICAST_V4_EPHEMERAL: { - results.push_back(SendTarget{type + ":Uv4", {"127.0.0.1", port}, {}}); - } break; - case UNICAST_V6_KNOWN: - case UNICAST_V6_EPHEMERAL: { - results.push_back(SendTarget{type + ":Uv6", {"::1", port}, {}}); - } break; - case BROADCAST_V4_KNOWN: - case BROADCAST_V4_EPHEMERAL: { - results.push_back(SendTarget{type + ":Bv4", {get_broadcast_addr(), port}, {}}); - } break; - case MULTICAST_V4_KNOWN: - case MULTICAST_V4_EPHEMERAL: { - results.push_back(SendTarget{type + ":Mv4", {IPV4_MULTICAST_ADDRESS, port}, {}}); - } break; - case MULTICAST_V6_KNOWN: - case MULTICAST_V6_EPHEMERAL: { - results.push_back(SendTarget{type + ":Mv6", {IPV6_MULTICAST_ADDRESS, port}, {IPV6_BIND, 0}}); - } break; + + struct SendTarget { + std::string data; + struct Target { + std::string address; + in_port_t port = 0; + }; + Target to{}; + Target from{}; + }; + + std::vector send_targets(const std::string& type, in_port_t port) const { + std::vector results; + + // Loop through the active tests and add the send targets + // Make sure that the type we are actually after is sent last + for (const auto& t : active_tests) { + switch (t) { + case UNICAST_V4_KNOWN: + case UNICAST_V4_EPHEMERAL: { + results.push_back(SendTarget{type + ":Uv4", {"127.0.0.1", port}, {}}); + } break; + case UNICAST_V6_KNOWN: + case UNICAST_V6_EPHEMERAL: { + results.push_back(SendTarget{type + ":Uv6", {"::1", port}, {}}); + } break; + case BROADCAST_V4_KNOWN: + case BROADCAST_V4_EPHEMERAL: { + results.push_back(SendTarget{type + ":Bv4", {get_broadcast_addr(), port}, {}}); + } break; + case MULTICAST_V4_KNOWN: + case MULTICAST_V4_EPHEMERAL: { + results.push_back(SendTarget{type + ":Mv4", {IPV4_MULTICAST_ADDRESS, port}, {}}); + } break; + case MULTICAST_V6_KNOWN: + case MULTICAST_V6_EPHEMERAL: { + results.push_back(SendTarget{type + ":Mv6", {IPV6_MULTICAST_ADDRESS, port}, {IPV6_BIND, 0}}); + } break; + } } - } - // remove duplicates - results.erase(std::unique(results.begin(), - results.end(), - [](const SendTarget& a, const SendTarget& b) { - return a.to.address == b.to.address && a.to.port == b.to.port && a.data == b.data - && a.from.address == b.from.address && a.from.port == b.from.port; - }), - results.end()); - - // Stable sort so that the type we are after is last - std::stable_sort(results.begin(), results.end(), [](const SendTarget& /*a*/, const SendTarget& b) { - // We want to sort such that the one we are after is last and everything else is unmodified - // That means that every comparision except one should be false - // This is because equality is implied if a < b == false and b < a == false - // The only time we should return true is when b is our target (which would make a less than it) - return b.data.substr(0, 3) == b.data.substr(5, 8); - }); - - return results; -} + // remove duplicates + results.erase(std::unique(results.begin(), + results.end(), + [](const SendTarget& a, const SendTarget& b) { + return a.to.address == b.to.address && a.to.port == b.to.port && a.data == b.data + && a.from.address == b.from.address && a.from.port == b.from.port; + }), + results.end()); + + // Stable sort so that the type we are after is last + std::stable_sort(results.begin(), results.end(), [](const SendTarget& /*a*/, const SendTarget& b) { + // We want to sort such that the one we are after is last and everything else is unmodified + // That means that every comparision except one should be false + // This is because equality is implied if a < b == false and b < a == false + // The only time we should return true is when b is our target (which would make a less than it) + return b.data.substr(0, 3) == b.data.substr(5, 8); + }); -struct Finished { - Finished(std::string name) : name(std::move(name)) {} - std::string name; -}; + return results; + } -class TestReactor : public test_util::TestBase { -private: void handle_data(const std::string& name, const UDP::Packet& packet) { const std::string data(packet.payload.begin(), packet.payload.end()); @@ -176,8 +183,8 @@ class TestReactor : public test_util::TestBase { } } -public: - TestReactor(std::unique_ptr environment) : TestBase(std::move(environment), false) { + TestReactor(std::unique_ptr environment, const std::vector& active_tests_) + : TestBase(std::move(environment), false), active_tests(active_tests_) { for (const auto& t : active_tests) { switch (t) { @@ -343,7 +350,17 @@ class TestReactor : public test_util::TestBase { }); } + /// Events that occur during the test + std::vector events; + + in_port_t uni_v4_port = 0; // Ephemeral port for IPv4 unicast + in_port_t uni_v6_port = 0; // Ephemeral port for IPv6 unicast + in_port_t broad_v4_port = 0; // Ephemeral port for IPv4 broadcast + in_port_t multi_v4_port = 0; // Ephemeral port for IPv4 multicast + in_port_t multi_v6_port = 0; // Ephemeral port for IPv6 multicast + private: + std::vector active_tests; // The active tests to run size_t test_no = 0; }; @@ -351,6 +368,7 @@ class TestReactor : public test_util::TestBase { TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]") { // Build up the list of active tests based on what we have available + std::vector active_tests; active_tests.push_back(UNICAST_V4_KNOWN); active_tests.push_back(UNICAST_V4_EPHEMERAL); if (test_util::has_ipv6()) { @@ -371,7 +389,7 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" NUClear::PowerPlant plant(config); test_util::add_tracing(plant); plant.install(); - plant.install(); + const auto& reactor = plant.install(active_tests); plant.start(); std::vector expected; @@ -379,7 +397,7 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" switch (t) { case UNICAST_V4_KNOWN: { expected.push_back("- Known Unicast V4 Test -"); - for (const auto& line : send_targets("Uv4K", UNICAST_V4)) { + for (const auto& line : reactor.send_targets("Uv4K", UNICAST_V4)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } expected.push_back("Uv4K <- Uv4K:Uv4 (127.0.0.1:" + std::to_string(UNICAST_V4) + ")"); @@ -387,15 +405,15 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" case UNICAST_V4_EPHEMERAL: { expected.push_back("- Ephemeral Unicast V4 Test -"); - for (const auto& line : send_targets("Uv4E", uni_v4_port)) { + for (const auto& line : reactor.send_targets("Uv4E", reactor.uni_v4_port)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } - expected.push_back("Uv4E <- Uv4E:Uv4 (127.0.0.1:" + std::to_string(uni_v4_port) + ")"); + expected.push_back("Uv4E <- Uv4E:Uv4 (127.0.0.1:" + std::to_string(reactor.uni_v4_port) + ")"); } break; case UNICAST_V6_KNOWN: { expected.push_back("- Known Unicast V6 Test -"); - for (const auto& line : send_targets("Uv6K", UNICAST_V6)) { + for (const auto& line : reactor.send_targets("Uv6K", UNICAST_V6)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } expected.push_back("Uv6K <- Uv6K:Uv6 (::1:" + std::to_string(UNICAST_V6) + ")"); @@ -403,15 +421,15 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" case UNICAST_V6_EPHEMERAL: { expected.push_back("- Ephemeral Unicast V6 Test -"); - for (const auto& line : send_targets("Uv6E", uni_v6_port)) { + for (const auto& line : reactor.send_targets("Uv6E", reactor.uni_v6_port)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } - expected.push_back("Uv6E <- Uv6E:Uv6 (::1:" + std::to_string(uni_v6_port) + ")"); + expected.push_back("Uv6E <- Uv6E:Uv6 (::1:" + std::to_string(reactor.uni_v6_port) + ")"); } break; case BROADCAST_V4_KNOWN: { expected.push_back("- Known Broadcast V4 Test -"); - for (const auto& line : send_targets("Bv4K", BROADCAST_V4)) { + for (const auto& line : reactor.send_targets("Bv4K", BROADCAST_V4)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } expected.push_back("Bv4K <- Bv4K:Bv4 (" + get_broadcast_addr() + ":" + std::to_string(BROADCAST_V4) @@ -420,16 +438,16 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" case BROADCAST_V4_EPHEMERAL: { expected.push_back("- Ephemeral Broadcast V4 Test -"); - for (const auto& line : send_targets("Bv4E", broad_v4_port)) { + for (const auto& line : reactor.send_targets("Bv4E", reactor.broad_v4_port)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } - expected.push_back("Bv4E <- Bv4E:Bv4 (" + get_broadcast_addr() + ":" + std::to_string(broad_v4_port) - + ")"); + expected.push_back("Bv4E <- Bv4E:Bv4 (" + get_broadcast_addr() + ":" + + std::to_string(reactor.broad_v4_port) + ")"); } break; case MULTICAST_V4_KNOWN: { expected.push_back("- Known Multicast V4 Test -"); - for (const auto& line : send_targets("Mv4K", MULTICAST_V4)) { + for (const auto& line : reactor.send_targets("Mv4K", MULTICAST_V4)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } expected.push_back("Mv4K <- Mv4K:Mv4 (" + IPV4_MULTICAST_ADDRESS + ":" + std::to_string(MULTICAST_V4) @@ -438,16 +456,16 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" case MULTICAST_V4_EPHEMERAL: { expected.push_back("- Ephemeral Multicast V4 Test -"); - for (const auto& line : send_targets("Mv4E", multi_v4_port)) { + for (const auto& line : reactor.send_targets("Mv4E", reactor.multi_v4_port)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } - expected.push_back("Mv4E <- Mv4E:Mv4 (" + IPV4_MULTICAST_ADDRESS + ":" + std::to_string(multi_v4_port) - + ")"); + expected.push_back("Mv4E <- Mv4E:Mv4 (" + IPV4_MULTICAST_ADDRESS + ":" + + std::to_string(reactor.multi_v4_port) + ")"); } break; case MULTICAST_V6_KNOWN: { expected.push_back("- Known Multicast V6 Test -"); - for (const auto& line : send_targets("Mv6K", MULTICAST_V6)) { + for (const auto& line : reactor.send_targets("Mv6K", MULTICAST_V6)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } expected.push_back("Mv6K <- Mv6K:Mv6 (" + IPV6_MULTICAST_ADDRESS + ":" + std::to_string(MULTICAST_V6) @@ -456,18 +474,18 @@ TEST_CASE("Testing sending and receiving of UDP messages", "[api][network][udp]" case MULTICAST_V6_EPHEMERAL: { expected.push_back("- Ephemeral Multicast V6 Test -"); - for (const auto& line : send_targets("Mv6E", multi_v6_port)) { + for (const auto& line : reactor.send_targets("Mv6E", reactor.multi_v6_port)) { expected.push_back(" -> " + line.to.address + ":" + std::to_string(line.to.port)); } - expected.push_back("Mv6E <- Mv6E:Mv6 (" + IPV6_MULTICAST_ADDRESS + ":" + std::to_string(multi_v6_port) - + ")"); + expected.push_back("Mv6E <- Mv6E:Mv6 (" + IPV6_MULTICAST_ADDRESS + ":" + + std::to_string(reactor.multi_v6_port) + ")"); } break; } } // Make an info print the diff in an easy to read way if we fail - INFO(test_util::diff_string(expected, events)); + INFO(test_util::diff_string(expected, reactor.events)); // Check the events fired in order and only those events - REQUIRE(events == expected); + REQUIRE(reactor.events == expected); } diff --git a/tests/tests/dsl/Watchdog.cpp b/tests/tests/dsl/Watchdog.cpp index cf476c42..6f3eaf08 100644 --- a/tests/tests/dsl/Watchdog.cpp +++ b/tests/tests/dsl/Watchdog.cpp @@ -20,11 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include -#include +#include #include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/With.cpp b/tests/tests/dsl/With.cpp index fd389bcc..0124dcfa 100644 --- a/tests/tests/dsl/With.cpp +++ b/tests/tests/dsl/With.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/emit/Delay.cpp b/tests/tests/dsl/emit/Delay.cpp index 807aeb3e..c221dc43 100644 --- a/tests/tests/dsl/emit/Delay.cpp +++ b/tests/tests/dsl/emit/Delay.cpp @@ -20,9 +20,15 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/TimeUnit.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/dsl/emit/EmitFusion.cpp b/tests/tests/dsl/emit/EmitFusion.cpp index 36ff06d3..92f53ab0 100644 --- a/tests/tests/dsl/emit/EmitFusion.cpp +++ b/tests/tests/dsl/emit/EmitFusion.cpp @@ -20,12 +20,17 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include #include +#include +#include "nuclear" #include "test_util/TestBase.hpp" -#include "test_util/common.hpp" + +namespace { // Anonymous namespace for internal linkage /// Events that occur during the test std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,-warnings-as-errors) @@ -33,31 +38,33 @@ std::vector events; // NOLINT(cppcoreguidelines-avoid-non-const-gl template struct E1 { static void emit(const NUClear::PowerPlant& /*powerplant*/, - std::shared_ptr p, + const std::shared_ptr& p, const int& a, const std::string& b) { events.push_back("E1a " + *p + " " + std::to_string(a) + " " + b); } - static void emit(const NUClear::PowerPlant& /*powerplant*/, std::shared_ptr p, const std::string& c) { + static void emit(const NUClear::PowerPlant& /*powerplant*/, const std::shared_ptr& p, const std::string& c) { events.push_back("E1b " + *p + " " + c); } }; template struct E2 { - static void emit(const NUClear::PowerPlant& /*powerplant*/, std::shared_ptr p, const bool& d) { + static void emit(const NUClear::PowerPlant& /*powerplant*/, const std::shared_ptr& p, const bool& d) { events.push_back("E2a " + *p + " " + (d ? "true" : "false")); } static void emit(const NUClear::PowerPlant& /*powerplant*/, - std::shared_ptr p, + const std::shared_ptr& p, const int& e, const std::string& f) { events.push_back("E2b " + *p + " " + std::to_string(e) + " " + f); } }; +} // namespace + class TestReactor : public test_util::TestBase { public: TestReactor(std::unique_ptr environment) : TestBase(std::move(environment)) { diff --git a/tests/tests/dsl/emit/Initialise.cpp b/tests/tests/dsl/emit/Initialise.cpp index 5af96d46..e7b1b06f 100644 --- a/tests/tests/dsl/emit/Initialise.cpp +++ b/tests/tests/dsl/emit/Initialise.cpp @@ -20,9 +20,14 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include -#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/TestBase.hpp" #include "test_util/common.hpp" diff --git a/tests/tests/log/Log.cpp b/tests/tests/log/Log.cpp index a9dbb30c..c60d9c10 100644 --- a/tests/tests/log/Log.cpp +++ b/tests/tests/log/Log.cpp @@ -21,11 +21,16 @@ */ #include -#include -#include +#include +#include +#include +#include +#include +#include "nuclear" #include "test_util/common.hpp" -#include "test_util/executable_path.hpp" + +namespace { // Anonymous namespace for internal linkage // This is a free floating function that we can use to test the log function when not in a reactor template @@ -42,6 +47,8 @@ struct LogTestOutput { /// All the log messages received std::vector messages; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +} // namespace + // All the log levels // NOLINTNEXTLINE(cert-err58-cpp,cppcoreguidelines-avoid-non-const-global-variables) const std::vector levels = {NUClear::LogLevel::TRACE, diff --git a/tests/tests/threading/CountingLock.cpp b/tests/tests/threading/CountingLock.cpp index 01a9ab52..6db6485a 100644 --- a/tests/tests/threading/CountingLock.cpp +++ b/tests/tests/threading/CountingLock.cpp @@ -21,6 +21,7 @@ */ #include "threading/scheduler/CountingLock.hpp" +#include #include #include #include @@ -40,8 +41,8 @@ namespace threading { std::atomic active{2 * base + offset}; WHEN("Two locks are attempted") { - std::unique_ptr a1 = std::make_unique(active, -base, offset); - std::unique_ptr a2 = std::make_unique(active, -base, offset); + auto a1 = std::make_unique(active, -base, offset); + auto a2 = std::make_unique(active, -base, offset); THEN("The last lock should obtain the lock") { CHECK(a1->lock() == false); @@ -50,7 +51,7 @@ namespace threading { AND_WHEN("The locked lock is released and a third lock is attempted") { a2.reset(); - std::unique_ptr a3 = std::make_unique(active, -base, offset); + auto a3 = std::make_unique(active, -base, offset); THEN("Only the third lock should obtain the lock") { CHECK(a1->lock() == false); @@ -60,7 +61,7 @@ namespace threading { AND_WHEN("The unlocked lock is released and a third lock is attempted") { a1.reset(); - std::unique_ptr a3 = std::make_unique(active, -base, offset); + auto a3 = std::make_unique(active, -base, offset); THEN("The third lock should obtain the lock as well") { CHECK(a2->lock() == true); diff --git a/tests/tests/threading/Group.cpp b/tests/tests/threading/Group.cpp index ea94b683..69bed9aa 100644 --- a/tests/tests/threading/Group.cpp +++ b/tests/tests/threading/Group.cpp @@ -22,8 +22,14 @@ #include "threading/scheduler/Group.hpp" #include +#include #include #include +#include + +#include "id.hpp" +#include "threading/scheduler/Lock.hpp" +#include "util/GroupDescriptor.hpp" namespace NUClear { namespace threading { diff --git a/tests/tests/util/demangle.cpp b/tests/tests/util/demangle.cpp index 0703e7d3..bbf13497 100644 --- a/tests/tests/util/demangle.cpp +++ b/tests/tests/util/demangle.cpp @@ -20,13 +20,20 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "util/demangle.hpp" + #include -#include #include #include struct TestSymbol {}; +namespace symbol { +namespace in_a_namespace { + struct NamespacedSymbol {}; +} // namespace in_a_namespace +} // namespace symbol + template struct TestTemplate {}; @@ -97,8 +104,8 @@ SCENARIO("Test the demangle function correctly demangles symbols", "[util][deman } GIVEN("A symbol in a namespace") { - const char* symbol = typeid(NUClear::message::CommandLineArguments).name(); - const std::string expected = "NUClear::message::CommandLineArguments"; + const char* symbol = typeid(symbol::in_a_namespace::NamespacedSymbol).name(); + const std::string expected = "symbol::in_a_namespace::NamespacedSymbol"; WHEN("Demangle is called") { const std::string result = NUClear::util::demangle(symbol); diff --git a/tests/tests/util/network/resolve.cpp b/tests/tests/util/network/resolve.cpp index f18601ea..43fe6db5 100644 --- a/tests/tests/util/network/resolve.cpp +++ b/tests/tests/util/network/resolve.cpp @@ -23,8 +23,11 @@ #include "util/network/resolve.hpp" #include +#include #include +#include "util/platform.hpp" + TEST_CASE("resolve function returns expected socket address", "[util][network][resolve]") { diff --git a/tests/tests/util/serialise/serialise.cpp b/tests/tests/util/serialise/serialise.cpp index 50784f74..f8406082 100644 --- a/tests/tests/util/serialise/serialise.cpp +++ b/tests/tests/util/serialise/serialise.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/tests/util/serialise/xxhash.cpp b/tests/tests/util/serialise/xxhash.cpp index 3013ddfa..be1ecef2 100644 --- a/tests/tests/util/serialise/xxhash.cpp +++ b/tests/tests/util/serialise/xxhash.cpp @@ -22,6 +22,7 @@ #include "util/serialise/xxhash.hpp" +#include #include #include #include diff --git a/tests/tests/util/string_join.cpp b/tests/tests/util/string_join.cpp index a1f2d7c1..98ae1cf7 100644 --- a/tests/tests/util/string_join.cpp +++ b/tests/tests/util/string_join.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include