You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/util-unittest.c

349 lines
7.5 KiB
C

/* 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 pcre *parse_regex;
static pcre_extra *parse_regex_study;
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)
{
const char *eb;
int eo;
int opts = PCRE_CASELESS;;
if(regex_arg == NULL)
return -1;
parse_regex = pcre_compile(regex_arg, opts, &eb, &eo, NULL);
if(parse_regex == NULL)
{
printf("pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", regex_arg, eo, eb);
goto error;
}
parse_regex_study = pcre_study(parse_regex, 0, &eb);
if(eb != NULL)
{
printf("pcre study failed: %s\n", eb);
goto error;
}
return 1;
error:
return -1;
}
#define MAX_SUBSTRINGS 30
/** \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;
int ov[MAX_SUBSTRINGS];
rcomp = UtRegex(regex_arg);
for (ut = ut_list; ut != NULL; ut = ut->next) {
if (rcomp == 1) {
ret = pcre_exec(parse_regex, parse_regex_study, ut->name,
strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS);
if (ret >= 1) {
printf("%s\n", ut->name);
}
}
else {
printf("%s\n", ut->name);
}
}
}
/** \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;
int ov[MAX_SUBSTRINGS];
StreamTcpInitMemuse();
StreamTcpReassembleInitMemuse();
rcomp = UtRegex(regex_arg);
if(rcomp == 1){
for (ut = ut_list; ut != NULL; ut = ut->next) {
ret = pcre_exec(parse_regex, parse_regex_study, ut->name, strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS);
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");
}
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);
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 */
/**
* @}
*/