|
| 1 | +// |
| 2 | +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | +// SPDX-License-Identifier: MIT |
| 4 | +// |
| 5 | + |
| 6 | +#ifndef OCVSMD_COMMON_IPC_GTEST_HELPERS_HPP_INCLUDED |
| 7 | +#define OCVSMD_COMMON_IPC_GTEST_HELPERS_HPP_INCLUDED |
| 8 | + |
| 9 | +#include "dsdl_helpers.hpp" |
| 10 | +#include "ipc/pipe/pipe_types.hpp" |
| 11 | + |
| 12 | +#include "ocvsmd/common/ipc/RouteChannelEnd_1_0.hpp" |
| 13 | +#include "ocvsmd/common/ipc/RouteChannelMsg_1_0.hpp" |
| 14 | +#include "ocvsmd/common/ipc/RouteConnect_1_0.hpp" |
| 15 | +#include "ocvsmd/common/ipc/Route_1_0.hpp" |
| 16 | + |
| 17 | +#include <uavcan/node/Version_1_0.hpp> |
| 18 | +#include <uavcan/primitive/Empty_1_0.hpp> |
| 19 | + |
| 20 | +#include <cetl/pf17/cetlpf.hpp> |
| 21 | + |
| 22 | +#include <gmock/gmock.h> |
| 23 | +#include <gtest/gtest-matchers.h> |
| 24 | +#include <gtest/gtest-printers.h> |
| 25 | + |
| 26 | +#include <cstdint> |
| 27 | +#include <ios> |
| 28 | +#include <ostream> |
| 29 | +#include <vector> |
| 30 | + |
| 31 | +// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) |
| 32 | + |
| 33 | +namespace ocvsmd |
| 34 | +{ |
| 35 | +namespace common |
| 36 | +{ |
| 37 | +namespace ipc |
| 38 | +{ |
| 39 | + |
| 40 | +// MARK: - GTest Printers: |
| 41 | + |
| 42 | +inline void PrintTo(const uavcan::primitive::Empty_1_0&, std::ostream* os) |
| 43 | +{ |
| 44 | + *os << "Empty_1_0"; |
| 45 | +} |
| 46 | + |
| 47 | +inline void PrintTo(const uavcan::node::Version_1_0& ver, std::ostream* os) |
| 48 | +{ |
| 49 | + *os << "Version_1_0{'" << static_cast<int>(ver.major) << "." << static_cast<int>(ver.minor) << "'}"; |
| 50 | +} |
| 51 | + |
| 52 | +inline void PrintTo(const RouteConnect_1_0& conn, std::ostream* os) |
| 53 | +{ |
| 54 | + *os << "RouteConnect_1_0{ver="; |
| 55 | + PrintTo(conn.version, os); |
| 56 | + *os << "}"; |
| 57 | +} |
| 58 | + |
| 59 | +inline void PrintTo(const RouteChannelMsg_1_0& msg, std::ostream* os) |
| 60 | +{ |
| 61 | + *os << "RouteChannelMsg_1_0{tag=" << msg.tag << ", seq=" << msg.sequence << ", srv=0x" << std::hex << msg.service_id |
| 62 | + << "}"; |
| 63 | +} |
| 64 | + |
| 65 | +inline void PrintTo(const RouteChannelEnd_1_0& msg, std::ostream* os) |
| 66 | +{ |
| 67 | + *os << "RouteChannelEnd_1_0{tag=" << msg.tag << ", err=" << msg.error_code << "}"; |
| 68 | +} |
| 69 | + |
| 70 | +inline void PrintTo(const Route_1_0& route, std::ostream* os) |
| 71 | +{ |
| 72 | + *os << "Route_1_0{"; |
| 73 | + cetl::visit([os](const auto& v) { PrintTo(v, os); }, route.union_value); |
| 74 | + *os << "}"; |
| 75 | +} |
| 76 | + |
| 77 | +// MARK: - Equitable-s for matching: |
| 78 | + |
| 79 | +inline bool operator==(const RouteConnect_1_0& lhs, const RouteConnect_1_0& rhs) |
| 80 | +{ |
| 81 | + return lhs.version.major == rhs.version.major && lhs.version.minor == rhs.version.minor; |
| 82 | +} |
| 83 | + |
| 84 | +inline bool operator==(const RouteChannelMsg_1_0& lhs, const RouteChannelMsg_1_0& rhs) |
| 85 | +{ |
| 86 | + return lhs.tag == rhs.tag && lhs.sequence == rhs.sequence && lhs.service_id == rhs.service_id; |
| 87 | +} |
| 88 | + |
| 89 | +inline bool operator==(const RouteChannelEnd_1_0& lhs, const RouteChannelEnd_1_0& rhs) |
| 90 | +{ |
| 91 | + return lhs.tag == rhs.tag && lhs.error_code == rhs.error_code; |
| 92 | +} |
| 93 | + |
| 94 | +// MARK: - GTest Matchers: |
| 95 | + |
| 96 | +template <typename T> |
| 97 | +class PayloadMatcher |
| 98 | +{ |
| 99 | +public: |
| 100 | + explicit PayloadMatcher(testing::Matcher<const typename T::VariantType&> matcher, |
| 101 | + cetl::pmr::memory_resource& memory) |
| 102 | + : matcher_(std::move(matcher)) |
| 103 | + , memory_{memory} |
| 104 | + |
| 105 | + { |
| 106 | + } |
| 107 | + |
| 108 | + bool MatchAndExplain(const pipe::Payload& payload, testing::MatchResultListener* listener) const |
| 109 | + { |
| 110 | + T msg{&memory_}; |
| 111 | + const auto result = tryDeserializePayload<T>(payload, msg); |
| 112 | + if (!result) |
| 113 | + { |
| 114 | + if (listener->IsInterested()) |
| 115 | + { |
| 116 | + *listener << "Failed to deserialize the payload."; |
| 117 | + } |
| 118 | + return false; |
| 119 | + } |
| 120 | + |
| 121 | + const bool match = matcher_.MatchAndExplain(msg.union_value, listener); |
| 122 | + if (!match && listener->IsInterested()) |
| 123 | + { |
| 124 | + *listener << ".\n Payload: "; |
| 125 | + *listener << testing::PrintToString(msg); |
| 126 | + } |
| 127 | + return match; |
| 128 | + } |
| 129 | + |
| 130 | + bool MatchAndExplain(const pipe::Payloads& payloads, testing::MatchResultListener* listener) const |
| 131 | + { |
| 132 | + std::vector<std::uint8_t> flatten; |
| 133 | + for (const auto& payload : payloads) |
| 134 | + { |
| 135 | + flatten.insert(flatten.end(), payload.begin(), payload.end()); |
| 136 | + } |
| 137 | + return MatchAndExplain({flatten.data(), flatten.size()}, listener); |
| 138 | + } |
| 139 | + |
| 140 | + void DescribeTo(std::ostream* os) const |
| 141 | + { |
| 142 | + *os << "is a variant<> with value of type '" << "GetTypeName()" |
| 143 | + << "' and the value "; |
| 144 | + matcher_.DescribeTo(os); |
| 145 | + } |
| 146 | + |
| 147 | + void DescribeNegationTo(std::ostream* os) const |
| 148 | + { |
| 149 | + *os << "is a variant<> with value of type other than '" << "GetTypeName()" |
| 150 | + << "' or the value "; |
| 151 | + matcher_.DescribeNegationTo(os); |
| 152 | + } |
| 153 | + |
| 154 | +private: |
| 155 | + const testing::Matcher<const typename T::VariantType&> matcher_; |
| 156 | + cetl::pmr::memory_resource& memory_; |
| 157 | + |
| 158 | +}; // PayloadMatcher |
| 159 | + |
| 160 | +template <typename T> |
| 161 | +testing::PolymorphicMatcher<PayloadMatcher<T>> PayloadWith( |
| 162 | + |
| 163 | + const testing::Matcher<const typename T::VariantType&>& matcher, |
| 164 | + cetl::pmr::memory_resource& memory) |
| 165 | +{ |
| 166 | + return testing::MakePolymorphicMatcher(PayloadMatcher<T>(matcher, memory)); |
| 167 | +} |
| 168 | + |
| 169 | +inline auto PayloadRouteConnectEq(cetl::pmr::memory_resource& mr, |
| 170 | + const std::uint8_t ver_major = VERSION_MAJOR, |
| 171 | + const std::uint8_t ver_minor = VERSION_MINOR) |
| 172 | +{ |
| 173 | + const RouteConnect_1_0 connect{{ver_major, ver_minor, &mr}, &mr}; |
| 174 | + return PayloadWith<Route_1_0>(testing::VariantWith<RouteConnect_1_0>(connect), mr); |
| 175 | +} |
| 176 | + |
| 177 | +template <typename Msg> |
| 178 | +auto PayloadOfRouteChannel(cetl::pmr::memory_resource& mr, |
| 179 | + const std::uint64_t tag, |
| 180 | + const std::uint64_t seq, |
| 181 | + const cetl::string_view srv_name = "") |
| 182 | +{ |
| 183 | + const RouteChannelMsg_1_0 msg{tag, seq, AnyChannel::getServiceId<Msg>(srv_name), &mr}; |
| 184 | + return PayloadWith<Route_1_0>(testing::VariantWith<RouteChannelMsg_1_0>(msg), mr); |
| 185 | +} |
| 186 | + |
| 187 | +} // namespace ipc |
| 188 | +} // namespace common |
| 189 | +} // namespace ocvsmd |
| 190 | + |
| 191 | +// NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) |
| 192 | + |
| 193 | +#endif // OCVSMD_COMMON_IPC_GTEST_HELPERS_HPP_INCLUDED |
0 commit comments