diff --git a/docs/doxygen/pages.dox b/docs/doxygen/pages.dox index fba6ecf2..15cbc69d 100644 --- a/docs/doxygen/pages.dox +++ b/docs/doxygen/pages.dox @@ -75,16 +75,16 @@ Some configuration settings are C pre-processor constants, and some are function /** @page shadow_functions Functions @brief Primary functions of the Shadow library:

-@subpage shadow_matchtopic_function
-@subpage shadow_gettopicstring_function
+@subpage shadow_matchtopicstring_function
+@subpage shadow_assembletopicstring_function
-@page shadow_matchtopic_function Shadow_MatchTopic -@snippet shadow.h declare_shadow_matchtopic -@copydoc Shadow_MatchTopic +@page shadow_matchtopicstring_function Shadow_MatchTopicString +@snippet shadow.h declare_shadow_matchtopicstring +@copydoc Shadow_MatchTopicString -@page shadow_gettopicstring_function Shadow_GetTopicString -@snippet shadow.h declare_shadow_gettopicstring -@copydoc Shadow_GetTopicString +@page shadow_assembletopicstring_function Shadow_AssembleTopicString +@snippet shadow.h declare_shadow_assembletopicstring +@copydoc Shadow_AssembleTopicString */ diff --git a/lexicon.txt b/lexicon.txt index 6f03e3b4..98a31c59 100644 --- a/lexicon.txt +++ b/lexicon.txt @@ -43,6 +43,8 @@ matchtopic mdash messagetype mqtt +myshadow +myshadowname mything mythingname noninfringement @@ -51,11 +53,16 @@ operationlength os outlength param +pconsumedtopiclength pmessagetype png posix +pname +pnamelength poutlength pre +pshadowname +pshadownamelength pstring psubstring pthingname @@ -65,6 +72,8 @@ ptopicbuffer ptopicname rm sdk +shadowname +shadownamelength shadowstatus shadowtopicstringtypedelete shadowtopicstringtypedeleteaccepted @@ -87,6 +96,7 @@ sublicense substringlength suffixlength td +testshadowname testthingname thingname thingnamelength @@ -97,3 +107,4 @@ topicnamelength topictype tr utest +un diff --git a/source/include/shadow.h b/source/include/shadow.h index eb7175a9..37d3873c 100644 --- a/source/include/shadow.h +++ b/source/include/shadow.h @@ -67,7 +67,7 @@ typedef enum ShadowMessageType * @ingroup shadow_enum_types * @brief Each of these values describes the type of a shadow topic string. * - * These are used for topicType parameter of Shadow_GetTopicString() to tell it + * These are used for topicType parameter of Shadow_AssembleTopicString() to tell it * what topic string to assemble. */ typedef enum ShadowTopicStringType @@ -92,15 +92,17 @@ typedef enum ShadowTopicStringType */ typedef enum ShadowStatus { - SHADOW_SUCCESS = 0, /**< @brief Shadow function success. */ - SHADOW_FAIL, /**< @brief Shadow function encountered error. */ - SHADOW_BAD_PARAMETER, /**< @brief Input parameter is invalid. */ - SHADOW_BUFFER_TOO_SMALL, /**< @brief The provided buffer is too small. */ - SHADOW_THINGNAME_PARSE_FAILED, /**< @brief Could not parse the thing name. */ - SHADOW_SHADOW_MESSAGE_TYPE_PARSE_FAILED /**< @brief Could not parse the shadow type. */ + SHADOW_SUCCESS = 0, /**< @brief Shadow function success. */ + SHADOW_FAIL, /**< @brief Shadow function encountered error. */ + SHADOW_BAD_PARAMETER, /**< @brief Input parameter is invalid. */ + SHADOW_BUFFER_TOO_SMALL, /**< @brief The provided buffer is too small. */ + SHADOW_THINGNAME_PARSE_FAILED, /**< @brief Could not parse the thing name. */ + SHADOW_MESSAGE_TYPE_PARSE_FAILED, /**< @brief Could not parse the shadow type. */ + SHADOW_ROOT_PARSE_FAILED, /**< @brief Could not parse the classic or named shadow root. */ + SHADOW_SHADOWNAME_PARSE_FAILED /**< @brief Could not parse the shadow name (in the case of a named shadow topic). */ } ShadowStatus_t; -/*------------------------ Shadow library functions -------------------------*/ +/*------------------------ Shadow library constants -------------------------*/ /** * @ingroup shadow_constants @@ -115,11 +117,37 @@ typedef enum ShadowStatus */ #define SHADOW_PREFIX_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_PREFIX ) - 1U ) ) +/** + * @ingroup shadow_constants + * @brief The root of all unnamed "Classic" Shadow MQTT topics + * from here https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-mqtt.html. + */ +#define SHADOW_CLASSIC_ROOT "/shadow" + +/** + * @ingroup shadow_constants + * @brief The length of #SHADOW_CLASSIC_ROOT. + */ +#define SHADOW_CLASSIC_ROOT_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_CLASSIC_ROOT ) - 1U ) ) + +/** + * @ingroup shadow_constants + * @brief The common root of all named Shadow MQTT topics + * from here https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-mqtt.html. + */ +#define SHADOW_NAMED_ROOT "/shadow/name/" + +/** + * @ingroup shadow_constants + * @brief The length of #SHADOW_NAMED_ROOT. + */ +#define SHADOW_NAMED_ROOT_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_NAMED_ROOT ) - 1U ) ) + /** * @ingroup shadow_constants * @brief The string representing a Shadow "DELETE" operation in a Shadow MQTT topic. */ -#define SHADOW_OP_DELETE "/shadow/delete" +#define SHADOW_OP_DELETE "/delete" /** * @ingroup shadow_constants @@ -131,7 +159,7 @@ typedef enum ShadowStatus * @ingroup shadow_constants * @brief The string representing a Shadow "GET" operation in a Shadow MQTT topic. */ -#define SHADOW_OP_GET "/shadow/get" +#define SHADOW_OP_GET "/get" /** * @ingroup shadow_constants @@ -143,7 +171,7 @@ typedef enum ShadowStatus * @ingroup shadow_constants * @brief The string representing a Shadow "UPDATE" operation in a Shadow MQTT topic. */ -#define SHADOW_OP_UPDATE "/shadow/update" +#define SHADOW_OP_UPDATE "/update" /** * @ingroup shadow_constants @@ -217,119 +245,230 @@ typedef enum ShadowStatus */ #define SHADOW_THINGNAME_LENGTH_MAX ( 128U ) +/** + * @ingroup shadow_constants + * @brief The maximum length of Shadow Name. + */ +#define SHADOW_NAME_LENGTH_MAX ( 64U ) + +/** + * @ingroup shadow_constants + * @brief The name string for the unnamed "Classic" shadow. + */ +#define SHADOW_NAME_CLASSIC "" + +/** + * @ingroup shadow_constants + * @brief The length of #SHADOW_NAME_CLASSIC. + */ +#define SHADOW_NAME_CLASSIC_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_NAME_CLASSIC ) - 1U ) ) + /** * @ingroup shadow_constants * @brief Compute shadow topic length. * * The format of shadow topic strings is defined at https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-mqtt.html * - * A shadow topic string takes one of the two forms: + * A shadow topic string takes one of the two forms, in the case of an unnamed ("Classic") shadow: * $aws/things/\/shadow/\ * $aws/things/\/shadow/\/\ * - * The \, \ and \ segments correspond to the three input - * parameters of this macro. The \ part can be null. + * Or as follows, in the case of a named shadow: + * $aws/things/\/shadow/name// + * $aws/things/\/shadow/name///\ * - * When thingName is known to be "myThing" at compile time, invoke the macro like this: + * The \, \, \ and \ segments correspond to the + * four input parameters of this macro. The \ part can be null. + * + * When thingName and shadow name are known to be "myThing" and "myShadow" at compile time, + * invoke the macro like this: * (In this case, the length is a constant at compile time.) * - * SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, 7 ) + * SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, 7, 8 ) * - * When thingName is only known at run time and held in a variable myThingName, invoke - * the macro like this: + * When thingName and shadowName are only known at run time, and held in variables myThingName + * and myShadowName, invoke the macro like this: * - * SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, - * strlen( ( const char * ) myThingName ) ) + * SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, + * strlen( ( const char * ) myThingName ), + * strlen( ( const char * ) myShadowName ) ) * - * @param[operationLength] Can be one of: - * - #SHADOW_OP_UPDATE_LENGTH - * - #SHADOW_OP_DELETE_LENGTH - * - #SHADOW_OP_GET_LENGTH - * @param[suffixLength] Can be one of: - * - #SHADOW_SUFFIX_NULL_LENGTH - * - #SHADOW_SUFFIX_ACCEPTED_LENGTH - * - #SHADOW_SUFFIX_REJECTED_LENGTH - * - #SHADOW_SUFFIX_DELTA_LENGTH - * - #SHADOW_SUFFIX_DOCUMENTS_LENGTH - * @param[thingNameLength] Length of the thingName excluding the ending NULL. + * To compute an unnamed ("Classic") shadow length, the shadowName length passed must be zero. + * + * @param[in] operationLength Can be one of: + * - #SHADOW_OP_UPDATE_LENGTH + * - #SHADOW_OP_DELETE_LENGTH + * - #SHADOW_OP_GET_LENGTH + * @param[in] suffixLength Can be one of: + * - #SHADOW_SUFFIX_NULL_LENGTH + * - #SHADOW_SUFFIX_ACCEPTED_LENGTH + * - #SHADOW_SUFFIX_REJECTED_LENGTH + * - #SHADOW_SUFFIX_DELTA_LENGTH + * - #SHADOW_SUFFIX_DOCUMENTS_LENGTH + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. * * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH( operationLength, suffixLength, thingNameLength ) \ - ( operationLength + suffixLength + thingNameLength + SHADOW_PREFIX_LENGTH ) +#define SHADOW_TOPIC_LEN( operationLength, suffixLength, thingNameLength, shadowNameLength ) \ + ( operationLength + suffixLength + thingNameLength + shadowNameLength + \ + SHADOW_PREFIX_LENGTH + \ + ( ( shadowNameLength > 0 ) ? SHADOW_NAMED_ROOT_LENGTH : SHADOW_CLASSIC_ROOT_LENGTH ) ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/update". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/update" or + * "$aws/things//shadow/name//update". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_UPDATE( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_UPDATE( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/update/accepted". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/update/accepted" or + * "$aws/things//shadow/name//update/accepted". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_UPDATE_ACC( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/update/rejected". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/update/rejected" or + * "$aws/things//shadow/name//update/rejected". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_UPDATE_REJ( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/update/documents". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/update/documents" or + * "$aws/things//shadow/name//update/documents". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DOCUMENTS_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_UPDATE_DOCS( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DOCUMENTS_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/update/delta". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/update/delta" or + * "$aws/things//shadow/name//update/delta". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_UPDATE_DELTA( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_UPDATE_DELTA( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DELTA_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/get". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/get" or + * "$aws/things//shadow/name//get". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_GET( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_GET( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/get/accepted". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/get/accepted" or + * "$aws/things//shadow/name//get/accepted". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_GET_ACCEPTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_GET_ACC( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/get/rejected". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/get/rejected" or + * "$aws/things//shadow/name//get/rejected". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_GET_REJECTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_GET_REJ( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_GET_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/delete". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/delete" or + * "$aws/things//shadow/name//delete". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_DELETE( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_DELETE( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_NULL_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/delete/accepted". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/delete/accepted" or + * "$aws/things//shadow/name//delete/accepted". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_DELETE_ACC( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_ACCEPTED_LENGTH, thingNameLength, shadowNameLength ) /** - * @brief Compute the length of shadow topic "$aws/things//shadow/delete/rejected". + * @ingroup shadow_constants + * @brief Compute the length of shadow topic "$aws/things//shadow/delete/rejected" or + * "$aws/things//shadow/name//delete/rejected". + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_DELETE_REJECTED( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_DELETE_REJ( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_DELETE_LENGTH, SHADOW_SUFFIX_REJECTED_LENGTH, thingNameLength, shadowNameLength ) /** * @ingroup shadow_constants * @brief Compute the length of the longest shadow topic. + * + * @param[in] thingNameLength Length of the thingName excluding the ending NULL. + * @param[in] shadowNameLength Length of the shadowName excluding the ending NULL. Zero for "Classic" shadow. + * + * @return Length of the shadow topic in bytes. */ -#define SHADOW_TOPIC_LENGTH_MAX( thingNameLength ) \ - SHADOW_TOPIC_LENGTH( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DOCUMENTS_LENGTH, thingNameLength ) +#define SHADOW_TOPIC_LEN_MAX( thingNameLength, shadowNameLength ) \ + SHADOW_TOPIC_LEN( SHADOW_OP_UPDATE_LENGTH, SHADOW_SUFFIX_DOCUMENTS_LENGTH, thingNameLength, shadowNameLength ) /** * @ingroup shadow_constants @@ -337,99 +476,181 @@ typedef enum ShadowStatus * * When thingName is known to be "myThing" at compile time, invoke the macro like this: * - * SHADOW_TOPIC_STRING( SHADOW_OP_UPDATE, SHADOW_SUFFIX_DELTA, "myThing" ) + * SHADOW_TOPIC_STR( SHADOW_OP_UPDATE, SHADOW_SUFFIX_DELTA, "myThing" ) * * When thingName is only known at run time, do not use this macro. Use the * Shadow_GetTopicString() function instead. * - * @param[operation] Can be one of: - * - #SHADOW_OP_UPDATE - * - #SHADOW_OP_DELETE - * - #SHADOW_OP_GET - * @param[suffix] Can be one of: - * - #SHADOW_SUFFIX_NULL - * - #SHADOW_SUFFIX_ACCEPTED - * - #SHADOW_SUFFIX_REJECTED - * - #SHADOW_SUFFIX_DELTA - * - #SHADOW_SUFFIX_DOCUMENTS + * @param[in] operation Can be one of: + * - #SHADOW_OP_UPDATE + * - #SHADOW_OP_DELETE + * - #SHADOW_OP_GET + * @param[in] suffix Can be one of: + * - #SHADOW_SUFFIX_NULL + * - #SHADOW_SUFFIX_ACCEPTED + * - #SHADOW_SUFFIX_REJECTED + * - #SHADOW_SUFFIX_DELTA + * - #SHADOW_SUFFIX_DOCUMENTS * - * @param[thingName] Thing Name. + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. * * @return Topic string. */ -#define SHADOW_TOPIC_STRING( thingName, operation, suffix ) \ - ( SHADOW_PREFIX thingName operation suffix ) +#define SHADOW_TOPIC_STR( thingName, shadowName, operation, suffix ) \ + ( ( sizeof( shadowName ) > 1 ) ? \ + ( SHADOW_PREFIX thingName SHADOW_NAMED_ROOT shadowName operation suffix ) : \ + ( SHADOW_PREFIX thingName SHADOW_CLASSIC_ROOT operation suffix ) ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/update". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/update" or + * "$aws/things//shadow/name//update". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_UPDATE( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_NULL ) +#define SHADOW_TOPIC_STR_UPDATE( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_NULL ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/update/accepted". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/update/accepted" or + * "$aws/things//shadow/name//update/accepted". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_ACCEPTED ) +#define SHADOW_TOPIC_STR_UPDATE_ACC( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_ACCEPTED ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/update/rejected". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/update/rejected" or + * "$aws/things//shadow/name//update/rejected". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_UPDATE_REJECTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_REJECTED ) +#define SHADOW_TOPIC_STR_UPDATE_REJ( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_REJECTED ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/update/documents". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/update/documents" or + * "$aws/things//shadow/name//update/documents". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_DOCUMENTS ) +#define SHADOW_TOPIC_STR_UPDATE_DOCS( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_DOCUMENTS ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/update/delta". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/update/delta" or + * "$aws/things//shadow/name//update/delta". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_UPDATE_DELTA( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_DELTA ) +#define SHADOW_TOPIC_STR_UPDATE_DELTA( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_UPDATE, SHADOW_SUFFIX_DELTA ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/get". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/get" or + * "$aws/things//shadow/name//get". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_GET( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_GET, SHADOW_SUFFIX_NULL ) +#define SHADOW_TOPIC_STR_GET( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_GET, SHADOW_SUFFIX_NULL ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/get/accepted". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/get/accepted" or + * "$aws/things//shadow/name//get/accepted". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_GET_ACCEPTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_GET, SHADOW_SUFFIX_ACCEPTED ) +#define SHADOW_TOPIC_STR_GET_ACC( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_GET, SHADOW_SUFFIX_ACCEPTED ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/get/rejected". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/get/rejected" or + * "$aws/things//shadow/name//get/rejected". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_GET_REJECTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_GET, SHADOW_SUFFIX_REJECTED ) +#define SHADOW_TOPIC_STR_GET_REJ( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_GET, SHADOW_SUFFIX_REJECTED ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/delete". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/delete" or + * "$aws/things//shadow/name//delete". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_DELETE( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_DELETE, SHADOW_SUFFIX_NULL ) +#define SHADOW_TOPIC_STR_DELETE( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_DELETE, SHADOW_SUFFIX_NULL ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/delete/accepted". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/delete/accepted" or + * "$aws/things//shadow/name//delete/accepted". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_DELETE_ACCEPTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_DELETE, SHADOW_SUFFIX_ACCEPTED ) +#define SHADOW_TOPIC_STR_DELETE_ACC( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_DELETE, SHADOW_SUFFIX_ACCEPTED ) /** - * @brief Assemble shadow topic string "$aws/things//shadow/delete/rejected". + * @ingroup shadow_constants + * @brief Assemble shadow topic string "$aws/things//shadow/delete/rejected". or + * "$aws/things//shadow/name//delete/rejected". + * + * @param[in] thingName Thing Name. + * @param[in] shadowName Shadow Name. Empty string for an unnamed ("Classic") shadow. + * + * @return Topic string. */ -#define SHADOW_TOPIC_STRING_DELETE_REJECTED( thingName ) \ - SHADOW_TOPIC_STRING( thingName, SHADOW_OP_DELETE, SHADOW_SUFFIX_REJECTED ) +#define SHADOW_TOPIC_STR_DELETE_REJ( thingName, shadowName ) \ + SHADOW_TOPIC_STR( thingName, shadowName, SHADOW_OP_DELETE, SHADOW_SUFFIX_REJECTED ) + +/*------------------------ Shadow library functions -------------------------*/ /** - * @brief Assemble shadow topic string when Thing Name is only known at run time. - * If the Thing Name is known at compile time, use @link #SHADOW_TOPIC_STRING_UPDATE - * SHADOW_TOPIC_STRING_* @endlink macros instead. + * @brief Assemble shadow topic string when Thing Name or Shadow Name is only known at run time. + * If both the Thing Name and Shadow Name are known at compile time, use + * @link #SHADOW_TOPIC_STR SHADOW_TOPIC_STR_* @endlink macros instead. * * @param[in] topicType Indicates what topic will be written into the buffer pointed to by pTopicBuffer. * can be one of: @@ -446,6 +667,8 @@ typedef enum ShadowStatus * - ShadowTopicStringTypeUpdateDelta * @param[in] pThingName Thing Name string. No need to be null terminated. Must not be NULL. * @param[in] thingNameLength Length of Thing Name string pointed to by pThingName. Must not be zero. + * @param[in] pShadowName Shadow Name string. No need to be null terminated. Must not be NULL. Empty string for classic shadow. + * @param[in] shadowNameLength Length of Shadow Name string pointed to by pShadowName. Zero for classic shadow. * @param[out] pTopicBuffer Pointer to buffer for returning the topic string. * Caller is responsible for supplying memory pointed to by pTopicBuffer. * This function does not fill in the terminating null character. The app @@ -468,15 +691,19 @@ typedef enum ShadowStatus * char topicBuffer[ SHADOW_TOPIC_MAX_LENGTH ] = { 0 }; * uint16_t bufferSize = SHADOW_TOPIC_MAX_LENGTH; * uint16_t outLength = 0; - * const char * pThingName = "TestThingName"; + * const char thingName[] = "TestThingName"; * uint16_t thingNameLength = ( sizeof( thingName ) - 1U ); + * const char shadowName[] = "TestShadowName"; + * uint16_t shadowNameLength = ( sizeof( shadowName ) - 1U ); * - * shadowStatus = Shadow_GetTopicString( ShadowTopicStringTypeUpdateDelta, - * pThingName, - * thingNameLength, - * & ( topicBuffer[ 0 ] ), - * bufferSize, - * & outLength ); + * shadowStatus = Shadow_AssembleTopicString( ShadowTopicStringTypeUpdateDelta, + * thingName, + * thingNameLength, + * shadowName, + * shadowNameLength, + * & ( topicBuffer[ 0 ] ), + * bufferSize, + * & outLength ); * * if( shadowStatus == SHADOW_SUCCESS ) * { @@ -485,26 +712,30 @@ typedef enum ShadowStatus * * @endcode */ -/* @[declare_shadow_gettopicstring] */ -ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, - const char * pThingName, - uint8_t thingNameLength, - char * pTopicBuffer, - uint16_t bufferSize, - uint16_t * pOutLength ); -/* @[declare_shadow_gettopicstring] */ +/* @[declare_shadow_assembletopicstring] */ +ShadowStatus_t Shadow_AssembleTopicString( ShadowTopicStringType_t topicType, + const char * pThingName, + uint8_t thingNameLength, + const char * pShadowName, + uint8_t shadowNameLength, + char * pTopicBuffer, + uint16_t bufferSize, + uint16_t * pOutLength ); +/* @[declare_shadow_assembletopicstring] */ /** * @brief Given the topic string of an incoming message, determine whether it is * related to a device shadow; if it is, return information about the type of - * device shadow message, and a pointer to the Thing Name inside of the topic string. - * See #ShadowMessageType_t for the list of message types. Those types correspond to - * Device Shadow Topics. + * device shadow message, and pointers to the Thing Name and Shadow Name inside of + * the topic string. See #ShadowMessageType_t for the list of message types. + * Those types correspond to Device Shadow Topics. * * @note When this function returns, the pointer pThingName points at the first character - * of the \ segment inside of the topic string. + * of the \ segment inside of the topic string. Likewise, the pointer pShadowName + * points at the first character of the \ segment inside of the topic string + * (if the topic is for a named shadow, not the "Classic" shadow.) * Caller is responsible for keeping the memory holding the topic string around while - * accessing the Thing Name through pThingName. + * accessing the Thing Name through pThingName and the Shadow Name through pShadowName. * * @param[in] pTopic Pointer to the MQTT topic string. Does not have to be null-terminated. * @param[in] topicLength Length of the MQTT topic string. @@ -513,6 +744,12 @@ ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, * null if caller does not need to know the Thing Name contained in the topic string. * @param[out] pThingNameLength Pointer to caller-supplied memory for returning the length of the Thing Name, * and can be null if caller does not need to know the Thing Name contained in the topic string. + * @param[out] pShadowName Points to the 1st character of Shadow Name inside of the topic string, and can be + * null if caller does not need to know the Shadow Name contained in the topic string. Null is + * returned if the shadow is Classic. + * @param[out] pShadowNameLength Pointer to caller-supplied memory for returning the length of the Shadow Name, + * and can be null if caller does not need to know the Shadow Name contained in the topic string. + * A value of 0 is returned if the shadow is Classic. * @return One of the following: * - #SHADOW_SUCCESS if the message is related to a device shadow; * - An error code defined in #ShadowStatus_t if the message is not related to a device shadow, @@ -531,11 +768,13 @@ ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, * uint16_t topicNameLength; //usually supplied by MQTT stack * ShadowMessageType_t messageType; * - * shadowStatus = Shadow_MatchTopic( pTopicName, - * topicNameLength, - * & messageType, - * NULL, - * NULL ); + * shadowStatus = Shadow_MatchTopicString( pTopicName, + * topicNameLength, + * &messageType, + * NULL, + * NULL, + * NULL, + * NULL ); * * if( shadowStatus == SHADOW_SUCCESS ) * { @@ -545,12 +784,272 @@ ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, * * @endcode */ +/* @[declare_shadow_matchtopicstring] */ +ShadowStatus_t Shadow_MatchTopicString( const char * pTopic, + uint16_t topicLength, + ShadowMessageType_t * pMessageType, + const char ** pThingName, + uint16_t * pThingNameLength, + const char ** pShadowName, + uint16_t * pShadowNameLength ); +/* @[declare_shadow_matchtopicstring] */ + +/*------------- Shadow library backwardly-compatible constants -------------*/ + +/** + * @brief Compute unnamed "Classic" shadow topic length. + * @deprecated Please use @ref #SHADOW_TOPIC_LEN in new designs. + * + * See @ref #SHADOW_TOPIC_LEN for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH( operationLength, suffixLength, thingNameLength ) \ + SHADOW_TOPIC_LEN( operationLength, suffixLength, thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/update". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_UPDATE in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_UPDATE for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_UPDATE( thingNameLength ) \ + SHADOW_TOPIC_LEN_UPDATE( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/update/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_UPDATE_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_UPDATE_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_UPDATE_ACC( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/update/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_UPDATE_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_UPDATE_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_UPDATE_REJ( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/update/documents". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_UPDATE_DOCS in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_UPDATE_DOCS for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS( thingNameLength ) \ + SHADOW_TOPIC_LEN_UPDATE_DOCS( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/update/delta". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_UPDATE_DELTA in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_UPDATE_DELTA for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_UPDATE_DELTA( thingNameLength ) \ + SHADOW_TOPIC_LEN_UPDATE_DELTA( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/get". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_GET in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_GET for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_GET( thingNameLength ) \ + SHADOW_TOPIC_LEN_GET( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/get/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_GET_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_GET_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_GET_ACCEPTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_GET_ACC( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/get/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_GET_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_GET_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_GET_REJECTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_GET_REJ( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/delete". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_DELETE in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_DELETE for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_DELETE( thingNameLength ) \ + SHADOW_TOPIC_LEN_DELETE( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/delete/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_DELETE_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_DELETE_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_DELETE_ACC( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of unnamed "Classic" shadow topic "$aws/things//shadow/delete/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_DELETE_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_LEN_DELETE_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_DELETE_REJECTED( thingNameLength ) \ + SHADOW_TOPIC_LEN_DELETE_REJ( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Compute the length of the longest unnamed "Classic" shadow topic. + * @deprecated Please use @ref #SHADOW_TOPIC_LEN_MAX in new designs. + * + * See @ref #SHADOW_TOPIC_LEN for documentation of common behavior. + */ +#define SHADOW_TOPIC_LENGTH_MAX( thingNameLength ) \ + SHADOW_TOPIC_LEN_MAX( thingNameLength, SHADOW_NAME_CLASSIC_LENGTH ) + +/** + * @brief Assemble constant unnamed "Classic" shadow topic strings when Thing Name is known at compile time. + * @deprecated Please use @ref #SHADOW_TOPIC_STR in new designs. + * + * See @ref #SHADOW_TOPIC_STR for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING( thingName, operation, suffix ) \ + SHADOW_TOPIC_STR( thingName, SHADOW_NAME_CLASSIC, operation, suffix ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/update". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_UPDATE in new designs. + * + * See @ref #SHADOW_TOPIC_STR_UPDATE for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_UPDATE( thingName ) \ + SHADOW_TOPIC_STR_UPDATE( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/update/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_UPDATE_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_STR_UPDATE_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( thingName ) \ + SHADOW_TOPIC_STR_UPDATE_ACC( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/update/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_UPDATE_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_STR_UPDATE_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_UPDATE_REJECTED( thingName ) \ + SHADOW_TOPIC_STR_UPDATE_REJ( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/update/documents". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_UPDATE_DOCS in new designs. + * + * See @ref #SHADOW_TOPIC_STR_UPDATE_DOCS for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS( thingName ) \ + SHADOW_TOPIC_STR_UPDATE_DOCS( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/update/delta". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_UPDATE_DELTA in new designs. + * + * See @ref #SHADOW_TOPIC_STR_UPDATE_DELTA for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_UPDATE_DELTA( thingName ) \ + SHADOW_TOPIC_STR_UPDATE_DELTA( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/get". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_GET in new designs. + * + * See @ref #SHADOW_TOPIC_STR_GET for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_GET( thingName ) \ + SHADOW_TOPIC_STR_GET( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble shadow topic string "$aws/things//shadow/get/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_GET_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_STR_GET_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_GET_ACCEPTED( thingName ) \ + SHADOW_TOPIC_STR_GET_ACC( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/get/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_GET_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_STR_GET_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_GET_REJECTED( thingName ) \ + SHADOW_TOPIC_STR_GET_REJ( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/delete". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_DELETE in new designs. + * + * See @ref #SHADOW_TOPIC_STR_DELETE for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_DELETE( thingName ) \ + SHADOW_TOPIC_STR_DELETE( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/delete/accepted". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_DELETE_ACC in new designs. + * + * See @ref #SHADOW_TOPIC_STR_DELETE_ACC for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_DELETE_ACCEPTED( thingName ) \ + SHADOW_TOPIC_STR_DELETE_ACC( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed "Classic" shadow topic string "$aws/things//shadow/delete/rejected". + * @deprecated Please use @ref #SHADOW_TOPIC_STR_DELETE_REJ in new designs. + * + * See @ref #SHADOW_TOPIC_STR_DELETE_REJ for documentation of common behavior. + */ +#define SHADOW_TOPIC_STRING_DELETE_REJECTED( thingName ) \ + SHADOW_TOPIC_STR_DELETE_REJ( thingName, SHADOW_NAME_CLASSIC ) + +/** + * @brief Assemble unnamed ("Classic") shadow topic string when Thing Name is only known at run time. + * If the Thing Name is known at compile time, use + * @link #SHADOW_TOPIC_STRING SHADOW_TOPIC_STRING @endlink macro instead. + * + * @deprecated Please use @ref Shadow_AssembleTopicString in new designs. + * + * See @ref Shadow_AssembleTopicString for documentation of common behavior. + */ +/* @[declare_shadow_gettopicstring] */ +#define Shadow_GetTopicString( topicType, pThingName, thingNameLength, pTopicBuffer, bufferSize, pOutLength ) \ + Shadow_AssembleTopicString( topicType, pThingName, thingNameLength, SHADOW_NAME_CLASSIC, 0, \ + pTopicBuffer, bufferSize, pOutLength ) +/* @[declare_shadow_gettopicstring] */ + +/** + * @brief Given the topic string of an incoming message, determine whether it is related to + * an unnamed ("Classic") device shadow; if it is, return information about the type + * of device shadow message, and a pointers to the Thing Name inside of + * the topic string. See #ShadowMessageType_t for the list of message types. + * Those types correspond to Device Shadow Topics. + * + * @deprecated Please use @ref Shadow_MatchTopicString in new designs. + * + * See @ref Shadow_MatchTopicString for documentation of common behavior. + */ /* @[declare_shadow_matchtopic] */ -ShadowStatus_t Shadow_MatchTopic( const char * pTopic, - uint16_t topicLength, - ShadowMessageType_t * pMessageType, - const char ** pThingName, - uint16_t * pThingNameLength ); +#define Shadow_MatchTopic( pTopic, topicLength, pMessageType, pThingName, pThingNameLength ) \ + Shadow_MatchTopicString( pTopic, topicLength, pMessageType, pThingName, pThingNameLength, NULL, 0 ) /* @[declare_shadow_matchtopic] */ #endif /* ifndef SHADOW_H_ */ diff --git a/source/shadow.c b/source/shadow.c index 427d3312..214dbf0a 100644 --- a/source/shadow.c +++ b/source/shadow.c @@ -111,6 +111,20 @@ */ #define SHADOW_OP_DELETE_REJECTED_LENGTH ( SHADOW_OP_DELETE_LENGTH + SHADOW_SUFFIX_REJECTED_LENGTH ) +/** + * @brief Check if Shadow_MatchTopicString has valid parameters. + * + * @param[in] pTopic Pointer to the topic string. + * @param[in] topicLength Length of pTopic. + * @param[in] pMessageType Pointer to caller-supplied memory for returning the type of the shadow message. + * + * @return Return SHADOW_SUCCESS if the parameters are valid; + * return SHADOW_BAD_PARAMETER if not. + */ +static ShadowStatus_t validateMatchTopicParameters( const char * pTopic, + uint16_t topicLength, + const ShadowMessageType_t * pMessageType ); + /** * @brief Determine if the string contains the substring. * @@ -128,33 +142,50 @@ static ShadowStatus_t containsSubString( const char * pString, uint16_t subStringLength ); /** - * @brief Check if the Thing Name is valid. + * @brief Check if the Thing or Shadow Name is valid. * - * @param[in] pString Pointer to the starting of thing name. + * @param[in] pString Pointer to the starting of a name. * @param[in] stringLength Length of pString. - * @param[out] pThingNameLength Pointer to caller-supplied memory for returning the length of the Thing Name. + * @param[out] pNameLength Pointer to caller-supplied memory for returning the length of the Thing or Shadow Name. * * @return Return SHADOW_SUCCESS if it is valid; - * return SHADOW_THINGNAME_PARSE_FAILED if it is not. + * return SHADOW_FAIL if it is not. */ -static ShadowStatus_t validateThingName( const char * pString, - uint16_t stringLength, - uint16_t * pThingNameLength ); +static ShadowStatus_t validateName( const char * pString, + uint16_t stringLength, + uint16_t * pNameLength ); /** * @brief Extract the Shadow message type from a string. * * @param[in] pString Pointer to the string. * @param[in] stringLength Length of pString. - * @param[out] pMessageType Pointer to call-supplied memory for returning the type of the shadow message. + * @param[out] pMessageType Pointer to caller-supplied memory for returning the type of the shadow message. * * @return Return SHADOW_SUCCESS if successfully extracted; - * return SHADOW_SHADOW_MESSAGE_TYPE_PARSE_FAILED if failed. + * return SHADOW_MESSAGE_TYPE_PARSE_FAILED if failed. */ static ShadowStatus_t extractShadowMessageType( const char * pString, uint16_t stringLength, ShadowMessageType_t * pMessageType ); +/** + * @brief Extract the classic shadow root OR the named shadow root and shadow name from a topic string. + * + * @param[in] pTopic Pointer to the topic string. + * @param[in] topicLength Length of pTopic. + * @param[out] pConsumedTopicLength Pointer to caller-supplied memory for returning the consumed topic length. + * @param[out] pShadowNameLength Pointer to caller-supplied memory for returning the shadow name length. + * + * @return Return SHADOW_SUCCESS if successfully extracted; + * return SHADOW_ROOT_PARSE_FAILED shadow root parsing fails. + * return SHADOW_SHADOWNAME_PARSE_FAILED shadow name parsing fails. + */ +static ShadowStatus_t extractShadowRootAndName( const char * pTopic, + uint16_t topicLength, + uint16_t * pConsumedTopicLength, + uint16_t * pShadowNameLength ); + /** * @brief Get the shadow operation string for a given shadow topic type. * @@ -173,6 +204,45 @@ static const char * getShadowOperationString( ShadowTopicStringType_t topicType */ static uint16_t getShadowOperationLength( ShadowTopicStringType_t topicType ); +/** + * @brief Creates a shadow topic string + * + * @param[in] topicType The type of shadow topic to be constructed. + * @param[in] pThingName Pointer to the Thing name. + * @param[in] thingNameLength The length of the Thing name. + * @param[in] pShadowName Pointer to the Shadow name. + * @param[in] shadowNameLength The length of the Shadow name. + * @param[out] pTopicBuffer Pointer to caller-supplied memory for returning the constructed shadow topic string. + */ +static void createShadowTopicString( ShadowTopicStringType_t topicType, + const char * pThingName, + uint8_t thingNameLength, + const char * pShadowName, + uint8_t shadowNameLength, + char * pTopicBuffer ); + +/*-----------------------------------------------------------*/ + +static ShadowStatus_t validateMatchTopicParameters( const char * pTopic, + uint16_t topicLength, + const ShadowMessageType_t * pMessageType ) +{ + ShadowStatus_t shadowStatus = SHADOW_SUCCESS; + + if( ( pTopic == NULL ) || + ( topicLength == 0U ) || + ( pMessageType == NULL ) ) + { + shadowStatus = SHADOW_BAD_PARAMETER; + LogError( ( "Invalid input parameters pTopic: %p, topicLength: %u, pMessageType: %p.", + ( void * ) pTopic, + ( unsigned int ) topicLength, + ( void * ) pMessageType ) ); + } + + return shadowStatus; +} + /*-----------------------------------------------------------*/ static ShadowStatus_t containsSubString( const char * pString, @@ -196,38 +266,92 @@ static ShadowStatus_t containsSubString( const char * pString, return returnStatus; } + /*-----------------------------------------------------------*/ -static ShadowStatus_t validateThingName( const char * pString, - uint16_t stringLength, - uint16_t * pThingNameLength ) +static ShadowStatus_t validateName( const char * pString, + uint16_t stringLength, + uint16_t * pNameLength ) { uint16_t index = 0U; - ShadowStatus_t returnStatus = SHADOW_THINGNAME_PARSE_FAILED; + ShadowStatus_t returnStatus = SHADOW_FAIL; for( ; index < stringLength; index++ ) { + /* The name should always be terminated by a forward slash */ if( pString[ index ] == ( char ) '/' ) { + if( index > 0U ) + { + /* Only accept names of greater than zero length */ + *pNameLength = index; + returnStatus = SHADOW_SUCCESS; + } + break; } } - /* Zero length thing name is not valid, - * $"$aws/things// - * $"$aws/things/" - * will extract the same thing name result. - * Only empty thing name string like: - * "$aws/things/" or "$aws/things" will fail. - */ - if( index > 0U ) + return returnStatus; +} + +/*-----------------------------------------------------------*/ + +static ShadowStatus_t extractShadowRootAndName( const char * pTopic, + uint16_t topicLength, + uint16_t * pConsumedTopicLength, + uint16_t * pShadowNameLength ) +{ + ShadowStatus_t shadowStatus; + + /* Look for the named shadow root */ + shadowStatus = containsSubString( &( pTopic[ *pConsumedTopicLength ] ), + topicLength - *pConsumedTopicLength, + SHADOW_NAMED_ROOT, + SHADOW_NAMED_ROOT_LENGTH ); + + if( shadowStatus == SHADOW_SUCCESS ) { - *pThingNameLength = index; - returnStatus = SHADOW_SUCCESS; + /* Topic is a named shadow */ + *pConsumedTopicLength += SHADOW_NAMED_ROOT_LENGTH; + + /* Extract shadow name. */ + shadowStatus = validateName( &( pTopic[ *pConsumedTopicLength ] ), + topicLength - *pConsumedTopicLength, + pShadowNameLength ); + + if( shadowStatus == SHADOW_SUCCESS ) + { + *pConsumedTopicLength += *pShadowNameLength; + } + else + { + shadowStatus = SHADOW_SHADOWNAME_PARSE_FAILED; + LogDebug( ( "Not related to Shadow, failed to parse shadow name in pTopic %s", pTopic ) ); + } } + else + { + /* Not a named shadow. Try to match the classic shadow root. */ + shadowStatus = containsSubString( &( pTopic[ *pConsumedTopicLength ] ), + topicLength - *pConsumedTopicLength, + SHADOW_CLASSIC_ROOT, + SHADOW_CLASSIC_ROOT_LENGTH ); - return returnStatus; + if( shadowStatus == SHADOW_SUCCESS ) + { + *pConsumedTopicLength += SHADOW_CLASSIC_ROOT_LENGTH; + } + else + { + shadowStatus = SHADOW_ROOT_PARSE_FAILED; + LogDebug( ( "Not related to Shadow, failed to parse shadow root in pTopic %s", pTopic ) ); + } + } + + return shadowStatus; } + /*-----------------------------------------------------------*/ static ShadowStatus_t extractShadowMessageType( const char * pString, @@ -356,7 +480,7 @@ static const char * getShadowOperationString( ShadowTopicStringType_t topicType break; case ShadowTopicStringTypeUpdateDelta: - /* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_GetTopicString. */ + /* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_AssembleTopicString. */ default: shadowOperationString = SHADOW_OP_UPDATE_DELTA; break; @@ -414,7 +538,7 @@ static uint16_t getShadowOperationLength( ShadowTopicStringType_t topicType ) break; case ShadowTopicStringTypeUpdateDelta: - /* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_GetTopicString. */ + /* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_AssembleTopicString. */ default: shadowOperationLength = SHADOW_OP_UPDATE_DELTA_LENGTH; break; @@ -425,37 +549,93 @@ static uint16_t getShadowOperationLength( ShadowTopicStringType_t topicType ) /*-----------------------------------------------------------*/ +static void createShadowTopicString( ShadowTopicStringType_t topicType, + const char * pThingName, + uint8_t thingNameLength, + const char * pShadowName, + uint8_t shadowNameLength, + char * pTopicBuffer ) +{ + uint16_t offset = 0U, operationStringLength = 0U; + const char * pShadowPrefix = SHADOW_PREFIX; + const char * pOperationString = NULL; + const char * pClassicShadowRoot = SHADOW_CLASSIC_ROOT; + const char * pNamedShadowRoot = SHADOW_NAMED_ROOT; + + /* Copy the Shadow topic prefix into the topic buffer. */ + ( void ) memcpy( ( void * ) pTopicBuffer, + ( const void * ) pShadowPrefix, + ( size_t ) SHADOW_PREFIX_LENGTH ); + offset = ( uint16_t ) ( offset + SHADOW_PREFIX_LENGTH ); + + /* Copy the Thing Name into the topic buffer. */ + ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), + ( const void * ) pThingName, + ( size_t ) thingNameLength ); + offset = ( uint16_t ) ( offset + thingNameLength ); + + /* Are we assembling a named shadow? */ + if( shadowNameLength > 0U ) + { + /* Copy the named Shadow topic root into the topic buffer. */ + ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), + ( const void * ) pNamedShadowRoot, + ( size_t ) SHADOW_NAMED_ROOT_LENGTH ); + offset = ( uint16_t ) ( offset + SHADOW_NAMED_ROOT_LENGTH ); + + /* Copy the Shadow Name into the topic buffer. */ + ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), + ( const void * ) pShadowName, + ( size_t ) shadowNameLength ); + offset = ( uint16_t ) ( offset + shadowNameLength ); + } + else + { + /* Copy the Classic Shadow topic root into the topic buffer. */ + ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), + ( const void * ) pClassicShadowRoot, + ( size_t ) SHADOW_CLASSIC_ROOT_LENGTH ); + offset = ( uint16_t ) ( offset + SHADOW_CLASSIC_ROOT_LENGTH ); + } + + pOperationString = getShadowOperationString( topicType ); + operationStringLength = getShadowOperationLength( topicType ); + /* Copy the Shadow operation string into the topic buffer. */ + ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), + ( const void * ) pOperationString, + ( size_t ) operationStringLength ); +} + /*-----------------------------------------------------------*/ -ShadowStatus_t Shadow_MatchTopic( const char * pTopic, - uint16_t topicLength, - ShadowMessageType_t * pMessageType, - const char ** pThingName, - uint16_t * pThingNameLength ) +ShadowStatus_t Shadow_MatchTopicString( const char * pTopic, + uint16_t topicLength, + ShadowMessageType_t * pMessageType, + const char ** pThingName, + uint16_t * pThingNameLength, + const char ** pShadowName, + uint16_t * pShadowNameLength ) { uint16_t consumedTopicLength = 0U; ShadowStatus_t shadowStatus = SHADOW_SUCCESS; uint16_t thingNameLength = 0; + uint16_t shadowNameLength = 0; - if( ( pTopic == NULL ) || - ( topicLength == 0U ) || - ( pMessageType == NULL ) ) - { - shadowStatus = SHADOW_BAD_PARAMETER; - LogError( ( "Invalid input parameters pTopic: %p, topicLength: %u, pMessageType: %p.", - ( void * ) pTopic, - ( unsigned int ) topicLength, - ( void * ) pMessageType ) ); - } + shadowStatus = validateMatchTopicParameters( pTopic, topicLength, pMessageType ); - /* A shadow topic string takes one of the two forms: + /* A shadow topic string takes one of the two forms. + * Classic shadow: * $aws/things//shadow/ * $aws/things//shadow// + * Named shadow: + * $aws/things//shadow/name// + * $aws/things//shadow/name/// * * We need to match the following things: * 1. Prefix ($aws/things). * 2. Thing Name. - * 3. Shadow operation and suffix. + * 3. Classic shadow root (/shadow) OR Named shadow root (/shadow/name) and shadow name + * 4. Shadow operation and suffix. */ if( shadowStatus == SHADOW_SUCCESS ) { @@ -464,54 +644,55 @@ ShadowStatus_t Shadow_MatchTopic( const char * pTopic, topicLength - consumedTopicLength, SHADOW_PREFIX, SHADOW_PREFIX_LENGTH ); - } - if( shadowStatus == SHADOW_SUCCESS ) - { - consumedTopicLength += SHADOW_PREFIX_LENGTH; - - /* If no more topic string is left to parse, fail. */ - if( consumedTopicLength >= topicLength ) + if( shadowStatus == SHADOW_SUCCESS ) { - shadowStatus = SHADOW_THINGNAME_PARSE_FAILED; - LogDebug( ( "Not related to Shadow, thing name is not in pTopic %s, failed to parse thing name.", pTopic ) ); + consumedTopicLength += SHADOW_PREFIX_LENGTH; + } + else + { + LogDebug( ( "Not related to Shadow, failed to parse shadow topic prefix in pTopic %s.", pTopic ) ); } - } - else - { - LogDebug( ( "Not related to Shadow, failed to parse shadow topic prefix in pTopic %s.", pTopic ) ); } if( shadowStatus == SHADOW_SUCCESS ) { /* Extract thing name. */ - shadowStatus = validateThingName( &( pTopic[ consumedTopicLength ] ), - topicLength - consumedTopicLength, - &thingNameLength ); + shadowStatus = validateName( &( pTopic[ consumedTopicLength ] ), + topicLength - consumedTopicLength, + &thingNameLength ); if( shadowStatus == SHADOW_SUCCESS ) { consumedTopicLength += thingNameLength; - - /* If no more topic string is left to parse, fail. */ - if( consumedTopicLength >= topicLength ) - { - shadowStatus = SHADOW_SHADOW_MESSAGE_TYPE_PARSE_FAILED; - LogDebug( ( "Not related to Shadow, shadow message type is not in pTopic %s, failed to parse shadow message type.", pTopic ) ); - } } else { + shadowStatus = SHADOW_THINGNAME_PARSE_FAILED; LogDebug( ( "Not related to Shadow, failed to parse thing name in pTopic %s.", pTopic ) ); } } + if( shadowStatus == SHADOW_SUCCESS ) + { + shadowStatus = extractShadowRootAndName( pTopic, + topicLength, + &consumedTopicLength, + &shadowNameLength ); + } + if( shadowStatus == SHADOW_SUCCESS ) { /* Extract shadow message type. */ shadowStatus = extractShadowMessageType( &( pTopic[ consumedTopicLength ] ), topicLength - consumedTopicLength, pMessageType ); + + if( shadowStatus != SHADOW_SUCCESS ) + { + shadowStatus = SHADOW_MESSAGE_TYPE_PARSE_FAILED; + LogDebug( ( "Not related to Shadow, shadow message type is not in pTopic %s, failed to parse shadow message type.", pTopic ) ); + } } if( shadowStatus == SHADOW_SUCCESS ) @@ -527,41 +708,59 @@ ShadowStatus_t Shadow_MatchTopic( const char * pTopic, { *pThingNameLength = thingNameLength; } + + if( pShadowName != NULL ) + { + *pShadowName = &( pTopic[ SHADOW_PREFIX_LENGTH + thingNameLength + + SHADOW_NAMED_ROOT_LENGTH ] ); + } + + if( pShadowNameLength != NULL ) + { + *pShadowNameLength = shadowNameLength; + } } return shadowStatus; } /*-----------------------------------------------------------*/ - -ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, - const char * pThingName, - uint8_t thingNameLength, - char * pTopicBuffer, - uint16_t bufferSize, - uint16_t * pOutLength ) +ShadowStatus_t Shadow_AssembleTopicString( ShadowTopicStringType_t topicType, + const char * pThingName, + uint8_t thingNameLength, + const char * pShadowName, + uint8_t shadowNameLength, + char * pTopicBuffer, + uint16_t bufferSize, + uint16_t * pOutLength ) { - uint16_t offset = 0U, generatedTopicStringLength = 0U, operationStringLength = 0U; + uint16_t generatedTopicStringLength = 0U; ShadowStatus_t shadowStatus = SHADOW_SUCCESS; - const char * pOperationString = NULL; - const char * pShadowPrefix = SHADOW_PREFIX; if( ( pTopicBuffer == NULL ) || ( pThingName == NULL ) || ( thingNameLength == 0U ) || + ( ( pShadowName == NULL ) && ( shadowNameLength > 0U ) ) || ( topicType >= ShadowTopicStringTypeMaxNum ) || ( pOutLength == NULL ) ) { shadowStatus = SHADOW_BAD_PARAMETER; - LogError( ( "Invalid input parameters pTopicBuffer: %p, pThingName: %p, " - "thingNameLength: %u, topicType: %d, pOutLength: %p.", - ( void * ) pTopicBuffer, ( void * ) pThingName, - ( unsigned int ) thingNameLength, topicType, + LogError( ( "Invalid input parameters pTopicBuffer: %p, pThingName: %p, thingNameLength: %u,\ + pShadowName: %p, shadowNameLength: %u, topicType: %d, pOutLength: %p.", + ( void * ) pTopicBuffer, + ( void * ) pThingName, + ( unsigned int ) thingNameLength, + ( void * ) pShadowName, + ( unsigned int ) shadowNameLength, + topicType, ( void * ) pOutLength ) ); } else { - generatedTopicStringLength = SHADOW_PREFIX_LENGTH + /* Prefix ("$aws/things/"). */ - thingNameLength + /* Thing name. */ + generatedTopicStringLength = SHADOW_PREFIX_LENGTH + /* Prefix ("$aws/things/"). */ + thingNameLength + /* Thing name. */ + ( ( shadowNameLength > 0U ) ? /* Handle named or classic shadow */ + ( SHADOW_NAMED_ROOT_LENGTH + shadowNameLength ) : + SHADOW_CLASSIC_ROOT_LENGTH ) + getShadowOperationLength( topicType ); /* Shadow operation. */ if( bufferSize < generatedTopicStringLength ) @@ -573,24 +772,13 @@ ShadowStatus_t Shadow_GetTopicString( ShadowTopicStringType_t topicType, } else { - /* Copy the Shadow topic prefix into the topic buffer. */ - ( void ) memcpy( ( void * ) pTopicBuffer, - ( const void * ) pShadowPrefix, - ( size_t ) SHADOW_PREFIX_LENGTH ); - offset = ( uint16_t ) ( offset + SHADOW_PREFIX_LENGTH ); - - /* Copy the Thing Name into the topic buffer. */ - ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), - ( const void * ) pThingName, - ( size_t ) thingNameLength ); - offset = ( uint16_t ) ( offset + thingNameLength ); - - pOperationString = getShadowOperationString( topicType ); - operationStringLength = getShadowOperationLength( topicType ); - /* Copy the Shadow operation string into the topic buffer. */ - ( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ), - ( const void * ) pOperationString, - ( size_t ) operationStringLength ); + /* With everything validated, now create the topic string */ + createShadowTopicString( topicType, + pThingName, + thingNameLength, + pShadowName, + shadowNameLength, + pTopicBuffer ); /* Return the generated topic string length to the caller. */ *pOutLength = generatedTopicStringLength; diff --git a/test/cbmc/proofs/Shadow_GetTopicString/Makefile b/test/cbmc/proofs/Shadow_AssembleTopicString/Makefile similarity index 94% rename from test/cbmc/proofs/Shadow_GetTopicString/Makefile rename to test/cbmc/proofs/Shadow_AssembleTopicString/Makefile index 1d891407..61d5913a 100644 --- a/test/cbmc/proofs/Shadow_GetTopicString/Makefile +++ b/test/cbmc/proofs/Shadow_AssembleTopicString/Makefile @@ -20,8 +20,8 @@ # HARNESS_ENTRY=harness -HARNESS_FILE=Shadow_GetTopicString_harness -PROOF_UID = Shadow_GetTopicString +HARNESS_FILE=Shadow_AssembleTopicString_harness +PROOF_UID = Shadow_AssembleTopicString DEFINES += INCLUDES += diff --git a/test/cbmc/proofs/Shadow_GetTopicString/README.md b/test/cbmc/proofs/Shadow_AssembleTopicString/README.md similarity index 61% rename from test/cbmc/proofs/Shadow_GetTopicString/README.md rename to test/cbmc/proofs/Shadow_AssembleTopicString/README.md index d361b5af..90949932 100644 --- a/test/cbmc/proofs/Shadow_GetTopicString/README.md +++ b/test/cbmc/proofs/Shadow_AssembleTopicString/README.md @@ -1,7 +1,7 @@ -Shadow_GetTopicString proof +Shadow_AssembleTopicString proof ============== -This directory contains a memory safety proof for Shadow_GetTopicString. +This directory contains a memory safety proof for Shadow_AssembleTopicString. To run the proof. * Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer diff --git a/test/cbmc/proofs/Shadow_GetTopicString/Shadow_GetTopicString_harness.c b/test/cbmc/proofs/Shadow_AssembleTopicString/Shadow_AssembleTopicString_harness.c similarity index 72% rename from test/cbmc/proofs/Shadow_GetTopicString/Shadow_GetTopicString_harness.c rename to test/cbmc/proofs/Shadow_AssembleTopicString/Shadow_AssembleTopicString_harness.c index 0628b23f..215fc84f 100644 --- a/test/cbmc/proofs/Shadow_GetTopicString/Shadow_GetTopicString_harness.c +++ b/test/cbmc/proofs/Shadow_AssembleTopicString/Shadow_AssembleTopicString_harness.c @@ -21,8 +21,8 @@ */ /** - * @file Shadow_GetTopicString_harness.c - * @brief Implements the proof harness for Shadow_GetTopicString function. + * @file Shadow_AssembleTopicString_harness.c + * @brief Implements the proof harness for Shadow_AssembleTopicString function. */ #include "shadow.h" @@ -35,16 +35,21 @@ void harness() uint16_t * pOutLength; char * pThingName; uint8_t thingNameLength; + char * pShadowName; + uint8_t shadowNameLength; uint8_t topicType; topicBuffer = mallocCanFail( bufferSize ); pOutLength = mallocCanFail( sizeof( *pOutLength ) ); pThingName = mallocCanFail( thingNameLength ); + pShadowName = mallocCanFail( shadowNameLength ); - Shadow_GetTopicString( topicType, - pThingName, - thingNameLength, - &( topicBuffer[ 0 ] ), - bufferSize, - pOutLength ); + Shadow_AssembleTopicString( topicType, + pThingName, + thingNameLength, + pShadowName, + shadowNameLength, + &( topicBuffer[ 0 ] ), + bufferSize, + pOutLength ); } diff --git a/test/cbmc/proofs/Shadow_GetTopicString/cbmc-proof.txt b/test/cbmc/proofs/Shadow_AssembleTopicString/cbmc-proof.txt similarity index 100% rename from test/cbmc/proofs/Shadow_GetTopicString/cbmc-proof.txt rename to test/cbmc/proofs/Shadow_AssembleTopicString/cbmc-proof.txt diff --git a/test/cbmc/proofs/Shadow_GetTopicString/cbmc-viewer.json b/test/cbmc/proofs/Shadow_AssembleTopicString/cbmc-viewer.json similarity index 62% rename from test/cbmc/proofs/Shadow_GetTopicString/cbmc-viewer.json rename to test/cbmc/proofs/Shadow_AssembleTopicString/cbmc-viewer.json index 0b0688c3..18c1159a 100644 --- a/test/cbmc/proofs/Shadow_GetTopicString/cbmc-viewer.json +++ b/test/cbmc/proofs/Shadow_AssembleTopicString/cbmc-viewer.json @@ -2,6 +2,6 @@ [ ], - "proof-name": "Shadow_GetTopicString", + "proof-name": "Shadow_AssembleTopicString", "proof-root": "../cbmc/proofs" } diff --git a/test/cbmc/proofs/Shadow_MatchTopic/Makefile b/test/cbmc/proofs/Shadow_MatchTopicString/Makefile similarity index 69% rename from test/cbmc/proofs/Shadow_MatchTopic/Makefile rename to test/cbmc/proofs/Shadow_MatchTopicString/Makefile index 4def05ee..3cbcd22d 100644 --- a/test/cbmc/proofs/Shadow_MatchTopic/Makefile +++ b/test/cbmc/proofs/Shadow_MatchTopicString/Makefile @@ -20,25 +20,25 @@ # HARNESS_ENTRY=harness -HARNESS_FILE=Shadow_MatchTopic_harness -PROOF_UID = Shadow_MatchTopic +HARNESS_FILE=Shadow_MatchTopicString_harness +PROOF_UID = Shadow_MatchTopicString # The topic length is bounded to reduce the proof run time. This length bounds -# the time to look for the thing name in the topic string. The minimum length -# of the topic string is the length of the SHADOW_PREFIX ("$aws/things/") -# plus the maximum Shadow Message Type length ("/shadow/update/documents"). -# Memory safety on the buffer holding the topic string can be proven within -# a reasonable bound. It adds no value to the proof to input the largest possible -# topic string accepted by AWS (64KB). -TOPIC_STRING_LENGTH_MAX=50 +# the time to look for the thing and shadow names in the topic string. It adds +# no value to the proof to input the largest possible topic string accepted by +# AWS (64KB). We allow for a the longest named shadow topic, but with only +# reasonable allowance for typical Thing and Shadow names. +# $aws/things/thingName/shadow/name/shadowName/update/documents +TOPIC_STRING_LENGTH_MAX=65 DEFINES += -DTOPIC_STRING_LENGTH_MAX=$(TOPIC_STRING_LENGTH_MAX) INCLUDES += -# The maximum length of the message type ( /shadow/update/documents ) is 24. -UNWINDSET += strncmp.0:25 +# The maximum length of the message type ( /update/documents ) is 17. +UNWINDSET += strncmp.0:18 -UNWINDSET += __CPROVER_file_local_shadow_c_validateThingName.0:$(TOPIC_STRING_LENGTH_MAX) +# Allow for the longest possible Shadow name +UNWINDSET += __CPROVER_file_local_shadow_c_validateName.0:64 # The number of message types is 8. UNWINDSET += __CPROVER_file_local_shadow_c_extractShadowMessageType.0:9 diff --git a/test/cbmc/proofs/Shadow_MatchTopic/README.md b/test/cbmc/proofs/Shadow_MatchTopicString/README.md similarity index 85% rename from test/cbmc/proofs/Shadow_MatchTopic/README.md rename to test/cbmc/proofs/Shadow_MatchTopicString/README.md index d3052f3c..82b4f6f5 100644 --- a/test/cbmc/proofs/Shadow_MatchTopic/README.md +++ b/test/cbmc/proofs/Shadow_MatchTopicString/README.md @@ -1,7 +1,7 @@ -Shadow_MatchTopic proof +Shadow_MatchTopicString proof ============== -This directory contains a memory safety proof for Shadow_MatchTopic. +This directory contains a memory safety proof for Shadow_MatchTopicString. To run the proof. * Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer diff --git a/test/cbmc/proofs/Shadow_MatchTopic/Shadow_MatchTopic_harness.c b/test/cbmc/proofs/Shadow_MatchTopicString/Shadow_MatchTopicString_harness.c similarity index 73% rename from test/cbmc/proofs/Shadow_MatchTopic/Shadow_MatchTopic_harness.c rename to test/cbmc/proofs/Shadow_MatchTopicString/Shadow_MatchTopicString_harness.c index b3b0dbaa..ab008f62 100644 --- a/test/cbmc/proofs/Shadow_MatchTopic/Shadow_MatchTopic_harness.c +++ b/test/cbmc/proofs/Shadow_MatchTopicString/Shadow_MatchTopicString_harness.c @@ -21,8 +21,8 @@ */ /** - * @file Shadow_MatchTopic_harness.c - * @brief Implements the proof harness for Shadow_MatchTopic function. + * @file Shadow_MatchTopicString_harness.c + * @brief Implements the proof harness for Shadow_MatchTopicString function. */ #include "shadow.h" @@ -35,6 +35,8 @@ void harness() ShadowMessageType_t * pMessageType; const char ** pThingName; uint16_t * pThingNameLength; + const char ** pShadowName; + uint16_t * pShadowNameLength; __CPROVER_assume( topicNameLength < TOPIC_STRING_LENGTH_MAX ); pTopicName = mallocCanFail( topicNameLength ); @@ -44,9 +46,14 @@ void harness() pThingName = mallocCanFail( sizeof( *pThingName ) ); pThingNameLength = mallocCanFail( sizeof( *pThingNameLength ) ); - Shadow_MatchTopic( pTopicName, - topicNameLength, - pMessageType, - pThingName, - pThingNameLength ); + pShadowName = mallocCanFail( sizeof( *pShadowName ) ); + pShadowNameLength = mallocCanFail( sizeof( *pShadowNameLength ) ); + + Shadow_MatchTopicString( pTopicName, + topicNameLength, + pMessageType, + pThingName, + pThingNameLength, + pShadowName, + pShadowNameLength ); } diff --git a/test/cbmc/proofs/Shadow_MatchTopic/cbmc-proof.txt b/test/cbmc/proofs/Shadow_MatchTopicString/cbmc-proof.txt similarity index 100% rename from test/cbmc/proofs/Shadow_MatchTopic/cbmc-proof.txt rename to test/cbmc/proofs/Shadow_MatchTopicString/cbmc-proof.txt diff --git a/test/cbmc/proofs/Shadow_MatchTopic/cbmc-viewer.json b/test/cbmc/proofs/Shadow_MatchTopicString/cbmc-viewer.json similarity index 64% rename from test/cbmc/proofs/Shadow_MatchTopic/cbmc-viewer.json rename to test/cbmc/proofs/Shadow_MatchTopicString/cbmc-viewer.json index 084d64b8..6f66bd64 100644 --- a/test/cbmc/proofs/Shadow_MatchTopic/cbmc-viewer.json +++ b/test/cbmc/proofs/Shadow_MatchTopicString/cbmc-viewer.json @@ -2,6 +2,6 @@ [ ], - "proof-name": "Shadow_MatchTopic", + "proof-name": "Shadow_MatchTopicString", "proof-root": "../cbmc/proofs" } diff --git a/test/unit-test/shadow_utest.c b/test/unit-test/shadow_utest.c index 6d86942f..03d1b08c 100644 --- a/test/unit-test/shadow_utest.c +++ b/test/unit-test/shadow_utest.c @@ -42,198 +42,423 @@ /** * @brief The Thing Name shared among all the tests. */ -#define TEST_THING_NAME "TestThingName" +#define TEST_THING_NAME "TestThingName" /** * @brief The length of #TEST_THING_NAME. */ -#define TEST_THING_NAME_LENGTH ( sizeof( TEST_THING_NAME ) - 1 ) +#define TEST_THING_NAME_LENGTH ( sizeof( TEST_THING_NAME ) - 1 ) /** - * @brief The shadow topic string "update" shared among all test cases. + * @brief The shadow topic string "update" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_UPDATE "$aws/things/TestThingName/shadow/update" +#define TEST_CLASSIC_TOPIC_STRING_UPDATE "$aws/things/TestThingName/shadow/update" /** - * @brief The shadow topic string "update/accepted" shared among all test cases. + * @brief The shadow topic string "update/accepted" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED "$aws/things/TestThingName/shadow/update/accepted" +#define TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED "$aws/things/TestThingName/shadow/update/accepted" /** - * @brief The shadow topic string "update/rejected" shared among all test cases. + * @brief The shadow topic string "update/rejected" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_UPDATE_REJECTED "$aws/things/TestThingName/shadow/update/rejected" +#define TEST_CLASSIC_TOPIC_STRING_UPDATE_REJECTED "$aws/things/TestThingName/shadow/update/rejected" /** - * @brief The shadow topic string "update/documents" shared among all test cases. + * @brief The shadow topic string "update/documents" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS "$aws/things/TestThingName/shadow/update/documents" +#define TEST_CLASSIC_TOPIC_STRING_UPDATE_DOCUMENTS "$aws/things/TestThingName/shadow/update/documents" /** - * @brief The shadow topic string "update/delta" shared among all test cases. + * @brief The shadow topic string "update/delta" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_UPDATE_DELTA "$aws/things/TestThingName/shadow/update/delta" +#define TEST_CLASSIC_TOPIC_STRING_UPDATE_DELTA "$aws/things/TestThingName/shadow/update/delta" /** - * @brief The shadow topic string "get" shared among all test cases. + * @brief The shadow topic string "get" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_GET "$aws/things/TestThingName/shadow/get" +#define TEST_CLASSIC_TOPIC_STRING_GET "$aws/things/TestThingName/shadow/get" /** - * @brief The shadow topic string "get/accepted" shared among all test cases. + * @brief The shadow topic string "get/accepted" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED "$aws/things/TestThingName/shadow/get/accepted" +#define TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED "$aws/things/TestThingName/shadow/get/accepted" /** - * @brief The shadow topic string "get/rejected" shared among all test cases. + * @brief The shadow topic string "get/rejected" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_GET_REJECTED "$aws/things/TestThingName/shadow/get/rejected" +#define TEST_CLASSIC_TOPIC_STRING_GET_REJECTED "$aws/things/TestThingName/shadow/get/rejected" /** - * @brief The shadow topic string "delete" shared among all test cases. + * @brief The shadow topic string "delete" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_DELETE "$aws/things/TestThingName/shadow/delete" +#define TEST_CLASSIC_TOPIC_STRING_DELETE "$aws/things/TestThingName/shadow/delete" /** - * @brief The shadow topic string "delete/accepted" shared among all test cases. + * @brief The shadow topic string "delete/accepted" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_DELETE_ACCEPTED "$aws/things/TestThingName/shadow/delete/accepted" +#define TEST_CLASSIC_TOPIC_STRING_DELETE_ACCEPTED "$aws/things/TestThingName/shadow/delete/accepted" /** - * @brief The shadow topic string "delete/rejected" shared among all test cases. + * @brief The shadow topic string "delete/rejected" shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED "$aws/things/TestThingName/shadow/delete/rejected" +#define TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED "$aws/things/TestThingName/shadow/delete/rejected" /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_UPDATE shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_UPDATE shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_UPDATE ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_UPDATE ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_UPDATE ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_UPDATE ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_UPDATE_REJECTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_UPDATE_REJECTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_UPDATE_REJECTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_UPDATE_REJECTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_UPDATE_REJECTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_UPDATE_REJECTED ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_UPDATE_DOCUMENTS shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DOCUMENTS ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_UPDATE_DOCUMENTS ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_UPDATE_DELTA shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_UPDATE_DELTA shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_UPDATE_DELTA ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_UPDATE_DELTA ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DELTA ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_UPDATE_DELTA ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_GET shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_GET shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_GET ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_GET ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_GET ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_GET ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_GET_REJECTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_GET_REJECTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_GET_REJECTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_GET_REJECTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_GET_REJECTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_GET_REJECTED ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_DELETE shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_DELETE shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_DELETE ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_DELETE ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_DELETE ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_DELETE ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_DELETE_ACCEPTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_DELETE_ACCEPTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_DELETE_ACCEPTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_DELETE_ACCEPTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_DELETE_ACCEPTED ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED shared among all test cases. + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED shared among all Classic shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_DELETE_REJECTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED ) - 1U ) +#define TEST_CLASSIC_TOPIC_LENGTH_DELETE_REJECTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED ) - 1U ) /** * @brief A topic string with an empty thing name. */ -#define TEST_SHADOW_TOPIC_STRING_EMPTY_THINGNAME "$aws/things/" +#define TEST_TOPIC_STRING_EMPTY_THINGNAME "$aws/things/" /** * @brief A topic string with an invalid thing name. */ -#define TEST_SHADOW_TOPIC_STRING_INVALID_THINGNAME "$aws/things//" +#define TEST_TOPIC_STRING_INVALID_THINGNAME "$aws/things//" + +/** + * @brief A topic string with an un-terminated thing name + */ +#define TEST_TOPIC_STRING_UNTERMINATED_THINGNAME "$aws/things/TestThingName" + +/** + * @brief A topic string with an empty shadow root. + */ +#define TEST_TOPIC_STRING_EMPTY_SHADOW_ROOT "$aws/things/TestThingName/" + +/** + * @brief A topic string with an invalid shadow root. + */ +#define TEST_TOPIC_STRING_INVALID_SHADOW_ROOT "$aws/things/TestThingName/invalid" /** * @brief A topic string with an empty shadow message type. */ -#define TEST_SHADOW_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE "$aws/things/TestThingName" +#define TEST_CLASSIC_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE "$aws/things/TestThingName/shadow" /** * @brief A topic string that is not related to Shadow. */ -#define TEST_SHADOW_TOPIC_STRING_INVALID_SHADOW_RESPONSE "$aws/things/TestThingName/shadow/invalid/invalid" +#define TEST_CLASSIC_TOPIC_STRING_INVALID_SHADOW_RESPONSE "$aws/things/TestThingName/shadow/invalid/invalid" /** * @brief A topic string that is not related to Shadow. */ -#define TEST_SHADOW_TOPIC_STRING_INVALID_GET_REJECTED "$aws/things/TestThingName/shadow/get/rejected/gibberish" +#define TEST_CLASSIC_TOPIC_STRING_INVALID_GET_REJECTED "$aws/things/TestThingName/shadow/get/rejected/gibberish" + +/** + * @brief A topic string that is not related to Shadow. + */ +#define TEST_TOPIC_STRING_INVALID_PREFIX "$aws/jobs/TestThingName/shadow/get/rejected" + +/** + * @brief The length of #TEST_TOPIC_STRING_INVALID_PREFIX shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_INVALID_PREFIX ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_INVALID_PREFIX ) - 1U ) + +/** + * @brief The length of #TEST_TOPIC_STRING_EMPTY_THINGNAME shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_EMPTY_THINGNAME ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_EMPTY_THINGNAME ) - 1U ) + +/** + * @brief The length of #TEST_TOPIC_STRING_INVALID_THINGNAME shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_INVALID_THINGNAME ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_INVALID_THINGNAME ) - 1U ) + +/** + * @brief The length of #TEST_TOPIC_STRING_UNTERMINATED_THINGNAME shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_UNTERMINATED_THINGNAME ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_UNTERMINATED_THINGNAME ) - 1U ) + +/** + * @brief The length of #TEST_TOPIC_STRING_EMPTY_SHADOW_ROOT shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_EMPTY_SHADOW_ROOT ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_EMPTY_SHADOW_ROOT ) - 1U ) + +/** + * @brief The length of #TEST_TOPIC_STRING_INVALID_SHADOW_ROOT shared among all shadow test cases. + */ +#define TEST_TOPIC_LENGTH_INVALID_SHADOW_ROOT ( ( uint16_t ) sizeof( TEST_TOPIC_STRING_INVALID_SHADOW_ROOT ) - 1U ) + +/** + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE shared among all Classic shadow test cases. + */ +#define TEST_CLASSIC_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE ) - 1U ) + +/** + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_INVALID_SHADOW_RESPONSE shared among all Classic shadow test cases. + */ +#define TEST_CLASSIC_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_INVALID_SHADOW_RESPONSE ) - 1U ) + +/** + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_INVALID_GET_REJECTED shared among all Classic shadow test cases. + */ +#define TEST_CLASSIC_TOPIC_LENGTH_INVALID_GET_REJECTED ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_STRING_INVALID_GET_REJECTED ) - 1U ) + +/** + * @brief The init value for a topic buffer. + */ +#define TEST_CLASSIC_TOPIC_BUFFER_INITIALIZE "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmno" + +/** + * @brief The init value for a topic buffer. + */ +#define TEST_CLASSIC_TOPIC_BUFFER_MODIFIED "$aws/things/TestThingName/shadow/get/acceptedklmno" + +/** + * @brief The length of #TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED shared among all Classic shadow test cases. + */ +#define TEST_CLASSIC_TOPIC_BUFFER_LENGTH ( ( uint16_t ) sizeof( TEST_CLASSIC_TOPIC_BUFFER_INITIALIZE ) - 1U ) + + +/** + * @brief The Shadow Name shared among all the named shadow tests. + */ +#define TEST_SHADOW_NAME "TestShadowName" + +/** + * @brief The length of #TEST_SHADOW_NAME. + */ +#define TEST_SHADOW_NAME_LENGTH ( sizeof( TEST_SHADOW_NAME ) - 1 ) + +/** + * @brief The shadow topic string "update" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_UPDATE "$aws/things/TestThingName/shadow/name/TestShadowName/update" + +/** + * @brief The shadow topic string "update/accepted" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED "$aws/things/TestThingName/shadow/name/TestShadowName/update/accepted" + +/** + * @brief The shadow topic string "update/rejected" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_UPDATE_REJECTED "$aws/things/TestThingName/shadow/name/TestShadowName/update/rejected" + +/** + * @brief The shadow topic string "update/documents" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_UPDATE_DOCUMENTS "$aws/things/TestThingName/shadow/name/TestShadowName/update/documents" + +/** + * @brief The shadow topic string "update/delta" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_UPDATE_DELTA "$aws/things/TestThingName/shadow/name/TestShadowName/update/delta" + +/** + * @brief The shadow topic string "get" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_GET "$aws/things/TestThingName/shadow/name/TestShadowName/get" + +/** + * @brief The shadow topic string "get/accepted" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_GET_ACCEPTED "$aws/things/TestThingName/shadow/name/TestShadowName/get/accepted" + +/** + * @brief The shadow topic string "get/rejected" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_GET_REJECTED "$aws/things/TestThingName/shadow/name/TestShadowName/get/rejected" + +/** + * @brief The shadow topic string "delete" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_DELETE "$aws/things/TestThingName/shadow/name/TestShadowName/delete" + +/** + * @brief The shadow topic string "delete/accepted" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_DELETE_ACCEPTED "$aws/things/TestThingName/shadow/name/TestShadowName/delete/accepted" + +/** + * @brief The shadow topic string "delete/rejected" shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_STRING_DELETE_REJECTED "$aws/things/TestThingName/shadow/name/TestShadowName/delete/rejected" + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_UPDATE shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_UPDATE ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UPDATE ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_UPDATE_REJECTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_UPDATE_REJECTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UPDATE_REJECTED ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_UPDATE_DOCUMENTS shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_UPDATE_DOCUMENTS ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UPDATE_DOCUMENTS ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_UPDATE_DELTA shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_UPDATE_DELTA ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UPDATE_DELTA ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_GET shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_GET ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_GET ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_GET_ACCEPTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_GET_ACCEPTED ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_GET_REJECTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_GET_REJECTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_GET_REJECTED ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_DELETE shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_DELETE ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_DELETE ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_DELETE_ACCEPTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_DELETE_ACCEPTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_DELETE_ACCEPTED ) - 1U ) + +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_DELETE_REJECTED shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_DELETE_REJECTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_DELETE_REJECTED ) - 1U ) + +/** + * @brief A topic string with an empty shadow name. + */ +#define TEST_NAMED_TOPIC_STRING_EMPTY_SHADOWNAME "$aws/things/TestThingName/shadow/name/" + +/** + * @brief A topic string with an invalid shadow name. + */ +#define TEST_NAMED_TOPIC_STRING_INVALID_SHADOWNAME "$aws/things/TestThingName/shadow/name//" + +/** + * @brief A topic string with an un-terminated shadow name + */ +#define TEST_NAMED_TOPIC_STRING_UNTERMINATED_SHADOWNAME "$aws/things/TestThingName/shadow/name/TestShadowName" + +/** + * @brief A topic string with an empty shadow message type. + */ +#define TEST_NAMED_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE "$aws/things/TestThingName/shadow/name/TestShadowName/" /** * @brief A topic string that is not related to Shadow. */ -#define TEST_SHADOW_TOPIC_STRING_INVALID_PREFIX "$aws/jobs/TestThingName/shadow/get/rejected" +#define TEST_NAMED_TOPIC_STRING_INVALID_SHADOW_RESPONSE "$aws/things/TestThingName/shadow/name/TestShadowName/invalid/invalid" /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_EMPTY_THINGNAME shared among all test cases. + * @brief A topic string that is not related to Shadow. */ -#define TEST_SHADOW_TOPIC_LENGTH_EMPTY_THINGNAME ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_EMPTY_THINGNAME ) - 1U ) +#define TEST_NAMED_TOPIC_STRING_INVALID_GET_REJECTED "$aws/things/TestThingName/shadow/name/TestShadowName/get/rejected/gibberish" /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_INVALID_THINGNAME shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_EMPTY_SHADOWNAME shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_INVALID_THINGNAME ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_INVALID_THINGNAME ) - 1U ) +#define TEST_NAMED_TOPIC_LENGTH_EMPTY_SHADOWNAME ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_EMPTY_SHADOWNAME ) - 1U ) +/** + * @brief The length of #TEST_NAMED_TOPIC_STRING_INVALID_SHADOWNAME shared among all named shadow test cases. + */ +#define TEST_NAMED_TOPIC_LENGTH_INVALID_SHADOWNAME ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_INVALID_SHADOWNAME ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_UNTERMINATED_SHADOWNAME shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE ) - 1U ) +#define TEST_NAMED_TOPIC_LENGTH_UNTERMINATED_SHADOWNAME ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_UNTERMINATED_SHADOWNAME ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_INVALID_SHADOW_RESPONSE shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_INVALID_SHADOW_RESPONSE ) - 1U ) +#define TEST_NAMED_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_INVALID_GET_REJECTED shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_INVALID_SHADOW_RESPONSE shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_INVALID_GET_REJECTED ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_INVALID_GET_REJECTED ) - 1U ) +#define TEST_NAMED_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_INVALID_SHADOW_RESPONSE ) - 1U ) /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_INVALID_PREFIX shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_INVALID_GET_REJECTED shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_LENGTH_INVALID_PREFIX ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_STRING_INVALID_PREFIX ) - 1U ) +#define TEST_NAMED_TOPIC_LENGTH_INVALID_GET_REJECTED ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_STRING_INVALID_GET_REJECTED ) - 1U ) /** * @brief The init value for a topic buffer. */ -#define TEST_SHADOW_TOPIC_BUFFER_INITIALZIE "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmno" +#define TEST_NAMED_TOPIC_BUFFER_INITIALIZE "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz123456789" /** * @brief The init value for a topic buffer. */ -#define TEST_SHADOW_TOPIC_BUFFER_MODIFIED "$aws/things/TestThingName/shadow/get/acceptedklmno" +#define TEST_NAMED_TOPIC_BUFFER_MODIFIED "$aws/things/TestThingName/shadow/name/TestShadowName/get/accepted56789" /** - * @brief The length of #TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED shared among all test cases. + * @brief The length of #TEST_NAMED_TOPIC_STRING_DELETE_REJECTED shared among all named shadow test cases. */ -#define TEST_SHADOW_TOPIC_BUFFER_LENGTH ( ( uint16_t ) sizeof( TEST_SHADOW_TOPIC_BUFFER_INITIALZIE ) - 1U ) +#define TEST_NAMED_TOPIC_BUFFER_LENGTH ( ( uint16_t ) sizeof( TEST_NAMED_TOPIC_BUFFER_INITIALIZE ) - 1U ) /*-----------------------------------------------------------*/ @@ -262,90 +487,130 @@ int suiteTearDown( int numFailures ) /*-----------------------------------------------------------*/ /** - * @brief Tests the macros generates the expected strings. + * @brief Tests the macros generate the expected strings for Classic shadows. */ -void test_Shadow_MacrosString( void ) +void test_Shadow_Classic_MacrosString( void ) { - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_UPDATE, SHADOW_TOPIC_STRING_UPDATE( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED, SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_UPDATE_REJECTED, SHADOW_TOPIC_STRING_UPDATE_REJECTED( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS, SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_UPDATE_DELTA, SHADOW_TOPIC_STRING_UPDATE_DELTA( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_GET, SHADOW_TOPIC_STRING_GET( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED, SHADOW_TOPIC_STRING_GET_ACCEPTED( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_GET_REJECTED, SHADOW_TOPIC_STRING_GET_REJECTED( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_DELETE, SHADOW_TOPIC_STRING_DELETE( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_DELETE_ACCEPTED, SHADOW_TOPIC_STRING_DELETE_ACCEPTED( TEST_THING_NAME ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED, SHADOW_TOPIC_STRING_DELETE_REJECTED( TEST_THING_NAME ) ); + /* Test Classic shadow topic strings through the deprecated legacy macros, to verify the legacy macros. */ + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_UPDATE, SHADOW_TOPIC_STRING_UPDATE( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED, SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_UPDATE_REJECTED, SHADOW_TOPIC_STRING_UPDATE_REJECTED( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_UPDATE_DOCUMENTS, SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_UPDATE_DELTA, SHADOW_TOPIC_STRING_UPDATE_DELTA( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_GET, SHADOW_TOPIC_STRING_GET( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED, SHADOW_TOPIC_STRING_GET_ACCEPTED( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_GET_REJECTED, SHADOW_TOPIC_STRING_GET_REJECTED( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_DELETE, SHADOW_TOPIC_STRING_DELETE( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_DELETE_ACCEPTED, SHADOW_TOPIC_STRING_DELETE_ACCEPTED( TEST_THING_NAME ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED, SHADOW_TOPIC_STRING_DELETE_REJECTED( TEST_THING_NAME ) ); +} + +/** + * @brief Tests the macros generate the expected strings for named shadows. + */ +void test_Shadow_Named_MacrosString( void ) +{ + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_UPDATE, SHADOW_TOPIC_STR_UPDATE( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED, SHADOW_TOPIC_STR_UPDATE_ACC( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_UPDATE_REJECTED, SHADOW_TOPIC_STR_UPDATE_REJ( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_UPDATE_DOCUMENTS, SHADOW_TOPIC_STR_UPDATE_DOCS( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_UPDATE_DELTA, SHADOW_TOPIC_STR_UPDATE_DELTA( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_GET, SHADOW_TOPIC_STR_GET( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_GET_ACCEPTED, SHADOW_TOPIC_STR_GET_ACC( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_GET_REJECTED, SHADOW_TOPIC_STR_GET_REJ( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_DELETE, SHADOW_TOPIC_STR_DELETE( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_DELETE_ACCEPTED, SHADOW_TOPIC_STR_DELETE_ACC( TEST_THING_NAME, TEST_SHADOW_NAME ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_STRING_DELETE_REJECTED, SHADOW_TOPIC_STR_DELETE_REJ( TEST_THING_NAME, TEST_SHADOW_NAME ) ); } /*-----------------------------------------------------------*/ /** - * @brief Tests the macros generates the expected strings length. + * @brief Tests the macros generate the expected strings length for Classic shadows. */ -void test_Shadow_MacrosLength( void ) +void test_Shadow_Classic_MacrosLength( void ) { - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_UPDATE, SHADOW_TOPIC_LENGTH_UPDATE( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED, SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_UPDATE_REJECTED, SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS, SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_UPDATE_DELTA, SHADOW_TOPIC_LENGTH_UPDATE_DELTA( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_GET, SHADOW_TOPIC_LENGTH_GET( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED, SHADOW_TOPIC_LENGTH_GET_ACCEPTED( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_GET_REJECTED, SHADOW_TOPIC_LENGTH_GET_REJECTED( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_DELETE, SHADOW_TOPIC_LENGTH_DELETE( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED, SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( TEST_THING_NAME_LENGTH ) ); - TEST_ASSERT_EQUAL( TEST_SHADOW_TOPIC_LENGTH_DELETE_REJECTED, SHADOW_TOPIC_LENGTH_DELETE_REJECTED( TEST_THING_NAME_LENGTH ) ); + /* Test Classic shadow topic lengths through the deprecated legacy macros, to verify the legacy macros. */ + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_UPDATE, SHADOW_TOPIC_LENGTH_UPDATE( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED, SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_UPDATE_REJECTED, SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DOCUMENTS, SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DELTA, SHADOW_TOPIC_LENGTH_UPDATE_DELTA( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_GET, SHADOW_TOPIC_LENGTH_GET( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED, SHADOW_TOPIC_LENGTH_GET_ACCEPTED( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_GET_REJECTED, SHADOW_TOPIC_LENGTH_GET_REJECTED( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_DELETE, SHADOW_TOPIC_LENGTH_DELETE( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_DELETE_ACCEPTED, SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( TEST_THING_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_CLASSIC_TOPIC_LENGTH_DELETE_REJECTED, SHADOW_TOPIC_LENGTH_DELETE_REJECTED( TEST_THING_NAME_LENGTH ) ); +} + +/** + * @brief Tests the macros generate the expected strings length for named shadows. + */ +void test_Shadow_Named_MacrosLength( void ) +{ + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_UPDATE, SHADOW_TOPIC_LEN_UPDATE( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED, SHADOW_TOPIC_LEN_UPDATE_ACC( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_UPDATE_REJECTED, SHADOW_TOPIC_LEN_UPDATE_REJ( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_UPDATE_DOCUMENTS, SHADOW_TOPIC_LEN_UPDATE_DOCS( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_UPDATE_DELTA, SHADOW_TOPIC_LEN_UPDATE_DELTA( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_GET, SHADOW_TOPIC_LEN_GET( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED, SHADOW_TOPIC_LEN_GET_ACC( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_GET_REJECTED, SHADOW_TOPIC_LEN_GET_REJ( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_DELETE, SHADOW_TOPIC_LEN_DELETE( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_DELETE_ACCEPTED, SHADOW_TOPIC_LEN_DELETE_ACC( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); + TEST_ASSERT_EQUAL( TEST_NAMED_TOPIC_LENGTH_DELETE_REJECTED, SHADOW_TOPIC_LEN_DELETE_REJ( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ); } /*-----------------------------------------------------------*/ /** - * @brief Tests the behavior of Shadow_GetTopicString() with valid parameters. + * @brief Tests the behavior of Shadow_AssembleTopicString() for Classic shadows, + * with valid parameters. Tests Classic shadows through the deprecated legacy API macro + * Shadow_GetTopicString(), to verify the legacy macro. */ -void test_Shadow_GetTopicString_Happy_Path( void ) +void test_Shadow_AssembleTopicString_Classic_Happy_Path( void ) { ShadowStatus_t shadowStatus = SHADOW_SUCCESS; - uint16_t outLength = 0; - char topicBufferExceeded[ TEST_SHADOW_TOPIC_BUFFER_LENGTH ] = TEST_SHADOW_TOPIC_BUFFER_INITIALZIE; - uint16_t bufferSizeExceeded = TEST_SHADOW_TOPIC_BUFFER_LENGTH; + uint16_t outLength = 0U; + char topicBufferExceeded[ TEST_CLASSIC_TOPIC_BUFFER_LENGTH ] = TEST_CLASSIC_TOPIC_BUFFER_INITIALIZE; + uint16_t bufferSizeExceeded = TEST_CLASSIC_TOPIC_BUFFER_LENGTH; char topicBufferGetAccepted[ SHADOW_TOPIC_LENGTH_GET_ACCEPTED( TEST_THING_NAME_LENGTH ) ] = { 0 }; - uint16_t bufferSizeGetAccepted = TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED; + uint16_t bufferSizeGetAccepted = TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED; char topicBuffer[ SHADOW_TOPIC_LENGTH_MAX( TEST_THING_NAME_LENGTH ) ] = { 0 }; uint16_t bufferSize = SHADOW_TOPIC_LENGTH_MAX( TEST_THING_NAME_LENGTH ); - uint16_t index = 0; + uint16_t index = 0U; /* Lookup table for Shadow message string. */ static const uint16_t expectedBuffersSize[ ShadowTopicStringTypeMaxNum ] = { - TEST_SHADOW_TOPIC_LENGTH_UPDATE, - TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED, - TEST_SHADOW_TOPIC_LENGTH_UPDATE_REJECTED, - TEST_SHADOW_TOPIC_LENGTH_UPDATE_DOCUMENTS, - TEST_SHADOW_TOPIC_LENGTH_UPDATE_DELTA, - TEST_SHADOW_TOPIC_LENGTH_GET, - TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED, - TEST_SHADOW_TOPIC_LENGTH_GET_REJECTED, - TEST_SHADOW_TOPIC_LENGTH_DELETE, - TEST_SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED, - TEST_SHADOW_TOPIC_LENGTH_DELETE_REJECTED + TEST_CLASSIC_TOPIC_LENGTH_UPDATE, + TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED, + TEST_CLASSIC_TOPIC_LENGTH_UPDATE_REJECTED, + TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DOCUMENTS, + TEST_CLASSIC_TOPIC_LENGTH_UPDATE_DELTA, + TEST_CLASSIC_TOPIC_LENGTH_GET, + TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED, + TEST_CLASSIC_TOPIC_LENGTH_GET_REJECTED, + TEST_CLASSIC_TOPIC_LENGTH_DELETE, + TEST_CLASSIC_TOPIC_LENGTH_DELETE_ACCEPTED, + TEST_CLASSIC_TOPIC_LENGTH_DELETE_REJECTED }; /* Lookup table for Shadow message string. */ static const char * const expectedBuffers[ ShadowTopicStringTypeMaxNum ] = { - TEST_SHADOW_TOPIC_STRING_UPDATE, - TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED, - TEST_SHADOW_TOPIC_STRING_UPDATE_REJECTED, - TEST_SHADOW_TOPIC_STRING_UPDATE_DOCUMENTS, - TEST_SHADOW_TOPIC_STRING_UPDATE_DELTA, - TEST_SHADOW_TOPIC_STRING_GET, - TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED, - TEST_SHADOW_TOPIC_STRING_GET_REJECTED, - TEST_SHADOW_TOPIC_STRING_DELETE, - TEST_SHADOW_TOPIC_STRING_DELETE_ACCEPTED, - TEST_SHADOW_TOPIC_STRING_DELETE_REJECTED + TEST_CLASSIC_TOPIC_STRING_UPDATE, + TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED, + TEST_CLASSIC_TOPIC_STRING_UPDATE_REJECTED, + TEST_CLASSIC_TOPIC_STRING_UPDATE_DOCUMENTS, + TEST_CLASSIC_TOPIC_STRING_UPDATE_DELTA, + TEST_CLASSIC_TOPIC_STRING_GET, + TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED, + TEST_CLASSIC_TOPIC_STRING_GET_REJECTED, + TEST_CLASSIC_TOPIC_STRING_DELETE, + TEST_CLASSIC_TOPIC_STRING_DELETE_ACCEPTED, + TEST_CLASSIC_TOPIC_STRING_DELETE_REJECTED }; static const ShadowTopicStringType_t topicTypes[ ShadowTopicStringTypeMaxNum ] = @@ -372,9 +637,9 @@ void test_Shadow_GetTopicString_Happy_Path( void ) bufferSizeExceeded, &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); - TEST_ASSERT_EQUAL_INT( TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED, outLength ); + TEST_ASSERT_EQUAL_INT( TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED, outLength ); TEST_ASSERT_LESS_THAN( bufferSizeExceeded, outLength ); - TEST_ASSERT_EQUAL_STRING_LEN( TEST_SHADOW_TOPIC_BUFFER_MODIFIED, + TEST_ASSERT_EQUAL_STRING_LEN( TEST_CLASSIC_TOPIC_BUFFER_MODIFIED, topicBufferExceeded, bufferSizeExceeded ); @@ -386,12 +651,12 @@ void test_Shadow_GetTopicString_Happy_Path( void ) &( topicBufferGetAccepted[ 0 ] ), bufferSizeGetAccepted, &outLength ); - TEST_ASSERT_EQUAL_INT( TEST_SHADOW_TOPIC_LENGTH_GET_ACCEPTED, outLength ); - TEST_ASSERT_EQUAL_STRING_LEN( TEST_SHADOW_TOPIC_STRING_GET_ACCEPTED, + TEST_ASSERT_EQUAL_INT( TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED, outLength ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_CLASSIC_TOPIC_STRING_GET_ACCEPTED, topicBufferGetAccepted, bufferSizeGetAccepted ); - for( index = 0; index < ShadowTopicStringTypeMaxNum; index++ ) + for( index = 0U; index < ShadowTopicStringTypeMaxNum; index++ ) { /* Call Shadow_GetTopicString() with valid parameters with all types of topic string * and verify result. */ @@ -408,92 +673,241 @@ void test_Shadow_GetTopicString_Happy_Path( void ) } } +/** + * @brief Tests the behavior of Shadow_AssembleTopicString() for named shadows, with valid parameters. + */ +void test_Shadow_AssembleTopicString_Named_Happy_Path( void ) +{ + ShadowStatus_t shadowStatus = SHADOW_SUCCESS; + uint16_t outLength = 0U; + char topicBufferExceeded[ TEST_NAMED_TOPIC_BUFFER_LENGTH ] = TEST_NAMED_TOPIC_BUFFER_INITIALIZE; + uint16_t bufferSizeExceeded = TEST_NAMED_TOPIC_BUFFER_LENGTH; + char topicBufferGetAccepted[ SHADOW_TOPIC_LEN_GET_ACC( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ] = { 0 }; + uint16_t bufferSizeGetAccepted = TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED; + char topicBuffer[ SHADOW_TOPIC_LEN_MAX( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ) ] = { 0 }; + uint16_t bufferSize = SHADOW_TOPIC_LEN_MAX( TEST_THING_NAME_LENGTH, TEST_SHADOW_NAME_LENGTH ); + uint16_t index = 0U; + + /* Lookup table for Shadow message string. */ + static const uint16_t expectedBuffersSize[ ShadowTopicStringTypeMaxNum ] = + { + TEST_NAMED_TOPIC_LENGTH_UPDATE, + TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED, + TEST_NAMED_TOPIC_LENGTH_UPDATE_REJECTED, + TEST_NAMED_TOPIC_LENGTH_UPDATE_DOCUMENTS, + TEST_NAMED_TOPIC_LENGTH_UPDATE_DELTA, + TEST_NAMED_TOPIC_LENGTH_GET, + TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED, + TEST_NAMED_TOPIC_LENGTH_GET_REJECTED, + TEST_NAMED_TOPIC_LENGTH_DELETE, + TEST_NAMED_TOPIC_LENGTH_DELETE_ACCEPTED, + TEST_NAMED_TOPIC_LENGTH_DELETE_REJECTED + }; + + /* Lookup table for Shadow message string. */ + static const char * const expectedBuffers[ ShadowTopicStringTypeMaxNum ] = + { + TEST_NAMED_TOPIC_STRING_UPDATE, + TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED, + TEST_NAMED_TOPIC_STRING_UPDATE_REJECTED, + TEST_NAMED_TOPIC_STRING_UPDATE_DOCUMENTS, + TEST_NAMED_TOPIC_STRING_UPDATE_DELTA, + TEST_NAMED_TOPIC_STRING_GET, + TEST_NAMED_TOPIC_STRING_GET_ACCEPTED, + TEST_NAMED_TOPIC_STRING_GET_REJECTED, + TEST_NAMED_TOPIC_STRING_DELETE, + TEST_NAMED_TOPIC_STRING_DELETE_ACCEPTED, + TEST_NAMED_TOPIC_STRING_DELETE_REJECTED + }; + + static const ShadowTopicStringType_t topicTypes[ ShadowTopicStringTypeMaxNum ] = + { + ShadowTopicStringTypeUpdate, + ShadowTopicStringTypeUpdateAccepted, + ShadowTopicStringTypeUpdateRejected, + ShadowTopicStringTypeUpdateDocuments, + ShadowTopicStringTypeUpdateDelta, + ShadowTopicStringTypeGet, + ShadowTopicStringTypeGetAccepted, + ShadowTopicStringTypeGetRejected, + ShadowTopicStringTypeDelete, + ShadowTopicStringTypeDeleteAccepted, + ShadowTopicStringTypeDeleteRejected + }; + + /* Call Shadow_AssembleTopicString() with valid parameters but bufferSize exceeds topic string length + * and verify result. */ + shadowStatus = Shadow_AssembleTopicString( ShadowTopicStringTypeGetAccepted, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + TEST_SHADOW_NAME, + TEST_SHADOW_NAME_LENGTH, + &( topicBufferExceeded[ 0 ] ), + bufferSizeExceeded, + &outLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); + TEST_ASSERT_EQUAL_INT( TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED, outLength ); + TEST_ASSERT_LESS_THAN( bufferSizeExceeded, outLength ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_NAMED_TOPIC_BUFFER_MODIFIED, + topicBufferExceeded, + bufferSizeExceeded ); + + /* Call Shadow_AssembleTopicString() with valid parameters, bufferSize = expected outLength + * and verify result. */ + shadowStatus = Shadow_AssembleTopicString( ShadowTopicStringTypeGetAccepted, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + TEST_SHADOW_NAME, + TEST_SHADOW_NAME_LENGTH, + &( topicBufferGetAccepted[ 0 ] ), + bufferSizeGetAccepted, + &outLength ); + TEST_ASSERT_EQUAL_INT( TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED, outLength ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_NAMED_TOPIC_STRING_GET_ACCEPTED, + topicBufferGetAccepted, + bufferSizeGetAccepted ); + + for( index = 0U; index < ShadowTopicStringTypeMaxNum; index++ ) + { + /* Call Shadow_AssembleTopicString() with valid parameters with all types of topic string + * and verify result. */ + shadowStatus = Shadow_AssembleTopicString( topicTypes[ index ], + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + TEST_SHADOW_NAME, + TEST_SHADOW_NAME_LENGTH, + &( topicBuffer[ 0 ] ), + bufferSize, + &outLength ); + TEST_ASSERT_EQUAL_INT( expectedBuffersSize[ index ], outLength ); + TEST_ASSERT_EQUAL_STRING_LEN( expectedBuffers[ index ], + topicBuffer, + outLength ); + } +} + /*-----------------------------------------------------------*/ /** - * @brief Tests the behavior of Shadow_GetTopicString() with invalid parameters. + * @brief Tests the behavior of Shadow_AssembleTopicString() with invalid parameters */ -void test_Shadow_GetTopicString_Invalid_Parameters( void ) +void test_Shadow_AssembleTopicString_Invalid_Parameters( void ) { ShadowStatus_t shadowStatus = SHADOW_SUCCESS; - uint16_t outLength = 0; + uint16_t outLength = 0U; ShadowTopicStringType_t topicType = ShadowTopicStringTypeGetAccepted; - char topicBuffer[ TEST_SHADOW_TOPIC_BUFFER_LENGTH ] = TEST_SHADOW_TOPIC_BUFFER_INITIALZIE; - uint16_t bufferSize = TEST_SHADOW_TOPIC_BUFFER_LENGTH; + char classicTopicBuffer[ TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED ]; + uint16_t classicBufferSize = TEST_CLASSIC_TOPIC_LENGTH_GET_ACCEPTED; + char namedTopicBuffer[ TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED ]; + uint16_t namedBufferSize = TEST_NAMED_TOPIC_LENGTH_GET_ACCEPTED; - /* Call Shadow_GetTopicString() with various combinations of + /* Call Shadow_AssembleTopicString() with various combinations of * incorrect parameters. */ - shadowStatus = Shadow_GetTopicString( 0, - "", - 0, - &( topicBuffer[ 0 ] ), - bufferSize, - &outLength ); + shadowStatus = Shadow_AssembleTopicString( 0, + "", + 0, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + classicBufferSize, + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_GetTopicString( 0, - NULL, - 0, - &( topicBuffer[ 0 ] ), - bufferSize, - &outLength ); + shadowStatus = Shadow_AssembleTopicString( 0, + NULL, + 0, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + classicBufferSize, + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_GetTopicString( topicType, - TEST_THING_NAME, - TEST_THING_NAME_LENGTH, - NULL, - 0, - &outLength ); + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + SHADOW_NAME_CLASSIC, + 0, + NULL, + 0, + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); + shadowStatus = Shadow_AssembleTopicString( ShadowTopicStringTypeMaxNum + 1, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + classicBufferSize, + &outLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_GetTopicString( ShadowTopicStringTypeMaxNum + 1, - TEST_THING_NAME, - TEST_THING_NAME_LENGTH, - &( topicBuffer[ 0 ] ), - bufferSize, - &outLength ); + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + classicBufferSize, + NULL ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_GetTopicString( topicType, - TEST_THING_NAME, - TEST_THING_NAME_LENGTH, - &( topicBuffer[ 0 ] ), - bufferSize, - NULL ); + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + NULL, + 1, + namedTopicBuffer, + namedBufferSize, + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_GetTopicString( topicType, - TEST_THING_NAME, - TEST_THING_NAME_LENGTH, - &( topicBuffer[ 0 ] ), - 0, - &outLength ); + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + 0, + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BUFFER_TOO_SMALL, shadowStatus ); - shadowStatus = Shadow_GetTopicString( topicType, - TEST_THING_NAME, - TEST_THING_NAME_LENGTH, - &( topicBuffer[ 0 ] ), - ( bufferSize / 2 ), - &outLength ); + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + SHADOW_NAME_CLASSIC, + 0, + classicTopicBuffer, + ( classicBufferSize - 1 ), + &outLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_BUFFER_TOO_SMALL, shadowStatus ); + + shadowStatus = Shadow_AssembleTopicString( topicType, + TEST_THING_NAME, + TEST_THING_NAME_LENGTH, + TEST_SHADOW_NAME, + TEST_SHADOW_NAME_LENGTH, + namedTopicBuffer, + ( namedBufferSize - 1 ), + &outLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BUFFER_TOO_SMALL, shadowStatus ); } /*-----------------------------------------------------------*/ /** - * @brief Tests the behavior of Shadow_MatchTopic() with valid parameters. + * @brief Tests the behavior of Shadow_MatchTopicString() for classic shadow with valid parameters. Tests Classic + * shadows through the deprecated legacy API macro Shadow_MatchTopic(), to verify the legacy macros. */ -void test_Shadow_MatchTopic_Happy_Path( void ) +void test_Shadow_MatchTopicString_Classic_Happy_Path( void ) { ShadowStatus_t shadowStatus = SHADOW_SUCCESS; ShadowMessageType_t messageType = ShadowMessageTypeMaxNum; const char * pThingName = NULL; - uint16_t thingNameLength = 0; - const char topicBuffer[ TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED; - uint16_t bufferSize = TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED; + uint16_t thingNameLength = 0U; + const char topicBuffer[ TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED; + uint16_t bufferSize = TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED; /* Call Shadow_MatchTopic() with valid parameters and verify result. */ shadowStatus = Shadow_MatchTopic( &( topicBuffer[ 0 ] ), @@ -534,100 +948,293 @@ void test_Shadow_MatchTopic_Happy_Path( void ) TEST_ASSERT_EQUAL_INT( ShadowMessageTypeUpdateAccepted, messageType ); } +/** + * @brief Tests the behavior of Shadow_MatchTopicString() for named shadows with valid parameters. + */ +void test_Shadow_MatchTopicString_Named_Happy_Path( void ) +{ + ShadowStatus_t shadowStatus = SHADOW_SUCCESS; + ShadowMessageType_t messageType = ShadowMessageTypeMaxNum; + const char * pThingName = NULL; + uint16_t thingNameLength = 0U; + const char * pShadowName = NULL; + uint16_t shadowNameLength = 0U; + const char topicBuffer[ TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED; + uint16_t bufferSize = TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED; + + /* Call Shadow_MatchTopicString() with valid parameters and verify result. */ + shadowStatus = Shadow_MatchTopicString( &( topicBuffer[ 0 ] ), + bufferSize, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + + TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); + TEST_ASSERT_EQUAL_INT( TEST_THING_NAME_LENGTH, thingNameLength ); + TEST_ASSERT_EQUAL_INT( ShadowMessageTypeUpdateAccepted, messageType ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_THING_NAME, pThingName, TEST_THING_NAME_LENGTH ); + TEST_ASSERT_EQUAL_INT( TEST_SHADOW_NAME_LENGTH, shadowNameLength ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_SHADOW_NAME, pShadowName, TEST_SHADOW_NAME_LENGTH ); + + shadowStatus = Shadow_MatchTopicString( &( topicBuffer[ 0 ] ), + bufferSize, + &messageType, + &pThingName, + &thingNameLength, + NULL, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); + TEST_ASSERT_EQUAL_INT( TEST_THING_NAME_LENGTH, thingNameLength ); + TEST_ASSERT_EQUAL_INT( ShadowMessageTypeUpdateAccepted, messageType ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_THING_NAME, pThingName, TEST_THING_NAME_LENGTH ); + TEST_ASSERT_EQUAL_INT( TEST_SHADOW_NAME_LENGTH, shadowNameLength ); + + shadowStatus = Shadow_MatchTopicString( &( topicBuffer[ 0 ] ), + bufferSize, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + NULL ); + TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); + TEST_ASSERT_EQUAL_INT( TEST_THING_NAME_LENGTH, thingNameLength ); + TEST_ASSERT_EQUAL_INT( ShadowMessageTypeUpdateAccepted, messageType ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_THING_NAME, pThingName, TEST_THING_NAME_LENGTH ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_SHADOW_NAME, pShadowName, TEST_SHADOW_NAME_LENGTH ); + + shadowStatus = Shadow_MatchTopicString( &( topicBuffer[ 0 ] ), + bufferSize, + &messageType, + &pThingName, + &thingNameLength, + NULL, + NULL ); + TEST_ASSERT_EQUAL_INT( SHADOW_SUCCESS, shadowStatus ); + TEST_ASSERT_EQUAL_INT( TEST_THING_NAME_LENGTH, thingNameLength ); + TEST_ASSERT_EQUAL_INT( ShadowMessageTypeUpdateAccepted, messageType ); + TEST_ASSERT_EQUAL_STRING_LEN( TEST_THING_NAME, pThingName, TEST_THING_NAME_LENGTH ); +} + /*-----------------------------------------------------------*/ /** - * @brief Tests the behavior of Shadow_MatchTopic() with various - * invalid parameters. + * @brief Tests the behavior of Shadow_MatchTopicString() with various + * invalid parameters */ -void test_Shadow_MatchTopic_Invalid_Parameters( void ) +void test_Shadow_MatchTopicString_Invalid_Parameters( void ) { ShadowStatus_t shadowStatus = SHADOW_SUCCESS; ShadowMessageType_t messageType = ShadowMessageTypeMaxNum; const char * pThingName = NULL; - uint16_t thingNameLength = 0; - const char topicBuffer[ TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_SHADOW_TOPIC_STRING_UPDATE_ACCEPTED; - uint16_t bufferSize = TEST_SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED; - - /* Call Shadow_MatchTopic() with various combinations of + uint16_t thingNameLength = 0U; + const char * pShadowName = NULL; + uint16_t shadowNameLength = 0U; + const char classicTopicBuffer[ TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_CLASSIC_TOPIC_STRING_UPDATE_ACCEPTED; + uint16_t classicBufferSize = TEST_CLASSIC_TOPIC_LENGTH_UPDATE_ACCEPTED; + const char namedTopicBuffer[ TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED ] = TEST_NAMED_TOPIC_STRING_UPDATE_ACCEPTED; + uint16_t namedBufferSize = TEST_NAMED_TOPIC_LENGTH_UPDATE_ACCEPTED; + + /* Call Shadow_MatchTopicString() with various combinations of * incorrect parameters. */ - shadowStatus = Shadow_MatchTopic( NULL, - bufferSize, - &messageType, - &pThingName, - &thingNameLength ); + shadowStatus = Shadow_MatchTopicString( NULL, + classicBufferSize, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_MatchTopic( &( topicBuffer[ 0 ] ), - 0, - &messageType, - &pThingName, - &thingNameLength ); + shadowStatus = Shadow_MatchTopicString( classicTopicBuffer, + 0, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_MatchTopic( &( topicBuffer[ 0 ] ), - bufferSize, - NULL, - &pThingName, - &thingNameLength ); - + shadowStatus = Shadow_MatchTopicString( classicTopicBuffer, + classicBufferSize, + NULL, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_BAD_PARAMETER, shadowStatus ); - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_INVALID_PREFIX, - TEST_SHADOW_TOPIC_LENGTH_INVALID_PREFIX, - &messageType, - &pThingName, - &thingNameLength ); + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_INVALID_PREFIX, + TEST_TOPIC_LENGTH_INVALID_PREFIX, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_FAIL, shadowStatus ); - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_EMPTY_THINGNAME, - TEST_SHADOW_TOPIC_LENGTH_EMPTY_THINGNAME, - &messageType, - &pThingName, - &thingNameLength ); + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_EMPTY_THINGNAME, + TEST_TOPIC_LENGTH_EMPTY_THINGNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_THINGNAME_PARSE_FAILED, shadowStatus ); - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_INVALID_THINGNAME, - TEST_SHADOW_TOPIC_LENGTH_INVALID_THINGNAME, - &messageType, - &pThingName, - &thingNameLength ); + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_INVALID_THINGNAME, + TEST_TOPIC_LENGTH_INVALID_THINGNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); TEST_ASSERT_EQUAL_INT( SHADOW_THINGNAME_PARSE_FAILED, shadowStatus ); - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE, - TEST_SHADOW_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE, - &messageType, - &pThingName, - &thingNameLength ); - TEST_ASSERT_EQUAL_INT( SHADOW_SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); - - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_INVALID_SHADOW_RESPONSE, - TEST_SHADOW_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE, - &messageType, - &pThingName, - &thingNameLength ); - TEST_ASSERT_EQUAL_INT( SHADOW_FAIL, shadowStatus ); - - shadowStatus = Shadow_MatchTopic( TEST_SHADOW_TOPIC_STRING_INVALID_GET_REJECTED, - TEST_SHADOW_TOPIC_LENGTH_INVALID_GET_REJECTED, - &messageType, - &pThingName, - &thingNameLength ); - TEST_ASSERT_EQUAL_INT( SHADOW_FAIL, shadowStatus ); - - shadowStatus = Shadow_MatchTopic( &( topicBuffer[ 0 ] ), - bufferSize / 2, - &messageType, - &pThingName, - &thingNameLength ); - TEST_ASSERT_EQUAL_INT( SHADOW_SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_UNTERMINATED_THINGNAME, + TEST_TOPIC_LENGTH_UNTERMINATED_THINGNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_THINGNAME_PARSE_FAILED, shadowStatus ); - shadowStatus = Shadow_MatchTopic( &( topicBuffer[ 0 ] ), - bufferSize * 2, - &messageType, - &pThingName, - &thingNameLength ); - TEST_ASSERT_EQUAL_INT( SHADOW_FAIL, shadowStatus ); + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_EMPTY_SHADOW_ROOT, + TEST_TOPIC_LENGTH_EMPTY_SHADOW_ROOT, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_ROOT_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_TOPIC_STRING_INVALID_SHADOW_ROOT, + TEST_TOPIC_LENGTH_INVALID_SHADOW_ROOT, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_ROOT_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_EMPTY_SHADOWNAME, + TEST_NAMED_TOPIC_LENGTH_EMPTY_SHADOWNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_SHADOWNAME_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_INVALID_SHADOWNAME, + TEST_NAMED_TOPIC_LENGTH_INVALID_SHADOWNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_SHADOWNAME_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_UNTERMINATED_SHADOWNAME, + TEST_NAMED_TOPIC_LENGTH_UNTERMINATED_SHADOWNAME, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_SHADOWNAME_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_CLASSIC_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE, + TEST_CLASSIC_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_EMPTY_SHADOW_MESSAGE_TYPE, + TEST_NAMED_TOPIC_LENGTH_EMPTY_SHADOW_MESSAGE_TYPE, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_CLASSIC_TOPIC_STRING_INVALID_SHADOW_RESPONSE, + TEST_CLASSIC_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_INVALID_SHADOW_RESPONSE, + TEST_NAMED_TOPIC_LENGTH_INVALID_SHADOW_RESPONSE, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_CLASSIC_TOPIC_STRING_INVALID_GET_REJECTED, + TEST_CLASSIC_TOPIC_LENGTH_INVALID_GET_REJECTED, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( TEST_NAMED_TOPIC_STRING_INVALID_GET_REJECTED, + TEST_NAMED_TOPIC_LENGTH_INVALID_GET_REJECTED, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( classicTopicBuffer, + classicBufferSize - 1, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( namedTopicBuffer, + namedBufferSize - 1, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( classicTopicBuffer, + classicBufferSize + 1, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); + + shadowStatus = Shadow_MatchTopicString( namedTopicBuffer, + namedBufferSize + 1, + &messageType, + &pThingName, + &thingNameLength, + &pShadowName, + &shadowNameLength ); + TEST_ASSERT_EQUAL_INT( SHADOW_MESSAGE_TYPE_PARSE_FAILED, shadowStatus ); } /*-----------------------------------------------------------*/