per Intel policy to include file commit date using git cmd below. The policy does not apply to non-Intel (C) notices. git log --follow -C90% --format=%ad --date default <file> | tail -1 and then pull just the 4 digit year from the result. Intel copyrights were not added to files where Intel either had no contribution ot the contribution lacked substance (ie license header updates, formatting changes, etc). Contribution date used "--follow -C95%" to get the most accurate date. Note that several files in this patch didn't end the license/(c) block with a blank comment line so these were added as the vast majority of files do have this last blank line. Simply there for consistency. Signed-off-by: paul luse <paul.e.luse@intel.com> Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
989 lines
25 KiB
C
989 lines
25 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2016 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk_cunit.h"
|
|
|
|
#include "json/json_util.c"
|
|
|
|
/* For spdk_json_parse() */
|
|
#include "json/json_parse.c"
|
|
|
|
#define NUM_SETUP(x) \
|
|
snprintf(buf, sizeof(buf), "%s", x); \
|
|
v.type = SPDK_JSON_VAL_NUMBER; \
|
|
v.start = buf; \
|
|
v.len = sizeof(x) - 1
|
|
|
|
#define NUM_UINT16_PASS(s, i) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_uint16(&v, &u16) == 0); \
|
|
CU_ASSERT(u16 == i)
|
|
|
|
#define NUM_UINT16_FAIL(s) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_uint16(&v, &u16) != 0)
|
|
|
|
#define NUM_INT32_PASS(s, i) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_int32(&v, &i32) == 0); \
|
|
CU_ASSERT(i32 == i)
|
|
|
|
#define NUM_INT32_FAIL(s) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_int32(&v, &i32) != 0)
|
|
|
|
#define NUM_UINT64_PASS(s, i) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_uint64(&v, &u64) == 0); \
|
|
CU_ASSERT(u64 == i)
|
|
|
|
#define NUM_UINT64_FAIL(s) \
|
|
NUM_SETUP(s); \
|
|
CU_ASSERT(spdk_json_number_to_uint64(&v, &u64) != 0)
|
|
|
|
static void
|
|
test_strequal(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "test";
|
|
v.len = sizeof("test") - 1;
|
|
CU_ASSERT(spdk_json_strequal(&v, "test") == true);
|
|
CU_ASSERT(spdk_json_strequal(&v, "TEST") == false);
|
|
CU_ASSERT(spdk_json_strequal(&v, "hello") == false);
|
|
CU_ASSERT(spdk_json_strequal(&v, "t") == false);
|
|
|
|
v.type = SPDK_JSON_VAL_NAME;
|
|
CU_ASSERT(spdk_json_strequal(&v, "test") == true);
|
|
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
CU_ASSERT(spdk_json_strequal(&v, "test") == false);
|
|
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "test\0hello";
|
|
v.len = sizeof("test\0hello") - 1;
|
|
CU_ASSERT(spdk_json_strequal(&v, "test") == false);
|
|
}
|
|
|
|
static void
|
|
test_num_to_uint16(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
char buf[100];
|
|
uint16_t u16 = 0;
|
|
|
|
NUM_SETUP("1234");
|
|
CU_ASSERT(spdk_json_number_to_uint16(&v, &u16) == 0);
|
|
CU_ASSERT(u16 == 1234);
|
|
|
|
NUM_UINT16_PASS("0", 0);
|
|
NUM_UINT16_PASS("1234", 1234);
|
|
NUM_UINT16_PASS("1234.00000", 1234);
|
|
NUM_UINT16_PASS("1.2e1", 12);
|
|
NUM_UINT16_PASS("12340e-1", 1234);
|
|
|
|
NUM_UINT16_FAIL("1.2");
|
|
NUM_UINT16_FAIL("-1234");
|
|
NUM_UINT16_FAIL("1.2E0");
|
|
NUM_UINT16_FAIL("1.234e1");
|
|
NUM_UINT16_FAIL("12341e-1");
|
|
}
|
|
|
|
static void
|
|
test_num_to_int32(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
char buf[100];
|
|
int32_t i32 = 0;
|
|
|
|
NUM_SETUP("1234");
|
|
CU_ASSERT(spdk_json_number_to_int32(&v, &i32) == 0);
|
|
CU_ASSERT(i32 == 1234);
|
|
|
|
|
|
NUM_INT32_PASS("0", 0);
|
|
NUM_INT32_PASS("1234", 1234);
|
|
NUM_INT32_PASS("-1234", -1234);
|
|
NUM_INT32_PASS("1234.00000", 1234);
|
|
NUM_INT32_PASS("1.2e1", 12);
|
|
NUM_INT32_PASS("12340e-1", 1234);
|
|
NUM_INT32_PASS("-0", 0);
|
|
|
|
NUM_INT32_FAIL("1.2");
|
|
NUM_INT32_FAIL("1.2E0");
|
|
NUM_INT32_FAIL("1.234e1");
|
|
NUM_INT32_FAIL("12341e-1");
|
|
}
|
|
|
|
static void
|
|
test_num_to_uint64(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
char buf[100];
|
|
uint64_t u64 = 0;
|
|
|
|
NUM_SETUP("1234");
|
|
CU_ASSERT(spdk_json_number_to_uint64(&v, &u64) == 0);
|
|
CU_ASSERT(u64 == 1234);
|
|
|
|
|
|
NUM_UINT64_PASS("0", 0);
|
|
NUM_UINT64_PASS("1234", 1234);
|
|
NUM_UINT64_PASS("1234.00000", 1234);
|
|
NUM_UINT64_PASS("1.2e1", 12);
|
|
NUM_UINT64_PASS("12340e-1", 1234);
|
|
NUM_UINT64_PASS("123456780e-1", 12345678);
|
|
|
|
NUM_UINT64_FAIL("1.2");
|
|
NUM_UINT64_FAIL("-1234");
|
|
NUM_UINT64_FAIL("1.2E0");
|
|
NUM_UINT64_FAIL("1.234e1");
|
|
NUM_UINT64_FAIL("12341e-1");
|
|
NUM_UINT64_FAIL("123456781e-1");
|
|
}
|
|
|
|
static void
|
|
test_decode_object(void)
|
|
{
|
|
struct my_object {
|
|
char *my_name;
|
|
uint32_t my_int;
|
|
bool my_bool;
|
|
};
|
|
struct spdk_json_val object[] = {
|
|
{"", 6, SPDK_JSON_VAL_OBJECT_BEGIN},
|
|
{"first", 5, SPDK_JSON_VAL_NAME},
|
|
{"HELLO", 5, SPDK_JSON_VAL_STRING},
|
|
{"second", 6, SPDK_JSON_VAL_NAME},
|
|
{"234", 3, SPDK_JSON_VAL_NUMBER},
|
|
{"third", 5, SPDK_JSON_VAL_NAME},
|
|
{"", 1, SPDK_JSON_VAL_TRUE},
|
|
{"", 0, SPDK_JSON_VAL_OBJECT_END},
|
|
};
|
|
|
|
struct spdk_json_object_decoder decoders[] = {
|
|
{"first", offsetof(struct my_object, my_name), spdk_json_decode_string, false},
|
|
{"second", offsetof(struct my_object, my_int), spdk_json_decode_uint32, false},
|
|
{"third", offsetof(struct my_object, my_bool), spdk_json_decode_bool, false},
|
|
{"fourth", offsetof(struct my_object, my_bool), spdk_json_decode_bool, true},
|
|
};
|
|
struct my_object output = {
|
|
.my_name = NULL,
|
|
.my_int = 0,
|
|
.my_bool = false,
|
|
};
|
|
uint32_t answer = 234;
|
|
char *answer_str = "HELLO";
|
|
bool answer_bool = true;
|
|
|
|
/* Passing Test: object containing simple types */
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 4, &output) == 0);
|
|
SPDK_CU_ASSERT_FATAL(output.my_name != NULL);
|
|
CU_ASSERT(memcmp(output.my_name, answer_str, 6) == 0);
|
|
CU_ASSERT(output.my_int == answer);
|
|
CU_ASSERT(output.my_bool == answer_bool);
|
|
|
|
/* Failing Test: member with no matching decoder */
|
|
/* i.e. I remove the matching decoder from the boolean argument */
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 2, &output) != 0);
|
|
|
|
/* Failing Test: non-optional decoder with no corresponding member */
|
|
|
|
decoders[3].optional = false;
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 4, &output) != 0);
|
|
|
|
/* return to base state */
|
|
decoders[3].optional = true;
|
|
|
|
/* Failing Test: duplicated names for json values */
|
|
object[3].start = "first";
|
|
object[3].len = 5;
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 3, &output) != 0);
|
|
|
|
/* return to base state */
|
|
object[3].start = "second";
|
|
object[3].len = 6;
|
|
|
|
/* Failing Test: invalid value for decoder */
|
|
object[2].start = "HELO";
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 3, &output) != 0);
|
|
|
|
/* return to base state */
|
|
object[2].start = "HELLO";
|
|
|
|
/* Failing Test: not an object */
|
|
object[0].type = SPDK_JSON_VAL_ARRAY_BEGIN;
|
|
CU_ASSERT(spdk_json_decode_object(object, decoders, 3, &output) != 0);
|
|
|
|
free(output.my_name);
|
|
}
|
|
|
|
static void
|
|
test_free_object(void)
|
|
{
|
|
struct my_object {
|
|
char *my_name;
|
|
uint32_t my_int;
|
|
char *my_other_name;
|
|
char *empty_string;
|
|
};
|
|
struct spdk_json_object_decoder decoders[] = {
|
|
{"first", offsetof(struct my_object, my_name), spdk_json_decode_string, false},
|
|
{"second", offsetof(struct my_object, my_int), spdk_json_decode_uint32, false},
|
|
{"third", offsetof(struct my_object, my_other_name), spdk_json_decode_string, true},
|
|
{"fourth", offsetof(struct my_object, empty_string), spdk_json_decode_string, false},
|
|
};
|
|
struct my_object output = {
|
|
.my_name = strdup("hello"),
|
|
.my_int = 3,
|
|
.my_other_name = strdup("world"),
|
|
.empty_string = NULL
|
|
};
|
|
|
|
SPDK_CU_ASSERT_FATAL(output.my_name != NULL);
|
|
SPDK_CU_ASSERT_FATAL(output.my_other_name != NULL);
|
|
|
|
spdk_json_free_object(decoders, 4, &output);
|
|
CU_ASSERT(output.my_name == NULL);
|
|
CU_ASSERT(output.my_other_name == NULL);
|
|
CU_ASSERT(output.empty_string == NULL);
|
|
}
|
|
|
|
static void
|
|
test_decode_array(void)
|
|
{
|
|
struct spdk_json_val values[4];
|
|
uint32_t my_int[2] = {0, 0};
|
|
char *my_string[2] = {NULL, NULL};
|
|
size_t out_size;
|
|
|
|
/* passing integer test */
|
|
values[0].type = SPDK_JSON_VAL_ARRAY_BEGIN;
|
|
values[0].len = 2;
|
|
values[1].type = SPDK_JSON_VAL_NUMBER;
|
|
values[1].len = 4;
|
|
values[1].start = "1234";
|
|
values[2].type = SPDK_JSON_VAL_NUMBER;
|
|
values[2].len = 4;
|
|
values[2].start = "5678";
|
|
values[3].type = SPDK_JSON_VAL_ARRAY_END;
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_uint32, my_int, 2, &out_size,
|
|
sizeof(uint32_t)) == 0);
|
|
CU_ASSERT(my_int[0] == 1234);
|
|
CU_ASSERT(my_int[1] == 5678);
|
|
CU_ASSERT(out_size == 2);
|
|
|
|
/* array length exceeds max */
|
|
values[0].len = 3;
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_uint32, my_int, 2, &out_size,
|
|
sizeof(uint32_t)) != 0);
|
|
|
|
/* mixed types */
|
|
values[0].len = 2;
|
|
values[2].type = SPDK_JSON_VAL_STRING;
|
|
values[2].len = 5;
|
|
values[2].start = "HELLO";
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_uint32, my_int, 2, &out_size,
|
|
sizeof(uint32_t)) != 0);
|
|
|
|
/* no array start */
|
|
values[0].type = SPDK_JSON_VAL_NUMBER;
|
|
values[2].type = SPDK_JSON_VAL_NUMBER;
|
|
values[2].len = 4;
|
|
values[2].start = "5678";
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_uint32, my_int, 2, &out_size,
|
|
sizeof(uint32_t)) != 0);
|
|
|
|
/* mismatched array type and parser */
|
|
values[0].type = SPDK_JSON_VAL_ARRAY_BEGIN;
|
|
values[1].type = SPDK_JSON_VAL_STRING;
|
|
values[1].len = 5;
|
|
values[1].start = "HELLO";
|
|
values[2].type = SPDK_JSON_VAL_STRING;
|
|
values[2].len = 5;
|
|
values[2].start = "WORLD";
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_uint32, my_int, 2, &out_size,
|
|
sizeof(uint32_t)) != 0);
|
|
|
|
/* passing String example */
|
|
CU_ASSERT(spdk_json_decode_array(values, spdk_json_decode_string, my_string, 2, &out_size,
|
|
sizeof(char *)) == 0);
|
|
SPDK_CU_ASSERT_FATAL(my_string[0] != NULL);
|
|
SPDK_CU_ASSERT_FATAL(my_string[1] != NULL);
|
|
CU_ASSERT(memcmp(my_string[0], "HELLO", 6) == 0);
|
|
CU_ASSERT(memcmp(my_string[1], "WORLD", 6) == 0);
|
|
CU_ASSERT(out_size == 2);
|
|
|
|
free(my_string[0]);
|
|
free(my_string[1]);
|
|
}
|
|
|
|
static void
|
|
test_decode_bool(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
bool b;
|
|
|
|
/* valid bool (true) */
|
|
v.type = SPDK_JSON_VAL_TRUE;
|
|
b = false;
|
|
CU_ASSERT(spdk_json_decode_bool(&v, &b) == 0);
|
|
CU_ASSERT(b == true);
|
|
|
|
/* valid bool (false) */
|
|
v.type = SPDK_JSON_VAL_FALSE;
|
|
b = true;
|
|
CU_ASSERT(spdk_json_decode_bool(&v, &b) == 0);
|
|
CU_ASSERT(b == false);
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_NULL;
|
|
CU_ASSERT(spdk_json_decode_bool(&v, &b) != 0);
|
|
}
|
|
|
|
static void
|
|
test_decode_int32(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
int32_t i;
|
|
|
|
/* correct type and valid value */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "33";
|
|
v.len = 2;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == 33);
|
|
|
|
/* correct type and invalid value (float) */
|
|
v.start = "32.45";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "String";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_TRUE;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* edge case (integer max) */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "2147483647";
|
|
v.len = 10;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == 2147483647);
|
|
|
|
/* invalid value (overflow) */
|
|
v.start = "2147483648";
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* edge case (integer min) */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "-2147483648";
|
|
v.len = 11;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == -2147483648);
|
|
|
|
/* invalid value (overflow) */
|
|
v.start = "-2147483649";
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* valid exponent */
|
|
v.start = "4e3";
|
|
v.len = 3;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == 4000);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "-400e-4";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "400e-4";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* valid negative exponent */
|
|
v.start = "-400e-2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == -4);
|
|
|
|
/* invalid exponent (overflow) */
|
|
v.start = "-2e32";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
|
|
/* valid exponent with decimal */
|
|
v.start = "2.13e2";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) == 0);
|
|
CU_ASSERT(i == 213);
|
|
|
|
/* invalid exponent with decimal */
|
|
v.start = "2.134e2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_int32(&v, &i) != 0);
|
|
}
|
|
|
|
static void
|
|
test_decode_uint16(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
uint32_t i;
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "Strin";
|
|
v.len = 5;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* invalid value (float) */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "123.4";
|
|
v.len = 5;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* edge case (0) */
|
|
v.start = "0";
|
|
v.len = 1;
|
|
i = 456;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) == 0);
|
|
CU_ASSERT(i == 0);
|
|
|
|
/* invalid value (negative) */
|
|
v.start = "-1";
|
|
v.len = 2;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* edge case (maximum) */
|
|
v.start = "65535";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) == 0);
|
|
CU_ASSERT(i == 65535);
|
|
|
|
/* invalid value (overflow) */
|
|
v.start = "65536";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* valid exponent */
|
|
v.start = "66E2";
|
|
v.len = 4;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) == 0);
|
|
CU_ASSERT(i == 6600);
|
|
|
|
/* invalid exponent (overflow) */
|
|
v.start = "66E3";
|
|
v.len = 4;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* invalid exponent (decimal) */
|
|
v.start = "65.535E2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* valid exponent with decimal */
|
|
v.start = "65.53E2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) == 0);
|
|
CU_ASSERT(i == 6553);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "40e-2";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "-40e-1";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) != 0);
|
|
|
|
/* valid negative exponent */
|
|
v.start = "40e-1";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint16(&v, &i) == 0);
|
|
CU_ASSERT(i == 4);
|
|
}
|
|
|
|
static void
|
|
test_decode_uint32(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
uint32_t i;
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "String";
|
|
v.len = 6;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* invalid value (float) */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "123.45";
|
|
v.len = 6;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* edge case (0) */
|
|
v.start = "0";
|
|
v.len = 1;
|
|
i = 456;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 0);
|
|
|
|
/* invalid value (negative) */
|
|
v.start = "-1";
|
|
v.len = 2;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* edge case (maximum) */
|
|
v.start = "4294967295";
|
|
v.len = 10;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 4294967295);
|
|
|
|
/* invalid value (overflow) */
|
|
v.start = "4294967296";
|
|
v.len = 10;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* valid exponent */
|
|
v.start = "42E2";
|
|
v.len = 4;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 4200);
|
|
|
|
/* invalid exponent (overflow) */
|
|
v.start = "42e32";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* invalid exponent (decimal) */
|
|
v.start = "42.323E2";
|
|
v.len = 8;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* valid exponent with decimal */
|
|
v.start = "42.32E2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 4232);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "400e-4";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "-400e-2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) != 0);
|
|
|
|
/* valid negative exponent */
|
|
v.start = "400e-2";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 4);
|
|
|
|
/* valid negative exponent */
|
|
v.start = "10e-1";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint32(&v, &i) == 0);
|
|
CU_ASSERT(i == 1);
|
|
}
|
|
|
|
static void
|
|
test_decode_uint64(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
uint64_t i;
|
|
|
|
/* incorrect type */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "String";
|
|
v.len = 6;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* invalid value (float) */
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
v.start = "123.45";
|
|
v.len = 6;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* edge case (0) */
|
|
v.start = "0";
|
|
v.len = 1;
|
|
i = 456;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) == 0);
|
|
CU_ASSERT(i == 0);
|
|
|
|
/* invalid value (negative) */
|
|
v.start = "-1";
|
|
v.len = 2;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* edge case (maximum) */
|
|
v.start = "18446744073709551615";
|
|
v.len = 20;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) == 0);
|
|
CU_ASSERT(i == 18446744073709551615U);
|
|
|
|
/* invalid value (overflow) */
|
|
v.start = "18446744073709551616";
|
|
v.len = 20;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* valid exponent */
|
|
v.start = "42E2";
|
|
v.len = 4;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) == 0);
|
|
CU_ASSERT(i == 4200);
|
|
|
|
/* invalid exponent (overflow) */
|
|
v.start = "42e64";
|
|
v.len = 5;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* invalid exponent (decimal) */
|
|
v.start = "42.323E2";
|
|
v.len = 8;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* valid exponent with decimal */
|
|
v.start = "42.32E2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) == 0);
|
|
CU_ASSERT(i == 4232);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "400e-4";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* invalid negative exponent */
|
|
v.start = "-400e-2";
|
|
v.len = 7;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) != 0);
|
|
|
|
/* valid negative exponent */
|
|
v.start = "400e-2";
|
|
v.len = 6;
|
|
i = 0;
|
|
CU_ASSERT(spdk_json_decode_uint64(&v, &i) == 0);
|
|
CU_ASSERT(i == 4);
|
|
}
|
|
|
|
static void
|
|
test_decode_string(void)
|
|
{
|
|
struct spdk_json_val v;
|
|
char *value = NULL;
|
|
|
|
/* Passing Test: Standard */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "HELLO";
|
|
v.len = 5;
|
|
CU_ASSERT(spdk_json_decode_string(&v, &value) == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(memcmp(value, v.start, 6) == 0);
|
|
|
|
/* Edge Test: Empty String */
|
|
v.start = "";
|
|
v.len = 0;
|
|
CU_ASSERT(spdk_json_decode_string(&v, &value) == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(memcmp(value, v.start, 1) == 0);
|
|
|
|
/*
|
|
* Failing Test: Null Terminator In String
|
|
* It is valid for a json string to contain \u0000 and the parser will accept it.
|
|
* However, a null terminated C string cannot contain '\0' and should be rejected
|
|
* if that character is found before the end of the string.
|
|
*/
|
|
v.start = "HELO";
|
|
v.len = 5;
|
|
CU_ASSERT(spdk_json_decode_string(&v, &value) != 0);
|
|
|
|
/* Failing Test: Wrong Type */
|
|
v.start = "45673";
|
|
v.type = SPDK_JSON_VAL_NUMBER;
|
|
CU_ASSERT(spdk_json_decode_string(&v, &value) != 0);
|
|
|
|
/* Passing Test: Special Characters */
|
|
v.type = SPDK_JSON_VAL_STRING;
|
|
v.start = "HE\bLL\tO\\WORLD";
|
|
v.len = 13;
|
|
CU_ASSERT(spdk_json_decode_string(&v, &value) == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(memcmp(value, v.start, 14) == 0);
|
|
|
|
free(value);
|
|
}
|
|
|
|
char ut_json_text[] =
|
|
"{"
|
|
" \"string\": \"Some string data\","
|
|
" \"object\": { "
|
|
" \"another_string\": \"Yet another string data\","
|
|
" \"array name with space\": [1, [], {} ]"
|
|
" },"
|
|
" \"array\": [ \"Text\", 2, {} ]"
|
|
"}"
|
|
;
|
|
|
|
static void
|
|
test_find(void)
|
|
{
|
|
struct spdk_json_val *values, *key, *val, *key2, *val2;
|
|
ssize_t values_cnt;
|
|
ssize_t rc;
|
|
|
|
values_cnt = spdk_json_parse(ut_json_text, strlen(ut_json_text), NULL, 0, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt > 0);
|
|
|
|
values = calloc(values_cnt, sizeof(struct spdk_json_val));
|
|
SPDK_CU_ASSERT_FATAL(values != NULL);
|
|
|
|
rc = spdk_json_parse(ut_json_text, strlen(ut_json_text), values, values_cnt, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt == rc);
|
|
|
|
key = val = NULL;
|
|
rc = spdk_json_find(values, "string", &key, &val, SPDK_JSON_VAL_STRING);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
CU_ASSERT(key != NULL && spdk_json_strequal(key, "string") == true);
|
|
CU_ASSERT(val != NULL && spdk_json_strequal(val, "Some string data") == true);
|
|
|
|
key = val = NULL;
|
|
rc = spdk_json_find(values, "object", &key, &val, SPDK_JSON_VAL_OBJECT_BEGIN);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
CU_ASSERT(key != NULL && spdk_json_strequal(key, "object") == true);
|
|
|
|
/* Find key in "object" by passing SPDK_JSON_VAL_ANY to match any type */
|
|
key2 = val2 = NULL;
|
|
rc = spdk_json_find(val, "array name with space", &key2, &val2, SPDK_JSON_VAL_ANY);
|
|
CU_ASSERT(rc == 0);
|
|
CU_ASSERT(key2 != NULL && spdk_json_strequal(key2, "array name with space") == true);
|
|
CU_ASSERT(val2 != NULL && val2->type == SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
|
|
/* Find the "array" key in "object" by passing SPDK_JSON_VAL_ARRAY_BEGIN to match only array */
|
|
key2 = val2 = NULL;
|
|
rc = spdk_json_find(val, "array name with space", &key2, &val2, SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
CU_ASSERT(rc == 0);
|
|
CU_ASSERT(key2 != NULL && spdk_json_strequal(key2, "array name with space") == true);
|
|
CU_ASSERT(val2 != NULL && val2->type == SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
|
|
/* Negative test - key doesn't exist */
|
|
key2 = val2 = NULL;
|
|
rc = spdk_json_find(val, "this_key_does_not_exist", &key2, &val2, SPDK_JSON_VAL_ANY);
|
|
CU_ASSERT(rc == -ENOENT);
|
|
|
|
/* Negative test - key type doesn't match */
|
|
key2 = val2 = NULL;
|
|
rc = spdk_json_find(val, "another_string", &key2, &val2, SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
CU_ASSERT(rc == -EDOM);
|
|
|
|
free(values);
|
|
}
|
|
|
|
static void
|
|
test_find_array(void)
|
|
{
|
|
char array_json_text[] = "[ \"Text\", 2, {} ]";
|
|
struct spdk_json_val *values, *key;
|
|
ssize_t values_cnt;
|
|
ssize_t rc;
|
|
|
|
values_cnt = spdk_json_parse(array_json_text, strlen(array_json_text), NULL, 0, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt > 0);
|
|
|
|
values = calloc(values_cnt, sizeof(struct spdk_json_val));
|
|
SPDK_CU_ASSERT_FATAL(values != NULL);
|
|
|
|
rc = spdk_json_parse(array_json_text, strlen(array_json_text), values, values_cnt, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt == rc);
|
|
|
|
/* spdk_json_find cannot be used on arrays. The element "Text" does exist in the array,
|
|
* but spdk_json_find can only be used for finding keys in an object. So this
|
|
* test should fail.
|
|
*/
|
|
key = NULL;
|
|
rc = spdk_json_find(values, "Text", &key, NULL, SPDK_JSON_VAL_STRING);
|
|
CU_ASSERT(rc == -EPROTOTYPE);
|
|
|
|
free(values);
|
|
}
|
|
|
|
static void
|
|
test_iterating(void)
|
|
{
|
|
struct spdk_json_val *values;
|
|
struct spdk_json_val *string_key;
|
|
struct spdk_json_val *object_key, *object_val;
|
|
struct spdk_json_val *array_key, *array_val;
|
|
struct spdk_json_val *another_string_key;
|
|
struct spdk_json_val *array_name_with_space_key, *array_name_with_space_val;
|
|
struct spdk_json_val *it;
|
|
ssize_t values_cnt;
|
|
ssize_t rc;
|
|
|
|
values_cnt = spdk_json_parse(ut_json_text, strlen(ut_json_text), NULL, 0, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt > 0);
|
|
|
|
values = calloc(values_cnt, sizeof(struct spdk_json_val));
|
|
SPDK_CU_ASSERT_FATAL(values != NULL);
|
|
|
|
rc = spdk_json_parse(ut_json_text, strlen(ut_json_text), values, values_cnt, NULL, 0);
|
|
SPDK_CU_ASSERT_FATAL(values_cnt == rc);
|
|
|
|
/* Iterate over object keys. JSON spec doesn't guarantee order of keys in object but
|
|
* SPDK implementation implicitly does.
|
|
*/
|
|
string_key = spdk_json_object_first(values);
|
|
CU_ASSERT(spdk_json_strequal(string_key, "string") == true);
|
|
|
|
object_key = spdk_json_next(string_key);
|
|
object_val = json_value(object_key);
|
|
CU_ASSERT(spdk_json_strequal(object_key, "object") == true);
|
|
|
|
array_key = spdk_json_next(object_key);
|
|
array_val = json_value(array_key);
|
|
CU_ASSERT(spdk_json_strequal(array_key, "array") == true);
|
|
|
|
/* NULL '}' */
|
|
CU_ASSERT(spdk_json_next(array_key) == NULL);
|
|
|
|
/* Iterate over subobjects */
|
|
another_string_key = spdk_json_object_first(object_val);
|
|
CU_ASSERT(spdk_json_strequal(another_string_key, "another_string") == true);
|
|
|
|
array_name_with_space_key = spdk_json_next(another_string_key);
|
|
array_name_with_space_val = json_value(array_name_with_space_key);
|
|
CU_ASSERT(spdk_json_strequal(array_name_with_space_key, "array name with space") == true);
|
|
|
|
CU_ASSERT(spdk_json_next(array_name_with_space_key) == NULL);
|
|
|
|
/* Iterate over array in subobject */
|
|
it = spdk_json_array_first(array_name_with_space_val);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_NUMBER);
|
|
|
|
it = spdk_json_next(it);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_ARRAY_BEGIN);
|
|
|
|
it = spdk_json_next(it);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_OBJECT_BEGIN);
|
|
|
|
it = spdk_json_next(it);
|
|
CU_ASSERT(it == NULL);
|
|
|
|
/* Iterate over array in root object */
|
|
it = spdk_json_array_first(array_val);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_STRING);
|
|
|
|
it = spdk_json_next(it);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_NUMBER);
|
|
|
|
it = spdk_json_next(it);
|
|
SPDK_CU_ASSERT_FATAL(it != NULL);
|
|
CU_ASSERT(it->type == SPDK_JSON_VAL_OBJECT_BEGIN);
|
|
|
|
/* Array end */
|
|
it = spdk_json_next(it);
|
|
CU_ASSERT(it == NULL);
|
|
|
|
free(values);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
CU_pSuite suite = NULL;
|
|
unsigned int num_failures;
|
|
|
|
CU_set_error_action(CUEA_ABORT);
|
|
CU_initialize_registry();
|
|
|
|
suite = CU_add_suite("json", NULL, NULL);
|
|
|
|
CU_ADD_TEST(suite, test_strequal);
|
|
CU_ADD_TEST(suite, test_num_to_uint16);
|
|
CU_ADD_TEST(suite, test_num_to_int32);
|
|
CU_ADD_TEST(suite, test_num_to_uint64);
|
|
CU_ADD_TEST(suite, test_decode_object);
|
|
CU_ADD_TEST(suite, test_decode_array);
|
|
CU_ADD_TEST(suite, test_decode_bool);
|
|
CU_ADD_TEST(suite, test_decode_uint16);
|
|
CU_ADD_TEST(suite, test_decode_int32);
|
|
CU_ADD_TEST(suite, test_decode_uint32);
|
|
CU_ADD_TEST(suite, test_decode_uint64);
|
|
CU_ADD_TEST(suite, test_decode_string);
|
|
CU_ADD_TEST(suite, test_find);
|
|
CU_ADD_TEST(suite, test_find_array);
|
|
CU_ADD_TEST(suite, test_iterating);
|
|
CU_ADD_TEST(suite, test_free_object);
|
|
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
|
|
CU_basic_run_tests();
|
|
|
|
num_failures = CU_get_number_of_failures();
|
|
CU_cleanup_registry();
|
|
|
|
return num_failures;
|
|
}
|