feat: add int64 support

This commit adds int64 support for cjson. To enable int64, you need to
define the macro ENABLE_INT64. To make it more clear, you need to build
cjson like this:

mkdir build
cd build
cmake -DENABLE_INT64=ON ..
make

This implementation changed the type of valueint in struct cJSON: from
int to long long(int64), and added a new flag cJSON_IsInt64.
For a int64 cJSON item, the value of item->type would be cJSON_Number |
cJSON_IsInt64.

The existing functions parse_number and print_number can handle int64
now.

Considering I have added a new type cJSON_IsInt64, some new functions
have been added:
CJSON_PUBLIC(long long *) cJSON_GetInt64NumberValue(cJSON * const item)
CJSON_PUBLIC(cJSON_bool) cJSON_IsInt64Number(const cJSON * const item)
CJSON_PUBLIC(cJSON *) cJSON_CreateInt64Number(long long integer)
CJSON_PUBLIC(cJSON*) cJSON_AddInt64NumberToObject(cJSON * const object, const char * const name, const long long integer)
CJSON_PUBLIC(long long) cJSON_SetInt64NumberValue(cJSON * const object, const long long integer)

And some existing functions are also adjusted for int64, including
parse_number, cJSON_SetNumberHelper, print_number, cJSON_CreateNumber,
cJSON_Compare and compare_json(in cJSON_Utils).

Besides the code changes, we have also added some testcases for int64.
These tests will run if ENABLE_INT64 is turned on.
This commit is contained in:
PeterAlfredLee 2022-05-19 16:01:30 +08:00
parent b45f48e600
commit c95332c58c
12 changed files with 730 additions and 1 deletions

View File

