diff options
Diffstat (limited to 'src/util-unittest.c')
-rw-r--r-- | src/util-unittest.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/src/util-unittest.c b/src/util-unittest.c new file mode 100644 index 0000000..d4ef5dc --- /dev/null +++ b/src/util-unittest.c @@ -0,0 +1,345 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien <victor@inliniac.net> + * \author Breno Silva <breno.silva@gmail.com> + * + * Unit test framework + */ + +/** + * \defgroup Testing Testing + * + * \brief Unit testing support functions. + * + * @{ + */ + +#include "suricata-common.h" +#include "runmodes.h" +#include "util-unittest.h" +#include "util-debug.h" +#include "util-time.h" +#include "conf.h" + +#include "stream-tcp.h" +#include "stream-tcp-reassemble.h" + +#ifdef UNITTESTS + +static pcre2_code *parse_regex; +static pcre2_match_data *parse_regex_match; + +static UtTest *ut_list; + +int unittests_fatal = 0; + +/** + * \brief Allocate UtTest list member + * + * \retval ut Pointer to UtTest + */ + +static UtTest *UtAllocTest(void) +{ + UtTest *ut = SCMalloc(sizeof(UtTest)); + if (unlikely(ut == NULL)) + return NULL; + + memset(ut, 0, sizeof(UtTest)); + + return ut; +} + +/** + * \brief Append test in UtTest list + * + * \param list Pointer to the start of the IP packet + * \param test Pointer to unit test + * + * \retval 0 Function always returns zero + */ + +static int UtAppendTest(UtTest **list, UtTest *test) +{ + if (*list == NULL) { + *list = test; + } else { + UtTest *tmp = *list; + + while (tmp->next != NULL) { + tmp = tmp->next; + } + tmp->next = test; + } + + return 0; +} + +/** + * \brief Register unit test + * + * \param name Unit test name + * \param TestFn Unit test function + */ + +void UtRegisterTest(const char *name, int(*TestFn)(void)) +{ + UtTest *ut = UtAllocTest(); + if (ut == NULL) + return; + + ut->name = name; + ut->TestFn = TestFn; + ut->next = NULL; + + /* append */ + UtAppendTest(&ut_list, ut); +} + +/** + * \brief Compile a regex to run a specific unit test + * + * \param regex_arg The regular expression + * + * \retval 1 Regex compiled + * \retval -1 Regex error + */ +static int UtRegex (const char *regex_arg) +{ + int en; + PCRE2_SIZE eo; + int opts = PCRE2_CASELESS; + + if(regex_arg == NULL) + return -1; + + parse_regex = + pcre2_compile((PCRE2_SPTR8)regex_arg, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL); + if(parse_regex == NULL) + { + PCRE2_UCHAR errbuffer[256]; + pcre2_get_error_message(en, errbuffer, sizeof(errbuffer)); + SCLogError("pcre2 compile of \"%s\" failed at " + "offset %d: %s", + regex_arg, (int)eo, errbuffer); + goto error; + } + parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL); + + return 1; + +error: + return -1; +} + +/** \brief List all registered unit tests. + * + * \param regex_arg Regular expression to limit listed tests. + */ +void UtListTests(const char *regex_arg) +{ + UtTest *ut; + int ret = 0, rcomp = 0; + + rcomp = UtRegex(regex_arg); + + for (ut = ut_list; ut != NULL; ut = ut->next) { + if (rcomp == 1) { + ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, + parse_regex_match, NULL); + if (ret >= 1) { + printf("%s\n", ut->name); + } + } + else { + printf("%s\n", ut->name); + } + } + pcre2_code_free(parse_regex); + pcre2_match_data_free(parse_regex_match); +} + +/** \brief Run all registered unittests. + * + * \param regex_arg The regular expression + * + * \retval 0 all successful + * \retval result number of tests that failed + */ + +uint32_t UtRunTests(const char *regex_arg) +{ + UtTest *ut; + uint32_t good = 0, bad = 0, matchcnt = 0; + int ret = 0, rcomp = 0; + + StreamTcpInitMemuse(); + StreamTcpReassembleInitMemuse(); + + rcomp = UtRegex(regex_arg); + + if(rcomp == 1){ + for (ut = ut_list; ut != NULL; ut = ut->next) { + ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0, + parse_regex_match, NULL); + if( ret >= 1 ) { + printf("Test %-60.60s : ", ut->name); + matchcnt++; + fflush(stdout); /* flush so in case of a segv we see the testname */ + + /* reset the time */ + TimeModeSetOffline(); + TimeSetToCurrentTime(); + + ret = ut->TestFn(); + + if (StreamTcpMemuseCounter() != 0) { + printf("STREAM MEMORY IN USE %"PRIu64"\n", StreamTcpMemuseCounter()); + ret = 0; + } + if (FlowGetMemuse() != 0) { + printf("FLOW MEMORY IN USE %"PRIu64"\n", FlowGetMemuse()); + ret = 0; + } + + if (StreamTcpReassembleMemuseGlobalCounter() != 0) { + printf("STREAM REASSEMBLY MEMORY IN USE %"PRIu64"\n", StreamTcpReassembleMemuseGlobalCounter()); + ret = 0; + } + + printf("%s\n", ret ? "pass" : "FAILED"); + + if (!ret) { + if (unittests_fatal == 1) { + fprintf(stderr, "ERROR: unittest failed.\n"); + exit(EXIT_FAILURE); + } + bad++; + } else { + good++; + } + } + } + if(matchcnt > 0){ + printf("==== TEST RESULTS ====\n"); + printf("PASSED: %" PRIu32 "\n", good); + printf("FAILED: %" PRIu32 "\n", bad); + printf("======================\n"); + } else { + SCLogInfo("UtRunTests: regex provided regex_arg: %s did not match any tests",regex_arg); + } + } else { + SCLogInfo("UtRunTests: pcre compilation failed"); + } + pcre2_code_free(parse_regex); + pcre2_match_data_free(parse_regex_match); + return bad; +} +/** + * \brief Initialize unit test list + */ + +void UtInitialize(void) +{ + ut_list = NULL; +} + +/** + * \brief Cleanup unit test list + */ + +void UtCleanup(void) +{ + + UtTest *tmp = ut_list, *otmp; + + while (tmp != NULL) { + otmp = tmp->next; + SCFree(tmp); + tmp = otmp; + } + + ut_list = NULL; +} + +void UtRunModeRegister(void) +{ + RunModeRegisterNewRunMode(RUNMODE_UNITTEST, "unittest", "Unittest mode", NULL, NULL); + + return; +} + +/* + * unittests for the unittests code + */ + +/** \brief True test + * + * \retval 1 True + * \retval 0 False + */ +static int UtSelftestTrue(void) +{ + if (1)return 1; + else return 0; +} + +/** \brief False test + * + * \retval 1 False + * \retval 0 True + */ +static int UtSelftestFalse(void) +{ + if (0)return 0; + else return 1; +} + +/** \brief Run self tests + * + * \param regex_arg The regular expression + * + * \retval 0 all successful + */ + +int UtRunSelftest (const char *regex_arg) +{ + printf("* Running Unittesting subsystem selftests...\n"); + + UtInitialize(); + + UtRegisterTest("true", UtSelftestTrue); + UtRegisterTest("false", UtSelftestFalse); + + int ret = UtRunTests(regex_arg); + if (ret == 0) + printf("* Done running Unittesting subsystem selftests...\n"); + else + printf("* ERROR running Unittesting subsystem selftests failed...\n"); + + UtCleanup(); + return 0; +} +#endif /* UNITTESTS */ + +/** + * @} + */ |