/* * coreJSON v3.2.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file core_json_utest.c * @brief Unit tests for the coreJSON library. */ #include #include #include #include #include "unity.h" #include "catch_assert.h" /* Include paths for public enums, structures, and macros. */ #include "core_json.h" #include "core_json_annex.h" /* Sample test from the docs. */ #define JSON_QUERY_SEPARATOR "." #define FIRST_QUERY_KEY "bar" #define FIRST_QUERY_KEY_LENGTH ( sizeof( FIRST_QUERY_KEY ) - 1 ) #define SECOND_QUERY_KEY "foo" #define SECOND_QUERY_KEY_LENGTH ( sizeof( SECOND_QUERY_KEY ) - 1 ) #define COMPLETE_QUERY_KEY \ FIRST_QUERY_KEY \ JSON_QUERY_SEPARATOR \ SECOND_QUERY_KEY #define COMPLETE_QUERY_KEY_LENGTH ( sizeof( COMPLETE_QUERY_KEY ) - 1 ) #define COMPLETE_QUERY_KEY_ANSWER "xyz" #define COMPLETE_QUERY_KEY_ANSWER_TYPE JSONString #define COMPLETE_QUERY_KEY_ANSWER_LENGTH ( sizeof( COMPLETE_QUERY_KEY_ANSWER ) - 1 ) #define FIRST_QUERY_KEY_ANSWER \ "{\"" SECOND_QUERY_KEY "\":\"" \ COMPLETE_QUERY_KEY_ANSWER "\"}" #define FIRST_QUERY_KEY_ANSWER_TYPE JSONObject #define FIRST_QUERY_KEY_ANSWER_LENGTH ( sizeof( FIRST_QUERY_KEY_ANSWER ) - 1 ) #define ARRAY_ELEMENT_0 "123" #define ARRAY_ELEMENT_1 "456" #define ARRAY_ELEMENT_2_SUB_0 "abc" #define ARRAY_ELEMENT_2_SUB_1 "[88,99]" #define ARRAY_ELEMENT_2_SUB_1_SUB_0 "88" #define ARRAY_ELEMENT_2_SUB_1_SUB_1 "99" #define ARRAY_ELEMENT_3 "true" #define ARRAY_ELEMENT_4 "false" #define ARRAY_ELEMENT_5 "null" #define JSON_NESTED_OBJECT \ "{\"" FIRST_QUERY_KEY "\":\"" ARRAY_ELEMENT_2_SUB_0 "\",\"" \ SECOND_QUERY_KEY "\":" ARRAY_ELEMENT_2_SUB_1 "}" #define JSON_NESTED_OBJECT_LENGTH ( sizeof( JSON_NESTED_OBJECT ) - 1 ) #define ARRAY_ELEMENT_2 JSON_NESTED_OBJECT #define JSON_DOC_LEGAL_ARRAY \ "[" ARRAY_ELEMENT_0 "," ARRAY_ELEMENT_1 "," ARRAY_ELEMENT_2 "," \ ARRAY_ELEMENT_3 "," ARRAY_ELEMENT_4 "," ARRAY_ELEMENT_5 "]" #define JSON_DOC_LEGAL_ARRAY_LENGTH ( sizeof( JSON_DOC_LEGAL_ARRAY ) - 1 ) #define ARRAY_ELEMENT_0_TYPE JSONNumber #define ARRAY_ELEMENT_1_TYPE JSONNumber #define ARRAY_ELEMENT_2_TYPE JSONObject #define ARRAY_ELEMENT_2_SUB_0_TYPE JSONString #define ARRAY_ELEMENT_2_SUB_1_TYPE JSONArray #define ARRAY_ELEMENT_2_SUB_1_SUB_0_TYPE JSONNumber #define ARRAY_ELEMENT_2_SUB_1_SUB_1_TYPE JSONNumber #define ARRAY_ELEMENT_3_TYPE JSONTrue #define ARRAY_ELEMENT_4_TYPE JSONFalse #define ARRAY_ELEMENT_5_TYPE JSONNull /* This JSON document covers all cases where scalars are exponents, literals, numbers, and decimals. */ #define JSON_DOC_VARIED_SCALARS \ "{\"literal\":true, \"more_literals\": {\"literal2\":false, \"literal3\":null}," \ "\"exp1\": 5E+3, \"more_exponents\": [5e+2,\t4e-2,\r93E-5, 128E-6],\n " \ "\"number\": -123412, " \ "\"decimal\":109238.42091289, " \ "\"foo\":\"abc\",\"" FIRST_QUERY_KEY "\":" FIRST_QUERY_KEY_ANSWER "}" #define JSON_DOC_VARIED_SCALARS_LENGTH ( sizeof( JSON_DOC_VARIED_SCALARS ) - 1 ) #define MULTIPLE_VALID_ESCAPES "\\\\ \\\" \\/ \\b \\f \\n \\r \\t \\\x12" #define MULTIPLE_VALID_ESCAPES_LENGTH ( sizeof( MULTIPLE_VALID_ESCAPES ) - 1 ) #define JSON_DOC_QUERY_KEY_NOT_FOUND "{\"hello\": \"world\"}" #define JSON_DOC_QUERY_KEY_NOT_FOUND_LENGTH ( sizeof( JSON_DOC_QUERY_KEY_NOT_FOUND ) - 1 ) #define JSON_DOC_MULTIPLE_VALID_ESCAPES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" :\t\"" MULTIPLE_VALID_ESCAPES "\"}}" #define JSON_DOC_MULTIPLE_VALID_ESCAPES_LENGTH ( sizeof( JSON_DOC_MULTIPLE_VALID_ESCAPES ) - 1 ) /* A single byte in UTF-8 is just an ASCII character, so it's not included here. */ #define LEGAL_UTF8_BYTE_SEQUENCES "\xc2\xa9 \xe2\x98\x95 \xf0\x9f\x98\x80" #define LEGAL_UTF8_BYTE_SEQUENCES_LENGTH ( sizeof( LEGAL_UTF8_BYTE_SEQUENCES ) - 1 ) #define JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" LEGAL_UTF8_BYTE_SEQUENCES "\"}}" #define JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES_LENGTH ( sizeof( JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES ) - 1 ) /* Unicode escape sequences in the Basic Multilingual Plane. */ #define UNICODE_ESCAPE_SEQUENCES_BMP "\\uCB00\\uEFFF" #define UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH ( sizeof( UNICODE_ESCAPE_SEQUENCES_BMP ) - 1 ) #define JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" UNICODE_ESCAPE_SEQUENCES_BMP "\"}}" #define JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH ( sizeof( JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP ) - 1 ) /* Unicode escape sequences using surrogates for Astral Code Points (outside BMP). */ #define LEGAL_UNICODE_ESCAPE_SURROGATES "\\uD83D\\ude07" #define LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH ( sizeof( LEGAL_UNICODE_ESCAPE_SURROGATES ) - 1 ) #define JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" LEGAL_UNICODE_ESCAPE_SURROGATES "\"}}" #define JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH ( sizeof( JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES ) - 1 ) #define JSON_DOC_LEGAL_TRAILING_SPACE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" COMPLETE_QUERY_KEY_ANSWER "\"}} " #define JSON_DOC_LEGAL_TRAILING_SPACE_LENGTH ( sizeof( JSON_DOC_LEGAL_TRAILING_SPACE ) - 1 ) /* A single scalar is still considered a valid JSON document. */ #define SINGLE_SCALAR "\"l33t\"" #define SINGLE_SCALAR_LENGTH ( sizeof( SINGLE_SCALAR ) - 1 ) /* Illegal scalar entry in the array. */ #define ILLEGAL_SCALAR_IN_ARRAY "{\"hello\": [42, world]\"" #define ILLEGAL_SCALAR_IN_ARRAY_LENGTH ( sizeof( ILLEGAL_SCALAR_IN_ARRAY ) - 1 ) #define ILLEGAL_SCALAR_IN_ARRAY2 "[42, world]" #define ILLEGAL_SCALAR_IN_ARRAY2_LENGTH ( sizeof( ILLEGAL_SCALAR_IN_ARRAY2 ) - 1 ) #define TRAILING_COMMA_AFTER_VALUE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" COMPLETE_QUERY_KEY_ANSWER "\",}}" #define TRAILING_COMMA_AFTER_VALUE_LENGTH ( sizeof( TRAILING_COMMA_AFTER_VALUE ) - 1 ) #define MISSING_COMMA_AFTER_VALUE "{\"foo\":{}\"bar\":\"abc\"}" #define MISSING_COMMA_AFTER_VALUE_LENGTH ( sizeof( MISSING_COMMA_AFTER_VALUE ) - 1 ) #define MISSING_VALUE_AFTER_KEY "{\"foo\":{\"bar\":}}" #define MISSING_VALUE_AFTER_KEY_LENGTH ( sizeof( MISSING_VALUE_AFTER_KEY ) - 1 ) #define MISMATCHED_BRACKETS "{\"foo\":{\"bar\":\"xyz\"]}" #define MISMATCHED_BRACKETS_LENGTH ( sizeof( MISMATCHED_BRACKETS ) - 1 ) #define MISMATCHED_BRACKETS2 "{\"foo\":[\"bar\",\"xyz\"}}" #define MISMATCHED_BRACKETS2_LENGTH ( sizeof( MISMATCHED_BRACKETS2 ) - 1 ) #define MISMATCHED_BRACKETS3 "{\"foo\":[\"bar\",\"xyz\"]]" #define MISMATCHED_BRACKETS3_LENGTH ( sizeof( MISMATCHED_BRACKETS3 ) - 1 ) #define MISMATCHED_BRACKETS4 "[\"foo\",\"bar\",\"xyz\"}" #define MISMATCHED_BRACKETS4_LENGTH ( sizeof( MISMATCHED_BRACKETS4 ) - 1 ) #define INCORRECT_OBJECT_SEPARATOR "{\"foo\": \"bar\"; \"bar\": \"foo\"}" #define INCORRECT_OBJECT_SEPARATOR_LENGTH ( sizeof( INCORRECT_OBJECT_SEPARATOR ) - 1 ) #define MISSING_ENCLOSING_ARRAY_MARKER \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : []]}}" #define MISSING_ENCLOSING_ARRAY_MARKER_LENGTH ( sizeof( MISSING_ENCLOSING_ARRAY_MARKER ) - 1 ) #define MISSING_ENCLOSING_OBJECT_MARKER \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" COMPLETE_QUERY_KEY_ANSWER "\"}" #define MISSING_ENCLOSING_OBJECT_MARKER_LENGTH ( sizeof( MISSING_ENCLOSING_OBJECT_MARKER ) - 1 ) #define CUT_AFTER_OBJECT_OPEN_BRACE "{\"foo\":\"abc\",\"bar\":{" #define CUT_AFTER_OBJECT_OPEN_BRACE_LENGTH ( sizeof( CUT_AFTER_OBJECT_OPEN_BRACE ) - 1 ) #define LEADING_ZEROS_IN_NUMBER \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : 07}}" #define LEADING_ZEROS_IN_NUMBER_LENGTH ( sizeof( LEADING_ZEROS_IN_NUMBER ) - 1 ) #define TRAILING_COMMA_IN_ARRAY "[{\"hello\": [\"foo\",]}]" #define TRAILING_COMMA_IN_ARRAY_LENGTH ( sizeof( TRAILING_COMMA_IN_ARRAY ) - 1 ) #define CUT_AFTER_COMMA_SEPARATOR "{\"hello\": [5," #define CUT_AFTER_COMMA_SEPARATOR_LENGTH ( sizeof( CUT_AFTER_COMMA_SEPARATOR ) - 1 ) #define CLOSING_SQUARE_BRACKET "]" #define CLOSING_SQUARE_BRACKET_LENGTH ( sizeof( CLOSING_SQUARE_BRACKET ) - 1 ) #define CLOSING_CURLY_BRACKET "}" #define CLOSING_CURLY_BRACKET_LENGTH ( sizeof( CLOSING_CURLY_BRACKET ) - 1 ) #define OPENING_CURLY_BRACKET "{" #define OPENING_CURLY_BRACKET_LENGTH ( sizeof( OPENING_CURLY_BRACKET ) - 1 ) #define QUERY_KEY_TRAILING_SEPARATOR FIRST_QUERY_KEY JSON_QUERY_SEPARATOR #define QUERY_KEY_TRAILING_SEPARATOR_LENGTH ( sizeof( QUERY_KEY_TRAILING_SEPARATOR ) - 1 ) #define QUERY_KEY_EMPTY JSON_QUERY_SEPARATOR SECOND_QUERY_KEY #define QUERY_KEY_EMPTY_LENGTH ( sizeof( QUERY_KEY_EMPTY ) - 1 ) /* Separator between a key and a value must be a colon (:). */ #define WRONG_KEY_VALUE_SEPARATOR \ "{\"foo\";\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\":\"" COMPLETE_QUERY_KEY_ANSWER "\"}} " #define WRONG_KEY_VALUE_SEPARATOR_LENGTH ( sizeof( WRONG_KEY_VALUE_SEPARATOR ) - 1 ) /* Key must be a string. */ #define ILLEGAL_KEY_NOT_STRING \ "{foo:\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"" COMPLETE_QUERY_KEY_ANSWER "\"}}" #define ILLEGAL_KEY_NOT_STRING_LENGTH ( sizeof( ILLEGAL_KEY_NOT_STRING ) - 1 ) /* A non-number after the exponent marker is illegal. */ #define LETTER_AS_EXPONENT \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : 5Ea}}" #define LETTER_AS_EXPONENT_LENGTH ( sizeof( LETTER_AS_EXPONENT ) - 1 ) /* The octet values C0, C1, and F5 to FF are illegal, since C0 and C1 * would introduce a non-shortest sequence, and F5 or above would * introduce a value greater than the last code point, 0x10FFFF. */ #define ILLEGAL_UTF8_NEXT_BYTE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xc2\x00\"}}" #define ILLEGAL_UTF8_NEXT_BYTE_LENGTH ( sizeof( ILLEGAL_UTF8_NEXT_BYTE ) - 1 ) /* The first byte in a UTF-8 sequence must be greater than C1. */ #define ILLEGAL_UTF8_START_C1 \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xC1\"}}" #define ILLEGAL_UTF8_START_C1_LENGTH ( sizeof( ILLEGAL_UTF8_START_C1 ) - 1 ) /* The first byte in a UTF-8 sequence must be less than F5. */ #define ILLEGAL_UTF8_START_F5 \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xF5\"}}" #define ILLEGAL_UTF8_START_F5_LENGTH ( sizeof( ILLEGAL_UTF8_START_F5 ) - 1 ) /* Additional bytes must match 10xxxxxx, so this case is illegal UTF8. */ #define ILLEGAL_UTF8_NEXT_BYTES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xc2\xC0\"}}" #define ILLEGAL_UTF8_NEXT_BYTES_LENGTH ( sizeof( ILLEGAL_UTF8_NEXT_BYTES ) - 1 ) #define ILLEGAL_UTF8_SURROGATE_RANGE_MIN \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xED\xA0\x80\"}}" #define ILLEGAL_UTF8_SURROGATE_RANGE_MIN_LENGTH ( sizeof( ILLEGAL_UTF8_SURROGATE_RANGE_MIN ) - 1 ) #define ILLEGAL_UTF8_SURROGATE_RANGE_MAX \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xED\xBF\xBF\"}}" #define ILLEGAL_UTF8_SURROGATE_RANGE_MAX_LENGTH ( sizeof( ILLEGAL_UTF8_SURROGATE_RANGE_MAX ) - 1 ) #define ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xC2\x80\x80\"}}" #define ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES_LENGTH ( sizeof( ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES ) - 1 ) #define ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xF4\x9F\xBF\xBF\"}}" #define ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES_LENGTH ( sizeof( ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES ) - 1 ) #define ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xF0\x80\x80\x80\"}}" #define ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES_LENGTH ( sizeof( ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES ) - 1 ) /* The following escapes are considered ILLEGAL. */ /* Hex characters must be used for the unicode escape sequence to be valid. */ #define ILLEGAL_UNICODE_LITERAL_HEX \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\u\xD8\x3D\\u\xde\x07\"}}" #define ILLEGAL_UNICODE_LITERAL_HEX_LENGTH ( sizeof( ILLEGAL_UNICODE_LITERAL_HEX ) - 1 ) #define UNICODE_PREMATURE_LOW_SURROGATE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\ude07\\uD83D\"}}" #define UNICODE_PREMATURE_LOW_SURROGATE_LENGTH ( sizeof( UNICODE_PREMATURE_LOW_SURROGATE ) - 1 ) #define UNICODE_INVALID_LOWERCASE_HEX \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uge07\\uD83D\"}}" #define UNICODE_INVALID_LOWERCASE_HEX_LENGTH ( sizeof( UNICODE_INVALID_LOWERCASE_HEX ) - 1 ) #define UNICODE_INVALID_UPPERCASE_HEX \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\ude07\\uG83D\"}}" #define UNICODE_INVALID_UPPERCASE_HEX_LENGTH ( sizeof( UNICODE_INVALID_UPPERCASE_HEX ) - 1 ) #define UNICODE_NON_LETTER_OR_DIGIT_HEX \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\u\0e07\\uG83D\"}}" #define UNICODE_NON_LETTER_OR_DIGIT_HEX_LENGTH ( sizeof( UNICODE_NON_LETTER_OR_DIGIT_HEX ) - 1 ) #define UNICODE_VALID_HIGH_NO_LOW_SURROGATE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uD83D. Hello there!\"}}" #define UNICODE_VALID_HIGH_NO_LOW_SURROGATE_LENGTH ( sizeof( UNICODE_VALID_HIGH_NO_LOW_SURROGATE ) - 1 ) #define UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uD83D\\Ude07\"}}" #define UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE_LENGTH ( sizeof( UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE ) - 1 ) #define UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uD83D\\uEFFF\"}}" #define UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE_LENGTH ( sizeof( UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE ) - 1 ) #define UNICODE_BOTH_SURROGATES_HIGH \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uD83D\\uD83D\"}}" #define UNICODE_BOTH_SURROGATES_HIGH_LENGTH ( sizeof( UNICODE_BOTH_SURROGATES_HIGH ) - 1 ) /* For security, \u0000 is disallowed. */ #define UNICODE_ESCAPE_SEQUENCE_ZERO_CP \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\u0000\"}}" #define UNICODE_ESCAPE_SEQUENCE_ZERO_CP_LENGTH ( sizeof( UNICODE_ESCAPE_SEQUENCE_ZERO_CP ) - 1 ) /* /NUL escape is disallowed. */ #define NUL_ESCAPE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\\x0\"}}" #define NUL_ESCAPE_LENGTH ( sizeof( NUL_ESCAPE ) - 1 ) #define ESCAPE_CHAR_ALONE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\\"}}" #define ESCAPE_CHAR_ALONE_LENGTH ( sizeof( ESCAPE_CHAR_ALONE ) - 1 ) /* Valid control characters are those in the range of (NUL,SPACE). * Therefore, both cases below are invalid. */ #define SPACE_CONTROL_CHAR \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\ \"}}" #define SPACE_CONTROL_CHAR_LENGTH ( sizeof( SPACE_CONTROL_CHAR ) - 1 ) /* \x80 implies a single one in the MSB, leading to a negative value. */ #define LT_ZERO_CONTROL_CHAR \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\\x80 \"}}" #define LT_ZERO_CONTROL_CHAR_LENGTH ( sizeof( LT_ZERO_CONTROL_CHAR ) - 1 ) /* An unescaped control character is considered ILLEGAL. */ #define UNESCAPED_CONTROL_CHAR \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\x15\"}}" #define UNESCAPED_CONTROL_CHAR_LENGTH ( sizeof( UNESCAPED_CONTROL_CHAR ) - 1 ) /* Each skip function has a check that the iterator i has not exceeded the * length of the buffer. The cases below test that those checks work as intended. */ /* Triggers the case in which i >= max for search. */ #define PADDED_OPENING_CURLY_BRACKET " { " #define PADDED_OPENING_CURLY_BRACKET_LENGTH ( sizeof( PADDED_OPENING_CURLY_BRACKET ) - 1 ) /* Triggers the case in which i >= max for skipUTF8MultiByte. * UTF-8 is illegal if the number of bytes in the sequence is * less than what was expected from the first byte. */ #define CUT_AFTER_UTF8_FIRST_BYTE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\xC2" #define CUT_AFTER_UTF8_FIRST_BYTE_LENGTH ( sizeof( CUT_AFTER_UTF8_FIRST_BYTE ) - 1 ) /* Triggers the case in which end >= max for skipHexEscape. */ #define UNICODE_STRING_END_AFTER_HIGH_SURROGATE \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : \"\\uD83D\"}}" #define UNICODE_STRING_END_AFTER_HIGH_SURROGATE_LENGTH ( sizeof( UNICODE_STRING_END_AFTER_HIGH_SURROGATE ) - 1 ) /* Triggers the case in which i >= max for skipDigits. */ #define CUT_AFTER_NUMBER \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : 1" #define CUT_AFTER_NUMBER_LENGTH ( sizeof( CUT_AFTER_NUMBER ) - 1 ) /* Triggers the case in which i >= max for skipDecimals. */ #define CUT_AFTER_DECIMAL_POINT \ "{\"foo\":\"abc\",\"" FIRST_QUERY_KEY \ "\":{\"" SECOND_QUERY_KEY "\" : 1." #define CUT_AFTER_DECIMAL_POINT_LENGTH ( sizeof( CUT_AFTER_DECIMAL_POINT ) - 1 ) /* Triggers the case in which ( i + 1U ) >= max for skipEscape. */ #define ESCAPE_CHAR_ALONE_NOT_ENCLOSED "\"\\" #define ESCAPE_CHAR_ALONE_NOT_ENCLOSED_LENGTH ( sizeof( ESCAPE_CHAR_ALONE_NOT_ENCLOSED ) - 1 ) /* Triggers the case in which i >= max for skipExponent. */ #define CUT_AFTER_EXPONENT_MARKER "4e" #define CUT_AFTER_EXPONENT_MARKER_LENGTH ( sizeof( CUT_AFTER_EXPONENT_MARKER ) - 1 ) /* Triggers the case in which i >= max for skipString. */ #define WHITE_SPACE " " #define WHITE_SPACE_LENGTH ( sizeof( WHITE_SPACE ) - 1 ) /* Triggers the case in which i >= max for skipArrayScalars. */ #define CUT_AFTER_ARRAY_START_MARKER "{\"hello\": [" #define CUT_AFTER_ARRAY_START_MARKER_LENGTH ( sizeof( CUT_AFTER_ARRAY_START_MARKER ) - 1 ) /* Triggers the cases in which i >= max for skipObjectScalars and nextKeyValuePair. */ #define CUT_AFTER_OBJECT_START_MARKER "{\"hello\": {" #define CUT_AFTER_OBJECT_START_MARKER_LENGTH ( sizeof( CUT_AFTER_OBJECT_START_MARKER ) - 1 ) #define CUT_AFTER_KEY "{\"hello\"" #define CUT_AFTER_KEY_LENGTH ( sizeof( CUT_AFTER_KEY ) - 1 ) /* This prefix is used to generate multiple levels of nested objects. */ #define NESTED_OBJECT_PREFIX "{\"k\":" #define NESTED_OBJECT_PREFIX_LENGTH ( sizeof( NESTED_OBJECT_PREFIX ) - 1 ) /* The value of the nested object with the largest depth. */ #define NESTED_OBJECT_VALUE "\"v\"" #define NESTED_OBJECT_VALUE_LENGTH ( sizeof( NESTED_OBJECT_VALUE ) - 1 ) #ifndef JSON_MAX_DEPTH #define JSON_MAX_DEPTH 32 #endif /* ============================ UNITY FIXTURES ============================ */ /* Called before each test method. */ void setUp() { } /* Called after each test method. */ void tearDown() { } /* Called at the beginning of the whole suite. */ void suiteSetUp() { } /* Called at the end of the whole suite. */ int suiteTearDown( int numFailures ) { return numFailures; } /* ========================================================================== */ /** * @brief Create a nested JSON array that exceeds JSON_MAX_DEPTH. */ char * allocateMaxDepthArray( void ) { size_t i, len = ( JSON_MAX_DEPTH + 1 ) * 2; char * nestedArray; nestedArray = malloc( sizeof( char ) * ( len + 1 ) ); for( i = 0; i < len / 2; i++ ) { nestedArray[ i ] = '['; nestedArray[ len - 1 - i ] = ']'; } nestedArray[ len ] = '\0'; return nestedArray; } /** * @brief Create a nested JSON object that exceeds JSON_MAX_DEPTH. */ char * allocateMaxDepthObject( void ) { size_t i = 0, len = NESTED_OBJECT_VALUE_LENGTH + ( JSON_MAX_DEPTH + 1 ) * ( NESTED_OBJECT_PREFIX_LENGTH + CLOSING_CURLY_BRACKET_LENGTH ); char * nestedObject, * nestedObjectCur; nestedObject = malloc( sizeof( char ) * ( len + 1 ) ); nestedObjectCur = nestedObject; while( i < ( JSON_MAX_DEPTH + 1 ) * NESTED_OBJECT_PREFIX_LENGTH ) { memcpy( nestedObjectCur, NESTED_OBJECT_PREFIX, NESTED_OBJECT_PREFIX_LENGTH ); i += NESTED_OBJECT_PREFIX_LENGTH; nestedObjectCur += NESTED_OBJECT_PREFIX_LENGTH; } memcpy( nestedObjectCur, NESTED_OBJECT_VALUE, NESTED_OBJECT_VALUE_LENGTH ); i += NESTED_OBJECT_VALUE_LENGTH; nestedObjectCur += NESTED_OBJECT_VALUE_LENGTH; /* This loop writes the correct number of closing brackets so long as there * are JSON_MAX_DEPTH + 1 entries for each bracket accounted for in len. */ while( i < len ) { *( nestedObjectCur++ ) = '}'; i++; } nestedObject[ len ] = '\0'; return nestedObject; } /** * @brief Test that JSON_Validate is able to classify any null or bad parameters. */ void test_JSON_Validate_Invalid_Params( void ) { JSONStatus_t jsonStatus; jsonStatus = JSON_Validate( NULL, 0 ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_LEGAL_TRAILING_SPACE, 0 ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); } /** * @brief Test that JSON_Validate is able to classify valid JSON correctly. */ void test_JSON_Validate_Legal_Documents( void ) { JSONStatus_t jsonStatus; jsonStatus = JSON_Validate( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_LEGAL_TRAILING_SPACE, JSON_DOC_LEGAL_TRAILING_SPACE_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_MULTIPLE_VALID_ESCAPES, JSON_DOC_MULTIPLE_VALID_ESCAPES_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES, JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES, JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP, JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); jsonStatus = JSON_Validate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); } /** * @brief Test that JSON_Validate is able to classify an illegal JSON document correctly. */ void test_JSON_Validate_Illegal_Documents( void ) { JSONStatus_t jsonStatus; jsonStatus = JSON_Validate( INCORRECT_OBJECT_SEPARATOR, INCORRECT_OBJECT_SEPARATOR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_KEY_NOT_STRING, ILLEGAL_KEY_NOT_STRING_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( WRONG_KEY_VALUE_SEPARATOR, WRONG_KEY_VALUE_SEPARATOR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( TRAILING_COMMA_IN_ARRAY, TRAILING_COMMA_IN_ARRAY_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_COMMA_SEPARATOR, CUT_AFTER_COMMA_SEPARATOR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_KEY, CUT_AFTER_KEY_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( TRAILING_COMMA_AFTER_VALUE, TRAILING_COMMA_AFTER_VALUE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISSING_COMMA_AFTER_VALUE, MISSING_COMMA_AFTER_VALUE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISSING_VALUE_AFTER_KEY, MISSING_VALUE_AFTER_KEY_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISMATCHED_BRACKETS, MISMATCHED_BRACKETS_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISMATCHED_BRACKETS2, MISMATCHED_BRACKETS2_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISMATCHED_BRACKETS3, MISMATCHED_BRACKETS3_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISMATCHED_BRACKETS4, MISMATCHED_BRACKETS4_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( NUL_ESCAPE, NUL_ESCAPE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( SPACE_CONTROL_CHAR, SPACE_CONTROL_CHAR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( LT_ZERO_CONTROL_CHAR, LT_ZERO_CONTROL_CHAR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CLOSING_SQUARE_BRACKET, CLOSING_SQUARE_BRACKET_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CLOSING_CURLY_BRACKET, CLOSING_CURLY_BRACKET_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_EXPONENT_MARKER, CUT_AFTER_EXPONENT_MARKER_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( MISSING_ENCLOSING_ARRAY_MARKER, MISSING_ENCLOSING_ARRAY_MARKER_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( LETTER_AS_EXPONENT, LETTER_AS_EXPONENT_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_DECIMAL_POINT, CUT_AFTER_DECIMAL_POINT_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( LEADING_ZEROS_IN_NUMBER, LEADING_ZEROS_IN_NUMBER_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_SCALAR_IN_ARRAY, ILLEGAL_SCALAR_IN_ARRAY_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ESCAPE_CHAR_ALONE, ESCAPE_CHAR_ALONE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ESCAPE_CHAR_ALONE_NOT_ENCLOSED, ESCAPE_CHAR_ALONE_NOT_ENCLOSED_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNESCAPED_CONTROL_CHAR, UNESCAPED_CONTROL_CHAR_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_NEXT_BYTE, ILLEGAL_UTF8_NEXT_BYTE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_START_C1, ILLEGAL_UTF8_START_C1_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_START_F5, ILLEGAL_UTF8_START_F5_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_UTF8_FIRST_BYTE, CUT_AFTER_UTF8_FIRST_BYTE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_NEXT_BYTES, ILLEGAL_UTF8_NEXT_BYTES_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES, ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES, ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES, ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_SURROGATE_RANGE_MIN, ILLEGAL_UTF8_SURROGATE_RANGE_MIN_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_SURROGATE_RANGE_MAX, ILLEGAL_UTF8_SURROGATE_RANGE_MAX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UTF8_SURROGATE_RANGE_MAX, ILLEGAL_UTF8_SURROGATE_RANGE_MAX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( ILLEGAL_UNICODE_LITERAL_HEX, ILLEGAL_UNICODE_LITERAL_HEX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_VALID_HIGH_NO_LOW_SURROGATE, UNICODE_VALID_HIGH_NO_LOW_SURROGATE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE, UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_STRING_END_AFTER_HIGH_SURROGATE, UNICODE_STRING_END_AFTER_HIGH_SURROGATE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_PREMATURE_LOW_SURROGATE, UNICODE_PREMATURE_LOW_SURROGATE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_INVALID_LOWERCASE_HEX, UNICODE_INVALID_LOWERCASE_HEX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_INVALID_UPPERCASE_HEX, UNICODE_INVALID_UPPERCASE_HEX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_NON_LETTER_OR_DIGIT_HEX, UNICODE_NON_LETTER_OR_DIGIT_HEX_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_BOTH_SURROGATES_HIGH, UNICODE_BOTH_SURROGATES_HIGH_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_ESCAPE_SEQUENCE_ZERO_CP, UNICODE_ESCAPE_SEQUENCE_ZERO_CP_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); jsonStatus = JSON_Validate( UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE, UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE_LENGTH ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); } /** * @brief Test that JSON_Validate is able to classify a partial JSON document correctly. */ void test_JSON_Validate_Partial_Documents( void ) { JSONStatus_t jsonStatus; jsonStatus = JSON_Validate( OPENING_CURLY_BRACKET, OPENING_CURLY_BRACKET_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); jsonStatus = JSON_Validate( WHITE_SPACE, WHITE_SPACE_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_OBJECT_OPEN_BRACE, CUT_AFTER_OBJECT_OPEN_BRACE_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_NUMBER, CUT_AFTER_NUMBER_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_ARRAY_START_MARKER, CUT_AFTER_ARRAY_START_MARKER_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); jsonStatus = JSON_Validate( CUT_AFTER_OBJECT_START_MARKER, CUT_AFTER_OBJECT_START_MARKER_LENGTH ); TEST_ASSERT_EQUAL( JSONPartial, jsonStatus ); } /** * @brief Test that JSON_Search can find the right value given a query key. */ void test_JSON_Search_Legal_Documents( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; JSONTypes_t outType; jsonStatus = JSON_SearchT( JSON_DOC_LEGAL_TRAILING_SPACE, JSON_DOC_LEGAL_TRAILING_SPACE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength, &outType ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( COMPLETE_QUERY_KEY_ANSWER_TYPE, outType ); TEST_ASSERT_EQUAL( outValueLength, COMPLETE_QUERY_KEY_ANSWER_LENGTH ); TEST_ASSERT_EQUAL_STRING_LEN( COMPLETE_QUERY_KEY_ANSWER, outValue, outValueLength ); jsonStatus = JSON_Search( JSON_DOC_LEGAL_TRAILING_SPACE, JSON_DOC_LEGAL_TRAILING_SPACE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( outValueLength, COMPLETE_QUERY_KEY_ANSWER_LENGTH ); TEST_ASSERT_EQUAL_STRING_LEN( COMPLETE_QUERY_KEY_ANSWER, outValue, outValueLength ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( COMPLETE_QUERY_KEY_ANSWER_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( COMPLETE_QUERY_KEY_ANSWER, outValue, COMPLETE_QUERY_KEY_ANSWER_LENGTH ); jsonStatus = JSON_SearchT( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, FIRST_QUERY_KEY, FIRST_QUERY_KEY_LENGTH, &outValue, &outValueLength, &outType ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( FIRST_QUERY_KEY_ANSWER_TYPE, outType ); TEST_ASSERT_EQUAL( FIRST_QUERY_KEY_ANSWER_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( FIRST_QUERY_KEY_ANSWER, outValue, FIRST_QUERY_KEY_ANSWER_LENGTH ); jsonStatus = JSON_Search( JSON_DOC_MULTIPLE_VALID_ESCAPES, JSON_DOC_MULTIPLE_VALID_ESCAPES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( MULTIPLE_VALID_ESCAPES_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( MULTIPLE_VALID_ESCAPES, outValue, MULTIPLE_VALID_ESCAPES_LENGTH ); jsonStatus = JSON_Search( JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES, JSON_DOC_LEGAL_UTF8_BYTE_SEQUENCES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( LEGAL_UTF8_BYTE_SEQUENCES_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( LEGAL_UTF8_BYTE_SEQUENCES, outValue, LEGAL_UTF8_BYTE_SEQUENCES_LENGTH ); jsonStatus = JSON_Search( JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES, JSON_DOC_LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( LEGAL_UNICODE_ESCAPE_SURROGATES, outValue, LEGAL_UNICODE_ESCAPE_SURROGATES_LENGTH ); jsonStatus = JSON_Search( JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP, JSON_DOC_UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); TEST_ASSERT_EQUAL( UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH, outValueLength ); TEST_ASSERT_EQUAL_STRING_LEN( UNICODE_ESCAPE_SEQUENCES_BMP, outValue, UNICODE_ESCAPE_SEQUENCES_BMP_LENGTH ); } /** * @brief Test that JSON_Search can find the right value given a query key using arrays. */ void test_JSON_Search_Legal_Array_Documents( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; JSONTypes_t outType; #define doSearch( query, type, answer ) \ jsonStatus = JSON_SearchT( JSON_DOC_LEGAL_ARRAY, \ JSON_DOC_LEGAL_ARRAY_LENGTH, \ ( query ), \ ( sizeof( query ) - 1 ), \ &outValue, \ &outValueLength, \ &outType ); \ TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); \ TEST_ASSERT_EQUAL( type, outType ); \ TEST_ASSERT_EQUAL( outValueLength, ( sizeof( answer ) - 1 ) ); \ TEST_ASSERT_EQUAL_STRING_LEN( ( answer ), \ outValue, \ outValueLength ); doSearch( "[0]", ARRAY_ELEMENT_0_TYPE, ARRAY_ELEMENT_0 ); doSearch( "[1]", ARRAY_ELEMENT_1_TYPE, ARRAY_ELEMENT_1 ); doSearch( "[2]." FIRST_QUERY_KEY, ARRAY_ELEMENT_2_SUB_0_TYPE, ARRAY_ELEMENT_2_SUB_0 ); doSearch( "[2]." SECOND_QUERY_KEY, ARRAY_ELEMENT_2_SUB_1_TYPE, ARRAY_ELEMENT_2_SUB_1 ); doSearch( "[2]." SECOND_QUERY_KEY "[0]", ARRAY_ELEMENT_2_SUB_1_SUB_0_TYPE, ARRAY_ELEMENT_2_SUB_1_SUB_0 ); doSearch( "[2]." SECOND_QUERY_KEY "[1]", ARRAY_ELEMENT_2_SUB_1_SUB_1_TYPE, ARRAY_ELEMENT_2_SUB_1_SUB_1 ); doSearch( "[3]", ARRAY_ELEMENT_3_TYPE, ARRAY_ELEMENT_3 ); doSearch( "[4]", ARRAY_ELEMENT_4_TYPE, ARRAY_ELEMENT_4 ); doSearch( "[5]", ARRAY_ELEMENT_5_TYPE, ARRAY_ELEMENT_5 ); } /** * @brief Test that JSON_Iterate returns the given values from a JSON array. */ void test_JSON_Iterate_Legal_Array_Documents( void ) { JSONStatus_t jsonStatus; size_t start = 0, next = 0; JSONPair_t pair = { 0 }; #define iterateArray( type, answer ) \ jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, \ JSON_DOC_LEGAL_ARRAY_LENGTH, \ &start, \ &next, \ &pair ); \ TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); \ TEST_ASSERT_EQUAL( NULL, pair.key ); \ TEST_ASSERT_EQUAL( 0, pair.keyLength ); \ TEST_ASSERT_EQUAL( type, pair.jsonType ); \ TEST_ASSERT_EQUAL( ( sizeof( answer ) - 1 ), pair.valueLength ); \ TEST_ASSERT_EQUAL_STRING_LEN( ( answer ), \ pair.value, \ pair.valueLength ); iterateArray( ARRAY_ELEMENT_0_TYPE, ARRAY_ELEMENT_0 ); iterateArray( ARRAY_ELEMENT_1_TYPE, ARRAY_ELEMENT_1 ); iterateArray( ARRAY_ELEMENT_2_TYPE, ARRAY_ELEMENT_2 ); iterateArray( ARRAY_ELEMENT_3_TYPE, ARRAY_ELEMENT_3 ); iterateArray( ARRAY_ELEMENT_4_TYPE, ARRAY_ELEMENT_4 ); iterateArray( ARRAY_ELEMENT_5_TYPE, ARRAY_ELEMENT_5 ); jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); } /** * @brief Test that JSON_Iterate returns the given keys and values from a JSON object. */ void test_JSON_Iterate_Legal_Object_Documents( void ) { JSONStatus_t jsonStatus; size_t start = 0, next = 0; JSONPair_t pair = { 0 }; #define iterateObject( key_, type, answer ) \ jsonStatus = JSON_Iterate( JSON_NESTED_OBJECT, \ JSON_NESTED_OBJECT_LENGTH, \ &start, \ &next, \ &pair ); \ TEST_ASSERT_EQUAL( JSONSuccess, jsonStatus ); \ TEST_ASSERT_EQUAL( ( sizeof( key_ ) - 1 ), pair.keyLength ); \ TEST_ASSERT_EQUAL_STRING_LEN( ( key_ ), \ pair.key, \ pair.keyLength ); \ TEST_ASSERT_EQUAL( type, pair.jsonType ); \ TEST_ASSERT_EQUAL( ( sizeof( answer ) - 1 ), pair.valueLength ); \ TEST_ASSERT_EQUAL_STRING_LEN( ( answer ), \ pair.value, \ pair.valueLength ); iterateObject( FIRST_QUERY_KEY, ARRAY_ELEMENT_2_SUB_0_TYPE, ARRAY_ELEMENT_2_SUB_0 ); iterateObject( SECOND_QUERY_KEY, ARRAY_ELEMENT_2_SUB_1_TYPE, ARRAY_ELEMENT_2_SUB_1 ); jsonStatus = JSON_Iterate( JSON_NESTED_OBJECT, JSON_NESTED_OBJECT_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); } /** * @brief Test that JSON_Iterate returns an error for an invalid collection. */ void test_JSON_Iterate_Illegal_Documents( void ) { JSONStatus_t jsonStatus; size_t start = 0, next = 0; JSONPair_t pair = { 0 }; jsonStatus = JSON_Iterate( FIRST_QUERY_KEY, FIRST_QUERY_KEY_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONIllegalDocument, jsonStatus ); } /** * @brief Test that JSON_Search can returns JSONNotFound when a query key does * not apply to a JSON document. */ void test_JSON_Search_Query_Key_Not_Found( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; jsonStatus = JSON_Search( JSON_DOC_QUERY_KEY_NOT_FOUND, JSON_DOC_QUERY_KEY_NOT_FOUND_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_QUERY_KEY_NOT_FOUND, JSON_DOC_QUERY_KEY_NOT_FOUND_LENGTH, "[0]", ( sizeof( "[0]" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, "[9]", ( sizeof( "[9]" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( WHITE_SPACE, WHITE_SPACE_LENGTH, "[0]", ( sizeof( "[0]" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( "[" WHITE_SPACE, WHITE_SPACE_LENGTH + 1, "[0]", ( sizeof( "[0]" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_SCALAR_IN_ARRAY2, ILLEGAL_SCALAR_IN_ARRAY2_LENGTH, "[1]", ( sizeof( "[1]" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); } /** * @brief Test that JSON_Search can find the right value given an incorrect query * key or Illegal JSON string. */ void test_JSON_Search_Illegal_Documents( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; jsonStatus = JSON_Search( WHITE_SPACE, WHITE_SPACE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( PADDED_OPENING_CURLY_BRACKET, PADDED_OPENING_CURLY_BRACKET_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_OBJECT_OPEN_BRACE, CUT_AFTER_OBJECT_OPEN_BRACE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CLOSING_CURLY_BRACKET, CLOSING_CURLY_BRACKET_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( OPENING_CURLY_BRACKET, OPENING_CURLY_BRACKET_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CLOSING_SQUARE_BRACKET, CLOSING_SQUARE_BRACKET_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( INCORRECT_OBJECT_SEPARATOR, INCORRECT_OBJECT_SEPARATOR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_KEY_NOT_STRING, ILLEGAL_KEY_NOT_STRING_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( WRONG_KEY_VALUE_SEPARATOR, WRONG_KEY_VALUE_SEPARATOR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_KEY, CUT_AFTER_KEY_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( TRAILING_COMMA_IN_ARRAY, TRAILING_COMMA_IN_ARRAY_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_COMMA_SEPARATOR, CUT_AFTER_COMMA_SEPARATOR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( TRAILING_COMMA_AFTER_VALUE, TRAILING_COMMA_AFTER_VALUE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( NUL_ESCAPE, NUL_ESCAPE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( SPACE_CONTROL_CHAR, SPACE_CONTROL_CHAR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( LT_ZERO_CONTROL_CHAR, LT_ZERO_CONTROL_CHAR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CLOSING_CURLY_BRACKET, CLOSING_CURLY_BRACKET_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( MISSING_ENCLOSING_ARRAY_MARKER, MISSING_ENCLOSING_ARRAY_MARKER_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( LETTER_AS_EXPONENT, LETTER_AS_EXPONENT_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_DECIMAL_POINT, CUT_AFTER_DECIMAL_POINT_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( LEADING_ZEROS_IN_NUMBER, LEADING_ZEROS_IN_NUMBER_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_SCALAR_IN_ARRAY, ILLEGAL_SCALAR_IN_ARRAY_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ESCAPE_CHAR_ALONE, ESCAPE_CHAR_ALONE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNESCAPED_CONTROL_CHAR, UNESCAPED_CONTROL_CHAR_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_NEXT_BYTE, ILLEGAL_UTF8_NEXT_BYTE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_START_C1, ILLEGAL_UTF8_START_C1_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_START_F5, ILLEGAL_UTF8_START_F5_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_UTF8_FIRST_BYTE, CUT_AFTER_UTF8_FIRST_BYTE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_NEXT_BYTES, ILLEGAL_UTF8_NEXT_BYTES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES, ILLEGAL_UTF8_GT_MIN_CP_FOUR_BYTES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES, ILLEGAL_UTF8_GT_MIN_CP_THREE_BYTES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES, ILLEGAL_UTF8_LT_MAX_CP_FOUR_BYTES_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_SURROGATE_RANGE_MIN, ILLEGAL_UTF8_SURROGATE_RANGE_MIN_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_SURROGATE_RANGE_MAX, ILLEGAL_UTF8_SURROGATE_RANGE_MAX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UTF8_SURROGATE_RANGE_MAX, ILLEGAL_UTF8_SURROGATE_RANGE_MAX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( ILLEGAL_UNICODE_LITERAL_HEX, ILLEGAL_UNICODE_LITERAL_HEX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_VALID_HIGH_NO_LOW_SURROGATE, UNICODE_VALID_HIGH_NO_LOW_SURROGATE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE, UNICODE_WRONG_ESCAPE_AFTER_HIGH_SURROGATE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_STRING_END_AFTER_HIGH_SURROGATE, UNICODE_STRING_END_AFTER_HIGH_SURROGATE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_PREMATURE_LOW_SURROGATE, UNICODE_PREMATURE_LOW_SURROGATE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_INVALID_LOWERCASE_HEX, UNICODE_INVALID_LOWERCASE_HEX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_INVALID_UPPERCASE_HEX, UNICODE_INVALID_UPPERCASE_HEX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_NON_LETTER_OR_DIGIT_HEX, UNICODE_NON_LETTER_OR_DIGIT_HEX_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_BOTH_SURROGATES_HIGH, UNICODE_BOTH_SURROGATES_HIGH_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_ESCAPE_SEQUENCE_ZERO_CP, UNICODE_ESCAPE_SEQUENCE_ZERO_CP_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE, UNICODE_VALID_HIGH_INVALID_LOW_SURROGATE_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); } /** * @brief Test that JSON_Search is able to classify any null or bad parameters. */ void test_JSON_Search_Invalid_Params( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; jsonStatus = JSON_Search( NULL, 0, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, NULL, 0, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, NULL, &outValueLength ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, NULL ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, 0, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, COMPLETE_QUERY_KEY, 0, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, QUERY_KEY_TRAILING_SEPARATOR, QUERY_KEY_TRAILING_SEPARATOR_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, QUERY_KEY_EMPTY, QUERY_KEY_EMPTY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, "[", ( sizeof( "[" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, "[0", ( sizeof( "[0" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Search( JSON_DOC_VARIED_SCALARS, JSON_DOC_VARIED_SCALARS_LENGTH, "[0}", ( sizeof( "[0}" ) - 1 ), &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); } /** * @brief Test that JSON_Iterate is able to classify any null or bad parameters. */ void test_JSON_Iterate_Invalid_Params( void ) { JSONStatus_t jsonStatus; size_t start = 0, next = 0; JSONPair_t pair = { 0 }; jsonStatus = JSON_Iterate( NULL, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, 0, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, NULL, &next, &pair ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, NULL, &pair ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, &next, NULL ); TEST_ASSERT_EQUAL( JSONNullParameter, jsonStatus ); start = JSON_DOC_LEGAL_ARRAY_LENGTH + 1; jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); start = 0; next = JSON_DOC_LEGAL_ARRAY_LENGTH + 1; jsonStatus = JSON_Iterate( JSON_DOC_LEGAL_ARRAY, JSON_DOC_LEGAL_ARRAY_LENGTH, &start, &next, &pair ); TEST_ASSERT_EQUAL( JSONBadParameter, jsonStatus ); } /** * @brief Test that JSON_Search is able to classify a partial JSON document correctly. * * @note JSON_Search returns JSONIllegalDocument when it finds a partial document. */ void test_JSON_Search_Partial_Documents( void ) { JSONStatus_t jsonStatus; char * outValue; size_t outValueLength; jsonStatus = JSON_Search( CUT_AFTER_NUMBER, CUT_AFTER_NUMBER_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_ARRAY_START_MARKER, CUT_AFTER_ARRAY_START_MARKER_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_OBJECT_START_MARKER, CUT_AFTER_OBJECT_START_MARKER_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); jsonStatus = JSON_Search( CUT_AFTER_KEY, CUT_AFTER_KEY_LENGTH, COMPLETE_QUERY_KEY, COMPLETE_QUERY_KEY_LENGTH, &outValue, &outValueLength ); TEST_ASSERT_EQUAL( JSONNotFound, jsonStatus ); } /** * @brief Test that a nested collection can only have up to JSON_MAX_DEPTH levels * of nesting. */ void test_JSON_Max_Depth( void ) { JSONStatus_t jsonStatus; char * maxNestedObject, * maxNestedArray; maxNestedArray = allocateMaxDepthArray(); jsonStatus = JSON_Validate( maxNestedArray, strlen( maxNestedArray ) ); TEST_ASSERT_EQUAL( JSONMaxDepthExceeded, jsonStatus ); maxNestedObject = allocateMaxDepthObject(); jsonStatus = JSON_Validate( maxNestedObject, strlen( maxNestedObject ) ); TEST_ASSERT_EQUAL( JSONMaxDepthExceeded, jsonStatus ); free( maxNestedArray ); free( maxNestedObject ); } /** * @brief Trip all asserts in internal functions. */ void test_JSON_asserts( void ) { char buf[] = "x", queryKey[] = "y"; size_t start = 1, max = 1, length = 1, next = 0; uint16_t u = 0; size_t key, keyLength, value, valueLength; int32_t queryIndex = 0; catch_assert( skipSpace( NULL, &start, max ) ); catch_assert( skipSpace( buf, NULL, max ) ); /* assert: max != 0 */ catch_assert( skipSpace( buf, &start, 0 ) ); /* first argument is length; assert: 2 <= length <= 4 */ catch_assert( shortestUTF8( 1, u ) ); catch_assert( shortestUTF8( 5, u ) ); catch_assert( skipUTF8MultiByte( NULL, &start, max ) ); catch_assert( skipUTF8MultiByte( buf, NULL, max ) ); catch_assert( skipUTF8MultiByte( buf, &start, 0 ) ); /* assert: start < max */ catch_assert( skipUTF8MultiByte( buf, &start, max ) ); /* assert: buf[0] < '\0' */ catch_assert( skipUTF8MultiByte( buf, &start, ( start + 1 ) ) ); catch_assert( skipUTF8( NULL, &start, max ) ); catch_assert( skipUTF8( buf, NULL, max ) ); catch_assert( skipUTF8( buf, &start, 0 ) ); catch_assert( skipOneHexEscape( NULL, &start, max, &u ) ); catch_assert( skipOneHexEscape( buf, NULL, max, &u ) ); catch_assert( skipOneHexEscape( buf, &start, 0, &u ) ); catch_assert( skipOneHexEscape( buf, &start, max, NULL ) ); catch_assert( skipHexEscape( NULL, &start, max ) ); catch_assert( skipHexEscape( buf, NULL, max ) ); catch_assert( skipHexEscape( buf, &start, 0 ) ); catch_assert( skipEscape( NULL, &start, max ) ); catch_assert( skipEscape( buf, NULL, max ) ); catch_assert( skipEscape( buf, &start, 0 ) ); catch_assert( skipString( NULL, &start, max ) ); catch_assert( skipString( buf, NULL, max ) ); catch_assert( skipString( buf, &start, 0 ) ); catch_assert( strnEq( NULL, buf, max ) ); catch_assert( strnEq( buf, NULL, max ) ); catch_assert( skipLiteral( NULL, &start, max, "lit", length ) ); catch_assert( skipLiteral( buf, NULL, max, "lit", length ) ); catch_assert( skipLiteral( buf, &start, 0, "lit", length ) ); catch_assert( skipLiteral( buf, &start, max, NULL, length ) ); catch_assert( skipDigits( NULL, &start, max, NULL ) ); catch_assert( skipDigits( buf, NULL, max, NULL ) ); catch_assert( skipDigits( buf, &start, 0, NULL ) ); catch_assert( skipDecimals( NULL, &start, max ) ); catch_assert( skipDecimals( buf, NULL, max ) ); catch_assert( skipDecimals( buf, &start, 0 ) ); catch_assert( skipExponent( NULL, &start, max ) ); catch_assert( skipExponent( buf, NULL, max ) ); catch_assert( skipExponent( buf, &start, 0 ) ); catch_assert( skipNumber( NULL, &start, max ) ); catch_assert( skipNumber( buf, NULL, max ) ); catch_assert( skipNumber( buf, &start, 0 ) ); catch_assert( skipSpaceAndComma( NULL, &start, max ) ); catch_assert( skipSpaceAndComma( buf, NULL, max ) ); catch_assert( skipSpaceAndComma( buf, &start, 0 ) ); catch_assert( skipArrayScalars( NULL, &start, max ) ); catch_assert( skipArrayScalars( buf, NULL, max ) ); catch_assert( skipArrayScalars( buf, &start, 0 ) ); catch_assert( skipObjectScalars( NULL, &start, max ) ); catch_assert( skipObjectScalars( buf, NULL, max ) ); catch_assert( skipObjectScalars( buf, &start, 0 ) ); /* assert: mode is '[' or '{' */ catch_assert( skipScalars( buf, &start, max, '(' ) ); catch_assert( skipCollection( NULL, &start, max ) ); catch_assert( skipCollection( buf, NULL, max ) ); catch_assert( skipCollection( buf, &start, 0 ) ); catch_assert( nextValue( NULL, &start, max, &value, &valueLength ) ); catch_assert( nextValue( buf, NULL, max, &value, &valueLength ) ); catch_assert( nextValue( buf, &start, 0, &value, &valueLength ) ); catch_assert( nextValue( buf, &start, max, NULL, &valueLength ) ); catch_assert( nextValue( buf, &start, max, &value, NULL ) ); catch_assert( nextKeyValuePair( NULL, &start, max, &key, &keyLength, &value, &valueLength ) ); catch_assert( nextKeyValuePair( buf, NULL, max, &key, &keyLength, &value, &valueLength ) ); catch_assert( nextKeyValuePair( buf, &start, 0, &key, &keyLength, &value, &valueLength ) ); catch_assert( nextKeyValuePair( buf, &start, max, NULL, &keyLength, &value, &valueLength ) ); catch_assert( nextKeyValuePair( buf, &start, max, &key, NULL, &value, &valueLength ) ); catch_assert( nextKeyValuePair( buf, &start, max, &key, &keyLength, NULL, &valueLength ) ); catch_assert( nextKeyValuePair( buf, &start, max, &key, &keyLength, &value, NULL ) ); catch_assert( objectSearch( NULL, max, queryKey, keyLength, &value, &valueLength ) ); catch_assert( objectSearch( buf, max, NULL, keyLength, &value, &valueLength ) ); catch_assert( objectSearch( buf, max, queryKey, keyLength, NULL, &valueLength ) ); catch_assert( objectSearch( buf, max, queryKey, keyLength, &value, NULL ) ); catch_assert( arraySearch( NULL, max, queryIndex, &value, &valueLength ) ); catch_assert( arraySearch( buf, max, queryIndex, NULL, &valueLength ) ); catch_assert( arraySearch( buf, max, queryIndex, &value, NULL ) ); catch_assert( skipQueryPart( NULL, &start, max, &valueLength ) ); catch_assert( skipQueryPart( buf, NULL, max, &valueLength ) ); catch_assert( skipQueryPart( buf, &start, 0, &valueLength ) ); catch_assert( skipQueryPart( buf, &start, max, NULL ) ); catch_assert( multiSearch( NULL, max, queryKey, keyLength, &value, &valueLength ) ); catch_assert( multiSearch( buf, 0, queryKey, keyLength, &value, &valueLength ) ); catch_assert( multiSearch( buf, max, NULL, keyLength, &value, &valueLength ) ); catch_assert( multiSearch( buf, max, queryKey, 0, &value, &valueLength ) ); catch_assert( multiSearch( buf, max, queryKey, keyLength, NULL, &valueLength ) ); catch_assert( multiSearch( buf, max, queryKey, keyLength, &value, NULL ) ); catch_assert( iterate( NULL, max, &start, &next, &key, &keyLength, &value, &valueLength ) ); catch_assert( iterate( buf, 0, &start, &next, &key, &keyLength, &value, &valueLength ) ); catch_assert( iterate( buf, max, NULL, &next, &key, &keyLength, &value, &valueLength ) ); catch_assert( iterate( buf, max, &start, NULL, &key, &keyLength, &value, &valueLength ) ); catch_assert( iterate( buf, max, &start, &next, NULL, &keyLength, &value, &valueLength ) ); catch_assert( iterate( buf, max, &start, &next, &key, NULL, &value, &valueLength ) ); catch_assert( iterate( buf, max, &start, &next, &key, &keyLength, NULL, &valueLength ) ); catch_assert( iterate( buf, max, &start, &next, &key, &keyLength, &value, NULL ) ); } /** * @brief These checks are not otherwise reached. */ void test_JSON_unreached( void ) { char buf[ 2 ]; size_t start, max; /* return false when start >= max */ start = max = 1; TEST_ASSERT_EQUAL( false, skipUTF8( "abc", &start, max ) ); /* return false when buf[ 0 ] != '\\' */ buf[ 0 ] = 'x'; start = 0; TEST_ASSERT_EQUAL( false, skipEscape( buf, &start, sizeof( buf ) ) ); /* set output value to -1 when integer conversion exceeds max */ { #define TOO_BIG "100000000000" int32_t out; start = 0; TEST_ASSERT_EQUAL( true, skipDigits( TOO_BIG, &start, ( sizeof( TOO_BIG ) - 1 ), &out ) ); TEST_ASSERT_EQUAL( -1, out ); } /* return JSONNotFound when start >= max */ { size_t next, key, keyLength, value, valueLength; start = max = 1; TEST_ASSERT_EQUAL( JSONNotFound, iterate( buf, max, &start, &next, &key, &keyLength, &value, &valueLength ) ); } } /** * @brief Test overflows. */ void test_JSON_overflows( void ) { char buf[] = UNICODE_ESCAPE_SEQUENCES_BMP; size_t start; uint16_t u; start = SIZE_MAX; TEST_ASSERT_EQUAL( false, skipOneHexEscape( buf, &start, SIZE_MAX, &u ) ); }