@ -14,12 +14,23 @@ set(CJSON_UTILS_VERSION_SO 1)
set(custom_compiler_flags)
option(ENABLE_INT64 "Enable the use of int64(long long), please note this will use c99 instead of c89" OFF)
if (ENABLE_INT64)
add_definitions(-DENABLE_INT64)
list(APPEND custom_compiler_flags
-std=c99
)
else()
list(APPEND custom_compiler_flags
-std=c89
)
endif ()
include(CheckCCompilerFlag)
option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags" ON)
if (ENABLE_CUSTOM_COMPILER_FLAGS)
if (("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
list(APPEND custom_compiler_flags
-std=c89
-pedantic
-Wall
-Wextra

View File

@ -119,6 +119,7 @@ You can change the build process with a list of different options that you can p
* `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default )
* `-DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On`: Enable overriding the value of `BUILD_SHARED_LIBS` with `-DCJSON_BUILD_SHARED_LIBS`.
* `-DENABLE_CJSON_VERSION_SO`: Enable cJSON so version. ( on by default )
* `-DENABLE_INT64`: Enable int64 support for cjson. Please note this will use c99 instead of c89. ( off by default )
If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example:
```

323
cJSON.c
View File

@ -106,6 +106,18 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
return item->valuestring;
}
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(long long *) cJSON_GetInt64NumberValue(cJSON * const item)
{
if (!cJSON_IsInt64Number(item))
{
return NULL;
}
return &(item->valueint);
}
#endif
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
{
if (!cJSON_IsNumber(item))
@ -301,6 +313,106 @@ typedef struct
/* get a pointer to the buffer at the position */
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
#ifdef __CJSON_USE_INT64
/* Parse the input text to generate a number, and populate the result into item. */
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
{
double number = 0;
long long integer = 0;
unsigned char *after_end = NULL;
unsigned char number_c_string[64];
unsigned char decimal_point = get_decimal_point();
size_t i = 0;
cJSON_bool is_integer = true;
if ((input_buffer == NULL) || (input_buffer->content == NULL))
{
return false;
}
/* copy the number into a temporary buffer and replace '.' with the decimal point
* of the current locale (for strtod)
* This also takes care of '\0' not necessarily being available for marking the end of the input */
for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
{
switch (buffer_at_offset(input_buffer)[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
number_c_string[i] = buffer_at_offset(input_buffer)[i];
break;
case 'e':
case 'E':
number_c_string[i] = buffer_at_offset(input_buffer)[i];
is_integer = false;
break;
case '.':
number_c_string[i] = decimal_point;
is_integer = false;
break;
default:
goto loop_end;
}
}
loop_end:
number_c_string[i] = '\0';
/* use guard clause to process the int64 case first */
if (is_integer)
{
/* for int64 values, set cJSON_IsInt64 */
item->type = cJSON_Number | cJSON_IsInt64;
integer = strtoll((const char*)number_c_string, (char**)&after_end, 10);
if (number_c_string == after_end)
{
return false; /* parse_error */
}
item->valueint = integer;
item->valuedouble = (double)integer;
goto parse_end;
}
number = strtod((const char*)number_c_string, (char**)&after_end);
if (number_c_string == after_end)
{
return false; /* parse_error */
}
item->valuedouble = number;
/* use saturation in case of overflow */
if (number >= (double)LLONG_MAX)
{
item->valueint = LLONG_MAX;
}
else if (number <= (double)LLONG_MIN)
{
item->valueint = LLONG_MIN;
}
else
{
item->valueint = (long long)number;
}
item->type = cJSON_Number;
parse_end:
input_buffer->offset += (size_t)(after_end - number_c_string);
return true;
}
#else
/* Parse the input text to generate a number, and populate the result into item. */
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
{
@ -377,7 +489,49 @@ loop_end:
input_buffer->offset += (size_t)(after_end - number_c_string);
return true;
}
#endif /* __CJSON_USE_INT64 */
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(long long) cJSON_SetInt64NumberValue(cJSON * const object, const long long integer)
{
if (object == NULL)
{
return integer;
}
/* check the type before setting values */
if (!(object->type & cJSON_Number) || !(object->type & cJSON_IsInt64))
{
return integer;
}
object->valueint = integer;
object->valuedouble = (double)integer;
return integer;
}
#endif /* __CJSON_USE_INT64 */
#ifdef __CJSON_USE_INT64
/* note that double max(DBL_MAX) is greater than long long max(LLONG_MAX) */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
{
if (number >= (double)LLONG_MAX)
{
object->valueint = LLONG_MAX;
}
else if (number <= (double)LLONG_MIN)
{
object->valueint = LLONG_MIN;
}
else
{
object->valueint = (long long)number;
}
return object->valuedouble = number;
}
#else
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
{
@ -396,6 +550,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
return object->valuedouble = number;
}
#endif /* #ifdef __CJSON_USE_INT64 */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{
@ -541,6 +696,82 @@ static cJSON_bool compare_double(double a, double b)
return (fabs(a - b) <= maxVal * DBL_EPSILON);
}
#ifdef __CJSON_USE_INT64
/* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
unsigned char *output_pointer = NULL;
double d = item->valuedouble;
long long integer = item->valueint;
int length = 0;
size_t i = 0;
unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
unsigned char decimal_point = get_decimal_point();
double test = 0.0;
if (output_buffer == NULL)
{
return false;
}
if (item->type & cJSON_IsInt64)
{
/* use lld to print the long long integer */
length = sprintf((char*)number_buffer, "%lld", integer);
}
else /* item->type == cJSON_NUMBER */
{
/* This checks for NaN and Infinity */
if (isnan(d) || isinf(d))
{
length = sprintf((char*)number_buffer, "null");
}
else
{
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", d);
/* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
}
}
}
/* sprintf failed or buffer overrun occurred */
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
{
return false;
}
/* reserve appropriate space in the output */
output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
if (output_pointer == NULL)
{
return false;
}
/* copy the printed number to the output and replace locale
* dependent decimal point with '.' */
for (i = 0; i < ((size_t)length); i++)
{
if (number_buffer[i] == decimal_point)
{
output_pointer[i] = '.';
continue;
}
output_pointer[i] = number_buffer[i];
}
output_pointer[i] = '\0';
output_buffer->offset += (size_t)length;
return true;
}
#else
/* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
@ -610,6 +841,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
return true;
}
#endif /* __CJSON_USE_INT64 */
/* parse 4 digit hexadecimal number */
static unsigned parse_hex4(const unsigned char * const input)
@ -2124,6 +2356,20 @@ CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * co
return NULL;
}
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON*) cJSON_AddInt64NumberToObject(cJSON * const object, const char * const name, const long long integer)
{
cJSON *int_item = cJSON_CreateInt64Number(integer);
if (add_item_to_object(object, name, int_item, &global_hooks, false))
{
return int_item;
}
cJSON_Delete(int_item);
return NULL;
}
#endif /* __CJSON_USE_INT64 */
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
{
cJSON *number_item = cJSON_CreateNumber(number);
@ -2426,6 +2672,48 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
return item;
}
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON *) cJSON_CreateInt64Number(long long integer)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_Number | cJSON_IsInt64;
item->valueint = integer;
item->valuedouble = (double)integer;
}
return item;
}
#endif /* __CJSON_USE_INT64 */
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_Number;
item->valuedouble = num;
/* use saturation in case of overflow */
if (num >= (double)LLONG_MAX)
{
item->valueint = LLONG_MAX;
}
else if (num <= (double)LLONG_MIN)
{
item->valueint = LLONG_MIN;
}
else
{
item->valueint = (long long)num;
}
}
return item;
}
#else
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
cJSON *item = cJSON_New_Item(&global_hooks);
@ -2451,6 +2739,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
return item;
}
#endif /* __CJSON_USE_INT64 */
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
@ -2933,6 +3222,18 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
return (item->type & 0xFF) == cJSON_NULL;
}
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON_bool) cJSON_IsInt64Number(const cJSON * const item)
{
if (item == NULL)
{
return false;
}
return cJSON_IsNumber(item) && (item->type & cJSON_IsInt64);
}
#endif /* __CJSON_USE_INT64 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
{
if (item == NULL)
@ -3021,12 +3322,34 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
case cJSON_NULL:
return true;
#ifdef __CJSON_USE_INT64
case cJSON_Number:
if (!compare_double(a->valuedouble, b->valuedouble))
{
return false;
}
if ((a->type & cJSON_IsInt64) != (b->type & cJSON_IsInt64))
{
/* cJSON_IsInt64 should also be considered */
return false;
}
if ((a->type & cJSON_IsInt64) && (b->type & cJSON_IsInt64))
{
/* compare valueint if both values are int64 */
return a->valueint == b->valueint;
}
return true;
#else
case cJSON_Number:
if (compare_double(a->valuedouble, b->valuedouble))
{
return true;
}
return false;
#endif /* __CJSON_USE_INT64 */
case cJSON_String:
case cJSON_Raw:

28
cJSON.h
View File

@ -85,6 +85,11 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
#include <stddef.h>
/* use int64 if it is enabled and supported */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && defined(ENABLE_INT64)
#define __CJSON_USE_INT64
#endif
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
@ -98,6 +103,9 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
#ifdef __CJSON_USE_INT64
#define cJSON_IsInt64 1024
#endif
/* The cJSON structure: */
typedef struct cJSON
@ -113,8 +121,13 @@ typedef struct cJSON
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
#ifdef __CJSON_USE_INT64
/* use long long if int64 is enabled */
long long valueint;
#else
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
#endif /* __CJSON_USE_INT64 */
/* The item's number, if type==cJSON_Number */
double valuedouble;
@ -177,6 +190,9 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(long long *) cJSON_GetInt64NumberValue(cJSON * const item);
#endif
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
@ -185,6 +201,9 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON_bool) cJSON_IsInt64Number(const cJSON * const item);
#endif
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
@ -197,6 +216,9 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON *) cJSON_CreateInt64Number(long long integer);
#endif
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
@ -265,12 +287,18 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * co
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(cJSON*) cJSON_AddInt64NumberToObject(cJSON * const object, const char * const name, const long long integer);
#endif
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
#ifdef __CJSON_USE_INT64
CJSON_PUBLIC(long long) cJSON_SetInt64NumberValue(cJSON * const object, const long long integer);
#endif
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */

