From 4c6d4dbd05f5ae947881be1070f1c1004f3988f5 Mon Sep 17 00:00:00 2001 From: PengZheng Date: Tue, 16 Jan 2024 23:00:40 +0800 Subject: [PATCH] More tests for `jsonSerializer_parseAny`. --- conanfile.py | 2 + libs/dfi/gtest/CMakeLists.txt | 1 + libs/dfi/gtest/src/dyn_type_ei_tests.cc | 4 +- .../dfi/gtest/src/json_serializer_ei_tests.cc | 44 ++++++++++++++++++- libs/dfi/gtest/src/json_serializer_tests.cpp | 9 ++++ libs/dfi/src/dyn_type.c | 4 +- libs/dfi/src/json_serializer.c | 37 +++++++++------- libs/error_injector/CMakeLists.txt | 6 +++ libs/error_injector/jansson/CMakeLists.txt | 28 ++++++++++++ .../jansson/include/jansson_ei.h | 33 ++++++++++++++ libs/error_injector/jansson/src/jansson_ei.cc | 31 +++++++++++++ 11 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 libs/error_injector/jansson/CMakeLists.txt create mode 100644 libs/error_injector/jansson/include/jansson_ei.h create mode 100644 libs/error_injector/jansson/src/jansson_ei.cc diff --git a/conanfile.py b/conanfile.py index b36bc30bb..10dffeb3e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -338,6 +338,8 @@ def generate(self): lst = [x.ref.name for x in self.requires.values()] if "mdnsresponder" in lst: tc.cache_variables["BUILD_ERROR_INJECTOR_MDNSRESPONDER"] = "ON" + if "jansson" in lst: + tc.cache_variables["BUILD_ERROR_INJECTOR_JANSSON"] = "ON" tc.cache_variables["CELIX_ERR_BUFFER_SIZE"] = str(self.options.celix_err_buffer_size) # tc.cache_variables["CMAKE_PROJECT_Celix_INCLUDE"] = os.path.join(self.build_folder, "conan_paths.cmake") # the following is workaround for https://github.com/conan-io/conan/issues/7192 diff --git a/libs/dfi/gtest/CMakeLists.txt b/libs/dfi/gtest/CMakeLists.txt index c780e3214..030c2a2c5 100644 --- a/libs/dfi/gtest/CMakeLists.txt +++ b/libs/dfi/gtest/CMakeLists.txt @@ -54,6 +54,7 @@ if (EI_TESTS) Celix::string_ei Celix::ffi_ei Celix::asprintf_ei + Celix::jansson_ei GTest::gtest GTest::gtest_main ) add_test(NAME run_test_dfi_with_ei COMMAND test_dfi_with_ei) diff --git a/libs/dfi/gtest/src/dyn_type_ei_tests.cc b/libs/dfi/gtest/src/dyn_type_ei_tests.cc index c52bd3e05..cf5c80560 100644 --- a/libs/dfi/gtest/src/dyn_type_ei_tests.cc +++ b/libs/dfi/gtest/src/dyn_type_ei_tests.cc @@ -142,7 +142,7 @@ TEST_F(DynTypeErrorInjectionTestSuite, SequenceAllocateError) { celix_ei_expect_calloc((void*)dynType_sequence_alloc, 0, nullptr); rc = dynType_sequence_alloc(type, seq, 1); ASSERT_NE(0, rc); - ASSERT_STREQ("Error allocating memory for buf", celix_err_popLastError()); + ASSERT_STREQ("Error allocating memory for seq buf", celix_err_popLastError()); dynType_free(type, seq); dynType_destroy(type); @@ -167,7 +167,7 @@ TEST_F(DynTypeErrorInjectionTestSuite, SequenceReserveError) { celix_ei_expect_realloc((void*)dynType_sequence_reserve, 0, nullptr); rc = dynType_sequence_reserve(type, seq, 1); ASSERT_NE(0, rc); - ASSERT_STREQ("Error allocating memory for buf", celix_err_popLastError()); + ASSERT_STREQ("Error allocating memory for seq buf", celix_err_popLastError()); dynType_free(type, seq); dynType_destroy(type); diff --git a/libs/dfi/gtest/src/json_serializer_ei_tests.cc b/libs/dfi/gtest/src/json_serializer_ei_tests.cc index dfd18b8b0..c1a538166 100644 --- a/libs/dfi/gtest/src/json_serializer_ei_tests.cc +++ b/libs/dfi/gtest/src/json_serializer_ei_tests.cc @@ -20,14 +20,19 @@ #include "json_serializer.h" #include "dyn_type.h" #include "celix_err.h" +#include "jansson_ei.h" #include "malloc_ei.h" +#include "string_ei.h" #include +#include class JsonSerializerErrorInjectionTestSuite : public ::testing::Test { public: JsonSerializerErrorInjectionTestSuite() = default; ~JsonSerializerErrorInjectionTestSuite() override { + celix_ei_expect_json_array_size(nullptr, 0, 0); + celix_ei_expect_strdup(nullptr, 0, nullptr); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_err_resetErrors(); } @@ -38,7 +43,6 @@ TEST_F(JsonSerializerErrorInjectionTestSuite, SerilizationError) { dyn_type *type; void *inst; - //simple string type = nullptr; inst = nullptr; rc = dynType_parseWithStr("t", nullptr, nullptr, &type); @@ -50,4 +54,42 @@ TEST_F(JsonSerializerErrorInjectionTestSuite, SerilizationError) { EXPECT_STREQ("Error cannot deserialize json. Input is '\"hello\"'", celix_err_popLastError()); EXPECT_STREQ("Error allocating memory for type 't'", celix_err_popLastError()); dynType_destroy(type); + + type = nullptr; + inst = nullptr; + rc = dynType_parseWithStr("t", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"("hello")"; + celix_ei_expect_strdup((void*) dynType_text_allocAndInit, 0, nullptr); + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_NE(0, rc); + EXPECT_STREQ("Error cannot deserialize json. Input is '\"hello\"'", celix_err_popLastError()); + EXPECT_STREQ("Cannot allocate memory for string", celix_err_popLastError()); + dynType_destroy(type); + + + type = nullptr; + inst = nullptr; + rc = dynType_parseWithStr("[t", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"(["hello", "world"])"; + celix_ei_expect_json_array_size((void*)jsonSerializer_deserializeJson, 3, (size_t)UINT32_MAX+1); + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_NE(0, rc); + EXPECT_STREQ("Error cannot deserialize json. Input is '[\"hello\", \"world\"]'", celix_err_popLastError()); + EXPECT_STREQ("Error array size(4294967296) too large", celix_err_popLastError()); + dynType_destroy(type); + + + type = nullptr; + inst = nullptr; + rc = dynType_parseWithStr("[t", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"(["hello", "world"])"; + celix_ei_expect_calloc((void*) dynType_sequence_alloc, 0, nullptr); + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_NE(0, rc); + EXPECT_STREQ("Error cannot deserialize json. Input is '[\"hello\", \"world\"]'", celix_err_popLastError()); + EXPECT_STREQ("Error allocating memory for seq buf", celix_err_popLastError()); + dynType_destroy(type); } \ No newline at end of file diff --git a/libs/dfi/gtest/src/json_serializer_tests.cpp b/libs/dfi/gtest/src/json_serializer_tests.cpp index 0d924f71e..a41c99dae 100644 --- a/libs/dfi/gtest/src/json_serializer_tests.cpp +++ b/libs/dfi/gtest/src/json_serializer_tests.cpp @@ -569,6 +569,15 @@ static void parseTests() { celix_err_printErrors(stderr, nullptr, nullptr); dynType_destroy(type); + // parse complex from non-object + rc = dynType_parseWithStr("{t a}", nullptr, nullptr, &type); + ASSERT_EQ(0, rc); + inputStr = R"(["a"])"; + rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst); + ASSERT_EQ(1, rc); + celix_err_printErrors(stderr, nullptr, nullptr); + dynType_destroy(type); + //simple string rc = dynType_parseWithStr("t", nullptr, nullptr, &type); ASSERT_EQ(0, rc); diff --git a/libs/dfi/src/dyn_type.c b/libs/dfi/src/dyn_type.c index 0ad3e330d..92fb4fe5f 100644 --- a/libs/dfi/src/dyn_type.c +++ b/libs/dfi/src/dyn_type.c @@ -590,7 +590,7 @@ int dynType_sequence_alloc(const dyn_type* type, void* inst, uint32_t cap) { seq->buf = calloc(cap, size); if (seq->buf == NULL) { seq->cap = 0; - celix_err_pushf("Error allocating memory for buf"); + celix_err_pushf("Error allocating memory for seq buf"); return MEM_ERROR; } seq->cap = cap; @@ -613,7 +613,7 @@ int dynType_sequence_reserve(const dyn_type* type, void* inst, uint32_t cap) { seq->buf = realloc(seq->buf, (size_t)(cap * size)); if (seq->buf == NULL) { seq->cap = 0; - celix_err_pushf("Error allocating memory for buf"); + celix_err_pushf("Error allocating memory for seq buf"); return MEM_ERROR; } memset(seq->buf+seq->cap*size, 0, (cap-seq->cap)*size); diff --git a/libs/dfi/src/json_serializer.c b/libs/dfi/src/json_serializer.c index da9953669..a3e4a7eac 100644 --- a/libs/dfi/src/json_serializer.c +++ b/libs/dfi/src/json_serializer.c @@ -188,8 +188,11 @@ static int jsonSerializer_parseAny(const dyn_type* type, void* loc, json_t* val) } break; case '{' : - if (status == OK) { + if (json_is_object(val)) { status = jsonSerializer_parseObject(type, val, loc); + } else { + status = ERROR; + celix_err_pushf("Expected json object type got '%i'", json_typeof(val)); } break; case '*' : @@ -202,7 +205,7 @@ static int jsonSerializer_parseAny(const dyn_type* type, void* loc, json_t* val) case 'P' : default : status = ERROR; - celix_err_pushf("Error provided type '%c' not supported for JSON\n", dynType_descriptorType(type)); + celix_err_pushf("Error provided type '%c' not supported for JSON\n", c); break; } @@ -214,21 +217,23 @@ static int jsonSerializer_parseSequence(const dyn_type* seq, json_t* array, void int status = OK; size_t size = json_array_size(array); - status = dynType_sequence_alloc(seq, seqLoc, (int) size); + if (size > UINT32_MAX) { + celix_err_pushf("Error array size(%zu) too large", size); + return ERROR; + } + if ((status = dynType_sequence_alloc(seq, seqLoc, (uint32_t) size)) != OK) { + return status; + } - if (status == OK) { - const dyn_type* itemType = dynType_sequence_itemType(seq); - size_t index; - json_t* val; - json_array_foreach(array, index, val) { - void* valLoc = NULL; - status = dynType_sequence_increaseLengthAndReturnLastLoc(seq, seqLoc, &valLoc); - if (status == OK) { - status = jsonSerializer_parseAny(itemType, valLoc, val); - if (status != OK) { - break; - } - } + const dyn_type* itemType = dynType_sequence_itemType(seq); + size_t index; + json_t* val; + json_array_foreach(array, index, val) { + void* valLoc = NULL; + (void)dynType_sequence_increaseLengthAndReturnLastLoc(seq, seqLoc, &valLoc); + status = jsonSerializer_parseAny(itemType, valLoc, val); + if (status != OK) { + break; } } diff --git a/libs/error_injector/CMakeLists.txt b/libs/error_injector/CMakeLists.txt index 958d99c94..0d5080458 100644 --- a/libs/error_injector/CMakeLists.txt +++ b/libs/error_injector/CMakeLists.txt @@ -37,7 +37,13 @@ add_subdirectory(sys_shm) add_subdirectory(socket) add_subdirectory(pthread) add_subdirectory(unistd) + celix_subproject(ERROR_INJECTOR_MDNSRESPONDER "Option to enable building the mdnsresponder error injector" OFF) if (ERROR_INJECTOR_MDNSRESPONDER) add_subdirectory(mdnsresponder) endif () + +celix_subproject(ERROR_INJECTOR_JANSSON "Option to enable building the jansson error injector", OFF) +if (ERROR_INJECTOR_JANSSON) + add_subdirectory(jansson) +endif () diff --git a/libs/error_injector/jansson/CMakeLists.txt b/libs/error_injector/jansson/CMakeLists.txt new file mode 100644 index 000000000..73fec4035 --- /dev/null +++ b/libs/error_injector/jansson/CMakeLists.txt @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +find_package(jansson REQUIRED) + +add_library(jansson_ei STATIC src/jansson_ei.cc) + +target_include_directories(jansson_ei PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) +target_link_libraries(jansson_ei PUBLIC Celix::error_injector jansson::jansson) + +target_link_options(jansson_ei INTERFACE + LINKER:--wrap,json_array_size + ) +add_library(Celix::jansson_ei ALIAS jansson_ei) diff --git a/libs/error_injector/jansson/include/jansson_ei.h b/libs/error_injector/jansson/include/jansson_ei.h new file mode 100644 index 000000000..a33693719 --- /dev/null +++ b/libs/error_injector/jansson/include/jansson_ei.h @@ -0,0 +1,33 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +#ifndef CELIX_JANSSON_EI_H +#define CELIX_JANSSON_EI_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "celix_error_injector.h" + +CELIX_EI_DECLARE(json_array_size, size_t); + +#ifdef __cplusplus +} +#endif +#endif //CELIX_JANSSON_EI_H diff --git a/libs/error_injector/jansson/src/jansson_ei.cc b/libs/error_injector/jansson/src/jansson_ei.cc new file mode 100644 index 000000000..df3a8ed02 --- /dev/null +++ b/libs/error_injector/jansson/src/jansson_ei.cc @@ -0,0 +1,31 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#include "jansson_ei.h" + +extern "C" { + +size_t __real_json_array_size(const json_t *array); +CELIX_EI_DEFINE(json_array_size, size_t) +size_t __wrap_json_array_size(const json_t *array) { + CELIX_EI_IMPL(json_array_size); + return __real_json_array_size(array); +} + +} \ No newline at end of file