Commit ec7ca51d authored by Gautier Pelloux-Prayer's avatar Gautier Pelloux-Prayer
Browse files

tester: use bctoolbox for utilities

parent 491ab7ec
......@@ -163,21 +163,6 @@ if(ENABLE_PCAP)
find_package(PCAP QUIET)
endif()
if(ENABLE_UNIT_TESTS)
find_package(CUnit)
if(CUNIT_FOUND)
cmake_push_check_state(RESET)
list(APPEND CMAKE_REQUIRED_INCLUDES ${CUNIT_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CUNIT_LIBRARIES})
check_symbol_exists("CU_get_suite" "CUnit/CUnit.h" HAVE_CU_GET_SUITE)
check_symbol_exists("CU_curses_run_tests" "CUnit/CUnit.h" HAVE_CU_CURSES)
cmake_pop_check_state()
else()
message(WARNING "Could not find the cunit library!")
set(ENABLE_UNIT_TESTS OFF CACHE BOOL "Enable compilation of unit tests." FORCE)
endif()
endif()
if(ENABLE_SRTP)
find_package(SRTP)
if(NOT SRTP_FOUND)
......
############################################################################
# FindCUnit.txt
# Copyright (C) 2015 Belledonne Communications, Grenoble France
#
############################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
############################################################################
#
# - Find the CUnit include file and library
#
# CUNIT_FOUND - system has CUnit
# CUNIT_INCLUDE_DIRS - the CUnit include directory
# CUNIT_LIBRARIES - The libraries needed to use CUnit
include(CheckIncludeFile)
include(CheckLibraryExists)
set(_CUNIT_ROOT_PATHS
${CMAKE_INSTALL_PREFIX}
)
find_path(CUNIT_INCLUDE_DIRS
NAMES CUnit/CUnit.h
HINTS _CUNIT_ROOT_PATHS
PATH_SUFFIXES include
)
if(CUNIT_INCLUDE_DIRS)
set(HAVE_CUNIT_CUNIT_H 1)
endif()
find_library(CUNIT_LIBRARIES
NAMES cunit
HINTS ${_CUNIT_ROOT_PATHS}
PATH_SUFFIXES bin lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CUnit
DEFAULT_MSG
CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES
)
mark_as_advanced(CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES)
......@@ -21,7 +21,6 @@
############################################################################
set(SOURCE_FILES_C
common/bc_tester_utils.c
mediastreamer2_adaptive_tester.c
mediastreamer2_audio_stream_tester.c
mediastreamer2_basic_audio_tester.c
......@@ -54,15 +53,14 @@ apply_compile_flags(SOURCE_FILES_OBJC "CPP" "OBJC")
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
add_library(mediastreamer2_tester_static STATIC ${SOURCE_FILES_C})
target_include_directories(mediastreamer2_tester_static PUBLIC ${CUNIT_INCLUDE_DIRS} PRIVATE common)
target_link_libraries(mediastreamer2_tester_static mediastreamer_voip mediastreamer_base ${CUNIT_LIBRARIES})
target_include_directories(mediastreamer2_tester_static PUBLIC ${BCTOOLBOX_INCLUDE_DIRS})
target_link_libraries(mediastreamer2_tester_static mediastreamer_voip mediastreamer_base ${BCTOOLBOX_LIBRARIES})
set(RUNTIME_COMPONENT_SOURCES
mediastreamer2_tester_windows.cpp
mediastreamer2_tester_windows.h
)
add_library(mediastreamer2_tester_runtime MODULE ${RUNTIME_COMPONENT_SOURCES})
target_include_directories(mediastreamer2_tester_runtime PRIVATE common)
target_include_directories(mediastreamer2_tester_runtime PRIVATE "../../../mswinrtvid") # HACK!!
target_link_libraries(mediastreamer2_tester_runtime mediastreamer2_tester_static)
set_target_properties(mediastreamer2_tester_runtime PROPERTIES VS_WINRT_COMPONENT TRUE)
......@@ -86,8 +84,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
else()
add_executable(mediastreamer2_tester ${SOURCE_FILES_C} ${SOURCE_FILES_OBJC})
target_include_directories(mediastreamer2_tester PUBLIC ${CUNIT_INCLUDE_DIRS} PRIVATE common)
target_link_libraries(mediastreamer2_tester mediastreamer_voip mediastreamer_base ${CUNIT_LIBRARIES})
target_include_directories(mediastreamer2_tester PUBLIC ${BCTOOLBOX_INCLUDE_DIRS})
target_link_libraries(mediastreamer2_tester mediastreamer_voip mediastreamer_base ${BCTOOLBOX_LIBRARIES})
string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}")
if(LINK_FLAGS_STR)
set_target_properties(mediastreamer2_tester PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}")
......
# Copyright (C) 2012 Belledonne Comunications, Grenoble, France
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Created by Gautier Pelloux-Prayer on 2014/10/24.
# This script adds auto-completion for liblinphone_tester binary for Bash and
# Zsh. To use it, just type: `source liblinphone_completion`, then for each
# supported exectuable (see end of file), you will get auto-completions.
# To use it permanently, source this file in your .rc file (.bashrc or .zshrc).
_liblinphone_complete() {
local completions command_requiring_argument prev_arg latest_arg available_tasks has_not_set_suite suite_name
if [ -n "$BASH_VERSION" ]; then
set -- "${COMP_WORDS[@]}" #convert them to arguments (eg $1,$#,$@,etc.)
elif [ -n "$ZSH_VERSION" ]; then
local args
read -cA args #read list of arguments user entered
set -- "${args[@]}" #convert them to arguments (eg $1,$#,$@,etc.)
fi
#skip program name
program=$1
shift
# if user required help, do not complete anything
if ! grep -q -- "--help" <<< "$@"; then
# retrieve the last argument
latest_arg=""
prev_arg=""
latest_is_empty=0
for arg in "$@"; do
if [ ! -z "$arg" ]; then
prev_arg="$latest_arg"
latest_arg="$arg"
else
latest_is_empty=1
fi
done
# get the tasks available, from --help
available_tasks="$($program 2>&1 --help | sed -nE "s/.*--([^ ]*).*/--\\1/p")"
# these commands expect an argument
command_requiring_argument="$($program 2>&1 --help | sed -nE "s/.*--(.*) <.*/--\\1/p")"
# remove all already provided tasks (it's useless to provide them twice)
if [[ ! -z "$@" ]]; then
current_tasks=$(echo $@ | grep -Eo -- "--([^ ])*" | tr '\n' '|' | sed 's/|/$|/g')--$
if [ ! -z "$current_tasks" ]; then
available_tasks=$(echo "$available_tasks" | grep -vE -- "(${current_tasks})")
fi
fi
# remove --test option if --suite is not provided yet!
has_not_set_suite=$(grep -q -- "--suite" <<< "$@"; echo $?)
if [ $has_not_set_suite = 1 ]; then
available_tasks=$(echo "$available_tasks" | grep -v -- --test)
fi
# if latest arg does not start with '--', it is a custom value
if [ $latest_is_empty = 0 ] && ! grep -q -- '^--' <<< "$latest_arg"; then
if [ "$prev_arg" = "--test" ] && [ $has_not_set_suite = 0 ]; then
suite_name=$(echo $@ | sed -nE 's/.*--suite ([^(--)]*) (--.*)$/\1/p' |sed "s@\\\\@@g")
completions="$($program --list-tests $suite_name)"
elif [ "$prev_arg" = "--suite" ] || [ "$prev_arg" = "--list-tests" ]; then
completions="$($program --list-suites)"
fi
elif [ "$latest_arg" = "--test" ]; then
# list available tests if --suite was provided
if [ $has_not_set_suite = 0 ]; then
suite_name=$(echo $@ | sed -nE 's/.*--suite ([^(--)]*) (--.*)/\1/p' |sed "s@\\\\@@g")
completions="$($program --list-tests $suite_name)"
fi
elif [ "$latest_arg" = "--suite" ] || [ "$latest_arg" = "--list-tests" ]; then
completions="$($program --list-suites)"
# we are waiting for a custom value, so do not hint anything
elif [[ ! -z "$latest_arg" ]] && grep -q -- "^$latest_arg$" <<< "$command_requiring_argument"; then
completions=""
else
completions="$available_tasks"
fi
fi
if [ ! -z "$completions" ]; then
if [ -n "$BASH_VERSION" ]; then
IFS=$'\n' #if that even necessary?
COMPREPLY=($(compgen -W "${completions}" -- ${COMP_WORDS[COMP_CWORD]}))
elif [ -n "$ZSH_VERSION" ]; then
reply=( "${(ps:\n:)completions}" )
fi
fi
}
for tester in liblinphone_tester mediastreamer2_tester belle_sip_tester pcap_playback \
bench mediastream msaudiocmp mtudiscover videodisplay linphone lpc2xml_test \
lp-gen-wrappers xml2lpc_test; do
if [ -n "$BASH_VERSION" ]; then
complete -F _liblinphone_complete $tester
elif [ -n "$ZSH_VERSION" ]; then
compctl -K _liblinphone_complete $tester
else
echo "Your shell might be not supported! Only bash and zsh tested."
fi
done
/*
tester - liblinphone test suite
Copyright (C) 2013 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
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
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* this must be provided at compile time*/
#include BC_CONFIG_FILE
#include "bc_tester_utils.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include "CUnit/Basic.h"
#include "CUnit/Automated.h"
#include "CUnit/MyMem.h"
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
#pragma GCC diagnostic pop
#endif
#ifdef _WIN32
#if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP)
#define BC_TESTER_WINDOWS_DESKTOP 1
#elif defined(WINAPI_FAMILY_PARTITION)
#if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#define BC_TESTER_WINDOWS_DESKTOP 1
#endif
#if defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
#define BC_TESTER_WINDOWS_PHONE 1
#endif
#if defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#define BC_TESTER_WINDOWS_UNIVERSAL 1
#endif
#endif
#endif
#ifdef __linux
/*for monitoring total space allocated via malloc*/
#include <malloc.h>
#endif
static char *bc_tester_resource_dir_prefix = NULL;
// by default writable will always write near the executable
static char *bc_tester_writable_dir_prefix = NULL;
static char *bc_current_suite_name = NULL;
static char *bc_current_test_name = NULL;
int bc_printf_verbosity_info;
int bc_printf_verbosity_error;
static test_suite_t **test_suite = NULL;
static int nb_test_suites = 0;
#ifdef HAVE_CU_CURSES
#include "CUnit/CUCurses.h"
static unsigned char curses = 0;
#endif
char* xml_file = "CUnitAutomated-Results.xml";
int xml_enabled = 0;
char * suite_name = NULL;
char * test_name = NULL;
char * tag_name = NULL;
static long max_vm_kb = 0;
void (*tester_printf_va)(int level, const char *format, va_list args);
void bc_tester_printf(int level, const char *format, ...) {
va_list args;
va_start (args, format);
tester_printf_va(level, format, args);
va_end (args);
}
int bc_tester_run_suite(test_suite_t *suite, const char *tag_name) {
int i;
CU_pSuite pSuite;
if (tag_name != NULL) {
int j;
int nb_tests_for_tag = 0;
for (i = 0; i < suite->nb_tests; i++) {
for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) {
if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) {
nb_tests_for_tag++;
}
}
}
if (nb_tests_for_tag > 0) {
pSuite = CU_add_suite(suite->name, suite->before_all, suite->after_all);
for (i = 0; i < suite->nb_tests; i++) {
for (j = 0; j < (sizeof(suite->tests[i].tags) / sizeof(suite->tests[i].tags[0])); j++) {
if ((suite->tests[i].tags[j] != NULL) && (strcasecmp(tag_name, suite->tests[i].tags[j]) == 0)) {
if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) {
return CU_get_error();
}
}
}
}
}
} else {
pSuite = CU_add_suite(suite->name, suite->before_all, suite->after_all);
for (i = 0; i < suite->nb_tests; i++) {
if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) {
return CU_get_error();
}
}
}
return 0;
}
const char * bc_tester_suite_name(int suite_index) {
if (suite_index >= nb_test_suites) return NULL;
return test_suite[suite_index]->name;
}
int bc_tester_suite_index(const char *suite_name) {
int i;
for (i = 0; i < nb_test_suites; i++) {
if (strcmp(suite_name, test_suite[i]->name) == 0) {
return i;
}
}
return -1;
}
int bc_tester_test_index(test_suite_t *suite, const char *test_name) {
int i;
for (i = 0; i < suite->nb_tests; i++) {
if (strcmp(test_name, suite->tests[i].name) == 0) {
return i;
}
}
return -1;
}
int bc_tester_nb_suites(void) {
return nb_test_suites;
}
const char * bc_tester_test_name(const char *suite_name, int test_index) {
int suite_index = bc_tester_suite_index(suite_name);
if ((suite_index < 0) || (suite_index >= nb_test_suites)) return NULL;
if (test_index >= test_suite[suite_index]->nb_tests) return NULL;
return test_suite[suite_index]->tests[test_index].name;
}
int bc_tester_nb_tests(const char *suite_name) {
int i = bc_tester_suite_index(suite_name);
if (i < 0) return 0;
return test_suite[i]->nb_tests;
}
void bc_tester_list_suites(void) {
int j;
for(j=0;j<nb_test_suites;j++) {
bc_tester_printf(bc_printf_verbosity_info, "%s", bc_tester_suite_name(j));
}
}
void bc_tester_list_tests(const char *suite_name) {
int j;
for( j = 0; j < bc_tester_nb_tests(suite_name); j++) {
const char *test_name = bc_tester_test_name(suite_name, j);
bc_tester_printf(bc_printf_verbosity_info, "%s", test_name);
}
}
static void all_complete_message_handler(const CU_pFailureRecord pFailure) {
#ifdef HAVE_CU_GET_SUITE
char * results = CU_get_run_results_string();
bc_tester_printf(bc_printf_verbosity_info,"\n%s",results);
CU_FREE(results);
#endif
}
static void suite_init_failure_message_handler(const CU_pSuite pSuite) {
bc_tester_printf(bc_printf_verbosity_error,"Suite initialization failed for [%s]", pSuite->pName);
}
static void suite_cleanup_failure_message_handler(const CU_pSuite pSuite) {
bc_tester_printf(bc_printf_verbosity_error,"Suite cleanup failed for [%s]", pSuite->pName);
}
#ifdef HAVE_CU_GET_SUITE
static time_t suite_start_time = 0;
static void suite_start_message_handler(const CU_pSuite pSuite) {
bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] started\n", pSuite->pName);
suite_start_time = time(NULL);
bc_current_suite_name = pSuite->pName;
}
static void suite_complete_message_handler(const CU_pSuite pSuite, const CU_pFailureRecord pFailure) {
bc_tester_printf(bc_printf_verbosity_info, "Suite [%s] ended in %lu sec\n", pSuite->pName,
time(NULL) - suite_start_time);
}
static time_t test_start_time = 0;
static void test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite) {
int suite_index = bc_tester_suite_index(pSuite->pName);
if (test_suite[suite_index]->before_each) {
test_suite[suite_index]->before_each();
}
bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] Test [%s] started", pSuite->pName,pTest->pName);
test_start_time = time(NULL);
bc_current_test_name = pTest->pName;
}
/*derivated from cunit*/
static void test_complete_message_handler(const CU_pTest pTest, const CU_pSuite pSuite,
const CU_pFailureRecord pFailureList) {
int i;
int suite_index = bc_tester_suite_index(pSuite->pName);
CU_pFailureRecord pFailure = pFailureList;
char *buffer = NULL;
char* result = bc_sprintf("Suite [%s] Test [%s] %s in %lu secs", pSuite->pName, pTest->pName,
pFailure ? "failed" : "passed", (unsigned long)(time(NULL) - test_start_time));
if (pFailure) {
for (i = 1; (NULL != pFailure); pFailure = pFailure->pNext, i++) {
buffer = bc_sprintf("%s\n %d. %s:%u - %s",
result,
i,
(NULL != pFailure->strFileName) ? pFailure->strFileName : "",
pFailure->uiLineNumber,
(NULL != pFailure->strCondition) ? pFailure->strCondition : "");
free(result);
result = buffer;
}
}
bc_tester_printf(bc_printf_verbosity_info,"%s", result);
free(result);
if (test_suite[suite_index]->after_each) {
int err = test_suite[suite_index]->after_each();
//if test passed but not after_each, count it as failure
if (err && !pFailure) {
CU_get_run_summary()->nTestsFailed++;
}
}
//insert empty line
bc_tester_printf(bc_printf_verbosity_info,"");
#ifdef __linux
/* use mallinfo() to monitor allocated space. It is linux specific but other methods don't work:
* setrlimit() RLIMIT_DATA doesn't count memory allocated via mmap() (which is used internally by malloc)
* setrlimit() RLIMIT_AS works but also counts virtual memory allocated by thread stacks, which is very big and
* hardly controllable.
* setrlimit() RLIMIT_RSS does nothing interesting on linux.
* getrusage() of RSS is unreliable: memory blocks can be leaked without being read or written, which would not
* appear in RSS.
* mallinfo() itself is the less worse solution. Allocated bytes are returned as 'int' so limited to 2GB
*/
if (max_vm_kb) {
struct mallinfo minfo = mallinfo();
if (minfo.uordblks > max_vm_kb * 1024) {
bc_tester_printf(
bc_printf_verbosity_error,
"The program exceeded the maximum amount of memory allocatable (%i bytes), aborting now.\n",
minfo.uordblks);
abort();
}
}
#endif
}
#endif
int bc_tester_run_tests(const char *suite_name, const char *test_name, const char *tag_name) {
int i;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
for (i = 0; i < nb_test_suites; i++) {
bc_tester_run_suite(test_suite[i], tag_name);
}
#ifdef HAVE_CU_GET_SUITE
CU_set_suite_start_handler(suite_start_message_handler);
CU_set_suite_complete_handler(suite_complete_message_handler);
CU_set_test_start_handler(test_start_message_handler);
CU_set_test_complete_handler(test_complete_message_handler);
#endif
CU_set_all_test_complete_handler(all_complete_message_handler);
CU_set_suite_init_failure_handler(suite_init_failure_message_handler);
CU_set_suite_cleanup_failure_handler(suite_cleanup_failure_message_handler);
if( xml_enabled != 0 ){
CU_automated_run_tests();
} else {
#ifndef HAVE_CU_GET_SUITE
if( suite_name ){
bc_tester_printf(bc_printf_verbosity_info, "Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'", suite_name);
}
#else
if (suite_name){
CU_pSuite suite;
suite=CU_get_suite(suite_name);
if (!suite) {
if (tag_name != NULL) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s' or this suite has no tests with tag '%s'. Available suites are:", suite_name, tag_name);
} else {
bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name);
}
bc_tester_list_suites();
return -1;
} else if (test_name) {
CU_pTest test=CU_get_test_by_name(test_name, suite);
if (!test) {
if (tag_name != NULL) {
bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s' or this test is not tagged '%s'. Available tests are:", test_name, suite_name, tag_name);
} else {
bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name);
}
// do not use suite_name here, since this method is case sensitive
bc_tester_list_tests(suite->pName);
return -2;
} else {
CU_ErrorCode err= CU_run_test(suite, test);
if (err != CUE_SUCCESS) bc_tester_printf(bc_printf_verbosity_error, "CU_basic_run_test error %d", err);
}
} else {
CU_run_suite(suite);
}
}
else
#endif
{
#ifdef HAVE_CU_CURSES
if (curses) {
/* Run tests using the CUnit curses interface */
CU_curses_run_tests();
}
else
#endif
{
/* Run all tests using the CUnit Basic interface */
CU_run_all_tests();
}
}
}
#ifdef __linux
bc_tester_printf(bc_printf_verbosity_info, "Still %i kilobytes allocated when all tests are finished.",
mallinfo().uordblks / 1024);
#endif
return CU_get_number_of_tests_failed()!=0;
}
void bc_tester_helper(const char *name, const char* additionnal_helper) {
bc_tester_printf(bc_printf_verbosity_info,
"%s --help\n"
#ifdef HAVE_CU_CURSES
"\t\t\t--curses\n"
#endif
"\t\t\t--list-suites\n"