View File

@ -610,6 +610,22 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
}
switch (a->type & 0xFF)
{
#ifdef __CJSON_USE_INT64
case cJSON_Number:
/* numeric mismatch. */
if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble)))
{
return false;
}
if ((a->type & cJSON_IsInt64) != (b->type & cJSON_IsInt64))
{
/* cJSON_IsInt64 should also be considered */
return false;
}
return true;
#else
case cJSON_Number:
/* numeric mismatch. */
if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble)))
@ -620,6 +636,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
{
return true;
}
#endif /* __CJSON_USE_INT64 */
case cJSON_String:
/* string mismatch. */

View File

@ -60,6 +60,12 @@ if(ENABLE_CJSON_TEST)
minify_tests
)
if (ENABLE_INT64)
add_definitions(-DUNITY_SUPPORT_64)
list(APPEND unity_tests
misc_int64_tests
)
endif()
option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.")
if (ENABLE_VALGRIND)
find_program(MEMORYCHECK_COMMAND valgrind)

View File

@ -278,6 +278,47 @@ static void cjson_add_number_should_fail_on_allocation_failure(void)
cJSON_Delete(root);
}
#ifdef __CJSON_USE_INT64
static void cjson_add_number_should_add_int64_number(void)
{
cJSON *root = cJSON_CreateObject();
cJSON *number = NULL;
cJSON_AddInt64NumberToObject(root, "number", 42LL);
TEST_ASSERT_NOT_NULL(number = cJSON_GetObjectItemCaseSensitive(root, "number"));
TEST_ASSERT_EQUAL_INT(number->type, cJSON_Number | cJSON_IsInt64);
TEST_ASSERT_EQUAL_DOUBLE(number->valuedouble, 42);
TEST_ASSERT_EQUAL_INT64(number->valueint, 42LL);
cJSON_Delete(root);
}
static void cjson_add_int64_number_should_fail_on_null_pointers(void)
{
cJSON *root = cJSON_CreateObject();
TEST_ASSERT_NULL(cJSON_AddInt64NumberToObject(NULL, "number", 42LL));
TEST_ASSERT_NULL(cJSON_AddInt64NumberToObject(root, NULL, 42LL));
cJSON_Delete(root);
}
static void cjson_add_int64_number_should_fail_on_allocation_failure(void)
{
cJSON *root = cJSON_CreateObject();
cJSON_InitHooks(&failing_hooks);
TEST_ASSERT_NULL(cJSON_AddInt64NumberToObject(root, "number", 42LL));
cJSON_InitHooks(NULL);
cJSON_Delete(root);
}
#endif /* __CJSON_USE_INT64 */
static void cjson_add_string_should_add_string(void)
{
cJSON *root = cJSON_CreateObject();
@ -451,6 +492,12 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_add_number_should_fail_with_null_pointers);
RUN_TEST(cjson_add_number_should_fail_on_allocation_failure);
#ifdef __CJSON_USE_INT64
RUN_TEST(cjson_add_number_should_add_int64_number);
RUN_TEST(cjson_add_int64_number_should_fail_on_null_pointers);
RUN_TEST(cjson_add_int64_number_should_fail_on_allocation_failure);
#endif /* __CJSON_USE_INT64 */
RUN_TEST(cjson_add_string_should_add_string);
RUN_TEST(cjson_add_string_should_fail_with_null_pointers);
RUN_TEST(cjson_add_string_should_fail_on_allocation_failure);

