mirror of
https://github.com/boostorg/mqtt5.git
synced 2025-07-29 20:17:37 +02:00
Support multiple subscription identifiers in received messages.
Summary: - refactor property encoding - change user property type to be std::pair<std::string, std::string> Reviewers: ivica Reviewed By: ivica Subscribers: korina Differential Revision: https://repo.mireo.local/D27867
This commit is contained in:
@ -10,7 +10,7 @@ This section lists all possible __AUTH__ Properties and describes their usage:
|
||||
[[authentication_method] [`std::string`] [A UTF-8 Encoded String containing the name of the authentication method used for extended authentication.]]
|
||||
[[authentication_data] [`std::string`] [Binary Data containing authentication data. The contents of the data are defined by the authentication method.]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -19,6 +19,9 @@ After obtaining an instance of `async_mqtt5::auth_props`, the subscript operator
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -27,17 +30,21 @@ The following example shows how to set a Property value:
|
||||
async_mqtt5::auth_props props;
|
||||
props[async_mqtt5::prop::authentication_method] = "SCRAM-SHA-1";
|
||||
props[async_mqtt5::prop::authentication_data] = "data";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> auth_data = props[async_mqtt5::prop::authentication_data];
|
||||
if (auth_data.has_value())
|
||||
// authentication data property was previously set
|
||||
else
|
||||
// authentication data property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -15,7 +15,7 @@ This section lists all possible __CONNACK__ Properties and describes their usage
|
||||
[[assigned_client_identifier] [`std::string`] [The Client Identifier which was assigned by the Server because a zero length Client Identifier was found in the __CONNECT__ packet]]
|
||||
[[topic_alias_maximum] [`uint16_t`] [The highest value that the Server will accept as a Topic Alias sent by the Client.]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
The meaning of these properties is not defined by the specification.]]
|
||||
[[wildcard_subscription_available] [`uint8_t`] [A value of 0 means that Wildcard Subscriptions are not supported.
|
||||
A value of 1 means they are supported. If not present, they are supported.]]
|
||||
@ -35,6 +35,9 @@ After obtaining an instance of `async_mqtt5::connack_props`, the subscript opera
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -43,17 +46,21 @@ The following example shows how to set a Property value:
|
||||
async_mqtt5::connack_props props;
|
||||
props[async_mqtt5::prop::maximum_packet_size] = 65535;
|
||||
props[async_mqtt5::prop::assigned_client_identifier] = "ClientID";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> auth_method = props[async_mqtt5::prop::authentication_method];
|
||||
if (auth_method.has_value())
|
||||
// authentication method property was previously set
|
||||
else
|
||||
// authentication method property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -15,7 +15,7 @@ This section lists all possible __CONNECT__ Properties and describes their usage
|
||||
[[request_problem_information] [`uint8_t`] [The value of 0 signals that the Server MAY return a Reason String or User Properties on a __CONNACK__ or __DISCONNECT__ packet,
|
||||
but MUST NOT send them on any packet other than __PUBLISH__, __CONNACK__, or __DISCONNECT__.
|
||||
If the value is 1, the Server MAY return a Reason String or User Properties where it is allowed.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
The meaning of these properties is not defined by the specification.]]
|
||||
[[authentication_method] [`std::string`] [A UTF-8 Encoded String containing the name of the authentication method used for extended authentication.]]
|
||||
[[authentication_data] [`std::string`] [Binary Data containing authentication data. The contents of the data are defined by the authentication method.]]
|
||||
@ -26,6 +26,9 @@ After obtaining an instance of `async_mqtt5::connect_props`, the subscript opera
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -34,17 +37,21 @@ The following example shows how to set a Property value:
|
||||
async_mqtt5::connect_props props;
|
||||
props[async_mqtt5::prop::session_expiry_interval] = 1200;
|
||||
props[async_mqtt5::prop::receive_maximum] = uint16_t(100);
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> auth_method = props[async_mqtt5::prop::authentication_method];
|
||||
if (auth_method.has_value())
|
||||
// authentication method property was previously set
|
||||
else
|
||||
// authentication method property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -9,7 +9,7 @@ This section lists all possible __DISCONNECT__ Properties and describes their us
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[session_expiry_interval] [`uint32_t`] [Represents the Session Expiry Internal in seconds. Can only be sent by the Client.]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
[[server_reference] [`std::string`] [A UTF-8 Encoded String which can be used by the Client to identfy another Server to use.]]
|
||||
]
|
||||
@ -19,6 +19,9 @@ After obtaining an instance of `async_mqtt5::disconnect_props`, the subscript op
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -26,17 +29,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::disconnect_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Lost connection!";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __PUBACK__ Properties and describes their usage:
|
||||
[table:puback_props PUBACK properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,6 +17,9 @@ After obtaining an instance of `async_mqtt5::puback_props`, the subscript operat
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -24,17 +27,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::puback_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __PUBCOMP__ Properties and describes their usage
|
||||
[table:pubcomp_props PUBCOMP properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,6 +17,9 @@ After obtaining an instance of `async_mqtt5::pubcomp_props`, the subscript opera
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -24,17 +27,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::pubcomp_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -12,9 +12,9 @@ This section lists all possible __PUBLISH__ Properties and describes their usage
|
||||
[[topic_alias] [`uint16_t`] [Two Byte integer representing the Topic Alias, an integer value that is used to identify the Topic instead of using the Topic Name.]]
|
||||
[[response_topic] [`std::string`] [A UTF-8 Encoded String which is used as the Topic Name for a response message.]]
|
||||
[[correlation_data] [`std::string`] [Binary Data used by the sender of the Request Message to identify which request the Response Message is for when it is received.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
The meaning of these properties is not defined by the specification.]]
|
||||
[[subscription_identifier] [`int32_t`] [Identifier of the Subscription in range of 1 to 268,435,455.]]
|
||||
[[subscription_identifier] [`int32_t`] [Identifier of the matching subscription. If there are multiple matching subscriptions, multiple identifiers may be included.]]
|
||||
[[content_type] [`std::string`] [A UTF-8 Encoded String describing the content of the Application Message.]]
|
||||
]
|
||||
|
||||
@ -23,6 +23,11 @@ After obtaining an instance of `async_mqtt5::publish_props`, the subscript opera
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property` and `async_mqtt5::prop::subscription_identifier`, where it will return an instance of
|
||||
`std::vector<std::pair<std::string, std::string>>` and `async_mqtt5::prop::subscription_identifiers` respectively.
|
||||
`async_mqtt5::prop::subscription_identifiers` has the interface of `boost::container::small_vector`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -32,17 +37,21 @@ The following example shows how to set a Property value:
|
||||
props[async_mqtt5::prop::payload_format_indicator] = uint8_t(1);
|
||||
props[async_mqtt5::prop::topic_alias] = uint16_t(12);
|
||||
props[async_mqtt5::prop::response_topic] = "response_topic";
|
||||
props[async_mqtt5::prop::subscription_identifier].push_back(40);
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<uint16_t> topic_alias = props[async_mqtt5::prop::topic_alias];
|
||||
if (topic_alias.has_value())
|
||||
// topic alias property was previously set
|
||||
else
|
||||
// topic alias property was not set
|
||||
|
||||
async_mqtt5::prop::subscription_identifiers& sub_ids = props[async_mqtt5::prop::subscription_identifier];
|
||||
if (!sub_ids.empty())
|
||||
// subscription identifier property was previously set
|
||||
else
|
||||
// subscription identifier property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __PUBREC__ Properties and describes their usage:
|
||||
[table:pubrec_props PUBREC properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,6 +17,9 @@ After obtaining an instance of `async_mqtt5::pubrec_props`, the subscript operat
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -24,17 +27,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::pubrec_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __PUBREL__ Properties and describes their usage:
|
||||
[table:pubrel_props PUBREL properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,23 +17,30 @@ After obtaining an instance of `async_mqtt5::pubrel_props`, the subscript operat
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
The following example shows how to set a Property value:
|
||||
|
||||
[!c++]
|
||||
async_mqtt5::pubrel_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __SUBACK__ Properties and describes their usage:
|
||||
[table:suback_props SUBACK properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,6 +17,9 @@ After obtaining an instance of `async_mqtt5::suback_props`, the subscript operat
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -24,17 +27,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::suback_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __SUBSCRIBE__ Properties and describes their usa
|
||||
[table:subscribe_props SUBSCRIBE properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[subscription_identifier] [`int32_t`] [Identifier of the Subscription in range of 1 to 268,435,455.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property can be used to send subscription related properties from the Client to the Server.
|
||||
The meaning of these properties is not defined by the specification ]]
|
||||
]
|
||||
@ -18,6 +18,11 @@ After obtaining an instance of `async_mqtt5::subscribe_props`, the subscript ope
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property` and `async_mqtt5::prop::subscription_identifier`, where it will return an instance of
|
||||
`std::vector<std::pair<std::string, std::string>>` and `async_mqtt5::prop::subscription_identifiers` respectively.
|
||||
`async_mqtt5::prop::subscription_identifiers` has the interface of `std::optional<int32_t>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -25,17 +30,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::subscribe_props props;
|
||||
props[async_mqtt5::prop::subscription_identifier] = 1234;
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<int32_t> sub_id = props[async_mqtt5::prop::subscription_identifier];
|
||||
async_mqtt5::prop::subscription_identifiers sub_id = props[async_mqtt5::prop::subscription_identifier];
|
||||
if (sub_id.has_value())
|
||||
// subscription identifier property was previously set
|
||||
else
|
||||
// subscription identifier property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -8,7 +8,7 @@ This section lists all possible __UNSUBACK__ Properties and describes their usag
|
||||
[table:unsuback_props UNSUBACK properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[reason_string] [`std::string`] [A UTF-8 Encoded String representing the reason associated with this response.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property may be used to provide additional diagnostic or other information. ]]
|
||||
]
|
||||
|
||||
@ -17,6 +17,9 @@ After obtaining an instance of `async_mqtt5::unsuback_props`, the subscript oper
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -24,17 +27,21 @@ The following example shows how to set a Property value:
|
||||
[!c++]
|
||||
async_mqtt5::unsuback_props props;
|
||||
props[async_mqtt5::prop::reason_string] = "Some reason...";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> reason_string = props[async_mqtt5::prop::reason_string];
|
||||
if (reason_string.has_value())
|
||||
// reason string property was previously set
|
||||
else
|
||||
// reason string property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -7,7 +7,7 @@ This section lists all possible __UNSUBSCRIBE__ Properties and describes their u
|
||||
|
||||
[table:unsubscribe_props UNSUBSCRIBE properties
|
||||
[[Identifier] [Value type] [Description]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
This property can be used to send subscription related properties from the Client to the Server.
|
||||
The meaning of these properties is not defined by the specification ]]
|
||||
]
|
||||
@ -17,22 +17,25 @@ After obtaining an instance of `async_mqtt5::unsubscribe_props`, the subscript o
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
|
||||
[!c++]
|
||||
async_mqtt5::unsubscribe_props props;
|
||||
props[async_mqtt5::prop::user_property].push_back("key");
|
||||
props[async_mqtt5::prop::user_property].push_back("value");
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::vector<std::string> user_props = props[async_mqtt5::prop::user_property];
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
|
||||
[endsect]
|
||||
|
@ -14,7 +14,7 @@ This section lists all possible [reflink2 will Will] Properties and describes th
|
||||
[[content_type] [`std::string`] [A UTF-8 Encoded String describing the content of the Will Message.]]
|
||||
[[response_topic] [`std::string`] [A UTF-8 Encoded String which is used as the Topic Name for a response message.]]
|
||||
[[correlation_data] [`std::string`] [Binary Data used by the sender of the Request Message to identify which request the Response Message is for when it is received.]]
|
||||
[[user_property] [`std::vector<std::string>`] [A list of name, value pairs (__UTF8_STRING_PAIR__) defining User Properties.
|
||||
[[user_property] [`std::pair<std::string, std::string>`] [Name, value pair (__UTF8_STRING_PAIR__) defining User Property. There can be multiple pairs in one packet.
|
||||
The meaning of these properties is not defined by the specification.]]
|
||||
]
|
||||
|
||||
@ -23,6 +23,9 @@ After creating an instance of [reflink2 will `async_mqtt5::will`], the subscript
|
||||
|
||||
The Identifiers listed in the table above are available within the `async_mqtt5::prop` namespace for Property access.
|
||||
|
||||
[note When accessing a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of `std::vector<std::pair<std::string, std::string>>`.]
|
||||
|
||||
[h4 Example]
|
||||
|
||||
The following example shows how to set a Property value:
|
||||
@ -31,12 +34,10 @@ The following example shows how to set a Property value:
|
||||
async_mqtt5::will will;
|
||||
will[async_mqtt5::prop::message_expiry_interval] = 90;
|
||||
will[async_mqtt5::prop::content_type] = "Notification";
|
||||
props[async_mqtt5::prop::user_property].emplace_back("name", "value");
|
||||
|
||||
The following example shows how to retrieve a Property value:
|
||||
|
||||
[note When retrieving a property value, the subscript operator will return a `std::optional` of the value type for all properties,
|
||||
except for `async_mqtt5::prop::user_property`, where it will return an instance of its value type, `std::vector<std::string>`.]
|
||||
|
||||
[!c++]
|
||||
std::optional<std::string> c_type = will[async_mqtt5::prop::content_type];
|
||||
if (c_type.has_value())
|
||||
@ -44,4 +45,10 @@ except for `async_mqtt5::prop::user_property`, where it will return an instance
|
||||
else
|
||||
// content type property was not set
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>& user_props = props[async_mqtt5::prop::user_property];
|
||||
if (!user_props.empty())
|
||||
// user property was previously set
|
||||
else
|
||||
// user property was not set
|
||||
|
||||
[endsect]
|
||||
|
@ -94,6 +94,13 @@ inline validation_result validate_mqtt_utf8(std::string_view str) {
|
||||
return validate_impl(str, is_valid_string_size, is_utf8);
|
||||
}
|
||||
|
||||
inline bool is_valid_string_pair(
|
||||
const std::pair<std::string, std::string>& str_pair
|
||||
) {
|
||||
return validate_mqtt_utf8(str_pair.first) == validation_result::valid &&
|
||||
validate_mqtt_utf8(str_pair.second) == validation_result::valid;
|
||||
}
|
||||
|
||||
} // namespace async_mqtt5::detail
|
||||
|
||||
#endif //ASYNC_MQTT5_UTF8_MQTT_HPP
|
||||
|
@ -349,49 +349,38 @@ bool parse_to_prop(
|
||||
It& iter, const It last,
|
||||
const Ctx& ctx, RCtx& rctx, Prop& prop
|
||||
) {
|
||||
using prop_type = decltype(prop);
|
||||
using prop_type = std::remove_reference_t<decltype(prop)>;
|
||||
|
||||
bool rv = false;
|
||||
if constexpr (is_optional<prop_type>) {
|
||||
using value_type =
|
||||
typename std::remove_reference_t<prop_type>::value_type;
|
||||
|
||||
if constexpr (std::is_same_v<value_type, uint8_t>) {
|
||||
uint8_t attr;
|
||||
rv = x3::byte_.parse(iter, last, ctx, rctx, attr);
|
||||
prop = attr;
|
||||
}
|
||||
if constexpr (std::is_same_v<value_type, uint16_t>) {
|
||||
uint16_t attr;
|
||||
rv = x3::big_word.parse(iter, last, ctx, rctx, attr);
|
||||
prop = attr;
|
||||
}
|
||||
if constexpr (std::is_same_v<value_type, int32_t>) {
|
||||
int32_t attr;
|
||||
rv = basic::varint_.parse(iter, last, ctx, rctx, attr);
|
||||
prop = attr;
|
||||
}
|
||||
if constexpr (std::is_same_v<value_type, uint32_t>) {
|
||||
uint32_t attr;
|
||||
rv = x3::big_dword.parse(iter, last, ctx, rctx, attr);
|
||||
prop = attr;
|
||||
}
|
||||
if constexpr (std::is_same_v<value_type, std::string>) {
|
||||
std::string attr;
|
||||
rv = basic::utf8_.parse(iter, last, ctx, rctx, attr);
|
||||
prop.emplace(std::move(attr));
|
||||
}
|
||||
if constexpr (std::is_same_v<prop_type, uint8_t>)
|
||||
rv = x3::byte_.parse(iter, last, ctx, rctx, prop);
|
||||
else if constexpr (std::is_same_v<prop_type, uint16_t>)
|
||||
rv = x3::big_word.parse(iter, last, ctx, rctx, prop);
|
||||
else if constexpr (std::is_same_v<prop_type, int32_t>)
|
||||
rv = basic::varint_.parse(iter, last, ctx, rctx, prop);
|
||||
else if constexpr (std::is_same_v<prop_type, uint32_t>)
|
||||
rv = x3::big_dword.parse(iter, last, ctx, rctx, prop);
|
||||
else if constexpr (std::is_same_v<prop_type, std::string>)
|
||||
rv = basic::utf8_.parse(iter, last, ctx, rctx, prop);
|
||||
|
||||
else if constexpr (is_optional<prop_type>) {
|
||||
typename prop_type::value_type val;
|
||||
rv = parse_to_prop(iter, last, ctx, rctx, val);
|
||||
if (rv) prop.emplace(std::move(val));
|
||||
}
|
||||
|
||||
if constexpr (async_mqtt5::is_vector<prop_type>) {
|
||||
std::string value;
|
||||
// key
|
||||
rv = basic::utf8_.parse(iter, last, ctx, rctx, value);
|
||||
if (rv) prop.push_back(std::move(value));
|
||||
// value
|
||||
rv = basic::utf8_.parse(iter, last, ctx, rctx, value);
|
||||
else if constexpr (is_pair<prop_type>) {
|
||||
rv = parse_to_prop(iter, last, ctx, rctx, prop.first);
|
||||
rv = parse_to_prop(iter, last, ctx, rctx, prop.second);
|
||||
}
|
||||
|
||||
else if constexpr (is_vector<prop_type> || is_small_vector<prop_type>) {
|
||||
typename std::remove_reference_t<prop_type>::value_type value;
|
||||
rv = parse_to_prop(iter, last, ctx, rctx, value);
|
||||
if (rv) prop.push_back(std::move(value));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -320,84 +320,26 @@ std::string& operator<<(std::string& s, T&& t) {
|
||||
|
||||
} // end namespace basic
|
||||
|
||||
namespace detail {
|
||||
|
||||
namespace pp = async_mqtt5::prop;
|
||||
|
||||
template <pp::property_type p, std::size_t I, typename Tuple>
|
||||
constexpr bool match_v = std::is_same_v<
|
||||
std::integral_constant<pp::property_type, p>,
|
||||
typename std::tuple_element_t<I, Tuple>::key
|
||||
>;
|
||||
|
||||
template <
|
||||
pp::property_type p, typename Tuple,
|
||||
typename Idxs = std::make_index_sequence<std::tuple_size_v<Tuple>>
|
||||
>
|
||||
struct type_index;
|
||||
|
||||
template <
|
||||
pp::property_type p, template <typename...> typename Tuple,
|
||||
typename... Args, std::size_t... Is
|
||||
>
|
||||
struct type_index<p, Tuple<Args...>, std::index_sequence<Is...>> :
|
||||
std::integral_constant<
|
||||
std::size_t, ((Is * match_v<p, Is, Tuple<Args...>>)+... + 0)
|
||||
>
|
||||
{
|
||||
static_assert(
|
||||
1 == (match_v<p, Is, Tuple<Args...>> + ... + 0),
|
||||
"T doesn't appear once in tuple"
|
||||
);
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
namespace prop {
|
||||
|
||||
namespace pp = async_mqtt5::prop;
|
||||
|
||||
template <pp::property_type p, typename T>
|
||||
struct prop_encoder_type {
|
||||
using key = std::integral_constant<pp::property_type, p>;
|
||||
using value = T;
|
||||
};
|
||||
|
||||
using encoder_types = std::tuple<
|
||||
prop_encoder_type<pp::shared_subscription_available_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::payload_format_indicator_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::message_expiry_interval_t, basic::int_def<uint32_t>>,
|
||||
prop_encoder_type<pp::content_type_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::response_topic_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::correlation_data_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::subscription_identifier_t, basic::int_def<basic::varint_t>>,
|
||||
prop_encoder_type<pp::session_expiry_interval_t, basic::int_def<uint32_t>>,
|
||||
prop_encoder_type<pp::assigned_client_identifier_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::server_keep_alive_t, basic::int_def<uint16_t>>,
|
||||
prop_encoder_type<pp::authentication_method_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::authentication_data_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::request_problem_information_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::will_delay_interval_t, basic::int_def<uint32_t>>,
|
||||
prop_encoder_type<pp::request_response_information_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::response_information_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::server_reference_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::reason_string_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::receive_maximum_t, basic::int_def<uint16_t>>,
|
||||
prop_encoder_type<pp::topic_alias_maximum_t, basic::int_def<uint16_t>>,
|
||||
prop_encoder_type<pp::topic_alias_t, basic::int_def<uint16_t>>,
|
||||
prop_encoder_type<pp::maximum_qos_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::retain_available_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::user_property_t, basic::utf8_def>,
|
||||
prop_encoder_type<pp::maximum_packet_size_t, basic::int_def<uint32_t>>,
|
||||
prop_encoder_type<pp::wildcard_subscription_available_t, basic::int_def<uint8_t>>,
|
||||
prop_encoder_type<pp::subscription_identifier_available_t, basic::int_def<uint8_t>>
|
||||
>;
|
||||
|
||||
template <pp::property_type p>
|
||||
constexpr auto encoder_for_prop = typename std::tuple_element_t<
|
||||
detail::type_index<p, encoder_types>::value, encoder_types
|
||||
>::value {};
|
||||
|
||||
template <typename T>
|
||||
auto encoder_for_prop_value(const T& val) {
|
||||
if constexpr (std::is_same_v<T, uint8_t>)
|
||||
return basic::int_def<uint8_t>{}(val);
|
||||
else if constexpr (std::is_same_v<T, uint16_t>)
|
||||
return basic::int_def<uint16_t>{}(val);
|
||||
else if constexpr (std::is_same_v<T, int32_t>)
|
||||
return basic::int_def<basic::varint_t>{}(val);
|
||||
else if constexpr (std::is_same_v<T, uint32_t>)
|
||||
return basic::int_def<uint32_t>{}(val);
|
||||
else if constexpr (std::is_same_v<T, std::string>)
|
||||
return basic::utf8_def{}(val);
|
||||
else if constexpr (is_pair<T>)
|
||||
return encoder_for_prop_value(val.first) &
|
||||
encoder_for_prop_value(val.second);
|
||||
}
|
||||
|
||||
template <typename T, pp::property_type p, typename Enable = void>
|
||||
class prop_val;
|
||||
@ -409,10 +351,8 @@ class prop_val<
|
||||
T, p,
|
||||
std::enable_if_t<!is_vector<T> && is_optional<T>>
|
||||
> : public basic::encoder {
|
||||
// T is always std::optional
|
||||
using opt_type = typename boost::remove_cv_ref_t<T>::value_type;
|
||||
// allows T to be reference type to std::optional
|
||||
static inline std::optional<opt_type> nulltype;
|
||||
static inline boost::remove_cv_ref_t<T> nulltype;
|
||||
T _val;
|
||||
public:
|
||||
prop_val(T val) : _val(val) {
|
||||
@ -422,16 +362,14 @@ public:
|
||||
|
||||
size_t byte_size() const {
|
||||
if (!_val) return 0;
|
||||
auto sval = encoder_for_prop<p>(_val);
|
||||
return 1 + sval.byte_size();
|
||||
return 1 + encoder_for_prop_value(*_val).byte_size();
|
||||
}
|
||||
|
||||
std::string& encode(std::string& s) const {
|
||||
if (!_val)
|
||||
return s;
|
||||
s.push_back(p);
|
||||
auto sval = encoder_for_prop<p>(_val);
|
||||
return sval.encode(s);
|
||||
return encoder_for_prop_value(*_val).encode(s);
|
||||
}
|
||||
};
|
||||
|
||||
@ -440,7 +378,7 @@ template <
|
||||
>
|
||||
class prop_val<
|
||||
T, p,
|
||||
std::enable_if_t<is_vector<T>>
|
||||
std::enable_if_t<is_vector<T> || is_small_vector<T>>
|
||||
> : public basic::encoder {
|
||||
// allows T to be reference type to std::vector
|
||||
static inline boost::remove_cv_ref_t<T> nulltype;
|
||||
@ -456,16 +394,8 @@ public:
|
||||
if (_val.empty()) return 0;
|
||||
|
||||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < _val.size() && i + 1 < _val.size(); i += 2) {
|
||||
auto skey = encoder_for_prop<p>(_val[i]);
|
||||
size_t key_size = skey.byte_size();
|
||||
|
||||
auto sval = encoder_for_prop<p>(_val[i + 1]);
|
||||
size_t val_size = sval.byte_size();
|
||||
|
||||
if (key_size && val_size)
|
||||
total_size += 1 + key_size + val_size;
|
||||
}
|
||||
for (const auto& elem : _val)
|
||||
total_size += 1 + encoder_for_prop_value(elem).byte_size();
|
||||
|
||||
return total_size;
|
||||
}
|
||||
@ -474,14 +404,9 @@ public:
|
||||
if (_val.empty())
|
||||
return s;
|
||||
|
||||
for (size_t i = 0; i < _val.size() && i + 1 < _val.size(); i += 2) {
|
||||
for (const auto& elem: _val) {
|
||||
s.push_back(p);
|
||||
|
||||
auto skey = encoder_for_prop<p>(_val[i]);
|
||||
skey.encode(s);
|
||||
|
||||
auto sval = encoder_for_prop<p>(_val[i + 1]);
|
||||
sval.encode(s);
|
||||
encoder_for_prop_value(elem).encode(s);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
#include <boost/type_traits/remove_cv_ref.hpp>
|
||||
|
||||
@ -30,6 +31,21 @@ constexpr bool is_vector = is_specialization<
|
||||
boost::remove_cv_ref_t<T>, std::vector
|
||||
>;
|
||||
|
||||
template <typename... Args>
|
||||
constexpr std::true_type is_small_vector_impl(
|
||||
boost::container::small_vector_base<Args...> const &
|
||||
);
|
||||
constexpr std::false_type is_small_vector_impl( ... );
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_small_vector =
|
||||
decltype(is_small_vector_impl(std::declval<T>()))::value;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_pair = is_specialization<
|
||||
boost::remove_cv_ref_t<T>, std::pair
|
||||
>;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_boost_iterator = is_specialization<
|
||||
boost::remove_cv_ref_t<T>, boost::iterator_range
|
||||
|
@ -131,8 +131,8 @@ private:
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
for (const auto& user_property: user_properties)
|
||||
if (!is_valid_string_pair(user_property))
|
||||
return client::error::malformed_packet;
|
||||
return error_code {};
|
||||
}
|
||||
|
@ -141,8 +141,8 @@ class endpoints {
|
||||
|
||||
public:
|
||||
template <typename Executor>
|
||||
endpoints(Executor ex, asio::steady_timer& timer)
|
||||
: _resolver(ex), _connect_timer(timer)
|
||||
endpoints(Executor ex, asio::steady_timer& timer) :
|
||||
_resolver(ex), _connect_timer(timer)
|
||||
{}
|
||||
|
||||
void clone_servers(const endpoints& other) {
|
||||
|
@ -379,16 +379,11 @@ private:
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
for (const auto& user_property: user_properties)
|
||||
if (!is_valid_string_pair(user_property))
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto subscription_identifier = props[prop::subscription_identifier];
|
||||
if (
|
||||
subscription_identifier &&
|
||||
(*subscription_identifier < min_subscription_identifier ||
|
||||
*subscription_identifier > max_subscription_identifier)
|
||||
)
|
||||
if (!props[prop::subscription_identifier].empty())
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto content_type = props[prop::content_type];
|
||||
|
@ -220,8 +220,8 @@ private:
|
||||
|
||||
error_code validate_props(const subscribe_props& props) const {
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
for (const auto& user_property: user_properties)
|
||||
if (!is_valid_string_pair(user_property))
|
||||
return client::error::malformed_packet;
|
||||
|
||||
auto sub_id = props[prop::subscription_identifier];
|
||||
|
@ -178,8 +178,8 @@ private:
|
||||
return client::error::invalid_topic;
|
||||
|
||||
auto user_properties = props[prop::user_property];
|
||||
for (const auto& user_prop: user_properties)
|
||||
if (validate_mqtt_utf8(user_prop) != validation_result::valid)
|
||||
for (const auto& user_property: user_properties)
|
||||
if (!is_valid_string_pair(user_property))
|
||||
return client::error::malformed_packet;
|
||||
return error_code {};
|
||||
}
|
||||
|
@ -368,14 +368,15 @@ public:
|
||||
*
|
||||
* \details The return type varies according to the property requested.
|
||||
* For all properties, the return type will be `std::optional` of their respective value type.
|
||||
* For `async_mqtt5::prop::user_property`, the return type is `std::vector<std::string>`.
|
||||
* For `async_mqtt5::prop::user_property`, the return type is
|
||||
* `std::vector<std::pair<std::string, std::string>>`.
|
||||
*
|
||||
* \param prop The \__CONNACK_PROPS\__ property value to retrieve.
|
||||
*
|
||||
* \par Example
|
||||
* \code
|
||||
* std::optional<std::string> auth_method = client.connack_property(async_mqtt5::prop::authentication_method); // ok
|
||||
* std::optional<std::string> c_type = client.connack_property(async_mqtt5::prop::content_type); // does not compile, not a CONNAK prop!
|
||||
* std::optional<std::string> c_type = client.connack_property(async_mqtt5::prop::content_type); // does not compile, not a CONNACK prop!
|
||||
* \endcode
|
||||
*
|
||||
* \see See \__CONNACK_PROPS\__ for all eligible properties.
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
namespace async_mqtt5::prop {
|
||||
|
||||
enum property_type : uint8_t {
|
||||
@ -39,9 +41,49 @@ enum property_type : uint8_t {
|
||||
shared_subscription_available_t = 0x2a
|
||||
};
|
||||
|
||||
class alignas(8) subscription_identifiers :
|
||||
public boost::container::small_vector<int32_t, 1>
|
||||
{
|
||||
using base_type = boost::container::small_vector<int32_t, 1>;
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
subscription_identifiers(int32_t val) : base_type { val } {}
|
||||
|
||||
bool has_value() const noexcept {
|
||||
return !empty();
|
||||
}
|
||||
|
||||
int32_t& operator*() noexcept {
|
||||
return front();
|
||||
}
|
||||
|
||||
int32_t operator*() const noexcept {
|
||||
return front();
|
||||
}
|
||||
|
||||
void emplace(int32_t val = 0) {
|
||||
*this = val;
|
||||
}
|
||||
|
||||
int32_t value() const {
|
||||
return front();
|
||||
}
|
||||
|
||||
int32_t value_or(int32_t default_val) const noexcept {
|
||||
return empty() ? default_val : front();
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
template <property_type p>
|
||||
struct property_traits;
|
||||
|
||||
using user_property_value_t = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
#define DEF_PROPERTY_TRAIT(Pname, Ptype) \
|
||||
template <> \
|
||||
struct property_traits<Pname##_t> { \
|
||||
@ -55,7 +97,7 @@ DEF_PROPERTY_TRAIT(message_expiry_interval, std::optional<uint32_t>);
|
||||
DEF_PROPERTY_TRAIT(content_type, std::optional<std::string>);
|
||||
DEF_PROPERTY_TRAIT(response_topic, std::optional<std::string>);
|
||||
DEF_PROPERTY_TRAIT(correlation_data, std::optional<std::string>);
|
||||
DEF_PROPERTY_TRAIT(subscription_identifier, std::optional<int32_t>);
|
||||
DEF_PROPERTY_TRAIT(subscription_identifier, subscription_identifiers);
|
||||
DEF_PROPERTY_TRAIT(session_expiry_interval, std::optional<uint32_t>);
|
||||
DEF_PROPERTY_TRAIT(assigned_client_identifier, std::optional<std::string>);
|
||||
DEF_PROPERTY_TRAIT(server_keep_alive, std::optional<uint16_t>);
|
||||
@ -72,7 +114,7 @@ DEF_PROPERTY_TRAIT(topic_alias_maximum, std::optional<uint16_t>);
|
||||
DEF_PROPERTY_TRAIT(topic_alias, std::optional<uint16_t>);
|
||||
DEF_PROPERTY_TRAIT(maximum_qos, std::optional<uint8_t>);
|
||||
DEF_PROPERTY_TRAIT(retain_available, std::optional<uint8_t>);
|
||||
DEF_PROPERTY_TRAIT(user_property, std::vector<std::string>);
|
||||
DEF_PROPERTY_TRAIT(user_property, user_property_value_t);
|
||||
DEF_PROPERTY_TRAIT(maximum_packet_size, std::optional<uint32_t>);
|
||||
DEF_PROPERTY_TRAIT(wildcard_subscription_available, std::optional<uint8_t>);
|
||||
DEF_PROPERTY_TRAIT(subscription_identifier_available, std::optional<uint8_t>);
|
||||
|
@ -41,8 +41,8 @@ public:
|
||||
/// \cond INTERNAL
|
||||
constexpr reason_code() : _code(0xff) {}
|
||||
|
||||
constexpr reason_code(uint8_t code, reason_codes::category cat)
|
||||
: _code(code), _category(cat)
|
||||
constexpr reason_code(uint8_t code, reason_codes::category cat) :
|
||||
_code(code), _category(cat)
|
||||
{}
|
||||
|
||||
constexpr explicit reason_code(uint8_t code) : _code(code) {}
|
||||
|
@ -80,7 +80,14 @@ inline std::string to_readable_props(Props props) {
|
||||
if (v.has_value())
|
||||
stream << *v << " ";
|
||||
if constexpr (is_vector<decltype(v)>)
|
||||
stream << boost::algorithm::join(v, ",");
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if constexpr (is_pair<decltype(v[i])>)
|
||||
stream << "(" << v[i].first << ", " << v[i].second << ")";
|
||||
else
|
||||
stream << v[i];
|
||||
if (i + 1 < v.size())
|
||||
stream << ", ";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return stream.str();
|
||||
|
@ -191,7 +191,8 @@ struct shared_connect_prop_test_data : shared_test_data {
|
||||
const uint16_t topic_alias_maximum = 12345;
|
||||
const uint8_t request_response_information = 1;
|
||||
const uint8_t request_problem_information = 0;
|
||||
const std::vector<std::string> user_properties = std::vector<std::string>{ "key", "val" };
|
||||
const std::vector<std::pair<std::string, std::string>> user_properties =
|
||||
{ { "key", "val" } };
|
||||
|
||||
connect_props cprops = create_connect_props();
|
||||
|
||||
@ -300,7 +301,8 @@ struct shared_connack_prop_test_data {
|
||||
const std::string assigned_client_id = "client_id";
|
||||
const uint16_t topic_alias_max = 128;
|
||||
const std::string reason_string = "reason string";
|
||||
const std::vector<std::string> user_properties = std::vector<std::string>{ "key", "val" };
|
||||
const std::vector<std::pair<std::string, std::string>> user_properties =
|
||||
{ { "key", "val" } };
|
||||
const uint8_t wildcard_sub = 1;
|
||||
const uint8_t sub_id = 1;
|
||||
const uint8_t shared_sub = 0;
|
||||
|
@ -125,6 +125,82 @@ BOOST_FIXTURE_TEST_CASE(receive_publish_qos2, shared_test_data) {
|
||||
run_test(std::move(broker_side));
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(receive_publish_properties, shared_test_data) {
|
||||
constexpr int expected_handlers_called = 1;
|
||||
int handlers_called = 0;
|
||||
|
||||
publish_props pprops;
|
||||
|
||||
pprops[prop::payload_format_indicator] = uint8_t(0);
|
||||
pprops[prop::message_expiry_interval] = 102u;
|
||||
pprops[prop::content_type] = "content/type";
|
||||
pprops[prop::response_topic] = "response/topic";
|
||||
pprops[prop::correlation_data] = std::string {
|
||||
static_cast<char>(0x00), static_cast<char>(0x01), static_cast<char>(0xFF)
|
||||
};
|
||||
pprops[prop::subscription_identifier] = { 40, 41, 42 };
|
||||
pprops[prop::topic_alias] = uint16_t(103);
|
||||
pprops[prop::user_property] = { { "name1", "value1" }, { "name2", "value2 "} };
|
||||
|
||||
auto publish = encoders::encode_publish(
|
||||
1, topic, payload,
|
||||
qos_e::at_most_once, retain_e::no, dup_e::no,
|
||||
pprops
|
||||
);
|
||||
|
||||
test::msg_exchange broker_side;
|
||||
broker_side
|
||||
.expect(connect)
|
||||
.complete_with(success, after(0ms))
|
||||
.reply_with(connack, after(0ms))
|
||||
.send(publish, after(10ms));
|
||||
|
||||
asio::io_context ioc;
|
||||
auto executor = ioc.get_executor();
|
||||
auto& broker = asio::make_service<test::test_broker>(
|
||||
ioc, executor, std::move(broker_side)
|
||||
);
|
||||
|
||||
using client_type = mqtt_client<test::test_stream>;
|
||||
client_type c(executor);
|
||||
c.brokers("127.0.0.1")
|
||||
.async_run(asio::detached);
|
||||
|
||||
c.async_receive([&handlers_called, &pprops, &c](
|
||||
error_code ec, std::string rec_topic, std::string rec_payload,
|
||||
publish_props rec_pprops
|
||||
){
|
||||
++handlers_called;
|
||||
auto data = shared_test_data();
|
||||
BOOST_TEST(!ec);
|
||||
BOOST_TEST(data.topic == rec_topic);
|
||||
BOOST_TEST(data.payload == rec_payload);
|
||||
BOOST_TEST(*pprops[prop::payload_format_indicator]
|
||||
== *rec_pprops[prop::payload_format_indicator]);
|
||||
BOOST_TEST(*pprops[prop::message_expiry_interval]
|
||||
== *rec_pprops[prop::message_expiry_interval]);
|
||||
BOOST_TEST(*pprops[prop::content_type]
|
||||
== *rec_pprops[prop::content_type]);
|
||||
BOOST_TEST(*pprops[prop::response_topic]
|
||||
== *rec_pprops[prop::response_topic]);
|
||||
BOOST_TEST(*pprops[prop::correlation_data]
|
||||
== *rec_pprops[prop::correlation_data]);
|
||||
BOOST_TEST(pprops[prop::subscription_identifier]
|
||||
== rec_pprops[prop::subscription_identifier]);
|
||||
BOOST_TEST(*pprops[prop::topic_alias]
|
||||
== *rec_pprops[prop::topic_alias]);
|
||||
BOOST_TEST(pprops[prop::user_property]
|
||||
== rec_pprops[prop::user_property]);
|
||||
c.cancel();
|
||||
}
|
||||
);
|
||||
|
||||
ioc.run();
|
||||
BOOST_TEST(handlers_called == expected_handlers_called);
|
||||
BOOST_TEST(broker.received_all_expected());
|
||||
}
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(receive_malformed_publish, shared_test_data) {
|
||||
// packets
|
||||
auto malformed_publish = encoders::encode_publish(
|
||||
@ -322,8 +398,10 @@ BOOST_FIXTURE_TEST_CASE(receive_big_publish, shared_test_data) {
|
||||
cprops[prop::maximum_packet_size] = 10'000'000;
|
||||
|
||||
publish_props big_props;
|
||||
for (int i = 0; i < 100; i++)
|
||||
big_props[prop::user_property].push_back(std::string(65534, 'u'));
|
||||
for (int i = 0; i < 50; i++)
|
||||
big_props[prop::user_property].emplace_back(
|
||||
std::string(65534, 'u'), std::string(65534, 'v')
|
||||
);
|
||||
|
||||
// packets
|
||||
auto connect_big_packets = encoders::encode_connect(
|
||||
|
@ -545,16 +545,12 @@ BOOST_FIXTURE_TEST_CASE(send_big_publish, shared_test_data) {
|
||||
const std::string big_topic = std::string(65534, 't');
|
||||
const std::string big_payload = std::string(65534, 'p');
|
||||
|
||||
publish_props big_props;
|
||||
for (int i = 0; i < 1; i++)
|
||||
big_props[prop::user_property].push_back(std::string(65534, 'u'));
|
||||
|
||||
// packets
|
||||
auto allow_big_connack = encoders::encode_connack(false, uint8_t(0x00), cprops);
|
||||
auto big_publish = encoders::encode_publish(
|
||||
1, big_topic, big_payload,
|
||||
qos_e::at_least_once, retain_e::no, dup_e::no,
|
||||
big_props
|
||||
publish_props{}
|
||||
);
|
||||
auto pingreq = encoders::encode_pingreq();
|
||||
auto pingresp = encoders::encode_pingresp();
|
||||
@ -590,7 +586,7 @@ BOOST_FIXTURE_TEST_CASE(send_big_publish, shared_test_data) {
|
||||
.async_run(asio::detached);
|
||||
|
||||
c.async_publish<qos_e::at_least_once>(
|
||||
big_topic, big_payload, retain_e::no, big_props,
|
||||
big_topic, big_payload, retain_e::no, publish_props{},
|
||||
[&handlers_called, &c](error_code ec, reason_code rc, puback_props) {
|
||||
++handlers_called;
|
||||
|
||||
|
@ -50,9 +50,16 @@ BOOST_AUTO_TEST_CASE(malformed_reason_string) {
|
||||
run_malformed_props_test(dprops);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property) {
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_key) {
|
||||
disconnect_props dprops;
|
||||
dprops[prop::user_property].push_back(std::string { 0x01 });
|
||||
dprops[prop::user_property].emplace_back(std::string { 0x01 }, "value");
|
||||
|
||||
run_malformed_props_test(dprops);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_value) {
|
||||
disconnect_props dprops;
|
||||
dprops[prop::user_property].emplace_back("key", std::string { 0x01 });
|
||||
|
||||
run_malformed_props_test(dprops);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(malformed_props_1) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_props_2) {
|
||||
publish_props pprops;
|
||||
pprops[prop::user_property].push_back(std::string { 0x01 });
|
||||
pprops[prop::user_property].emplace_back(std::string { 0x01 }, "value");
|
||||
|
||||
run_malformed_props_test(pprops);
|
||||
}
|
||||
@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(malformed_props_4) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_props_5) {
|
||||
publish_props pprops;
|
||||
pprops[prop::subscription_identifier] = 300'000'000;
|
||||
pprops[prop::subscription_identifier].push_back(40);
|
||||
|
||||
run_malformed_props_test(pprops);
|
||||
}
|
||||
|
@ -50,8 +50,7 @@ BOOST_AUTO_TEST_CASE(test_connect) {
|
||||
cprops[prop::topic_alias_maximum] = topic_alias_max;
|
||||
cprops[prop::request_response_information] = request_response_information;
|
||||
cprops[prop::request_problem_information] = request_problem_information;
|
||||
cprops[prop::user_property].emplace_back(user_property_1);
|
||||
cprops[prop::user_property].emplace_back(user_property_2);
|
||||
cprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
cprops[prop::authentication_method] = auth_method;
|
||||
cprops[prop::authentication_data] = auth_data;
|
||||
|
||||
@ -62,8 +61,7 @@ BOOST_AUTO_TEST_CASE(test_connect) {
|
||||
w[prop::content_type] = will_content_type;
|
||||
w[prop::response_topic] = will_response_topic;
|
||||
w[prop::correlation_data] = will_correlation_data;
|
||||
w[prop::user_property].emplace_back(will_user_property_1);
|
||||
w[prop::user_property].emplace_back(will_user_property_2);
|
||||
w[prop::user_property].emplace_back(will_user_property_1, will_user_property_2);
|
||||
std::optional<will> will_opt { std::move(w) };
|
||||
|
||||
auto msg = encoders::encode_connect(
|
||||
@ -96,9 +94,9 @@ BOOST_AUTO_TEST_CASE(test_connect) {
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::topic_alias_maximum], topic_alias_max);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::request_response_information], request_response_information);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::request_problem_information], request_problem_information);
|
||||
BOOST_ASSERT(cprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(cprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0].second, user_property_2);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::authentication_method], auth_method);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::authentication_data], auth_data);
|
||||
|
||||
@ -114,9 +112,9 @@ BOOST_AUTO_TEST_CASE(test_connect) {
|
||||
BOOST_CHECK_EQUAL(*(*w_)[prop::content_type], will_content_type);
|
||||
BOOST_CHECK_EQUAL(*(*w_)[prop::response_topic], will_response_topic);
|
||||
BOOST_CHECK_EQUAL(*(*w_)[prop::correlation_data], will_correlation_data);
|
||||
BOOST_ASSERT((*w_)[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL((*w_)[prop::user_property][0], will_user_property_1);
|
||||
BOOST_CHECK_EQUAL((*w_)[prop::user_property][1], will_user_property_2);
|
||||
BOOST_ASSERT((*w_)[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL((*w_)[prop::user_property][0].first, will_user_property_1);
|
||||
BOOST_CHECK_EQUAL((*w_)[prop::user_property][0].second, will_user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_connack) {
|
||||
@ -152,8 +150,7 @@ BOOST_AUTO_TEST_CASE(test_connack) {
|
||||
cprops[prop::assigned_client_identifier] = assigned_client_id;
|
||||
cprops[prop::topic_alias_maximum] = topic_alias_max;
|
||||
cprops[prop::reason_string] = reason_string;
|
||||
cprops[prop::user_property].push_back(user_property_1);
|
||||
cprops[prop::user_property].push_back(user_property_2);
|
||||
cprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
cprops[prop::wildcard_subscription_available] = wildcard_sub;
|
||||
cprops[prop::subscription_identifier_available] = sub_id;
|
||||
cprops[prop::shared_subscription_available] = shared_sub;
|
||||
@ -186,9 +183,9 @@ BOOST_AUTO_TEST_CASE(test_connack) {
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::assigned_client_identifier], assigned_client_id);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::topic_alias_maximum], topic_alias_max);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(cprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(cprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(cprops_[prop::user_property][0].second, user_property_2);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::wildcard_subscription_available], wildcard_sub);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::subscription_identifier_available], sub_id);
|
||||
BOOST_CHECK_EQUAL(*cprops_[prop::shared_subscription_available], shared_sub);
|
||||
@ -221,9 +218,8 @@ BOOST_AUTO_TEST_CASE(test_publish) {
|
||||
pprops[prop::topic_alias] = topic_alias;
|
||||
pprops[prop::response_topic] = response_topic;
|
||||
pprops[prop::correlation_data] = correlation_data;
|
||||
pprops[prop::user_property].emplace_back(publish_prop_1);
|
||||
pprops[prop::user_property].emplace_back(publish_prop_2);
|
||||
pprops[prop::subscription_identifier] = subscription_identifier;
|
||||
pprops[prop::user_property].emplace_back(publish_prop_1, publish_prop_2);
|
||||
pprops[prop::subscription_identifier].push_back(subscription_identifier);
|
||||
pprops[prop::content_type] = content_type;
|
||||
|
||||
auto msg = encoders::encode_publish(
|
||||
@ -252,10 +248,11 @@ BOOST_AUTO_TEST_CASE(test_publish) {
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::topic_alias], topic_alias);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::response_topic], response_topic);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::correlation_data], correlation_data);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0], publish_prop_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][1], publish_prop_2);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::subscription_identifier], subscription_identifier);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].first, publish_prop_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].second, publish_prop_2);
|
||||
BOOST_ASSERT(pprops_[prop::subscription_identifier].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::subscription_identifier][0], subscription_identifier);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::content_type], content_type);
|
||||
}
|
||||
|
||||
@ -297,8 +294,7 @@ BOOST_AUTO_TEST_CASE(test_puback) {
|
||||
|
||||
puback_props pprops;
|
||||
pprops[prop::reason_string] = reason_string;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
pprops[prop::user_property].emplace_back(user_property_2);
|
||||
pprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_puback(packet_id, reason_code, pprops);
|
||||
|
||||
@ -318,9 +314,9 @@ BOOST_AUTO_TEST_CASE(test_puback) {
|
||||
pprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(reason_code_, reason_code);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_pubrec) {
|
||||
@ -334,8 +330,7 @@ BOOST_AUTO_TEST_CASE(test_pubrec) {
|
||||
|
||||
pubrec_props pprops;
|
||||
pprops[prop::reason_string] = reason_string;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
pprops[prop::user_property].emplace_back(user_property_2);
|
||||
pprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_pubrec(packet_id, reason_code, pprops);
|
||||
|
||||
@ -355,9 +350,9 @@ BOOST_AUTO_TEST_CASE(test_pubrec) {
|
||||
pprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(reason_code_, reason_code);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_pubrel) {
|
||||
@ -371,8 +366,7 @@ BOOST_AUTO_TEST_CASE(test_pubrel) {
|
||||
|
||||
pubrel_props pprops;
|
||||
pprops[prop::reason_string] = reason_string;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
pprops[prop::user_property].emplace_back(user_property_2);
|
||||
pprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_pubrel(packet_id, reason_code, pprops);
|
||||
|
||||
@ -392,9 +386,9 @@ BOOST_AUTO_TEST_CASE(test_pubrel) {
|
||||
pprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(reason_code_, reason_code);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_pubcomp) {
|
||||
@ -408,8 +402,7 @@ BOOST_AUTO_TEST_CASE(test_pubcomp) {
|
||||
|
||||
pubcomp_props pprops;
|
||||
pprops[prop::reason_string] = reason_string;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
pprops[prop::user_property].emplace_back(user_property_2);
|
||||
pprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_pubcomp(packet_id, reason_code, pprops);
|
||||
|
||||
@ -429,9 +422,9 @@ BOOST_AUTO_TEST_CASE(test_pubcomp) {
|
||||
pprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(reason_code_, reason_code);
|
||||
BOOST_CHECK_EQUAL(*pprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(pprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(pprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_subscribe) {
|
||||
@ -447,8 +440,7 @@ BOOST_AUTO_TEST_CASE(test_subscribe) {
|
||||
|
||||
subscribe_props sprops;
|
||||
sprops[prop::subscription_identifier] = sub_id;
|
||||
sprops[prop::user_property].push_back(user_property_1);
|
||||
sprops[prop::user_property].push_back(user_property_2);
|
||||
sprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
std::vector<subscribe_topic> filters {
|
||||
{
|
||||
@ -484,9 +476,9 @@ BOOST_AUTO_TEST_CASE(test_subscribe) {
|
||||
|
||||
sprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(*sprops_[prop::subscription_identifier], sub_id);
|
||||
BOOST_ASSERT(sprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(sprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_suback) {
|
||||
@ -500,8 +492,7 @@ BOOST_AUTO_TEST_CASE(test_suback) {
|
||||
|
||||
suback_props sprops;
|
||||
sprops[prop::reason_string] = reason_string;
|
||||
sprops[prop::user_property].push_back(user_property_1);
|
||||
sprops[prop::user_property].push_back(user_property_2);
|
||||
sprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_suback(packet_id, reason_codes, sprops);
|
||||
|
||||
@ -521,9 +512,9 @@ BOOST_AUTO_TEST_CASE(test_suback) {
|
||||
|
||||
sprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(*sprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(sprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(sprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(sprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_unsubscribe) {
|
||||
@ -535,8 +526,7 @@ BOOST_AUTO_TEST_CASE(test_unsubscribe) {
|
||||
std::string user_property_2 = "UNSUBSCRIBE user prop val";
|
||||
|
||||
unsubscribe_props uprops;
|
||||
uprops[prop::user_property].push_back(user_property_1);
|
||||
uprops[prop::user_property].push_back(user_property_2);
|
||||
uprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_unsubscribe(packet_id, topics, uprops);
|
||||
|
||||
@ -555,9 +545,9 @@ BOOST_AUTO_TEST_CASE(test_unsubscribe) {
|
||||
BOOST_CHECK(topics_ == topics);
|
||||
|
||||
uprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_ASSERT(uprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(uprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_unsuback) {
|
||||
@ -571,8 +561,7 @@ BOOST_AUTO_TEST_CASE(test_unsuback) {
|
||||
|
||||
unsuback_props uprops;
|
||||
uprops[prop::reason_string] = reason_string;
|
||||
uprops[prop::user_property].push_back(user_property_1);
|
||||
uprops[prop::user_property].push_back(user_property_2);
|
||||
uprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_unsuback(packet_id, reason_codes, uprops);
|
||||
|
||||
@ -592,9 +581,9 @@ BOOST_AUTO_TEST_CASE(test_unsuback) {
|
||||
|
||||
uprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(*uprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(uprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(uprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(uprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_disconnect) {
|
||||
@ -610,8 +599,7 @@ BOOST_AUTO_TEST_CASE(test_disconnect) {
|
||||
disconnect_props dprops;
|
||||
dprops[prop::session_expiry_interval] = session_expiry_interval;
|
||||
dprops[prop::reason_string] = reason_string;
|
||||
dprops[prop::user_property].emplace_back(user_property_1);
|
||||
dprops[prop::user_property].emplace_back(user_property_2);
|
||||
dprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
dprops[prop::server_reference] = server_reference;
|
||||
|
||||
auto msg = encoders::encode_disconnect(reason_code, dprops);
|
||||
@ -630,9 +618,9 @@ BOOST_AUTO_TEST_CASE(test_disconnect) {
|
||||
dprops_.visit([](const auto& p, const auto&) { (void)p; BOOST_ASSERT(p); return true; });
|
||||
BOOST_CHECK_EQUAL(*dprops_[prop::session_expiry_interval], session_expiry_interval);
|
||||
BOOST_CHECK_EQUAL(*dprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(dprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(dprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(dprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(dprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(dprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(dprops_[prop::user_property][0].second, user_property_2);
|
||||
BOOST_CHECK_EQUAL(*dprops_[prop::server_reference], server_reference);
|
||||
}
|
||||
|
||||
@ -651,8 +639,7 @@ BOOST_AUTO_TEST_CASE(test_auth) {
|
||||
aprops[prop::authentication_method] = authentication_method;
|
||||
aprops[prop::authentication_data] = authentication_data;
|
||||
aprops[prop::reason_string] = reason_string;
|
||||
aprops[prop::user_property].emplace_back(user_property_1);
|
||||
aprops[prop::user_property].emplace_back(user_property_2);
|
||||
aprops[prop::user_property].emplace_back(user_property_1, user_property_2);
|
||||
|
||||
auto msg = encoders::encode_auth(reason_code, aprops);
|
||||
|
||||
@ -671,9 +658,9 @@ BOOST_AUTO_TEST_CASE(test_auth) {
|
||||
BOOST_CHECK_EQUAL(*aprops_[prop::authentication_method], authentication_method);
|
||||
BOOST_CHECK_EQUAL(*aprops_[prop::authentication_data], authentication_data);
|
||||
BOOST_CHECK_EQUAL(*aprops_[prop::reason_string], reason_string);
|
||||
BOOST_ASSERT(aprops_[prop::user_property].size() == 2);
|
||||
BOOST_CHECK_EQUAL(aprops_[prop::user_property][0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(aprops_[prop::user_property][1], user_property_2);
|
||||
BOOST_ASSERT(aprops_[prop::user_property].size() == 1);
|
||||
BOOST_CHECK_EQUAL(aprops_[prop::user_property][0].first, user_property_1);
|
||||
BOOST_CHECK_EQUAL(aprops_[prop::user_property][0].second, user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_pingreq) {
|
||||
@ -692,8 +679,7 @@ BOOST_AUTO_TEST_CASE(test_pingresp) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_user_property) {
|
||||
publish_props pprops;
|
||||
pprops[prop::user_property].emplace_back("");
|
||||
pprops[prop::user_property].emplace_back("");
|
||||
pprops[prop::user_property].emplace_back("", "");
|
||||
|
||||
auto msg = encoders::encode_publish(
|
||||
1, "topic", "payload",
|
||||
@ -712,69 +698,9 @@ BOOST_AUTO_TEST_CASE(empty_user_property) {
|
||||
const auto& [topic_, packet_id_, flags, pprops_, payload_] = *rv;
|
||||
|
||||
auto user_props_ = pprops_[prop::user_property];
|
||||
BOOST_ASSERT(user_props_.size() == 2);
|
||||
BOOST_CHECK_EQUAL(user_props_[0], "");
|
||||
BOOST_CHECK_EQUAL(user_props_[1], "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(omit_invalid_user_property) {
|
||||
// testing variables
|
||||
std::string_view user_property_1 = "key";
|
||||
std::string_view user_property_2 = "val";
|
||||
std::string_view user_property_3 = "lone key";
|
||||
|
||||
publish_props pprops;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
pprops[prop::user_property].emplace_back(user_property_2);
|
||||
pprops[prop::user_property].emplace_back(user_property_3);
|
||||
|
||||
auto msg = encoders::encode_publish(
|
||||
1, "topic", "payload",
|
||||
qos_e::at_least_once, retain_e::yes, dup_e::no,
|
||||
pprops
|
||||
);
|
||||
|
||||
byte_citer it = msg.cbegin(), last = msg.cend();
|
||||
auto header = decoders::decode_fixed_header(it, last);
|
||||
BOOST_ASSERT(header);
|
||||
|
||||
const auto& [control_byte, remain_length] = *header;
|
||||
auto rv = decoders::decode_publish(control_byte, remain_length, it);
|
||||
BOOST_ASSERT(rv);
|
||||
|
||||
const auto& [topic_, packet_id_, flags, pprops_, payload_] = *rv;
|
||||
|
||||
auto user_props_ = pprops_[prop::user_property];
|
||||
BOOST_ASSERT(user_props_.size() == 2);
|
||||
BOOST_CHECK_EQUAL(user_props_[0], user_property_1);
|
||||
BOOST_CHECK_EQUAL(user_props_[1], user_property_2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(omit_all_user_property) {
|
||||
// testing variables
|
||||
std::string_view user_property_1 = "key";
|
||||
|
||||
publish_props pprops;
|
||||
pprops[prop::user_property].emplace_back(user_property_1);
|
||||
|
||||
auto msg = encoders::encode_publish(
|
||||
1, "topic", "payload",
|
||||
qos_e::at_least_once, retain_e::yes, dup_e::no,
|
||||
pprops
|
||||
);
|
||||
|
||||
byte_citer it = msg.cbegin(), last = msg.cend();
|
||||
auto header = decoders::decode_fixed_header(it, last);
|
||||
BOOST_ASSERT(header);
|
||||
|
||||
const auto& [control_byte, remain_length] = *header;
|
||||
auto rv = decoders::decode_publish(control_byte, remain_length, it);
|
||||
BOOST_ASSERT(rv);
|
||||
|
||||
const auto& [topic_, packet_id_, flags, pprops_, payload_] = *rv;
|
||||
|
||||
auto user_props_ = pprops_[prop::user_property];
|
||||
BOOST_CHECK(user_props_.size() == 0);
|
||||
BOOST_ASSERT(user_props_.size() == 1);
|
||||
BOOST_CHECK_EQUAL(user_props_[0].first, "");
|
||||
BOOST_CHECK_EQUAL(user_props_[0].second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deserialize_user_property) {
|
||||
@ -795,9 +721,9 @@ BOOST_AUTO_TEST_CASE(deserialize_user_property) {
|
||||
|
||||
const auto& [reason_code_, pprops_] = *rv;
|
||||
auto user_props_ = pprops_[prop::user_property];
|
||||
BOOST_ASSERT(user_props_.size() == 2);
|
||||
BOOST_CHECK_EQUAL(user_props_[0], "key");
|
||||
BOOST_CHECK_EQUAL(user_props_[1], "val");
|
||||
BOOST_ASSERT(user_props_.size() == 1);
|
||||
BOOST_CHECK_EQUAL(user_props_[0].first, "key");
|
||||
BOOST_CHECK_EQUAL(user_props_[0].second, "val");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deserialize_empty_user_property) {
|
||||
@ -818,9 +744,9 @@ BOOST_AUTO_TEST_CASE(deserialize_empty_user_property) {
|
||||
|
||||
const auto& [reason_code_, pprops_] = *rv;
|
||||
auto user_props_ = pprops_[prop::user_property];
|
||||
BOOST_ASSERT(user_props_.size() == 2);
|
||||
BOOST_CHECK_EQUAL(user_props_[0], "");
|
||||
BOOST_CHECK_EQUAL(user_props_[1], "");
|
||||
BOOST_ASSERT(user_props_.size() == 1);
|
||||
BOOST_CHECK_EQUAL(user_props_[0].first, "");
|
||||
BOOST_CHECK_EQUAL(user_props_[0].second, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property) {
|
||||
|
@ -105,14 +105,14 @@ BOOST_AUTO_TEST_CASE(invalid_topic_filter_6) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_1) {
|
||||
subscribe_props sprops;
|
||||
sprops[prop::user_property].push_back(std::string(10, char(0x01)));
|
||||
sprops[prop::user_property].emplace_back("key", std::string(10, char(0x01)));
|
||||
|
||||
run_test(client::error::malformed_packet, "topic", sprops);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_2) {
|
||||
subscribe_props sprops;
|
||||
sprops[prop::user_property].push_back(std::string(75000, 'a'));
|
||||
sprops[prop::user_property].emplace_back("key", std::string(75000, 'a'));
|
||||
|
||||
run_test(client::error::malformed_packet, "topic", sprops);
|
||||
}
|
||||
|
@ -100,14 +100,14 @@ BOOST_AUTO_TEST_CASE(invalid_topic_filter_6) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_1) {
|
||||
unsubscribe_props uprops;
|
||||
uprops[prop::user_property].push_back(std::string(10, char(0x01)));
|
||||
uprops[prop::user_property].emplace_back("key", std::string(10, char(0x01)));
|
||||
|
||||
run_test(client::error::malformed_packet, "topic", uprops);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(malformed_user_property_2) {
|
||||
unsubscribe_props uprops;
|
||||
uprops[prop::user_property].push_back(std::string(75000, 'a'));
|
||||
uprops[prop::user_property].emplace_back("key", std::string(75000, 'a'));
|
||||
|
||||
run_test(client::error::malformed_packet, "topic", uprops);
|
||||
}
|
||||
|
Reference in New Issue
Block a user