Move logger traits out of detail namespace into logger_traits.hpp

Summary:
related to T15252, #24
- move logger traits out of detail namespace into logger_traits.hpp to allow writers of their own loggers to verify that their implementation satisfies the LoggerType requirements
- move impl/codecs/traits to detail/traits, traits functions are now in detail namespace
- logger outputs the contents of props in debug mode

Reviewers: ivica

Reviewed By: ivica

Subscribers: iljazovic, miljen

Differential Revision: https://repo.mireo.local/D32524
This commit is contained in:
Korina Šimičević
2024-12-02 10:18:43 +01:00
parent 319d024981
commit e5d36cf088
19 changed files with 226 additions and 129 deletions

View File

@ -10,6 +10,7 @@
#include <async_mqtt5/error.hpp> #include <async_mqtt5/error.hpp>
#include <async_mqtt5/logger.hpp> #include <async_mqtt5/logger.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/mqtt_client.hpp> #include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/property_types.hpp> #include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/reason_codes.hpp> #include <async_mqtt5/reason_codes.hpp>

View File

@ -13,8 +13,8 @@
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <boost/type_traits/is_detected.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/reason_codes.hpp> #include <async_mqtt5/reason_codes.hpp>
#include <async_mqtt5/property_types.hpp> #include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/types.hpp> #include <async_mqtt5/types.hpp>
@ -24,83 +24,12 @@ namespace async_mqtt5::detail {
namespace asio = boost::asio; namespace asio = boost::asio;
using boost::system::error_code; using boost::system::error_code;
// NOOP Logger template <typename LoggerType>
class noop_logger {};
// at_resolve
template <typename T>
using at_resolve_sig = decltype(
std::declval<T&>().at_resolve(
std::declval<error_code>(),
std::declval<std::string_view>(), std::declval<std::string_view>(),
std::declval<const asio::ip::tcp::resolver::results_type&>()
)
);
template <typename T>
constexpr bool has_at_resolve = boost::is_detected<at_resolve_sig, T>::value;
// at_tcp_connect
template <typename T>
using at_tcp_connect_sig = decltype(
std::declval<T&>().at_tcp_connect(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_tcp_connect = boost::is_detected<at_tcp_connect_sig, T>::value;
// at_tls_handshake
template <typename T>
using at_tls_handshake_sig = decltype(
std::declval<T&>().at_tls_handshake(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_tls_handshake = boost::is_detected<at_tls_handshake_sig, T>::value;
// at_ws_handshake
template <typename T>
using at_ws_handshake_sig = decltype(
std::declval<T&>().at_ws_handshake(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_ws_handshake = boost::is_detected<at_ws_handshake_sig, T>::value;
// at_connack
template <typename T>
using at_connack_sig = decltype(
std::declval<T&>().at_connack(
std::declval<reason_code>(),
std::declval<bool>(), std::declval<const connack_props&>()
)
);
template <typename T>
constexpr bool has_at_connack = boost::is_detected<at_connack_sig, T>::value;
// at_disconnect
template <typename T>
using at_disconnect_sig = decltype(
std::declval<T&>().at_disconnect(
std::declval<reason_code>(), std::declval<const disconnect_props&>()
)
);
template <typename T>
constexpr bool has_at_disconnect = boost::is_detected<at_disconnect_sig, T>::value;
template <typename LoggerType = noop_logger>
class log_invoke { class log_invoke {
LoggerType _logger; LoggerType _logger;
public: public:
explicit log_invoke(LoggerType&& logger = {}) : explicit log_invoke(LoggerType logger = {}) :
_logger(std::forward<LoggerType>(logger)) _logger(std::move(logger))
{} {}
void at_resolve( void at_resolve(

View File

@ -16,7 +16,7 @@
#include <boost/range/iterator_range_core.hpp> #include <boost/range/iterator_range_core.hpp>
#include <boost/type_traits/remove_cv_ref.hpp> #include <boost/type_traits/remove_cv_ref.hpp>
namespace async_mqtt5 { namespace async_mqtt5::detail {
template <typename> template <typename>
constexpr bool is_optional_impl = false; constexpr bool is_optional_impl = false;
@ -58,6 +58,6 @@ constexpr bool is_boost_iterator = is_specialization<
boost::remove_cv_ref_t<T>, boost::iterator_range boost::remove_cv_ref_t<T>, boost::iterator_range
>; >;
} // end namespace async_mqtt5 } // end namespace async_mqtt5::detail
#endif // !ASYNC_MQTT5_TRAITS_HPP #endif // !ASYNC_MQTT5_TRAITS_HPP

View File

@ -19,7 +19,7 @@
#include <boost/optional/optional.hpp> #include <boost/optional/optional.hpp>
#include <async_mqtt5/property_types.hpp> #include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/impl/codecs/traits.hpp> #include <async_mqtt5/detail/traits.hpp>
namespace async_mqtt5::decoders { namespace async_mqtt5::decoders {
@ -80,7 +80,7 @@ constexpr auto to(T& arg) {
return [&](auto& ctx) { return [&](auto& ctx) {
using ctx_type = decltype(ctx); using ctx_type = decltype(ctx);
using attr_type = decltype(x3::_attr(std::declval<const ctx_type&>())); using attr_type = decltype(x3::_attr(std::declval<const ctx_type&>()));
if constexpr (is_boost_iterator<attr_type>) if constexpr (detail::is_boost_iterator<attr_type>)
arg = T { x3::_attr(ctx).begin(), x3::_attr(ctx).end() }; arg = T { x3::_attr(ctx).begin(), x3::_attr(ctx).end() };
else else
arg = x3::_attr(ctx); arg = x3::_attr(ctx);
@ -289,8 +289,8 @@ struct len_prefix_parser : x3::parser<len_prefix_parser> {
} }
}; };
constexpr len_prefix_parser utf8_{}; constexpr len_prefix_parser utf8_ {};
constexpr len_prefix_parser binary_{}; constexpr len_prefix_parser binary_ {};
/* /*
Boost Spirit incorrectly deduces atribute type for a parser of the form Boost Spirit incorrectly deduces atribute type for a parser of the form
@ -362,6 +362,7 @@ bool parse_to_prop(
It& iter, const It last, It& iter, const It last,
const Ctx& ctx, RCtx& rctx, Prop& prop const Ctx& ctx, RCtx& rctx, Prop& prop
) { ) {
using namespace async_mqtt5::detail;
using prop_type = std::remove_reference_t<decltype(prop)>; using prop_type = std::remove_reference_t<decltype(prop)>;
bool rv = false; bool rv = false;

View File

@ -20,7 +20,7 @@
#include <boost/type_traits/remove_cv_ref.hpp> #include <boost/type_traits/remove_cv_ref.hpp>
#include <async_mqtt5/property_types.hpp> #include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/impl/codecs/traits.hpp> #include <async_mqtt5/detail/traits.hpp>
namespace async_mqtt5::encoders { namespace async_mqtt5::encoders {
@ -72,7 +72,7 @@ public:
template < template <
typename T, typename T,
typename projection = boost::identity, typename projection = boost::identity,
std::enable_if_t<is_optional<T>, bool> = true std::enable_if_t<detail::is_optional<T>, bool> = true
> >
auto operator()(T&& value, projection proj = {}) const { auto operator()(T&& value, projection proj = {}) const {
if constexpr (std::is_same_v<projection, boost::identity>) { if constexpr (std::is_same_v<projection, boost::identity>) {
@ -89,7 +89,7 @@ public:
template < template <
typename T, typename T,
typename projection = boost::identity, typename projection = boost::identity,
std::enable_if_t<!is_optional<T>, bool> = true std::enable_if_t<!detail::is_optional<T>, bool> = true
> >
auto operator()(T&& value, projection proj = {}) const { auto operator()(T&& value, projection proj = {}) const {
auto val = static_cast<repr>(std::invoke(proj, value)); auto val = static_cast<repr>(std::invoke(proj, value));
@ -125,7 +125,7 @@ public:
int_val(T val) : _val(val) {} int_val(T val) : _val(val) {}
size_t byte_size() const { size_t byte_size() const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
if (_val) return val_length(*_val); if (_val) return val_length(*_val);
return 0; return 0;
} }
@ -134,7 +134,7 @@ public:
} }
std::string& encode(std::string& s) const { std::string& encode(std::string& s) const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
if (_val) return encode_val(s, *_val); if (_val) return encode_val(s, *_val);
return s; return s;
} }
@ -176,7 +176,7 @@ public:
template <typename T, typename projection> template <typename T, typename projection>
auto operator()(T&& val, projection proj) const { auto operator()(T&& val, projection proj) const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
using rv_type = std::invoke_result_t< using rv_type = std::invoke_result_t<
projection, typename boost::remove_cv_ref_t<T>::value_type projection, typename boost::remove_cv_ref_t<T>::value_type
>; >;
@ -211,14 +211,14 @@ public:
} }
size_t byte_size() const { size_t byte_size() const {
if constexpr (is_optional<T>) if constexpr (detail::is_optional<T>)
return _val ? _with_length * 2 + val_length(*_val) : 0; return _val ? _with_length * 2 + val_length(*_val) : 0;
else else
return _with_length * 2 + val_length(_val); return _with_length * 2 + val_length(_val);
} }
std::string& encode(std::string& s) const { std::string& encode(std::string& s) const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
if (_val) return encode_val(s, *_val); if (_val) return encode_val(s, *_val);
return s; return s;
} }
@ -268,7 +268,7 @@ public:
template <typename T, typename projection> template <typename T, typename projection>
auto operator()(T&& val, projection proj) const { auto operator()(T&& val, projection proj) const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
using rv_type = std::invoke_result_t< using rv_type = std::invoke_result_t<
projection, typename boost::remove_cv_ref_t<T>::value_type projection, typename boost::remove_cv_ref_t<T>::value_type
>; >;
@ -346,7 +346,7 @@ auto encoder_for_prop_value(const T& val) {
return basic::int_def<uint32_t>{}(val); return basic::int_def<uint32_t>{}(val);
else if constexpr (std::is_same_v<T, std::string>) else if constexpr (std::is_same_v<T, std::string>)
return basic::utf8_def{}(val); return basic::utf8_def{}(val);
else if constexpr (is_pair<T>) else if constexpr (detail::is_pair<T>)
return encoder_for_prop_value(val.first) & return encoder_for_prop_value(val.first) &
encoder_for_prop_value(val.second); encoder_for_prop_value(val.second);
} }
@ -359,7 +359,7 @@ template <
> >
class prop_val< class prop_val<
T, p, T, p,
std::enable_if_t<!is_vector<T> && is_optional<T>> std::enable_if_t<!detail::is_vector<T> && detail::is_optional<T>>
> : public basic::encoder { > : public basic::encoder {
// allows T to be reference type to std::optional // allows T to be reference type to std::optional
static inline boost::remove_cv_ref_t<T> nulltype; static inline boost::remove_cv_ref_t<T> nulltype;
@ -388,7 +388,7 @@ template <
> >
class prop_val< class prop_val<
T, p, T, p,
std::enable_if_t<is_vector<T> || is_small_vector<T>> std::enable_if_t<detail::is_vector<T> || detail::is_small_vector<T>>
> : public basic::encoder { > : public basic::encoder {
// allows T to be reference type to std::vector // allows T to be reference type to std::vector
static inline boost::remove_cv_ref_t<T> nulltype; static inline boost::remove_cv_ref_t<T> nulltype;
@ -490,7 +490,7 @@ class props_def {
public: public:
template <typename T> template <typename T>
auto operator()(T&& prop_container) const { auto operator()(T&& prop_container) const {
if constexpr (is_optional<T>) { if constexpr (detail::is_optional<T>) {
if (prop_container.has_value()) if (prop_container.has_value())
return (*this)(*prop_container); return (*this)(*prop_container);
return props_val< return props_val<

View File

@ -54,10 +54,10 @@ public:
}); });
} }
run_op(run_op&&) noexcept = default; run_op(run_op&&) = default;
run_op(const run_op&) = delete; run_op(const run_op&) = delete;
run_op& operator=(run_op&&) noexcept = default; run_op& operator=(run_op&&) = default;
run_op& operator=(const run_op&) = delete; run_op& operator=(const run_op&) = delete;
using allocator_type = asio::associated_allocator_t<handler_type>; using allocator_type = asio::associated_allocator_t<handler_type>;

View File

@ -8,17 +8,19 @@
#ifndef ASYNC_MQTT5_LOGGER_HPP #ifndef ASYNC_MQTT5_LOGGER_HPP
#define ASYNC_MQTT5_LOGGER_HPP #define ASYNC_MQTT5_LOGGER_HPP
#include <cstdint>
#include <iostream> #include <iostream>
#include <string_view> #include <string_view>
#include <boost/system/error_code.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/system/error_code.hpp>
#include <boost/type_traits/remove_cv_ref.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/reason_codes.hpp> #include <async_mqtt5/reason_codes.hpp>
#include <async_mqtt5/property_types.hpp> #include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/types.hpp> #include <async_mqtt5/types.hpp>
#include <async_mqtt5/detail/traits.hpp>
#include <async_mqtt5/impl/codecs/traits.hpp>
namespace async_mqtt5 { namespace async_mqtt5 {
@ -83,7 +85,7 @@ public:
if (!ec && _level < log_level::info) if (!ec && _level < log_level::info)
return; return;
write_prefix(); output_prefix();
std::clog std::clog
<< "resolve: " << "resolve: "
<< host << ":" << port; << host << ":" << port;
@ -110,7 +112,7 @@ public:
if (!ec && _level < log_level::info) if (!ec && _level < log_level::info)
return; return;
write_prefix(); output_prefix();
std::clog std::clog
<< "connect: " << "connect: "
<< ep.address().to_string() << ":" << ep.port() << ep.address().to_string() << ":" << ep.port()
@ -128,7 +130,7 @@ public:
if (!ec && _level < log_level::info) if (!ec && _level < log_level::info)
return; return;
write_prefix(); output_prefix();
std::clog std::clog
<< "TLS handshake: " << "TLS handshake: "
<< ep.address().to_string() << ":" << ep.port() << ep.address().to_string() << ":" << ep.port()
@ -146,7 +148,7 @@ public:
if (!ec && _level < log_level::info) if (!ec && _level < log_level::info)
return; return;
write_prefix(); output_prefix();
std::clog std::clog
<< "WebSocket handshake: " << "WebSocket handshake: "
<< ep.address().to_string() << ":" << ep.port() << ep.address().to_string() << ":" << ep.port()
@ -165,13 +167,17 @@ public:
*/ */
void at_connack( void at_connack(
reason_code rc, reason_code rc,
bool /* session_present */, const connack_props& /* ca_props */ bool session_present, const connack_props& ca_props
) { ) {
if (!rc && _level < log_level::info) if (!rc && _level < log_level::info)
return; return;
write_prefix(); output_prefix();
std::clog << "connack: " << rc.message() << "."; std::clog << "connack: " << rc.message() << ".";
if (_level == log_level::debug) {
std::clog << " session_present:" << session_present << " ";
output_props(ca_props);
}
std::clog << std::endl; std::clog << std::endl;
} }
@ -183,19 +189,67 @@ public:
* \param dc_props \__DISCONNECT_PROPS\__ received in the \__DISCONNECT\__ packet. * \param dc_props \__DISCONNECT_PROPS\__ received in the \__DISCONNECT\__ packet.
*/ */
void at_disconnect(reason_code rc, const disconnect_props& dc_props) { void at_disconnect(reason_code rc, const disconnect_props& dc_props) {
write_prefix(); output_prefix();
std::clog << "disconnect: " << rc.message() << "."; std::clog << "disconnect: " << rc.message() << ".";
if (dc_props[prop::reason_string].has_value()) if (_level == log_level::debug)
std::clog << " Reason string: " << * dc_props[prop::reason_string]; output_props(dc_props);
std::clog << std::endl; std::clog << std::endl;
} }
private: private:
void write_prefix() { void output_prefix() {
std::clog << prefix << " "; std::clog << prefix << " ";
} }
template <typename Props>
void output_props(const Props& props) {
props.visit(
[](const auto& prop, const auto& val) -> bool {
if constexpr (detail::is_optional<decltype(val)>) {
if (val.has_value()) {
std::clog << property_name(prop) << ":";
using value_type = boost::remove_cv_ref_t<decltype(*val)>;
if constexpr (std::is_same_v<value_type, uint8_t>)
std::clog << std::to_string(*val) << " ";
else
std::clog << *val << " ";
}
} else { // is vector
if (val.empty())
return true;
std::clog << property_name(prop) << ":";
std::clog << "[";
for (auto i = 0; i < val.size(); i++) {
if constexpr (detail::is_pair<decltype(val[i])>)
std::clog << "(" << val[i].first << "," << val[i].second << ")";
else
std::clog << std::to_string(val[i]);
if (i + 1 < val.size())
std::clog << ", ";
}
std::clog << "]";
}
return true;
}
);
}
template <prop::property_type p>
static std::string_view property_name(std::integral_constant<prop::property_type, p>) {
return prop::name_v<p>;
}
}; };
// Verify that the logger class satisfies the LoggerType concept
static_assert(has_at_resolve<logger>);
static_assert(has_at_tcp_connect<logger>);
static_assert(has_at_tls_handshake<logger>);
static_assert(has_at_ws_handshake<logger>);
static_assert(has_at_connack<logger>);
static_assert(has_at_disconnect<logger>);
} // end namespace async_mqtt5 } // end namespace async_mqtt5

View File

@ -0,0 +1,103 @@
//
// Copyright (c) 2023-2024 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASYNC_MQTT5_LOGGER_TRAITS_HPP
#define ASYNC_MQTT5_LOGGER_TRAITS_HPP
#include <iostream>
#include <string_view>
#include <type_traits>
#include <boost/asio/ip/tcp.hpp>
#include <boost/system/error_code.hpp>
#include <boost/type_traits/is_detected.hpp>
#include <async_mqtt5/reason_codes.hpp>
#include <async_mqtt5/property_types.hpp>
#include <async_mqtt5/types.hpp>
namespace async_mqtt5 {
namespace asio = boost::asio;
using boost::system::error_code;
// NOOP Logger
class noop_logger {};
// at_resolve
template <typename T>
using at_resolve_sig = decltype(
std::declval<T&>().at_resolve(
std::declval<error_code>(),
std::declval<std::string_view>(), std::declval<std::string_view>(),
std::declval<const asio::ip::tcp::resolver::results_type&>()
)
);
template <typename T>
constexpr bool has_at_resolve = boost::is_detected<at_resolve_sig, T>::value;
// at_tcp_connect
template <typename T>
using at_tcp_connect_sig = decltype(
std::declval<T&>().at_tcp_connect(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_tcp_connect = boost::is_detected<at_tcp_connect_sig, T>::value;
// at_tls_handshake
template <typename T>
using at_tls_handshake_sig = decltype(
std::declval<T&>().at_tls_handshake(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_tls_handshake = boost::is_detected<at_tls_handshake_sig, T>::value;
// at_ws_handshake
template <typename T>
using at_ws_handshake_sig = decltype(
std::declval<T&>().at_ws_handshake(
std::declval<error_code>(), std::declval<asio::ip::tcp::endpoint>()
)
);
template <typename T>
constexpr bool has_at_ws_handshake = boost::is_detected<at_ws_handshake_sig, T>::value;
// at_connack
template <typename T>
using at_connack_sig = decltype(
std::declval<T&>().at_connack(
std::declval<reason_code>(),
std::declval<bool>(), std::declval<const connack_props&>()
)
);
template <typename T>
constexpr bool has_at_connack = boost::is_detected<at_connack_sig, T>::value;
// at_disconnect
template <typename T>
using at_disconnect_sig = decltype(
std::declval<T&>().at_disconnect(
std::declval<reason_code>(), std::declval<const disconnect_props&>()
)
);
template <typename T>
constexpr bool has_at_disconnect = boost::is_detected<at_disconnect_sig, T>::value;
} // end namespace async_mqtt5
#endif // !ASYNC_MQTT5_LOGGER_TRAITS_HPP

View File

@ -18,6 +18,7 @@
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <async_mqtt5/error.hpp> #include <async_mqtt5/error.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/types.hpp> #include <async_mqtt5/types.hpp>
#include <async_mqtt5/detail/log_invoke.hpp> #include <async_mqtt5/detail/log_invoke.hpp>
@ -52,7 +53,7 @@ namespace asio = boost::asio;
template < template <
typename StreamType, typename StreamType,
typename TlsContext = std::monostate, typename TlsContext = std::monostate,
typename LoggerType = detail::noop_logger typename LoggerType = noop_logger
> >
class mqtt_client { class mqtt_client {
public: public:
@ -134,7 +135,6 @@ public:
*/ */
mqtt_client(mqtt_client&&) noexcept = default; mqtt_client(mqtt_client&&) noexcept = default;
/** /**
* \brief Move assignment operator. * \brief Move assignment operator.
* *
@ -163,7 +163,6 @@ public:
return _impl->get_executor(); return _impl->get_executor();
} }
/** /**
* \brief Get the context object used in TLS/SSL connection. * \brief Get the context object used in TLS/SSL connection.
* *

View File

@ -12,6 +12,7 @@
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>

View File

@ -20,9 +20,9 @@
#include <boost/range/algorithm/transform.hpp> #include <boost/range/algorithm/transform.hpp>
#include <async_mqtt5/detail/control_packet.hpp> #include <async_mqtt5/detail/control_packet.hpp>
#include <async_mqtt5/detail/traits.hpp>
#include <async_mqtt5/impl/codecs/message_decoders.hpp> #include <async_mqtt5/impl/codecs/message_decoders.hpp>
#include <async_mqtt5/impl/codecs/message_encoders.hpp> #include <async_mqtt5/impl/codecs/message_encoders.hpp>
#include <async_mqtt5/impl/codecs/traits.hpp>
namespace async_mqtt5::test { namespace async_mqtt5::test {
@ -89,6 +89,7 @@ template <typename Props>
inline std::string to_readable_props(Props props) { inline std::string to_readable_props(Props props) {
std::ostringstream stream; std::ostringstream stream;
props.visit([&stream](const auto&, const auto& v) -> bool { props.visit([&stream](const auto&, const auto& v) -> bool {
using namespace async_mqtt5::detail;
if constexpr (is_optional<decltype(v)>) if constexpr (is_optional<decltype(v)>)
if (v.has_value()) if (v.has_value())
stream << *v << " "; stream << *v << " ";

View File

@ -30,7 +30,7 @@ using error_code = boost::system::error_code;
template < template <
typename StreamType, typename StreamType,
typename StreamContext = std::monostate, typename StreamContext = std::monostate,
typename LoggerType = async_mqtt5::detail::noop_logger typename LoggerType = async_mqtt5::noop_logger
> >
class test_autoconnect_stream { class test_autoconnect_stream {
public: public:

View File

@ -23,6 +23,7 @@
#include <async_mqtt5/mqtt_client.hpp> #include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/types.hpp> #include <async_mqtt5/types.hpp>
#include <async_mqtt5/detail/traits.hpp>
#include "test_common/message_exchange.hpp" #include "test_common/message_exchange.hpp"
#include "test_common/packet_util.hpp" #include "test_common/packet_util.hpp"
@ -406,7 +407,7 @@ BOOST_FIXTURE_TEST_CASE(connack_properties, shared_connack_prop_test_data) {
connack_props cprops_ = c.connack_properties(); connack_props cprops_ = c.connack_properties();
cprops_.visit([&](const auto& p, const auto& val) -> bool { cprops_.visit([&](const auto& p, const auto& val) -> bool {
BOOST_TEST_REQUIRE(p); BOOST_TEST_REQUIRE(p);
if constexpr (is_vector<decltype(val)>) if constexpr (detail::is_vector<decltype(val)>)
BOOST_TEST(val == cprops[p]); BOOST_TEST(val == cprops[p]);
else { else {
BOOST_TEST_REQUIRE(val.has_value()); BOOST_TEST_REQUIRE(val.has_value());
@ -429,7 +430,7 @@ BOOST_FIXTURE_TEST_CASE(connack_property, shared_connack_prop_test_data) {
std::move(broker_side), std::move(broker_side),
[&](client_type& c) { [&](client_type& c) {
cprops.visit([&](const auto& p, const auto& val) -> bool{ cprops.visit([&](const auto& p, const auto& val) -> bool{
if constexpr (is_vector<decltype(val)>) if constexpr (detail::is_vector<decltype(val)>)
BOOST_TEST(val == c.connack_property(p)); BOOST_TEST(val == c.connack_property(p));
else { else {
BOOST_TEST_REQUIRE(val.has_value()); BOOST_TEST_REQUIRE(val.has_value());

View File

@ -34,7 +34,11 @@ using strand_type = asio::strand<asio::any_io_executor>;
BOOST_AUTO_TEST_SUITE(executors) BOOST_AUTO_TEST_SUITE(executors)
void run_test(asio::io_context& ioc, strand_type io_ex, auto bind_async_run, auto bind_async_op) { template <typename AsyncRunOp, typename AsyncOp>
void run_test(
asio::io_context& ioc, strand_type io_ex,
AsyncRunOp&& bind_async_run, AsyncOp&& bind_async_op
) {
using test::after; using test::after;
using namespace std::chrono_literals; using namespace std::chrono_literals;

View File

@ -473,7 +473,7 @@ BOOST_FIXTURE_TEST_CASE(receive_buffer_overflow, shared_test_data) {
.async_run(asio::detached); .async_run(asio::detached);
asio::steady_timer timer(executor); asio::steady_timer timer(executor);
timer.expires_after(7s); timer.expires_after(10s);
timer.async_wait( timer.async_wait(
[&](error_code) { [&](error_code) {
c.async_receive([&]( c.async_receive([&](

View File

@ -16,6 +16,7 @@
#include <boost/asio/steady_timer.hpp> #include <boost/asio/steady_timer.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/types.hpp> #include <async_mqtt5/types.hpp>
#include <async_mqtt5/detail/log_invoke.hpp> #include <async_mqtt5/detail/log_invoke.hpp>
#include <async_mqtt5/detail/internal_types.hpp> #include <async_mqtt5/detail/internal_types.hpp>
@ -65,8 +66,8 @@ void run_unit_test(
std::move(h)(ec); std::move(h)(ec);
}; };
detail::log_invoke d; detail::log_invoke<noop_logger> d;
detail::connect_op<test::test_stream, detail::noop_logger>( detail::connect_op<test::test_stream, noop_logger>(
stream, mqtt_ctx, d, std::move(handler) stream, mqtt_ctx, d, std::move(handler)
).perform(*std::begin(eps), std::move(ap)); ).perform(*std::begin(eps), std::move(ap));

View File

@ -25,6 +25,7 @@
#include <async_mqtt5/mqtt_client.hpp> #include <async_mqtt5/mqtt_client.hpp>
#include <async_mqtt5/logger.hpp> #include <async_mqtt5/logger.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include "test_common/message_exchange.hpp" #include "test_common/message_exchange.hpp"
#include "test_common/test_service.hpp" #include "test_common/test_service.hpp"
@ -54,12 +55,12 @@ void assign_tls_sni(
void logger_test() { void logger_test() {
BOOST_STATIC_ASSERT(detail::has_at_resolve<logger>); BOOST_STATIC_ASSERT(has_at_resolve<logger>);
BOOST_STATIC_ASSERT(detail::has_at_tcp_connect<logger>); BOOST_STATIC_ASSERT(has_at_tcp_connect<logger>);
BOOST_STATIC_ASSERT(detail::has_at_tls_handshake<logger>); BOOST_STATIC_ASSERT(has_at_tls_handshake<logger>);
BOOST_STATIC_ASSERT(detail::has_at_ws_handshake<logger>); BOOST_STATIC_ASSERT(has_at_ws_handshake<logger>);
BOOST_STATIC_ASSERT(detail::has_at_connack<logger>); BOOST_STATIC_ASSERT(has_at_connack<logger>);
BOOST_STATIC_ASSERT(detail::has_at_disconnect<logger>); BOOST_STATIC_ASSERT(has_at_disconnect<logger>);
} }
using stream_type = boost::beast::websocket::stream< using stream_type = boost::beast::websocket::stream<

View File

@ -14,6 +14,7 @@
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <boost/asio/prepend.hpp> #include <boost/asio/prepend.hpp>
#include <async_mqtt5/logger_traits.hpp>
#include <async_mqtt5/detail/log_invoke.hpp> #include <async_mqtt5/detail/log_invoke.hpp>
#include <async_mqtt5/impl/client_service.hpp> #include <async_mqtt5/impl/client_service.hpp>
@ -113,7 +114,7 @@ void run_connect_to_localhost_test(int succeed_after) {
); );
auto stream_ctx = stream_context(std::monostate {}); auto stream_ctx = stream_context(std::monostate {});
auto log = detail::log_invoke(); auto log = detail::log_invoke<noop_logger>();
auto auto_stream = astream(ioc.get_executor(), stream_ctx, log); auto auto_stream = astream(ioc.get_executor(), stream_ctx, log);
auto_stream.brokers("localhost", 1883); auto_stream.brokers("localhost", 1883);
@ -147,7 +148,7 @@ BOOST_AUTO_TEST_CASE(no_servers) {
asio::io_context ioc; asio::io_context ioc;
auto stream_ctx = stream_context(std::monostate{}); auto stream_ctx = stream_context(std::monostate{});
auto log = detail::log_invoke(); auto log = detail::log_invoke<noop_logger>();
auto auto_stream = astream(ioc.get_executor(), stream_ctx, log); auto auto_stream = astream(ioc.get_executor(), stream_ctx, log);
auto_stream.brokers("", 1883); auto_stream.brokers("", 1883);

View File

@ -692,7 +692,7 @@ BOOST_AUTO_TEST_CASE(test_pingresp) {
BOOST_AUTO_TEST_CASE(subscription_identifiers) { BOOST_AUTO_TEST_CASE(subscription_identifiers) {
// check boost::container::small_vector interface // check boost::container::small_vector interface
BOOST_TEST_REQUIRE(is_small_vector<prop::subscription_identifiers>); BOOST_TEST_REQUIRE(detail::is_small_vector<prop::subscription_identifiers>);
// check optional interface // check optional interface
prop::subscription_identifiers sub_ids; prop::subscription_identifiers sub_ids;