View File

@ -72,6 +72,21 @@ static void cjson_compare_should_compare_numbers(void)
TEST_ASSERT_FALSE(compare_from_string("1", "2", false));
}
#ifdef __CJSON_USE_INT64
static void cjson_compare_should_compare_int64_numbers(void)
{
TEST_ASSERT_TRUE(compare_from_string("1", "1", true));
TEST_ASSERT_TRUE(compare_from_string("1", "1", false));
TEST_ASSERT_TRUE(compare_from_string("9223372036854775807", "9223372036854775807", true));
TEST_ASSERT_TRUE(compare_from_string("9223372036854775807", "9223372036854775807", false));
TEST_ASSERT_TRUE(compare_from_string("-9223372036854775808", "-9223372036854775808", true));
TEST_ASSERT_TRUE(compare_from_string("-9223372036854775808", "-9223372036854775808", false));
TEST_ASSERT_FALSE(compare_from_string("1", "2", true));
TEST_ASSERT_FALSE(compare_from_string("1", "2", false));
}
#endif /* __CJSON_USE_INT64 */
static void cjson_compare_should_compare_booleans(void)
{
/* true */
@ -196,6 +211,9 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_compare_should_compare_null_pointer_as_not_equal);
RUN_TEST(cjson_compare_should_compare_invalid_as_not_equal);
RUN_TEST(cjson_compare_should_compare_numbers);
#ifdef __CJSON_USE_INT64
RUN_TEST(cjson_compare_should_compare_int64_numbers);
#endif
RUN_TEST(cjson_compare_should_compare_booleans);
RUN_TEST(cjson_compare_should_compare_null);
RUN_TEST(cjson_compare_should_not_accept_invalid_types);

