From 5782780e11f932348558190537cfe36e53b1f81b Mon Sep 17 00:00:00 2001 From: Yoan Picchi Date: Fri, 16 May 2025 12:29:26 +0000 Subject: [PATCH] Add test suite for the Direct API Signed-off-by: Yoan Picchi --- unit/CMakeLists.txt | 15 + unit/direct_API/char_pair_set.cpp | 378 ++++++++++++++++++++ unit/direct_API/char_set.cpp | 333 +++++++++++++++++ unit/direct_API/common.h | 210 +++++++++++ unit/direct_API/long_literal.cpp | 394 ++++++++++++++++++++ unit/direct_API/main.cpp | 36 ++ unit/direct_API/multi_literal.cpp | 515 +++++++++++++++++++++++++++ unit/direct_API/short_literal.cpp | 377 ++++++++++++++++++++ unit/direct_API/single_char.cpp | 293 +++++++++++++++ unit/direct_API/single_char_pair.cpp | 303 ++++++++++++++++ 10 files changed, 2854 insertions(+) create mode 100644 unit/direct_API/char_pair_set.cpp create mode 100644 unit/direct_API/char_set.cpp create mode 100644 unit/direct_API/common.h create mode 100644 unit/direct_API/long_literal.cpp create mode 100644 unit/direct_API/main.cpp create mode 100644 unit/direct_API/multi_literal.cpp create mode 100644 unit/direct_API/short_literal.cpp create mode 100644 unit/direct_API/single_char.cpp create mode 100644 unit/direct_API/single_char_pair.cpp diff --git a/unit/CMakeLists.txt b/unit/CMakeLists.txt index 7e16f333..2ad2ea83 100644 --- a/unit/CMakeLists.txt +++ b/unit/CMakeLists.txt @@ -63,6 +63,21 @@ set(unit_hyperscan_SOURCES add_executable(unit-hyperscan ${unit_hyperscan_SOURCES}) target_link_libraries(unit-hyperscan hs expressionutil) +set(unit_direct_api_SOURCES + ${gtest_SOURCES} + direct_API/char_pair_set.cpp + direct_API/char_set.cpp + direct_API/common.h + direct_API/long_literal.cpp + direct_API/main.cpp + direct_API/multi_literal.cpp + direct_API/short_literal.cpp + direct_API/single_char_pair.cpp + direct_API/single_char.cpp + ) +add_executable(unit-direct-API ${unit_direct_api_SOURCES}) +target_link_libraries(unit-direct-API hs) + if (NOT FAT_RUNTIME AND BUILD_STATIC_LIBS) set(BUILD_UNIT_INTERNAL TRUE) set(unit_internal_SOURCES diff --git a/unit/direct_API/char_pair_set.cpp b/unit/direct_API/char_pair_set.cpp new file mode 100644 index 00000000..f371d996 --- /dev/null +++ b/unit/direct_API/char_pair_set.cpp @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#include "hwlm/noodle_internal.h" + +#define COMPILE_CHAR_PAIR_SET(in_character_array, in_pair_count) \ + const size_t pair_count = (in_pair_count); \ + const char *character_array = (in_character_array); \ + hs_char_pair_set_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = hs_compile_char_pair_set_search( \ + character_array, pair_count, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +#define SEARCH_CHAR_PAIR_SET(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array, in_expected_id_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match] = \ + BRACED_INIT_LIST in_expected_id_array; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += 2; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_char_pair_set_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +// ------------------------free tests------------------------------------------- + +/* +hs_free_char_pair_set_pattern + nullptr + general +*/ + +TEST(char_pair_set_free, nullptr) { + hs_char_pair_set_compiled_pattern_t *database = nullptr; + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_free, general) { + SETUP_MEM_LEAK_TEST(); + noodTable *clear_database = + reinterpret_cast(test_malloc(sizeof(noodTable))); + + hs_char_pair_set_compiled_pattern_t *database = + reinterpret_cast(clear_database); + + hs_free_char_pair_set_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_char_pair_set_search + single pair + multiple pair + pair duplicate + valid pair including null char + + empty char array + nullptr char array + nullptr output +*/ + +TEST(char_pair_set_compile, single_pair) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + (void) ret; + (void) buffer; + EXPECT_COMPILE_SUCCESS("test_compile_char_pair_set_single_pair"); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_compile, two_pairs) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 2); + (void) ret; + (void) buffer; + EXPECT_COMPILE_SUCCESS("test_compile_char_pair_set_two_pairs"); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_compile, duplicate) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_AB_DUPLICATE, 2); + (void) ret; + (void) buffer; + EXPECT_COMPILE_SUCCESS("test_compile_char_pair_set_duplicate"); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_compile, null_char) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_A_NULL_BC, 1); + (void) ret; + (void) buffer; + EXPECT_COMPILE_SUCCESS("test_compile_char_pair_set_null_char"); + hs_free_char_pair_set_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(char_pair_set_compile, no_expression) { + const size_t pair_count = 0; + const char *character_array = PAIR_SET_ABCD; + hs_char_pair_set_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_char_pair_set_search(character_array, pair_count, + &database), + "called with an empty set"); +} + +TEST(char_pair_set_compile, nullptr_char_array) { + hs_char_pair_set_compiled_pattern_t *database = nullptr; + EXPECT_DEATH( + hs_compile_char_pair_set_search(nullptr, 1, &database), + "called with nullptr"); +} + +TEST(char_pair_set_compile, nullptr_database) { + const size_t pair_count = 2; + const char *character_array = PAIR_SET_ABCD; + EXPECT_DEATH(hs_compile_char_pair_set_search(character_array, + pair_count, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_char_pair_set_search + general pattern + match at start + match middle (general) + match index 15 (cross over vector) + match at end + match past end + match null char + bad caseness + search several times + match a pair duplicate + match several pattern in the same search + match when there's more pairs than fit in a vector + buffer containing null char + pattern with null char + general pattern + + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(char_pair_set_search, start) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_start"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_general"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(char_pair_set_search, cross_vector) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_cross_vector"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15), (0, 0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, end) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_end"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN, 1, (30), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, past_end) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, null_char) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_A_NULL_BC, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_null_char"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, bad_case) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, several_search) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_several_search"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15), (0, 0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, duplicate) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_AB_DUPLICATE, 2); + ASSERT_COMPILE_SUCCESS("char_pair_set_search_duplicate"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, match_multiple) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 2); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_match_multiple"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 2, (5, 7), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, last_of_long_pattern) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_LONG_PATTERN_AB, 9); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_last_of_long_pattern"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (8)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, null_char_buff_and_pattern) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_A_NULL_BC, 2); + ASSERT_COMPILE_SUCCESS( + "test_char_pair_set_search_null_char_buff_and_pattern"); + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, null_char_buff) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 2); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_null_char_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +TEST(char_pair_set_search, empty_buff) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_CHAR_PAIR_SET("", 0, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_char_pair_set_search", character_array, buffer); + hs_free_char_pair_set_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(char_pair_set_search, nullptr_pattern) { + const hs_char_pair_set_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_CHAR_PAIR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr database"); +} + +TEST(char_pair_set_search, nullptr_buffer) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_CHAR_PAIR_SET(nullptr, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr buffer"); +} + +TEST(char_pair_set_search, nullptr_callback) { + COMPILE_CHAR_PAIR_SET(PAIR_SET_ABCD, 1); + ASSERT_COMPILE_SUCCESS("test_char_pair_set_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + size_t expected_id_array[expected_match] = {0}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += 2; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.expected_id_array = expected_id_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_char_pair_set_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/char_set.cpp b/unit/direct_API/char_set.cpp new file mode 100644 index 00000000..33909776 --- /dev/null +++ b/unit/direct_API/char_set.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#define COMPILE_CHAR_SET(in_character_array, in_character_count) \ + const size_t character_count = (in_character_count); \ + const char *character_array = (in_character_array); \ + hs_char_set_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = hs_compile_char_set_search( \ + character_array, character_count, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +#define SEARCH_CHAR_SET(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array, in_expected_id_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match] = \ + BRACED_INIT_LIST in_expected_id_array; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += 1; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_char_set_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +// ------------------------free tests------------------------------------------- + +/* +hs_free_char_set_pattern + nullptr + general +*/ + +TEST(char_set_free, nullptr) { + hs_char_set_compiled_pattern_t *database = nullptr; + hs_free_char_set_pattern(database); +} + +TEST(char_set_free, general) { + SETUP_MEM_LEAK_TEST(); + truffle_storage *clear_database = reinterpret_cast( + test_malloc(sizeof(truffle_storage))); + + hs_char_set_compiled_pattern_t *database = + reinterpret_cast(clear_database); + + hs_free_char_set_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_char_set_search + single char + same char twice + general (several different chars) + null char + + empty char array + nullptr char array + nullptr output +*/ + +TEST(char_set_compile, single_char) { + COMPILE_CHAR_SET(CHAR_SET_A, 1); + EXPECT_COMPILE_SUCCESS("test_compile_char_set_single_char"); + hs_free_char_set_pattern(database); +} + +TEST(char_set_compile, single_char_twice) { + COMPILE_CHAR_SET(CHAR_SET_A, 2); + EXPECT_COMPILE_SUCCESS("test_compile_char_set_single_char_twice"); + hs_free_char_set_pattern(database); +} + +TEST(char_set_compile, general) { + COMPILE_CHAR_SET(CHAR_SET_ABCDE, 5); + EXPECT_COMPILE_SUCCESS("test_compile_char_set_general"); + hs_free_char_set_pattern(database); +} + +TEST(char_set_compile, null_char) { + COMPILE_CHAR_SET(CHAR_SET_NULL, 1); + EXPECT_COMPILE_SUCCESS("test_compile_char_set_null_char"); + hs_free_char_set_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(char_set_compile, no_expression) { + const size_t character_count = 0; + const char *character_array = CHAR_SET_AB; + hs_char_set_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_char_set_search(character_array, character_count, + &database), + "called with an empty set"); +} + +TEST(char_set_compile, nullptr_char_array) { + hs_char_set_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_char_set_search(nullptr, 1, &database), + "called with nullptr"); +} + +TEST(char_set_compile, nullptr_database) { + const size_t character_count = 2; + const char *character_array = CHAR_SET_AB; + EXPECT_DEATH(hs_compile_char_set_search(character_array, + character_count, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_char_set_search + match at start + match middle (general) + match index 15 (last char of a vector) + match at end + match past end + match null char + bad caseness + search several times + match first char + match last char + buff size 0 + + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(char_set_search, start) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_start"); + SEARCH_CHAR_SET(EXPR_NOISE_0, EXPR_NOISE_LEN, 2, (0, 1), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_general"); + SEARCH_CHAR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 2, (5, 6), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(char_set_search, cross_vector) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_cross_vector"); + SEARCH_CHAR_SET(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 4, (5, 6, 15, 16), + (0, 1, 0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, end) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_end"); + SEARCH_CHAR_SET(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN, 2, (30, 31), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, past_end) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_past_end"); + SEARCH_CHAR_SET(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 1, (30), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, null_char) { + COMPILE_CHAR_SET(CHAR_SET_NULL, 1); + ASSERT_COMPILE_SUCCESS("test_char_set_search_null_char"); + SEARCH_CHAR_SET(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (6), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, bad_case) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_bad_case"); + SEARCH_CHAR_SET(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 1, (16), (1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, several_search) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_several_search"); + SEARCH_CHAR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 2, (5, 6), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + SEARCH_CHAR_SET(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 4, (5, 6, 15, 16), + (0, 1, 0, 1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, first_char) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_first_char"); + SEARCH_CHAR_SET(EXPR_UNIFORM_1_A, EXPR_UNIFORM_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array[0], buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, last_char) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_last_char"); + SEARCH_CHAR_SET(EXPR_UNIFORM_1_B, EXPR_UNIFORM_LEN, 1, (5), (1)); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array[1], buffer); + hs_free_char_set_pattern(database); +} + +TEST(char_set_search, empty_buff) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_CHAR_SET("", 0, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_char_set_search", character_array, buffer); + hs_free_char_set_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(char_set_search, nullptr_pattern) { + const hs_char_set_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_CHAR_SET(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr database"); +} + +TEST(char_set_search, nullptr_buffer) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_CHAR_SET(nullptr, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr buffer"); +} + +TEST(char_set_search, nullptr_callback) { + COMPILE_CHAR_SET(CHAR_SET_AB, 2); + ASSERT_COMPILE_SUCCESS("test_char_set_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 2; + size_t expected_start_array[expected_match] = {5, 6}; + size_t expected_end_array[expected_match] = {5, 6}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += 1; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_char_set_search(database, buffer, buffer_len, nullptr, &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/common.h b/unit/direct_API/common.h new file mode 100644 index 00000000..9aaaa355 --- /dev/null +++ b/unit/direct_API/common.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include + +#include "hs_common.h" +#include "hs_compile.h" +#include "hs_runtime.h" +#include "hs_direct_search.h" +#include "hs_direct_search_types.h" + +#include "gtest/gtest.h" + +// ----------------------------------------------------------------------------- + +#define PATTERN_0_CHAR "" +#define PATTERN_1_CHAR "a" +#define PATTERN_1_CHAR_NULL "\0" +#define PATTERN_2_CHAR "aB" +#define PATTERN_2_WITH_NULL "a\0" +#define PATTERN_3_CHAR "aBc" +#define PATTERN_5_CHAR "aBcde" +#define PATTERN_5_WITH_NULL "a\0Bcd" +#define PATTERN_8_CHAR "aBcdeoAb" +#define PATTERN_10_CHAR "aBcdeoAbCD" +#define PATTERN_25_CHAR "aBcdeoAbCDumefnvqmuz,crhUq" + +#define CHAR_SET_NULL "\0" +#define CHAR_SET_A "aaAA" +#define CHAR_SET_AB "aB" +#define CHAR_SET_ABCDE "aBcde" + +#define PAIR_SET_ABCD "aBcd" +#define PAIR_SET_A_NULL_BC "a\0Bc" +#define PAIR_SET_AB_DUPLICATE "aBaB" +#define PAIR_SET_LONG_PATTERN_AB "u0u1u2u3u4u5u6u7aB" + +#define PATTERN_ARRAY_CONTAIN_EMPTY_0 {""} +#define PATTERN_ARRAY_SINGLE_CHAR_PAT_1 {"a"} +#define PATTERN_ARRAY_SINGLE_PAT_5 {"aBcde"} +#define PATTERN_ARRAY_GENERAL_5_5 {"aBcde","fghij"} +#define PATTERN_ARRAY_GENERAL_5_DUPLICATE {"aBcde","aBcde"} +#define PATTERN_ARRAY_LONG_10_10 {"aBcdeoAbCD","muz,crhUqu"} +#define PATTERN_ARRAY_CONTAIN_NULLPTR_5_0 {"aBcde",nullptr} +#define PATTERN_ARRAY_CONTAIN_EMPTY_0 {""} +#define PATTERN_ARRAY_WITH_NULL_5_5 {"a\0Bcd","aBcde"} +#define PATTERN_ARRAY_OVERLAP_5_8 {"aBcde","cdeoAbCD"} +#define PATTERN_ARRAY_NULLPTR ((char**)nullptr) + +// ----------------------------------------------------------------------------- + +#define EXPR_NOISE_LEN 32 +#define EXPR_NOISE "zmeh vnMezr,xbzumefnvqmuz,crhUqu" +#define EXPR_NOISE_0 "aBcdeoAbCDr,xbzumefnvqmuz,crhUqu" +#define EXPR_NOISE_5 "zmeh aBcdeoAbCDumefnvqmuz,crhUqu" +#define EXPR_NOISE_5_NULL "zmeh a\0Bcdr,xbzumefnvqmuz,crhUqu" +#define EXPR_NOISE_5_15 "zmeh aBcdeoAbCDaBcdeoAbCD,crhUqu" +#define EXPR_NOISE_5_15_BAD_CASE "zmeh AbcdeoAbCDABcdeoAbCD,crhUqu" +#define EXPR_NOISE_MIX "zmeh fgcder,xbzumefnvqmuz,crhUqu" +#define EXPR_NOISE_PAT2_5 "zmeh fghijr,xbzumefnvqmuz,crhUqu" +#define EXPR_NOISE_DUO_5_15 "zmeh aBcdeoAbCDfghijvqmuz,crhUqu" +#define EXPR_NOISE_SHORT_ONLY_5 "zmeh aBcdeoAbHHumefnvqmuz,crhUqu" +#define EXPR_NOISE_5_AB "zmeh aBMezr,xbzumefnvqmuz,crhUqu" + +#define EXPR_NOISE_A_END_31 "zmeh vnMezr,xbzumefnvqmuz,crhUqa" +#define EXPR_NOISE_AB_END_30 "zmeh vnMezr,xbzumefnvqmuz,crhUaB" +#define EXPR_NOISE_ABCDE_END_27 "zmeh vnMezr,xbzumefnvqmuz,caBcde" +#define EXPR_NOISE_ABCDEOABCD_END_22 "zmeh vnMezr,xbzumefnvqaBcdeoAbCD" + +#define EXPR_UNIFORM_LEN 32 +#define EXPR_UNIFORM "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu" +#define EXPR_UNIFORM_1_A "uuuuuauuuuuuuuuuuuuuuuuuuuuuuuuu" +#define EXPR_UNIFORM_1_B "uuuuuBuuuuuuuuuuuuuuuuuuuuuuuuuu" + +// ----------------------------------------------------------------------------- + +#define BRACED_INIT_LIST(...) {__VA_ARGS__} + +#define EXPECT_COMPILE_SUCCESS(func_name) \ + EXPECT_EQ(compile_ret, HS_SUCCESS) \ + << "Fail to build the pattern in " << (func_name) << "\n"; \ + EXPECT_NE(database, nullptr) \ + << "Compilation returned nullptr database " << (func_name) << "\n"; + +#define EXPECT_COMPILE_FAILURE(func_name) \ + EXPECT_NE(compile_ret, HS_SUCCESS) \ + << "Pattern built fine when error was expected in " << (func_name) \ + << "\n"; + +#define ASSERT_COMPILE_SUCCESS(func_name) \ + ASSERT_EQ(compile_ret, HS_SUCCESS) \ + << "Fail to build the pattern in " << (func_name) << "\n"; \ + ASSERT_NE(database, nullptr) \ + << "Compilation returned nullptr database " << (func_name) << "\n"; + +#define ASSERT_COMPILE_FAILURE(func_name) \ + ASSERT_NE(compile_ret, HS_SUCCESS) \ + << "Pattern built fine when error was expected in " << (func_name) \ + << "\n"; + +#define EXPECT_SEARCH_SUCCESS(search_func_name, pattern, buffer) \ + EXPECT_EQ(HS_SUCCESS, ret) \ + << (search_func_name) << ", pattern: " << (pattern) << ", buffer: \"" \ + << (buffer) << "\"\n Search failed"; \ + EXPECT_EQ(context.array_size, context.number_matched) \ + << (search_func_name) << ", pattern: " << (pattern) << ", buffer: \"" \ + << (buffer) << "\"\n Missed some matches.\n"; \ + EXPECT_LE(0, context.number_wrong) \ + << (search_func_name) << ", pattern: " << (pattern) << ", buffer: \"" \ + << (buffer) << "\"\n Unexpected matches.\n"; + +// ----------------------------------------------------------------------------- + +typedef struct callback_context { + /* array of indices in the string where we expect match to start*/ + size_t *expected_start_array; + /* array of indices in the string where we expect match to end*/ + size_t *expected_end_array; + /* array of pattern ID we expect match to be reported, in order */ + size_t *expected_id_array; + size_t array_size; + /* counter of matches happening at a position in expected_array */ + size_t number_matched; + /* counter of matches happening at a position NOT in expected_array */ + size_t number_wrong; +} context_t; + +static +int callback(unsigned int id, unsigned long long start, + unsigned long long end_offset, unsigned int flags, + void *raw_context) { + (void)flags; + context_t *context = reinterpret_cast(raw_context); + bool matched = false; + // Check if the match is expected + for (size_t i = 0; i < context->array_size; i++) { + if (end_offset == context->expected_end_array[i] && + start == context->expected_start_array[i] && + id == context->expected_id_array[i]) { + matched = true; + } + } + // Tally the right counter whether the match was expected or not + if (matched) { + context->number_matched += 1; + // printf("match at index %llu\n", end_offset); + } else { + context->number_wrong += 1; + // printf("unplanned match at index %llu\n", end_offset); + } + return CB_CONTINUE_MATCHING; +} + +static std::unordered_set alloced_mem; + +static void* test_malloc(size_t size) { + void * mem = malloc(size); + alloced_mem.insert(mem); + return mem; +} + +static void test_free(void *ptr) { + size_t erased_count = alloced_mem.erase(ptr); + if(erased_count == 1) { + free(ptr); + } else { + printf("all currently allocated memory:\n"); + for (const void *elem : alloced_mem) + printf("%p ", elem); + printf("\nTrying to free: %p\n", ptr); + FAIL(); + } +} + +#define SETUP_MEM_LEAK_TEST() hs_set_allocator(test_malloc, test_free); +#define UNSET_MEM_LEAK_TEST() hs_set_allocator(nullptr, nullptr); +#define EXPECT_MEMORY_CLEAN() \ + EXPECT_TRUE(alloced_mem.empty()); \ + alloced_mem.clear(); + +#endif // COMMON_H diff --git a/unit/direct_API/long_literal.cpp b/unit/direct_API/long_literal.cpp new file mode 100644 index 00000000..31bace2f --- /dev/null +++ b/unit/direct_API/long_literal.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#include "fdr/fdr_internal.h" + +#define COMPILE_LONG_LITERAL(in_pattern, in_pattern_len) \ + size_t pattern_len = (in_pattern_len); \ + const char *pattern = (in_pattern); \ + hs_long_literal_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = \ + hs_compile_long_literal_search(pattern, pattern_len, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +// expected match array here is the index of the start of match. +#define SEARCH_LONG_LITERAL(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match]; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += pattern_len; \ + expected_id_array[i] = 0; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_long_literal_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +static_assert(HS_SHORT_PATTERN_THRESHOLD == 8, + "changing the threshold for short/long literal require changing " + "the tests to still test the threshold behavior"); + +// ------------------------free tests------------------------------------------- + +/* +hs_free_long_literal_pattern + nullptr + general +*/ + +TEST(long_literal_free, nullptr) { + hs_long_literal_compiled_pattern_t *database = nullptr; + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_free, general) { + SETUP_MEM_LEAK_TEST(); + combined_fdr_database *clear_database = + reinterpret_cast( + test_malloc(sizeof(combined_fdr_database))); + + hs_long_literal_compiled_pattern_t *database = + reinterpret_cast(clear_database); + + hs_free_long_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_long_literal_search + <=8 char + general (>8 char) + valid pattern including null char + + empty expression + nullptr expression + nullptr output +*/ + +TEST(long_literal_compile, short) { + COMPILE_LONG_LITERAL(PATTERN_5_CHAR, 5); + hs_free_long_literal_pattern(database); + EXPECT_COMPILE_SUCCESS("test_compile_long_literal_general"); +} + +TEST(long_literal_compile, general) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + hs_free_long_literal_pattern(database); + EXPECT_COMPILE_SUCCESS("test_compile_long_literal_general"); +} + +TEST(long_literal_compile, null_char) { + COMPILE_LONG_LITERAL(PATTERN_5_WITH_NULL, 5); + hs_free_long_literal_pattern(database); + EXPECT_COMPILE_SUCCESS("test_compile_long_literal_null_char"); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(long_literal_compile, empty_pattern) { + hs_long_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH( + hs_compile_long_literal_search(PATTERN_0_CHAR, 0, &database), + "called with an empty pattern"); +} + +TEST(long_literal_compile, nullptr_pattern) { + hs_long_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_long_literal_search(nullptr, 5, &database), + "called with nullptr"); +} + +TEST(long_literal_compile, nullptr_database) { + EXPECT_DEATH(hs_compile_long_literal_search(PATTERN_5_CHAR, 5, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_long_literal_search + short pattern + positive match + negative match + general pattern + general pattern but the buffer only have the short part of it + extra long pattern (vectorized confirm) + match at start + match middle (general) + match index 15 (cross over vector) + match at end + match past end (a few char ok, then end, so missing some chars) + bad caseness + search several times + single char pattern + general match + match at end + no match + buffer containing null char + pattern with null char + general pattern (no null char searched for) + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(long_literal_search, short_positive) { + COMPILE_LONG_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_general"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, short_negative) { + COMPILE_LONG_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_general"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, short_but_negative_long) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_short_but_negative_long"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE_SHORT_ONLY_5, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, start) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_start"); + SEARCH_LONG_LITERAL(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_general"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(long_literal_search, extra_long) { + COMPILE_LONG_LITERAL(PATTERN_25_CHAR, 25); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_extra_long"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, cross_vector) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_cross_vector"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, end) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_end"); + SEARCH_LONG_LITERAL(EXPR_NOISE_ABCDEOABCD_END_22, EXPR_NOISE_LEN, 1, (22)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, past_end) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE_ABCDEOABCD_END_22, EXPR_NOISE_LEN - 3, 0, + ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, bad_case) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, several_search) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_several_search"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + SEARCH_LONG_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, single_char) { + COMPILE_LONG_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_single_char"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, single_char_end) { + COMPILE_LONG_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_single_char_end"); + SEARCH_LONG_LITERAL(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 1, (30)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, single_char_no_match) { + COMPILE_LONG_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_single_char_no_match"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, null_char_buff_and_pattern) { + COMPILE_LONG_LITERAL(PATTERN_5_WITH_NULL, 5); + ASSERT_COMPILE_SUCCESS( + "test_long_literal_search_null_char_buff_and_pattern"); + SEARCH_LONG_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, null_char_buff) { + COMPILE_LONG_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_null_char_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +TEST(long_literal_search, empty_buff) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_LONG_LITERAL("", 0, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_long_literal_search", pattern, buffer); + hs_free_long_literal_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(long_literal_search, nullptr_pattern) { + const hs_long_literal_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + size_t pattern_len = 5; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_LONG_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr database"); +} + +TEST(long_literal_search, nullptr_buffer) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_LONG_LITERAL(nullptr, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr buffer"); +} + +TEST(long_literal_search, nullptr_callback) { + COMPILE_LONG_LITERAL(PATTERN_10_CHAR, 10); + ASSERT_COMPILE_SUCCESS("test_long_literal_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += pattern_len; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_long_literal_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/main.cpp b/unit/direct_API/main.cpp new file mode 100644 index 00000000..7a504574 --- /dev/null +++ b/unit/direct_API/main.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" + +// Driver: run all the tests (defined in other source files in this directory) +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/unit/direct_API/multi_literal.cpp b/unit/direct_API/multi_literal.cpp new file mode 100644 index 00000000..aa0797d2 --- /dev/null +++ b/unit/direct_API/multi_literal.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#include "fdr/fdr_internal.h" + +#define COMPILE_MULTI_LITERAL(in_pattern, in_pattern_count, in_pattern_len) \ + const size_t pattern_count = (in_pattern_count); \ + size_t pattern_len[pattern_count] = BRACED_INIT_LIST in_pattern_len; \ + const char *pattern_storage[] = in_pattern; \ + const char **pattern = pattern_storage; \ + hs_multi_literal_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = hs_compile_multi_literal_search( \ + pattern, pattern_count, pattern_len, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +// expected match array here is the index of the start of match, assuming it +// match a pattern with the same length as pattern 0 +#define SEARCH_MULTI_LITERAL(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array, in_expected_id_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match] = \ + BRACED_INIT_LIST in_expected_id_array; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += pattern_len[0]; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_multi_literal_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +// ------------------------free tests------------------------------------------- + +/* +hs_free_multi_literal_pattern + nullptr + general +*/ + +TEST(multi_literal_free, nullptr) { + hs_multi_literal_compiled_pattern_t *database = nullptr; + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_free, general) { + SETUP_MEM_LEAK_TEST(); + combined_fdr_database *clear_database = + reinterpret_cast( + test_malloc(sizeof(combined_fdr_database))); + + hs_multi_literal_compiled_pattern_t *database = + reinterpret_cast(clear_database); + + hs_free_multi_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_multi_literal_search + single expression + single char expression + general (several expressions) + pattern duplicate + valid pattern including null char + overlaping patterns (eg, "abba" and "bb") + + no expressions + empty expression + nullptr expression array + one of the expression is nullptr + nullptr output +*/ + +TEST(multi_literal_compile, single_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_SINGLE_PAT_5, 1, (5)); + EXPECT_COMPILE_SUCCESS("test_compile_multi_literal_single_pattern"); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_compile, single_pattern_single_char) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_SINGLE_CHAR_PAT_1, 1, (1)); + EXPECT_COMPILE_SUCCESS( + "test_compile_multi_literal_single_pattern_single_char"); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_compile, general) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + EXPECT_COMPILE_SUCCESS("test_compile_multi_literal_general"); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_compile, duplicate) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_DUPLICATE, 2, (5, 5)); + EXPECT_COMPILE_SUCCESS("test_compile_multi_literal_duplicate"); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_compile, with_null_char) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_WITH_NULL_5_5, 2, (5, 5)); + EXPECT_COMPILE_SUCCESS("test_compile_multi_literal_with_null_char"); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_compile, overlapping_patterns) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_OVERLAP_5_8, 2, (5, 8)); + EXPECT_COMPILE_SUCCESS("test_compile_multi_literal_overlapping_patterns"); + hs_free_multi_literal_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(multi_literal_compile, no_expression) { + const size_t pattern_count = 0; + const char *pattern_storage[] = PATTERN_ARRAY_GENERAL_5_5; + const char **pattern = pattern_storage; + hs_multi_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH( + { + size_t pattern_len[2]; + pattern_len[0] = 5; + pattern_len[1] = 5; + hs_compile_multi_literal_search(pattern, pattern_count, pattern_len, + &database); + }, + "called with no pattern"); +} + +TEST(multi_literal_compile, empty_expression) { + const size_t pattern_count = 1; + const size_t pattern_len[pattern_count] = {0}; + const char *pattern_storage[] = PATTERN_ARRAY_CONTAIN_EMPTY_0; + const char **pattern = pattern_storage; + hs_multi_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_multi_literal_search(pattern, pattern_count, + pattern_len, &database), + "called with an empty pattern"); +} + +TEST(multi_literal_compile, nullptr_pattern_array) { + const size_t pattern_count = 1; + const size_t pattern_len[pattern_count] = {5}; + const char **pattern = nullptr; + hs_multi_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_multi_literal_search(pattern, pattern_count, + pattern_len, &database), + "called with nullptr"); +} + +TEST(multi_literal_compile, nullptr_pattern_in_array) { + const size_t pattern_count = 2; + const size_t pattern_len[pattern_count] = {5, 5}; + const char *pattern_storage[] = PATTERN_ARRAY_CONTAIN_NULLPTR_5_0; + const char **pattern = pattern_storage; + hs_multi_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_multi_literal_search(pattern, pattern_count, + pattern_len, &database), + "called with an empty pattern"); +} + +TEST(multi_literal_compile, nullptr_database) { + const size_t pattern_count = 2; + const size_t pattern_len[pattern_count] = {5, 5}; + const char *pattern_storage[] = PATTERN_ARRAY_GENERAL_5_5; + const char **pattern = pattern_storage; + EXPECT_DEATH(hs_compile_multi_literal_search(pattern, pattern_count, + pattern_len, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_multi_literal_search + general pattern + match at start + match middle (general) + match index 15 (cross over vector) + match at end + match past end (a few char ok, then end, so missing some chars) + match long patterns + long pattern but the buffer only have the short part of it + bad caseness + search several times + match first pattern + match last pattern + match several pattern in the same search + match overlapping patterns + pattern mix (start with pattern A, finish with pattern B. Expect no +match) + match a pattern duplicate + single char pattern + general match + match at end + no match + buffer containing null char + pattern with null char + general pattern (no null char searched for) + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(multi_literal_search, start) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_start"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_general"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(multi_literal_search, cross_vector) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_cross_vector"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15), (0, 0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, end) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_end"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_ABCDE_END_27, EXPR_NOISE_LEN, 1, (27), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, past_end) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL(EXPR_NOISE_ABCDE_END_27, EXPR_NOISE_LEN - 3, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, long_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_LONG_10_10, 2, (10, 10)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_long_pattern"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 2, (5, 22), (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, short_but_negative_long) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_LONG_10_10, 2, (10, 10)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_short_but_negative_long"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_SHORT_ONLY_5, EXPR_NOISE_LEN, 1, (22), (1)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[1], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, bad_case) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, several_search) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_several_search"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15), (0, 0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, first_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_first_pattern"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, last_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_last_pattern"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_PAT2_5, EXPR_NOISE_LEN, 1, (5), (1)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[1], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, multi_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_multi_pattern"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_DUO_5_15, EXPR_NOISE_LEN, 2, (5, 15), + (0, 1)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, overlap) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_OVERLAP_5_8, 2, (5, 8)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_overlap"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 2; + size_t expected_start_array[expected_match] = {5, 7}; + size_t expected_end_array[expected_match] = {5, 7}; + size_t expected_id_array[expected_match] = {0, 1}; + for (size_t i = 0; i < expected_match; i++) { + // we need the length of the second pattern, hence not using the macro + expected_end_array[i] += pattern_len[i]; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.expected_id_array = expected_id_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + ret = hs_multi_literal_search(database, buffer, buffer_len, + callback, &context); + + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, pattern_mix) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_pattern_mix"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL(EXPR_NOISE_MIX, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, duplicate) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_DUPLICATE, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_duplicate"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, single_char) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_SINGLE_CHAR_PAT_1, 1, (1)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_single_char"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15), (0, 0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, single_char_end) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_SINGLE_CHAR_PAT_1, 1, (1)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_single_char_end"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 1, (30), + (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, single_char_no_match) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_SINGLE_CHAR_PAT_1, 1, (1)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_single_char_no_match"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL(EXPR_NOISE, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, null_char_buff_and_pattern) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_WITH_NULL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS( + "test_multi_literal_search_null_char_buff_and_pattern"); + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5), (0)); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, null_char_buff) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_null_char_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +TEST(multi_literal_search, empty_buff) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_MULTI_LITERAL("", 0, 0, (), ()); + EXPECT_SEARCH_SUCCESS("hs_multi_literal_search", pattern[0], buffer); + hs_free_multi_literal_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(multi_literal_search, nullptr_pattern) { + const hs_multi_literal_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + size_t pattern_len[2]; + pattern_len[0] = 5; + pattern_len[1] = 5; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_MULTI_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr database"); +} + +TEST(multi_literal_search, nullptr_buffer) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_MULTI_LITERAL(nullptr, EXPR_NOISE_LEN, 0, (), ()); + }, + "called with nullptr buffer"); +} + +TEST(multi_literal_search, nullptr_callback) { + COMPILE_MULTI_LITERAL(PATTERN_ARRAY_GENERAL_5_5, 2, (5, 5)); + ASSERT_COMPILE_SUCCESS("test_multi_literal_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += pattern_len[0]; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_multi_literal_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/short_literal.cpp b/unit/direct_API/short_literal.cpp new file mode 100644 index 00000000..016a3dec --- /dev/null +++ b/unit/direct_API/short_literal.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "direct_API/common.h" + +#include "hwlm/noodle_internal.h" + +#define COMPILE_SHORT_LITERAL(in_pattern, in_pattern_len) \ + size_t pattern_len = (in_pattern_len); \ + const char *pattern = (in_pattern); \ + hs_short_literal_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = \ + hs_compile_short_literal_search(pattern, pattern_len, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +// expected match array here is the index of the start of match. +#define SEARCH_SHORT_LITERAL(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match]; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += pattern_len; \ + expected_id_array[i] = 0; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_short_literal_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +static_assert(HS_SHORT_PATTERN_THRESHOLD == 8, + "changing the threshold for short/long literal require changing " + "the tests to still test the threshold behavior"); + +// ------------------------free tests------------------------------------------- + +/* +hs_free_short_literal_pattern + nullptr + general +*/ + +TEST(short_literal_free, nullptr) { + hs_short_literal_compiled_pattern_t *database = nullptr; + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_free, general) { + SETUP_MEM_LEAK_TEST(); + noodTable *clear_database = + reinterpret_cast(test_malloc(sizeof(noodTable))); + hs_short_literal_compiled_pattern_t *database = + reinterpret_cast( + clear_database); + + hs_free_short_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_short_literal_search + single char + general + 8 char + >8 char + valid pattern including null char + empty expression + nullptr expression + nullptr output +*/ + +TEST(short_literal_compile, single_char) { + COMPILE_SHORT_LITERAL(PATTERN_1_CHAR, 1); + EXPECT_COMPILE_SUCCESS("test_compile_short_literal_single_char"); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_compile, general) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + EXPECT_COMPILE_SUCCESS("test_compile_short_literal_general"); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_compile, max_length) { + COMPILE_SHORT_LITERAL(PATTERN_8_CHAR, 8); + EXPECT_COMPILE_SUCCESS("test_compile_short_literal_max_len"); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_compile, too_long) { + COMPILE_SHORT_LITERAL(PATTERN_10_CHAR, 10); + EXPECT_COMPILE_FAILURE("test_compile_short_literal_too_long"); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_compile, null_char) { + COMPILE_SHORT_LITERAL(PATTERN_5_WITH_NULL, 5); + EXPECT_COMPILE_SUCCESS("test_compile_short_literal_null_char"); + hs_free_short_literal_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(short_literal_compile, empty_pattern) { + hs_short_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH( + hs_compile_short_literal_search(PATTERN_0_CHAR, 0, &database), + "called with an empty pattern"); +} + +TEST(short_literal_compile, nullptr_pattern) { + hs_short_literal_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_short_literal_search(nullptr, 5, &database), + "called with nullptr"); +} + +TEST(short_literal_compile, nullptr_database) { + EXPECT_DEATH(hs_compile_short_literal_search(PATTERN_5_CHAR, 5, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_short_literal_search + general pattern + match at start + match middle (general) + match index 15 (noodle cross over vector) + match at end + match the full pattern, not just the first pair + match past end (2 char ok, then end, so missing some chars) + bad caseness + search several times + single char pattern + general match + match at end + no match + buffer containing null char + pattern with null char + general pattern + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(short_literal_search, start) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_start"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_general"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(short_literal_search, cross_vector) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_cross_vector"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, end) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_end"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_ABCDE_END_27, EXPR_NOISE_LEN, 1, (27)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, past_end) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL(EXPR_NOISE_ABCDE_END_27, EXPR_NOISE_LEN - 3, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, short_no_match) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_short_no_match"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_AB, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, bad_case) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, several_search) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_several_search"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + // cppcheck-suppress redundantAssignment + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, single_char) { + COMPILE_SHORT_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_single_char"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, single_char_end) { + COMPILE_SHORT_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_single_char_end"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 1, (30)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, single_char_no_match) { + COMPILE_SHORT_LITERAL(PATTERN_1_CHAR, 1); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_single_char_no_match"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL(EXPR_NOISE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, null_char_buff_and_pattern) { + COMPILE_SHORT_LITERAL(PATTERN_5_WITH_NULL, 5); + ASSERT_COMPILE_SUCCESS( + "test_short_literal_search_null_char_buff_and_pattern"); + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, null_char_buff) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_null_char_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +TEST(short_literal_search, empty_buff) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SHORT_LITERAL("", 0, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_short_literal_search", pattern, buffer); + hs_free_short_literal_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(short_literal_search, nullptr_pattern) { + const hs_short_literal_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + size_t pattern_len = 5; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SHORT_LITERAL(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr database"); +} + +TEST(short_literal_search, nullptr_buffer) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SHORT_LITERAL(nullptr, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr buffer"); +} + +TEST(short_literal_search, nullptr_callback) { + COMPILE_SHORT_LITERAL(PATTERN_5_CHAR, 5); + ASSERT_COMPILE_SUCCESS("test_short_literal_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += pattern_len; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_short_literal_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/single_char.cpp b/unit/direct_API/single_char.cpp new file mode 100644 index 00000000..a9ec0d68 --- /dev/null +++ b/unit/direct_API/single_char.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#include "hwlm/noodle_internal.h" + +#define COMPILE_SINGLE_CHAR(in_pattern) \ + const char pattern = *(in_pattern); \ + hs_single_char_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = hs_compile_single_char_search(pattern, &database);\ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +// expected match array here is the index of the start of match. +#define SEARCH_SINGLE_CHAR(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match]; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += 1; \ + expected_id_array[i] = 0; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_single_char_search(database, buffer, buffer_len, callback, \ + &context); \ + } + +// ------------------------free tests------------------------------------------- + +/* +hs_free_single_char_pattern + nullptr + general +*/ + +TEST(single_char_free, nullptr) { + hs_single_char_compiled_pattern_t *database = nullptr; + hs_free_single_char_pattern(database); +} + +TEST(single_char_free, general) { + SETUP_MEM_LEAK_TEST(); + truffle_storage *clear_database = reinterpret_cast( + test_malloc(sizeof(truffle_storage))); + hs_single_char_compiled_pattern_t *database = + reinterpret_cast(clear_database); + + hs_free_single_char_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_single_char_search + general (1 char) + null char pattern + + nullptr output +*/ + +TEST(single_char_compile, general) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR) + EXPECT_COMPILE_SUCCESS("test_compile_single_char_general") + hs_free_single_char_pattern(database); +} + +TEST(single_char_compile, null_char) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR) + EXPECT_COMPILE_SUCCESS("test_compile_single_char_null_char") + hs_free_single_char_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(single_char_compile, nullptr_database) { + EXPECT_DEATH(hs_compile_single_char_search(*PATTERN_1_CHAR, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_single_char_search + general pattern + match at start + match middle (general) + match vector end + match at buffer end + match past end + bad caseness + search several times + buffer containing null char + null char pattern + general pattern + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(single_char_search, start) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_start"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_general"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(single_char_search, end_vector) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_end_vector"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, end) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_end"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_A_END_31, EXPR_NOISE_LEN, 1, (31)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, past_end) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR(EXPR_NOISE_A_END_31, EXPR_NOISE_LEN - 1, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, bad_case) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, several_search) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_several_search"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, null_char_buff_and_pattern) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR_NULL); + ASSERT_COMPILE_SUCCESS( + "test_single_char_search_null_char_buff_and_pattern"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (6)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, null_char_buff) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_null_char_buff"); + SEARCH_SINGLE_CHAR(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +TEST(single_char_search, empty_buff) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR("", 0, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_search", pattern, buffer); + hs_free_single_char_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(single_char_search, nullptr_pattern) { + const hs_single_char_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SINGLE_CHAR(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr database"); +} + +TEST(single_char_search, nullptr_buffer) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SINGLE_CHAR(nullptr, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr buffer"); +} + +TEST(single_char_search, nullptr_callback) { + COMPILE_SINGLE_CHAR(PATTERN_1_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += 1; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_single_char_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif diff --git a/unit/direct_API/single_char_pair.cpp b/unit/direct_API/single_char_pair.cpp new file mode 100644 index 00000000..10307743 --- /dev/null +++ b/unit/direct_API/single_char_pair.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2024-2025, Arm ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +#include "hwlm/noodle_internal.h" + +#define COMPILE_SINGLE_CHAR_PAIR(in_pattern) \ + const char *pattern = (in_pattern); \ + hs_single_char_pair_compiled_pattern_t *database = nullptr; \ + hs_error_t compile_ret = \ + hs_compile_single_char_pair_search(pattern, &database); \ + hs_error_t ret = 0; \ + (void)ret; /* suppress a cppcheck warning when SEARCH is not called */ \ + const char *buffer = nullptr; \ + (void)buffer; \ + context_t context = {}; \ + (void) context; + +// expected match array here is the index of the start of match. +#define SEARCH_SINGLE_CHAR_PAIR(in_buffer, in_buffer_len, in_expected_match, \ + in_expected_start_array) \ + { \ + buffer = (in_buffer); \ + const size_t buffer_len = (in_buffer_len); \ + const size_t expected_match = (in_expected_match); \ + size_t expected_start_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_end_array[expected_match] = \ + BRACED_INIT_LIST in_expected_start_array; \ + size_t expected_id_array[expected_match]; \ + for (size_t i = 0; i < expected_match; i++) { \ + expected_end_array[i] += 2; \ + expected_id_array[i] = 0; \ + } \ + context.expected_start_array = expected_start_array; \ + context.expected_end_array = expected_end_array; \ + context.expected_id_array = expected_id_array; \ + context.array_size = expected_match; \ + context.number_matched = 0; \ + context.number_wrong = 0; \ + \ + ret = hs_single_char_pair_search(database, buffer, buffer_len, \ + callback, &context); \ + } + +// ------------------------free tests------------------------------------------- + +/* +hs_free_single_char_pair_pattern + nullptr + general +*/ + +TEST(single_char_pair_free, nullptr) { + hs_single_char_pair_compiled_pattern_t *database = nullptr; + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_free, general) { + SETUP_MEM_LEAK_TEST(); + noodTable *clear_database = + reinterpret_cast(test_malloc(sizeof(noodTable))); + hs_single_char_pair_compiled_pattern_t *database = + reinterpret_cast( + clear_database); + + hs_free_single_char_pair_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +// ------------------------compile tests---------------------------------------- + +/* +hs_compile_single_char_pair_search + general (2 char) + valid pattern including null char + + nullptr expression + nullptr output +*/ + +TEST(single_char_pair_compile, general) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR) + EXPECT_COMPILE_SUCCESS("test_compile_single_char_pair_general") + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_compile, with_null_char) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_WITH_NULL) + EXPECT_COMPILE_SUCCESS("test_compile_single_char_pair_with_null_char") + hs_free_single_char_pair_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(single_char_pair_compile, nullptr_pattern) { + hs_single_char_pair_compiled_pattern_t *database = nullptr; + EXPECT_DEATH(hs_compile_single_char_pair_search(nullptr, &database), + "called with nullptr"); +} + +TEST(single_char_pair_compile, nullptr_database) { + EXPECT_DEATH(hs_compile_single_char_pair_search(PATTERN_5_CHAR, nullptr), + "called with nullptr"); +} + +#endif + +// ------------------------search tests----------------------------------------- + +/* +hs_single_char_pair_search + general pattern + match at start + match middle (general) + match index 15 (cross over vector) + match at end + match past end (1 char ok, then end, so missing one chars) + bad caseness + search several times + buffer containing null char + pattern with null char + general pattern + buff size 0 + nullptr pattern + nullptr buffer + nullptr callback +*/ + +TEST(single_char_pair_search, start) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_start"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_0, EXPR_NOISE_LEN, 1, (0)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, general) { + SETUP_MEM_LEAK_TEST(); + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_general"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); + EXPECT_MEMORY_CLEAN(); + UNSET_MEM_LEAK_TEST(); +} + +TEST(single_char_pair_search, cross_vector) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_cross_vector"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, end) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_end"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN, 1, (30)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, past_end) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_past_end"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_AB_END_30, EXPR_NOISE_LEN - 1, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, bad_case) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_bad_case"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5_15_BAD_CASE, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, several_search) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_several_search"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5_15, EXPR_NOISE_LEN, 2, (5, 15)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, null_char_buff_and_pattern) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_WITH_NULL); + ASSERT_COMPILE_SUCCESS( + "test_single_char_pair_search_null_char_buff_and_pattern"); + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 1, (5)); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, null_char_buff) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_null_char_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5_NULL, EXPR_NOISE_LEN, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +TEST(single_char_pair_search, empty_buff) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_empty_buff"); + // cppcheck-suppress unsignedLessThanZero + SEARCH_SINGLE_CHAR_PAIR("", 0, 0, ()); + EXPECT_SEARCH_SUCCESS("hs_single_char_pair_search", pattern, buffer); + hs_free_single_char_pair_pattern(database); +} + +#if !defined(RELEASE_BUILD) +// test asserts + +TEST(single_char_pair_search, nullptr_pattern) { + const hs_single_char_pair_compiled_pattern_t *database = nullptr; + context_t context; + EXPECT_DEATH( + { + const char *buffer; + hs_error_t ret; + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SINGLE_CHAR_PAIR(EXPR_NOISE_5, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr database"); +} + +TEST(single_char_pair_search, nullptr_buffer) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_nullptr_buffer"); + EXPECT_DEATH( + { + // cppcheck-suppress unsignedLessThanZero + // cppcheck-suppress unreadVariable + SEARCH_SINGLE_CHAR_PAIR(nullptr, EXPR_NOISE_LEN, 0, ()); + }, + "called with nullptr buffer"); +} + +TEST(single_char_pair_search, nullptr_callback) { + COMPILE_SINGLE_CHAR_PAIR(PATTERN_2_CHAR); + ASSERT_COMPILE_SUCCESS("test_single_char_pair_search_nullptr_callback"); + + buffer = EXPR_NOISE_5; + const size_t buffer_len = EXPR_NOISE_LEN; + const size_t expected_match = 1; + size_t expected_start_array[expected_match] = {5}; + size_t expected_end_array[expected_match] = {5}; + for (size_t i = 0; i < expected_match; i++) { + expected_end_array[i] += 2; + } + context.expected_start_array = expected_start_array; + context.expected_end_array = expected_end_array; + context.array_size = expected_match; + context.number_matched = 0; + context.number_wrong = 0; + + EXPECT_DEATH( + { + hs_single_char_pair_search(database, buffer, buffer_len, nullptr, + &context); + }, + "called with nullptr callback"); +} + +#endif