diff --git a/.gitignore b/.gitignore index 07bf344b..521b063f 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,9 @@ config.h.in~ /tests/*.log /tests/*.trs +# Ignore test compiled binary files +/tests/tests/ctest_*.test + # Ignore auxiliary files /tap-driver.sh diff --git a/tests/Makefile.am b/tests/Makefile.am index e445847d..74ff7ab7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,10 +5,22 @@ TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ TESTS = \ startup.test \ - admin.test + admin.test \ + ctest_suite.test \ + ctest_resourcematch.test \ + ctest_refobject.test EXTRA_DIST = $(TESTS) EXTRA_DIST += \ icecast.xml \ on-connect.sh + +check_PROGRAMS = ctest_suite.test ctest_resourcematch.test ctest_refobject.test +noinst_HEADERS = ctest_lib.h + +ctest_suite_test_SOURCES=ctest_suite.c ctest_lib.c +ctest_resourcematch_test_SOURCES=ctest_resourcematch.c ctest_lib.c ../src/resourcematch.c +ctest_refobject_test_SOURCES=ctest_refobject.c ctest_lib.c ../src/refobject.c +ctest_refobject_test_DEPENDENCIES = ../src/common/thread/libicethread.la ../src/common/avl/libiceavl.la +ctest_refobject_test_LDADD = $(ctest_refobject_test_DEPENDENCIES) diff --git a/tests/ctest_lib.c b/tests/ctest_lib.c new file mode 100644 index 00000000..176a7df2 --- /dev/null +++ b/tests/ctest_lib.c @@ -0,0 +1,84 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "ctest_lib.h" + +static size_t ctest_g_test_num; +static int ctest_g_bailed_out; + +void ctest_init(void) +{ + ctest_g_test_num = 0; + ctest_g_bailed_out = 0; +} + +void ctest_fin(void) +{ + printf("1..%zu\n", ctest_g_test_num); +} + +void ctest_test(const char *desc, int res) +{ + const char *prefix = NULL; + + if (ctest_bailed_out()) + return; + + ctest_g_test_num++; + + if (res) { + prefix = "ok"; + } else { + prefix = "not ok"; + } + + if (desc) { + printf("%s %zu %s\n", prefix, ctest_g_test_num, desc); + } else { + printf("%s %zu\n", prefix, ctest_g_test_num); + } +} + +void ctest_diagnostic(const char *line) +{ + printf("# %s\n", line); +} + +void ctest_diagnostic_printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + + printf("# "); + vprintf(format, ap); + printf("\n"); + + va_end(ap); +} + +void ctest_bail_out(const char *reason) +{ + ctest_g_bailed_out = 1; + if (reason) { + printf("Bail out! %s\n", reason); + } else { + printf("Bail out!\n"); + } +} + +int ctest_bailed_out(void) +{ + return ctest_g_bailed_out; +} diff --git a/tests/ctest_lib.h b/tests/ctest_lib.h new file mode 100644 index 00000000..69eb22ab --- /dev/null +++ b/tests/ctest_lib.h @@ -0,0 +1,21 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifndef __CTEST_LIB_H__ +#define __CTEST_LIB_H__ + +void ctest_init(void); +void ctest_fin(void); + +void ctest_test(const char *desc, int res); +void ctest_diagnostic(const char *line); +void ctest_diagnostic_printf(const char *format, ...); +void ctest_bail_out(const char *reason); +int ctest_bailed_out(void); + +#endif diff --git a/tests/ctest_refobject.c b/tests/ctest_refobject.c new file mode 100644 index 00000000..9aa580e9 --- /dev/null +++ b/tests/ctest_refobject.c @@ -0,0 +1,178 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "ctest_lib.h" + +#include "../src/refobject.h" + +static void test_ptr(void) +{ + refobject_t a; + + a = REFOBJECT_NULL; + ctest_test("NULL is NULL", REFOBJECT_IS_NULL(a)); + + if (!REFOBJECT_IS_NULL(a)) + ctest_bailed_out(); +} + +static void test_create_ref_unref(void) +{ + refobject_t a; + + a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + ctest_test("referenced", refobject_ref(a) == 0); + ctest_test("un-referenced (1 of 2)", refobject_unref(a) == 0); + ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); +} + +static void test_sizes(void) +{ + refobject_t a; + + a = refobject_new(sizeof(refobject_base_t) + 1024, NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created with size=sizeof(refobject_base_t) + 1024", !REFOBJECT_IS_NULL(a)); + ctest_test("un-referenced", refobject_unref(a) == 0); + + a = refobject_new(sizeof(refobject_base_t) + 131072, NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created with size=sizeof(refobject_base_t) + 131072", !REFOBJECT_IS_NULL(a)); + ctest_test("un-referenced", refobject_unref(a) == 0); + + if (sizeof(refobject_base_t) >= 1) { + a = refobject_new(sizeof(refobject_base_t) - 1, NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a)); + if (!REFOBJECT_IS_NULL(a)) { + ctest_test("un-referenced", refobject_unref(a) == 0); + } + } + + a = refobject_new(0, NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created with size=0", REFOBJECT_IS_NULL(a)); + if (!REFOBJECT_IS_NULL(a)) { + ctest_test("un-referenced", refobject_unref(a) == 0); + } +} + +static void test_name(void) +{ + refobject_t a; + const char *name = "test object name"; + const char *ret; + + a = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + ret = refobject_get_name(a); + ctest_test("get name", ret != NULL); + ctest_test("name match", strcmp(name, ret) == 0); + + ctest_test("un-referenced", refobject_unref(a) == 0); +} + +static void test_userdata(void) +{ + refobject_t a; + int tmp = 0; + void *userdata = &tmp; + void *ret; + + a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + ret = refobject_get_userdata(a); + ctest_test("get userdata", ret == NULL); + ctest_test("set userdata", refobject_set_userdata(a, userdata) == 0); + ret = refobject_get_userdata(a); + ctest_test("get userdata", ret == userdata); + ctest_test("clearing userdata", refobject_set_userdata(a, NULL) == 0); + ret = refobject_get_userdata(a); + ctest_test("get userdata", ret == NULL); + + ctest_test("un-referenced", refobject_unref(a) == 0); + + a = refobject_new(sizeof(refobject_base_t), NULL, userdata, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + ret = refobject_get_userdata(a); + ctest_test("get userdata", ret == userdata); + ctest_test("clearing userdata", refobject_set_userdata(a, NULL) == 0); + ret = refobject_get_userdata(a); + ctest_test("get userdata", ret == NULL); + ctest_test("un-referenced", refobject_unref(a) == 0); +} + +static void test_associated(void) +{ + refobject_t a, b; + + a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + b = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, a); + ctest_test("refobject created with associated", !REFOBJECT_IS_NULL(b)); + + ctest_test("un-referenced (1 of 2)", refobject_unref(b) == 0); + ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); +} + +static void test_freecb(void) +{ + refobject_t a; + size_t called = 0; + void freecb(refobject_t self, void **userdata) + { + called++; + } + + a = refobject_new(sizeof(refobject_base_t), freecb, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + ctest_test("un-referenced", refobject_unref(a) == 0); + ctest_test("freecb called", called == 1); + + called = 0; + a = refobject_new(sizeof(refobject_base_t), freecb, NULL, NULL, REFOBJECT_NULL); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + ctest_test("referenced", refobject_ref(a) == 0); + ctest_test("freecb uncalled", called == 0); + ctest_test("un-referenced (1 of 2)", refobject_unref(a) == 0); + ctest_test("freecb uncalled", called == 0); + ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); + ctest_test("freecb called", called == 1); +} + +int main (void) +{ + ctest_init(); + + test_ptr(); + + if (ctest_bailed_out()) { + ctest_fin(); + return 1; + } + + test_create_ref_unref(); + + test_sizes(); + + test_name(); + test_userdata(); + test_associated(); + test_freecb(); + + ctest_fin(); + + return 0; +} diff --git a/tests/ctest_resourcematch.c b/tests/ctest_resourcematch.c new file mode 100644 index 00000000..641c2416 --- /dev/null +++ b/tests/ctest_resourcematch.c @@ -0,0 +1,173 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include /* for NULL */ +#include /* for snprintf() */ + +#include "ctest_lib.h" + +#include "../src/resourcematch.h" + +struct test { + const char *pattern; + const char *string; + resourcematch_result_t expected_result; +}; + +static const struct test tests[] = { + {NULL, NULL, RESOURCEMATCH_ERROR}, + {"", NULL, RESOURCEMATCH_ERROR}, + {NULL, "", RESOURCEMATCH_ERROR}, + {"", "", RESOURCEMATCH_MATCH}, + {"a", "a", RESOURCEMATCH_MATCH}, + {"aa", "b", RESOURCEMATCH_NOMATCH}, + {"aa", "ab", RESOURCEMATCH_NOMATCH}, + {"aa", "ba", RESOURCEMATCH_NOMATCH}, + {"aa", "aa", RESOURCEMATCH_MATCH}, + {"a/a", "a/a", RESOURCEMATCH_MATCH}, + {"a/%%a", "a/%a", RESOURCEMATCH_MATCH}, + + {"a/%i", "a/0", RESOURCEMATCH_MATCH}, + {"a/%i", "a/1", RESOURCEMATCH_MATCH}, + + {"a/%i", "a/12", RESOURCEMATCH_MATCH}, + {"a/%i", "a/0x12", RESOURCEMATCH_MATCH}, + {"a/%i", "a/012", RESOURCEMATCH_MATCH}, + + {"a/%d", "a/12", RESOURCEMATCH_MATCH}, + {"a/%d", "a/0x12", RESOURCEMATCH_NOMATCH}, + {"a/%d", "a/012", RESOURCEMATCH_MATCH}, + + {"a/%x", "a/12", RESOURCEMATCH_MATCH}, + {"a/%x", "a/0x12", RESOURCEMATCH_MATCH}, + {"a/%x", "a/012", RESOURCEMATCH_MATCH}, + + {"a/%o", "a/12", RESOURCEMATCH_MATCH}, + {"a/%o", "a/0x12", RESOURCEMATCH_NOMATCH}, + {"a/%o", "a/012", RESOURCEMATCH_MATCH}, + + {"a/%i/b", "a/X/b", RESOURCEMATCH_NOMATCH}, + + {"a/%d/b", "a/12/b", RESOURCEMATCH_MATCH}, + {"a/%d/b", "a/0x12/b", RESOURCEMATCH_NOMATCH}, + {"a/%d/b", "a/012/b", RESOURCEMATCH_MATCH}, + + {"a/%x/b", "a/12/b", RESOURCEMATCH_MATCH}, + {"a/%x/b", "a/0x12/b", RESOURCEMATCH_MATCH}, + {"a/%x/b", "a/012/b", RESOURCEMATCH_MATCH}, + + {"a/%o/b", "a/12/b", RESOURCEMATCH_MATCH}, + {"a/%o/b", "a/0x12/b", RESOURCEMATCH_NOMATCH}, + {"a/%o/b", "a/012/b", RESOURCEMATCH_MATCH}, + + {"a/%i/%i/b", "a/1/2/b", RESOURCEMATCH_MATCH} +}; + +static const char *res2str(resourcematch_result_t res) +{ + switch (res) { + case RESOURCEMATCH_ERROR: + return "error"; + break; + case RESOURCEMATCH_MATCH: + return "match"; + break; + case RESOURCEMATCH_NOMATCH: + return "nomatch"; + break; + default: + return ""; + break; + } +} + +static inline resourcematch_result_t run_test_base(const struct test *test, resourcematch_extract_t **extract) +{ + char name[128]; + resourcematch_result_t ret; + int ok = 1; + + ret = resourcematch_match(test->pattern, test->string, extract); + + //printf(" expected %s, got %s", res2str(test->expected_result), res2str(ret)); + + if (extract) { + if (test->expected_result == RESOURCEMATCH_MATCH) { + if (*extract) { + ctest_diagnostic(" got extract"); + } else { + ctest_diagnostic(" got no extract"); + ok = 0; + } + } + } + + snprintf(name, sizeof(name), "pattern \"%s\" and string \"%s\" %s extract", test->pattern, test->string, extract ? "with" : "without"); + ctest_test(name, test->expected_result == ret && ok); + + return ret; +} + +static inline void print_extract_group(resourcematch_extract_t *extract, size_t idx) +{ + switch (extract->group[idx].type) { + case 'i': + case 'd': + case 'x': + case 'o': + ctest_diagnostic_printf(" Group %zu, type \"%c\": value is %lli", idx, extract->group[idx].type, extract->group[idx].result.lli); + break; + default: + ctest_diagnostic_printf(" Group %zu, type \"%c\": ", idx, extract->group[idx].type, extract->group[idx].raw); + break; + } +} + +static inline void print_extract(resourcematch_extract_t *extract) +{ + size_t i; + + ctest_diagnostic_printf(" Extract with %zu groups:", extract->groups); + + for (i = 0; i < extract->groups; i++) { + print_extract_group(extract, i); + } +} + +static void run_test(const struct test *test) +{ + resourcematch_result_t ret; + resourcematch_extract_t *extract = NULL; + + run_test_base(test, NULL); + + ret = run_test_base(test, &extract); + if (extract) { + if (ret == RESOURCEMATCH_MATCH) + print_extract(extract); + + resourcematch_extract_free(extract); + } +} + +int main (void) +{ + size_t i; + + ctest_init(); + for (i = 0; i < (sizeof(tests)/sizeof(*tests)); i++) { + run_test(&(tests[i])); + } + ctest_fin(); + + return 0; +} diff --git a/tests/ctest_suite.c b/tests/ctest_suite.c new file mode 100644 index 00000000..91f75873 --- /dev/null +++ b/tests/ctest_suite.c @@ -0,0 +1,20 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ctest_lib.h" + +int main (void) { + ctest_init(); + ctest_test("suite working", 1); + ctest_fin(); + return 0; +}