185
tests/misc_int64_tests.c Normal file
View File

@ -0,0 +1,185 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_is_int64(cJSON *int64_number_item)
{
assert_has_type(int64_number_item, cJSON_Number);
TEST_ASSERT_BITS_MESSAGE(cJSON_IsInt64, cJSON_IsInt64, int64_number_item->type, "Item should be a int64 integer.");
}
static void cjson_get_object_item_should_get_object_items_with_int64(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItem(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItem(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItem(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
assert_is_int64(found);
found = cJSON_GetObjectItem(item, "tWo");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
assert_is_int64(found);
found = cJSON_GetObjectItem(item, "three");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
assert_is_int64(found);
found = cJSON_GetObjectItem(item, "four");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void cjson_get_object_item_case_sensitive_should_get_object_items_with_int64(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItemCaseSensitive(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItemCaseSensitive(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItemCaseSensitive(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
assert_is_int64(found);
found = cJSON_GetObjectItemCaseSensitive(item, "Two");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
assert_is_int64(found);
found = cJSON_GetObjectItemCaseSensitive(item, "tHree");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
assert_is_int64(found);
found = cJSON_GetObjectItemCaseSensitive(item, "One");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void cjson_set_number_value_should_set_numbers_with_int64(void)
{
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number | cJSON_IsInt64, NULL, 0, 0, NULL}};
cJSON_SetInt64NumberValue(number, 1LL);
TEST_ASSERT_EQUAL_INT64(1LL, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(1.0, number->valuedouble);
cJSON_SetInt64NumberValue(number, -1LL);
TEST_ASSERT_EQUAL_INT64(-1LL, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(-1.0, number->valuedouble);
cJSON_SetInt64NumberValue(number, 0LL);
TEST_ASSERT_EQUAL_INT64(0LL, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(0.0, number->valuedouble);
cJSON_SetInt64NumberValue(number, LLONG_MAX);
TEST_ASSERT_EQUAL_INT64(LLONG_MAX, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE((double)LLONG_MAX, number->valuedouble);
cJSON_SetInt64NumberValue(number, LLONG_MIN);
TEST_ASSERT_EQUAL_INT64(LLONG_MIN, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE((double)LLONG_MIN, number->valuedouble);
}
static void typecheck_functions_should_check_type_with_int64(void)
{
cJSON item[1];
item->type = cJSON_Number;
TEST_ASSERT_FALSE(cJSON_IsInt64Number(item));
item->type = cJSON_IsInt64;
TEST_ASSERT_FALSE(cJSON_IsInt64Number(item));
item->type = cJSON_Number | cJSON_IsInt64;
TEST_ASSERT_TRUE(cJSON_IsInt64Number(item));
item->type = cJSON_False;
TEST_ASSERT_FALSE(cJSON_IsInt64Number(item));
}
static void cjson_functions_should_not_crash_with_null_pointers_with_int64(void)
{
cJSON *item = cJSON_CreateString("item");
TEST_ASSERT_FALSE(cJSON_IsInt64Number(NULL));
cJSON_AddInt64NumberToObject(NULL, "item", 0LL);
cJSON_AddInt64NumberToObject(item, NULL, 0LL);
cJSON_AddInt64NumberToObject(NULL, NULL, 0LL);
TEST_ASSERT_NULL(cJSON_GetInt64NumberValue(NULL));
TEST_ASSERT_EQUAL_INT64(0LL, cJSON_SetInt64NumberValue(NULL, 0LL));
cJSON_Delete(item);
}
static void cjson_get_number_value_should_get_a_number_with_int64(void)
{
cJSON *string = cJSON_CreateString("test");
cJSON *number = cJSON_CreateInt64Number(1LL);
TEST_ASSERT_EQUAL_INT64(*cJSON_GetInt64NumberValue(number), number->valueint);
TEST_ASSERT_NULL(cJSON_GetInt64NumberValue(string));
TEST_ASSERT_NULL(cJSON_GetInt64NumberValue(NULL));
cJSON_Delete(number);
cJSON_Delete(string);
}
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
RUN_TEST(cjson_get_object_item_should_get_object_items_with_int64);
RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items_with_int64);
RUN_TEST(cjson_set_number_value_should_set_numbers_with_int64);
RUN_TEST(typecheck_functions_should_check_type_with_int64);
RUN_TEST(cjson_functions_should_not_crash_with_null_pointers_with_int64);
RUN_TEST(cjson_get_number_value_should_get_a_number_with_int64);
return UNITY_END();
}

View File

@ -231,6 +231,15 @@ static void cjson_set_number_value_should_set_numbers(void)
TEST_ASSERT_EQUAL(-1, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(-1.5, number->valuedouble);
#ifdef __CJSON_USE_INT64
cJSON_SetNumberValue(number, 1 + (double)LLONG_MAX);
TEST_ASSERT_EQUAL(LLONG_MAX, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(1 + (double)LLONG_MAX, number->valuedouble);
cJSON_SetNumberValue(number, -1 + (double)LLONG_MIN);
TEST_ASSERT_EQUAL(LLONG_MIN, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)LLONG_MIN, number->valuedouble);
#else
cJSON_SetNumberValue(number, 1 + (double)INT_MAX);
TEST_ASSERT_EQUAL(INT_MAX, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(1 + (double)INT_MAX, number->valuedouble);
@ -238,6 +247,7 @@ static void cjson_set_number_value_should_set_numbers(void)
cJSON_SetNumberValue(number, -1 + (double)INT_MIN);
TEST_ASSERT_EQUAL(INT_MIN, number->valueint);
TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)INT_MIN, number->valuedouble);
#endif /* __CJSON_USE_INT64 */
}
static void cjson_detach_item_via_pointer_should_detach_items(void)

View File

@ -55,6 +55,31 @@ static void assert_parse_number(const char *string, int integer, double real)
TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble);
}
#ifdef __CJSON_USE_INT64
static void assert_is_int64(cJSON *int64_number_item)
{
assert_is_number(int64_number_item);
TEST_ASSERT_BITS_MESSAGE(cJSON_IsInt64, cJSON_IsInt64, int64_number_item->type, "Item should be a int64 integer");
}
static void assert_parse_int64_number(const char *string, long long integer, double real)
{
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
buffer.content = (const unsigned char*)string;
buffer.length = strlen(string) + sizeof("");
TEST_ASSERT_TRUE(parse_number(item, &buffer));
TEST_ASSERT_EQUAL_INT64(integer, item->valueint);
TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble);
}
static void assert_parse_int64_number_with_type(const char *string, long long integer, double real)
{
assert_parse_int64_number(string, integer, real);
assert_is_int64(item);
}
#endif /* __CJSON_USE_INT64 */
static void parse_number_should_parse_zero(void)
{
assert_parse_number("0", 0, 0);
@ -81,8 +106,13 @@ static void parse_number_should_parse_positive_reals(void)
assert_parse_number("0.001", 0, 0.001);
assert_parse_number("10e-10", 0, 10e-10);
assert_parse_number("10E-10", 0, 10e-10);
#ifdef __CJSON_USE_INT64
assert_parse_int64_number("10e10", 100000000000LL, 10e10);
assert_parse_int64_number("123e+127", LLONG_MAX, 123e127);
#else
assert_parse_number("10e10", INT_MAX, 10e10);
assert_parse_number("123e+127", INT_MAX, 123e127);
#endif /* __CJSON_USE_INT64 */
assert_parse_number("123e-128", 0, 123e-128);
}
@ -91,11 +121,30 @@ static void parse_number_should_parse_negative_reals(void)
assert_parse_number("-0.001", 0, -0.001);
assert_parse_number("-10e-10", 0, -10e-10);
assert_parse_number("-10E-10", 0, -10e-10);
#ifdef __CJSON_USE_INT64
assert_parse_int64_number("-10e20", LLONG_MIN, -10e20);
assert_parse_int64_number("-123e+127", LLONG_MIN, -123e127);
#else
assert_parse_number("-10e20", INT_MIN, -10e20);
assert_parse_number("-123e+127", INT_MIN, -123e127);
#endif /* __CJSON_USE_INT64 */
assert_parse_number("-123e-128", 0, -123e-128);
}
#ifdef __CJSON_USE_INT64
static void parse_number_should_parse_int64_numbers(void)
{
assert_parse_int64_number_with_type("0", 0LL, 0);
assert_parse_int64_number_with_type("-1", -1LL, -1);
assert_parse_int64_number_with_type("-32768", -32768LL, -32768.0);
assert_parse_int64_number_with_type("-2147483648", -2147483648LL, -2147483648.0);
assert_parse_int64_number_with_type("2147483648", (long long)INT_MAX + 1, 2147483648.0);
assert_parse_int64_number_with_type("-2147483649", -2147483649LL, -2147483649.0);
assert_parse_int64_number_with_type("9223372036854775807", LLONG_MAX, 9223372036854775807.0);
assert_parse_int64_number_with_type("-9223372036854775808", LLONG_MIN, -9223372036854775808.0);
}
#endif /* __CJSON_USE_INT64 */
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
@ -106,5 +155,8 @@ int CJSON_CDECL main(void)
RUN_TEST(parse_number_should_parse_positive_integers);
RUN_TEST(parse_number_should_parse_positive_reals);
RUN_TEST(parse_number_should_parse_negative_reals);
#ifdef __CJSON_USE_INT64
RUN_TEST(parse_number_should_parse_int64_numbers);
#endif
return UNITY_END();
}

View File

@ -24,6 +24,25 @@
#include "unity/src/unity.h"
#include "common.h"
#ifdef __CJSON_USE_INT64
static void assert_print_int64_number(const char *expected, long long input)
{
unsigned char printed[1024];
cJSON item[1] = {{ NULL, NULL, NULL, cJSON_Number | cJSON_IsInt64, NULL, 0, 0, NULL }};
printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
buffer.hooks = global_hooks;
cJSON_SetInt64NumberValue(item, input);
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "Failed to print int64 number.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed int64 number is not as expected.");
}
#endif /* __CJSON_USE_INT64 */
static void assert_print_number(const char *expected, double input)
{
unsigned char printed[1024];
@ -72,6 +91,12 @@ static void print_number_should_print_negative_integers(void)
assert_print_number("-1", -1.0);
assert_print_number("-32768", -32768.0);
assert_print_number("-2147483648", -2147483648.0);
#ifdef __CJSON_USE_INT64
assert_print_int64_number("-1", -1LL);
assert_print_int64_number("-32768", -32768LL);
assert_print_int64_number("-2147483647", -2147483647LL);
assert_print_int64_number("-9223372036854775808", LLONG_MIN);
#endif /* __CJSON_USE_INT64 */
}
static void print_number_should_print_positive_integers(void)
@ -79,6 +104,12 @@ static void print_number_should_print_positive_integers(void)
assert_print_number("1", 1.0);
assert_print_number("32767", 32767.0);
assert_print_number("2147483647", 2147483647.0);
#ifdef __CJSON_USE_INT64
assert_print_int64_number("1", 1LL);
assert_print_int64_number("32767", 32767LL);
assert_print_int64_number("2147483647", 2147483647LL);
assert_print_int64_number("9223372036854775807", LLONG_MAX);
#endif /* __CJSON_USE_INT64 */
}
static void print_number_should_print_positive_reals(void)