From 1328e1ba08430b0eaa589919272d732bb84a6921 Mon Sep 17 00:00:00 2001 From: Will Storey Date: Sat, 21 Oct 2017 20:01:04 -0700 Subject: [PATCH 1/8] Add a test program to test mode parsing This uses GLib's testing framework. It is to test the changes to the mode parsing for #603. --- .gitignore | 3 + .travis.yml | 4 +- Makefile.am | 2 +- configure.ac | 3 + tests/Makefile.am | 1 + tests/irc/Makefile.am | 1 + tests/irc/core/Makefile.am | 36 ++++++ tests/irc/core/test-irc.c | 230 +++++++++++++++++++++++++++++++++++++ 8 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 tests/Makefile.am create mode 100644 tests/irc/Makefile.am create mode 100644 tests/irc/core/Makefile.am create mode 100644 tests/irc/core/test-irc.c diff --git a/.gitignore b/.gitignore index efc579cb..cf1cf72e 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,9 @@ src/perl/*/Makefile.old src/fe-fuzz/crash-* src/fe-fuzz/oom-* +tests/irc/core/test-irc +tests/irc/core/test-irc.trs + *.a *.bs *.la diff --git a/.travis.yml b/.travis.yml index 1d8786c4..1e04d943 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,5 +49,7 @@ before_script: - echo ^quit >> irssi-test/startup - irssi-build/bin/irssi --home irssi-test - cat irc.log.* + - cd $TRAVIS_BUILD_DIR -script: true +script: + - make check diff --git a/Makefile.am b/Makefile.am index f52ac92f..ba45d8ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,7 @@ irssi-version.h: VERSION="$(VERSION)" $(srcdir)/utils/irssi-version.sh $(srcdir) | \ cmp -s - $@ || VERSION="$(VERSION)" $(srcdir)/utils/irssi-version.sh $(srcdir) >$@ -SUBDIRS = src docs scripts themes utils +SUBDIRS = src tests docs scripts themes utils confdir = $(sysconfdir) conf_DATA = irssi.conf diff --git a/configure.ac b/configure.ac index 4b65d434..bf15e6ae 100644 --- a/configure.ac +++ b/configure.ac @@ -658,6 +658,9 @@ src/perl/ui/Makefile.PL src/perl/textui/Makefile.PL scripts/Makefile scripts/examples/Makefile +tests/Makefile +tests/irc/Makefile +tests/irc/core/Makefile docs/Makefile docs/help/Makefile docs/help/in/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 00000000..58c348df --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = irc diff --git a/tests/irc/Makefile.am b/tests/irc/Makefile.am new file mode 100644 index 00000000..52770885 --- /dev/null +++ b/tests/irc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = core diff --git a/tests/irc/core/Makefile.am b/tests/irc/core/Makefile.am new file mode 100644 index 00000000..fff2a246 --- /dev/null +++ b/tests/irc/core/Makefile.am @@ -0,0 +1,36 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/core \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + $(GLIB_CFLAGS) + +TESTS = test-irc +check_PROGRAMS = test-irc + +test_irc_CPPFLAGS = \ + -I$(top_srcdir)/src/irc/core \ + $(AM_CPPFLAGS) + +test_irc_DEPENDENCIES = \ + ../../../src/core/libcore.a \ + ../../../src/lib-config/libirssi_config.a + +test_irc_LDADD = \ + ../../../src/core/libcore.a \ + ../../../src/lib-config/libirssi_config.a \ + @GLIB_LIBS@ \ + @OPENSSL_LIBS@ + +test_irc_SOURCES = \ + test-irc.c \ + ../../../src/irc/core/irc-cap.c \ + ../../../src/irc/core/irc-nicklist.c \ + ../../../src/irc/core/irc-queries.c \ + ../../../src/irc/core/irc-servers-reconnect.c \ + ../../../src/irc/core/irc-servers-setup.c \ + ../../../src/irc/core/irc-servers.c \ + ../../../src/irc/core/irc.c \ + ../../../src/irc/core/mode-lists.c \ + ../../../src/irc/core/modes.c \ + ../../../src/irc/core/servers-idle.c \ + ../../../src/irc/core/servers-redirect.c diff --git a/tests/irc/core/test-irc.c b/tests/irc/core/test-irc.c new file mode 100644 index 00000000..7e85c9ba --- /dev/null +++ b/tests/irc/core/test-irc.c @@ -0,0 +1,230 @@ +/* + test-irc.c : irssi + + Copyright (C) 2017 Will Storey + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include + +static void test_event_get_param(void); +static void test_event_get_params(void); + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/test/event_get_param", test_event_get_param); + g_test_add_func("/test/event_get_params", test_event_get_params); + + return g_test_run(); +} + +static void test_event_get_param(void) +{ + struct test_case { + char const *const description; + char const *const input; + char const *const input_after; + char const *const output; + }; + + struct test_case const tests[] = { + { + .description = "Zero parameters", + .input = "", + .input_after = "", + .output = "", + }, + { + .description = "One parameter", + .input = "#test", + .input_after = "", + .output = "#test", + }, + { + .description = "One parameter, trailing space", + .input = "#test ", + .input_after = "", + .output = "#test", + }, + { + .description = "One parameter, more trailing space", + .input = "#test ", + .input_after = " ", + .output = "#test", + }, + { + .description = "Two parameters", + .input = "#test +o", + .input_after = "+o", + .output = "#test", + }, + { + .description = "Two parameters continued", + .input = "+o", + .input_after = "", + .output = "+o", + }, + { + .description = "Two parameters with trailing space", + .input = "#test +o ", + .input_after = "+o ", + .output = "#test", + }, + { + .description = "Two parameters with trailing space continued", + .input = "+o ", + .input_after = "", + .output = "+o", + }, + { + .description = "Two parameters with inline and trailing space", + .input = "#test +o ", + .input_after = " +o ", + .output = "#test", + }, + /* TODO: It seems not ideal that the caller has to deal with inline space. + */ + { + .description = "Two parameters with inline and trailing space continued", + .input = " +o ", + .input_after = "+o ", + .output = "", + }, + }; + + char *buf = g_malloc0(1024); + + int i = 0; + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + struct test_case const test = tests[i]; + + memcpy(buf, test.input, strlen(test.input)+1); + char *input = buf; + + char *const output = event_get_param(&input); + + g_assert_cmpstr(input, ==, test.input_after); + g_assert_cmpstr(output, ==, test.output); + } + + g_free(buf); +} + +static void test_event_get_params(void) +{ + struct test_case { + char const *const description; + char const *const input; + char const *const output0; + char const *const output1; + }; + + struct test_case const tests[] = { + { + .description = "Only a channel", + .input = "#test", + .output0 = "#test", + .output1 = "", + }, + { + .description = "Only a channel with trailing space", + .input = "#test ", + .output0 = "#test", + .output1 = "", + }, + { + .description = "No :, channel mode with one parameter after channel name", + .input = "#test +i", + .output0 = "#test", + .output1 = "+i", + }, + { + .description = "No :, channel mode with two parameters after channel name", + .input = "#test +o tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "No :, channel mode with three parameters afer channel name", + .input = "#test +ov tester tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "No :, channel mode with three parameters afer channel name, bunch of extra space", + .input = "#test +ov tester tester2 ", + .output0 = "#test", + .output1 = " +ov tester tester2 ", + }, + { + .description = "Channel mode with one parameter after channel name, : at the start of modes", + .input = "#test :+i", + .output0 = "#test", + .output1 = "+i", + }, + { + .description = "Channel mode with two parameters after channel name, : at the start of modes", + .input = "#test :+o tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "Channel mode with three parameters after channel name, : at the start of modes", + .input = "#test :+ov tester tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "Channel mode with two parameters after channel name, : on the final parameter", + .input = "#test +o :tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "Channel mode with three parameters after channel name, : on the final parameter", + .input = "#test +ov tester :tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "Channel mode with three parameters after channel name, : on the final parameter, also a second : present", + .input = "#test +ov tester :tester2 hi:there", + .output0 = "#test", + .output1 = "+ov tester tester2 hi:there", + }, + }; + + int i = 0; + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + struct test_case const test = tests[i]; + + char *output0 = NULL; + char *output1 = NULL; + char *const params = event_get_params(test.input, 2 | PARAM_FLAG_GETREST, + &output0, &output1); + + /* params happens to always point at the first output */ + g_assert_cmpstr(params, ==, test.output0); + g_assert_cmpstr(output0, ==, test.output0); + g_assert_cmpstr(output1, ==, test.output1); + + g_free(params); + } +} From c20eddeb385974d6f46494e71ab63d4493df119b Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Sun, 26 Nov 2017 16:19:31 +0100 Subject: [PATCH 2/8] add glib testing TAP utilities --- configure.ac | 2 + m4/glibtests.m4 | 28 ++ tests/irc/core/Makefile.am | 5 +- tests/irc/core/test-irc.c | 1 + utils/Makefile.am | 4 +- utils/glib-tap.mk | 134 ++++++++ utils/tap-driver.sh | 652 +++++++++++++++++++++++++++++++++++++ utils/tap-test | 5 + 8 files changed, 828 insertions(+), 3 deletions(-) create mode 100644 m4/glibtests.m4 create mode 100644 utils/glib-tap.mk create mode 100755 utils/tap-driver.sh create mode 100755 utils/tap-test diff --git a/configure.ac b/configure.ac index bf15e6ae..c780b9b8 100644 --- a/configure.ac +++ b/configure.ac @@ -295,6 +295,8 @@ fi LIBS="$LIBS $GLIB_LIBS" +GLIB_TESTS + dnl ** dnl ** OpenSSL checks dnl ** diff --git a/m4/glibtests.m4 b/m4/glibtests.m4 new file mode 100644 index 00000000..7d5920a4 --- /dev/null +++ b/m4/glibtests.m4 @@ -0,0 +1,28 @@ +dnl GLIB_TESTS +dnl + +AC_DEFUN([GLIB_TESTS], +[ + AC_ARG_ENABLE(installed-tests, + AS_HELP_STRING([--enable-installed-tests], + [Enable installation of some test cases]), + [case ${enableval} in + yes) ENABLE_INSTALLED_TESTS="1" ;; + no) ENABLE_INSTALLED_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-installed-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], test "$ENABLE_INSTALLED_TESTS" = "1") + AC_ARG_ENABLE(always-build-tests, + AS_HELP_STRING([--enable-always-build-tests], + [Enable always building tests during 'make all']), + [case ${enableval} in + yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;; + no) ENABLE_ALWAYS_BUILD_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-always-build-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_ALWAYS_BUILD_TESTS], test "$ENABLE_ALWAYS_BUILD_TESTS" = "1") + if test "$ENABLE_INSTALLED_TESTS" = "1"; then + AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME) + AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME) + fi +]) diff --git a/tests/irc/core/Makefile.am b/tests/irc/core/Makefile.am index fff2a246..b5345067 100644 --- a/tests/irc/core/Makefile.am +++ b/tests/irc/core/Makefile.am @@ -1,11 +1,12 @@ +include $(top_srcdir)/utils/glib-tap.mk + AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/core \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ $(GLIB_CFLAGS) -TESTS = test-irc -check_PROGRAMS = test-irc +test_programs = test-irc test_irc_CPPFLAGS = \ -I$(top_srcdir)/src/irc/core \ diff --git a/tests/irc/core/test-irc.c b/tests/irc/core/test-irc.c index 7e85c9ba..4c62e6a7 100644 --- a/tests/irc/core/test-irc.c +++ b/tests/irc/core/test-irc.c @@ -32,6 +32,7 @@ int main(int argc, char **argv) g_test_add_func("/test/event_get_param", test_event_get_param); g_test_add_func("/test/event_get_params", test_event_get_params); + g_test_set_nonfatal_assertions(); return g_test_run(); } diff --git a/utils/Makefile.am b/utils/Makefile.am index be24c17f..8af5c8f7 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -1,4 +1,6 @@ EXTRA_DIST = \ file2header.sh \ irssi-version.sh \ - syntax.pl + syntax.pl \ + tap-driver.sh \ + tap-test diff --git a/utils/glib-tap.mk b/utils/glib-tap.mk new file mode 100644 index 00000000..582f6d29 --- /dev/null +++ b/utils/glib-tap.mk @@ -0,0 +1,134 @@ +# GLIB - Library of useful C routines + +TESTS_ENVIRONMENT= \ + G_TEST_SRCDIR="$(abs_srcdir)" \ + G_TEST_BUILDDIR="$(abs_builddir)" \ + G_DEBUG=gc-friendly \ + MALLOC_CHECK_=2 \ + MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/utils/tap-driver.sh +LOG_COMPILER = $(top_srcdir)/utils/tap-test + +NULL = + +# initialize variables for unconditional += appending +BUILT_SOURCES = +BUILT_EXTRA_DIST = +CLEANFILES = *.log *.trs +DISTCLEANFILES = +MAINTAINERCLEANFILES = +EXTRA_DIST = +TESTS = + +installed_test_LTLIBRARIES = +installed_test_PROGRAMS = +installed_test_SCRIPTS = +nobase_installed_test_DATA = + +noinst_LTLIBRARIES = +noinst_PROGRAMS = +noinst_SCRIPTS = +noinst_DATA = + +check_LTLIBRARIES = +check_PROGRAMS = +check_SCRIPTS = +check_DATA = + +# We support a fairly large range of possible variables. It is expected that all types of files in a test suite +# will belong in exactly one of the following variables. +# +# First, we support the usual automake suffixes, but in lowercase, with the customary meaning: +# +# test_programs, test_scripts, test_data, test_ltlibraries +# +# The above are used to list files that are involved in both uninstalled and installed testing. The +# test_programs and test_scripts are taken to be actual testcases and will be run as part of the test suite. +# Note that _data is always used with the nobase_ automake variable name to ensure that installed test data is +# installed in the same way as it appears in the package layout. +# +# In order to mark a particular file as being only for one type of testing, use 'installed' or 'uninstalled', +# like so: +# +# installed_test_programs, uninstalled_test_programs +# installed_test_scripts, uninstalled_test_scripts +# installed_test_data, uninstalled_test_data +# installed_test_ltlibraries, uninstalled_test_ltlibraries +# +# Additionally, we support 'extra' infixes for programs and scripts. This is used for support programs/scripts +# that should not themselves be run as testcases (but exist to be used from other testcases): +# +# test_extra_programs, installed_test_extra_programs, uninstalled_test_extra_programs +# test_extra_scripts, installed_test_extra_scripts, uninstalled_test_extra_scripts +# +# Additionally, for _scripts and _data, we support the customary dist_ prefix so that the named script or data +# file automatically end up in the tarball. +# +# dist_test_scripts, dist_test_data, dist_test_extra_scripts +# dist_installed_test_scripts, dist_installed_test_data, dist_installed_test_extra_scripts +# dist_uninstalled_test_scripts, dist_uninstalled_test_data, dist_uninstalled_test_extra_scripts +# +# Note that no file is automatically disted unless it appears in one of the dist_ variables. This follows the +# standard automake convention of not disting programs scripts or data by default. +# +# test_programs, test_scripts, uninstalled_test_programs and uninstalled_test_scripts (as well as their disted +# variants) will be run as part of the in-tree 'make check'. These are all assumed to be runnable under +# gtester. That's a bit strange for scripts, but it's possible. + +TESTS += $(test_programs) $(test_scripts) $(uninstalled_test_programs) $(uninstalled_test_scripts) \ + $(dist_test_scripts) $(dist_uninstalled_test_scripts) + +# Note: build even the installed-only targets during 'make check' to ensure that they still work. +# We need to do a bit of trickery here and manage disting via EXTRA_DIST instead of using dist_ prefixes to +# prevent automake from mistreating gmake functions like $(wildcard ...) and $(addprefix ...) as if they were +# filenames, including removing duplicate instances of the opening part before the space, eg. '$(addprefix'. +all_test_programs = $(test_programs) $(uninstalled_test_programs) $(installed_test_programs) \ + $(test_extra_programs) $(uninstalled_test_extra_programs) $(installed_test_extra_programs) +all_test_scripts = $(test_scripts) $(uninstalled_test_scripts) $(installed_test_scripts) \ + $(test_extra_scripts) $(uninstalled_test_extra_scripts) $(installed_test_extra_scripts) +all_dist_test_scripts = $(dist_test_scripts) $(dist_uninstalled_test_scripts) $(dist_installed_test_scripts) \ + $(dist_test_extra_scripts) $(dist_uninstalled_test_extra_scripts) $(dist_installed_test_extra_scripts) +all_test_scripts += $(all_dist_test_scripts) +EXTRA_DIST += $(all_dist_test_scripts) +all_test_data = $(test_data) $(uninstalled_test_data) $(installed_test_data) +all_dist_test_data = $(dist_test_data) $(dist_uninstalled_test_data) $(dist_installed_test_data) +all_test_data += $(all_dist_test_data) +EXTRA_DIST += $(all_dist_test_data) +all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installed_test_ltlibraries) + +if ENABLE_ALWAYS_BUILD_TESTS +noinst_LTLIBRARIES += $(all_test_ltlibs) +noinst_PROGRAMS += $(all_test_programs) +noinst_SCRIPTS += $(all_test_scripts) +noinst_DATA += $(all_test_data) +else +check_LTLIBRARIES += $(all_test_ltlibs) +check_PROGRAMS += $(all_test_programs) +check_SCRIPTS += $(all_test_scripts) +check_DATA += $(all_test_data) +endif + +if ENABLE_INSTALLED_TESTS +installed_test_PROGRAMS += $(test_programs) $(installed_test_programs) \ + $(test_extra_programs) $(installed_test_extra_programs) +installed_test_SCRIPTS += $(test_scripts) $(installed_test_scripts) \ + $(test_extra_scripts) $(test_installed_extra_scripts) +installed_test_SCRIPTS += $(dist_test_scripts) $(dist_test_extra_scripts) \ + $(dist_installed_test_scripts) $(dist_installed_test_extra_scripts) +nobase_installed_test_DATA += $(test_data) $(installed_test_data) +nobase_installed_test_DATA += $(dist_test_data) $(dist_installed_test_data) +installed_test_LTLIBRARIES += $(test_ltlibraries) $(installed_test_ltlibraries) +installed_testcases = $(test_programs) $(installed_test_programs) \ + $(test_scripts) $(installed_test_scripts) \ + $(dist_test_scripts) $(dist_installed_test_scripts) + +installed_test_meta_DATA = $(installed_testcases:=.test) + +%.test: %$(EXEEXT) Makefile + $(AM_V_GEN) (echo '[Test]' > $@.tmp; \ + echo 'Type=session' >> $@.tmp; \ + echo 'Exec=$(installed_testdir)/$<' >> $@.tmp; \ + mv $@.tmp $@) + +CLEANFILES += $(installed_test_meta_DATA) +endif diff --git a/utils/tap-driver.sh b/utils/tap-driver.sh new file mode 100755 index 00000000..19aa531d --- /dev/null +++ b/utils/tap-driver.sh @@ -0,0 +1,652 @@ +#! /bin/sh +# Copyright (C) 2011-2013 Free Software Foundation, Inc. +# +# 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, 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 . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +scriptversion=2011-12-27.17; # UTC + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +me=tap-driver.sh + +fatal () +{ + echo "$me: fatal: $*" >&2 + exit 1 +} + +usage_error () +{ + echo "$me: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat < + # + trap : 1 3 2 13 15 + if test $merge -gt 0; then + exec 2>&1 + else + exec 2>&3 + fi + "$@" + echo $? + ) | LC_ALL=C ${AM_TAP_AWK-awk} \ + -v me="$me" \ + -v test_script_name="$test_name" \ + -v log_file="$log_file" \ + -v trs_file="$trs_file" \ + -v expect_failure="$expect_failure" \ + -v merge="$merge" \ + -v ignore_exit="$ignore_exit" \ + -v comments="$comments" \ + -v diag_string="$diag_string" \ +' +# FIXME: the usages of "cat >&3" below could be optimized when using +# FIXME: GNU awk, and/on on systems that supports /dev/fd/. + +# Implementation note: in what follows, `result_obj` will be an +# associative array that (partly) simulates a TAP result object +# from the `TAP::Parser` perl module. + +## ----------- ## +## FUNCTIONS ## +## ----------- ## + +function fatal(msg) +{ + print me ": " msg | "cat >&2" + exit 1 +} + +function abort(where) +{ + fatal("internal error " where) +} + +# Convert a boolean to a "yes"/"no" string. +function yn(bool) +{ + return bool ? "yes" : "no"; +} + +function add_test_result(result) +{ + if (!test_results_index) + test_results_index = 0 + test_results_list[test_results_index] = result + test_results_index += 1 + test_results_seen[result] = 1; +} + +# Whether the test script should be re-run by "make recheck". +function must_recheck() +{ + for (k in test_results_seen) + if (k != "XFAIL" && k != "PASS" && k != "SKIP") + return 1 + return 0 +} + +# Whether the content of the log file associated to this test should +# be copied into the "global" test-suite.log. +function copy_in_global_log() +{ + for (k in test_results_seen) + if (k != "PASS") + return 1 + return 0 +} + +# FIXME: this can certainly be improved ... +function get_global_test_result() +{ + if ("ERROR" in test_results_seen) + return "ERROR" + if ("FAIL" in test_results_seen || "XPASS" in test_results_seen) + return "FAIL" + all_skipped = 1 + for (k in test_results_seen) + if (k != "SKIP") + all_skipped = 0 + if (all_skipped) + return "SKIP" + return "PASS"; +} + +function stringify_result_obj(result_obj) +{ + if (result_obj["is_unplanned"] || result_obj["number"] != testno) + return "ERROR" + + if (plan_seen == LATE_PLAN) + return "ERROR" + + if (result_obj["directive"] == "TODO") + return result_obj["is_ok"] ? "XPASS" : "XFAIL" + + if (result_obj["directive"] == "SKIP") + return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL; + + if (length(result_obj["directive"])) + abort("in function stringify_result_obj()") + + return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL +} + +function decorate_result(result) +{ + color_name = color_for_result[result] + if (color_name) + return color_map[color_name] "" result "" color_map["std"] + # If we are not using colorized output, or if we do not know how + # to colorize the given result, we should return it unchanged. + return result +} + +function report(result, details) +{ + if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/) + { + msg = ": " test_script_name + add_test_result(result) + } + else if (result == "#") + { + msg = " " test_script_name ":" + } + else + { + abort("in function report()") + } + if (length(details)) + msg = msg " " details + # Output on console might be colorized. + print decorate_result(result) msg + # Log the result in the log file too, to help debugging (this is + # especially true when said result is a TAP error or "Bail out!"). + print result msg | "cat >&3"; +} + +function testsuite_error(error_message) +{ + report("ERROR", "- " error_message) +} + +function handle_tap_result() +{ + details = result_obj["number"]; + if (length(result_obj["description"])) + details = details " " result_obj["description"] + + if (plan_seen == LATE_PLAN) + { + details = details " # AFTER LATE PLAN"; + } + else if (result_obj["is_unplanned"]) + { + details = details " # UNPLANNED"; + } + else if (result_obj["number"] != testno) + { + details = sprintf("%s # OUT-OF-ORDER (expecting %d)", + details, testno); + } + else if (result_obj["directive"]) + { + details = details " # " result_obj["directive"]; + if (length(result_obj["explanation"])) + details = details " " result_obj["explanation"] + } + + report(stringify_result_obj(result_obj), details) +} + +# `skip_reason` should be empty whenever planned > 0. +function handle_tap_plan(planned, skip_reason) +{ + planned += 0 # Avoid getting confused if, say, `planned` is "00" + if (length(skip_reason) && planned > 0) + abort("in function handle_tap_plan()") + if (plan_seen) + { + # Error, only one plan per stream is acceptable. + testsuite_error("multiple test plans") + return; + } + planned_tests = planned + # The TAP plan can come before or after *all* the TAP results; we speak + # respectively of an "early" or a "late" plan. If we see the plan line + # after at least one TAP result has been seen, assume we have a late + # plan; in this case, any further test result seen after the plan will + # be flagged as an error. + plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN) + # If testno > 0, we have an error ("too many tests run") that will be + # automatically dealt with later, so do not worry about it here. If + # $plan_seen is true, we have an error due to a repeated plan, and that + # has already been dealt with above. Otherwise, we have a valid "plan + # with SKIP" specification, and should report it as a particular kind + # of SKIP result. + if (planned == 0 && testno == 0) + { + if (length(skip_reason)) + skip_reason = "- " skip_reason; + report("SKIP", skip_reason); + } +} + +function extract_tap_comment(line) +{ + if (index(line, diag_string) == 1) + { + # Strip leading `diag_string` from `line`. + line = substr(line, length(diag_string) + 1) + # And strip any leading and trailing whitespace left. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + # Return what is left (if any). + return line; + } + return ""; +} + +# When this function is called, we know that line is a TAP result line, +# so that it matches the (perl) RE "^(not )?ok\b". +function setup_result_obj(line) +{ + # Get the result, and remove it from the line. + result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0) + sub("^(not )?ok[ \t]*", "", line) + + # If the result has an explicit number, get it and strip it; otherwise, + # automatically assing the next progresive number to it. + if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/) + { + match(line, "^[0-9]+") + # The final `+ 0` is to normalize numbers with leading zeros. + result_obj["number"] = substr(line, 1, RLENGTH) + 0 + line = substr(line, RLENGTH + 1) + } + else + { + result_obj["number"] = testno + } + + if (plan_seen == LATE_PLAN) + # No further test results are acceptable after a "late" TAP plan + # has been seen. + result_obj["is_unplanned"] = 1 + else if (plan_seen && testno > planned_tests) + result_obj["is_unplanned"] = 1 + else + result_obj["is_unplanned"] = 0 + + # Strip trailing and leading whitespace. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + + # This will have to be corrected if we have a "TODO"/"SKIP" directive. + result_obj["description"] = line + result_obj["directive"] = "" + result_obj["explanation"] = "" + + if (index(line, "#") == 0) + return # No possible directive, nothing more to do. + + # Directives are case-insensitive. + rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*" + + # See whether we have the directive, and if yes, where. + pos = match(line, rx "$") + if (!pos) + pos = match(line, rx "[^a-zA-Z0-9_]") + + # If there was no TAP directive, we have nothing more to do. + if (!pos) + return + + # Let`s now see if the TAP directive has been escaped. For example: + # escaped: ok \# SKIP + # not escaped: ok \\# SKIP + # escaped: ok \\\\\# SKIP + # not escaped: ok \ # SKIP + if (substr(line, pos, 1) == "#") + { + bslash_count = 0 + for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--) + bslash_count += 1 + if (bslash_count % 2) + return # Directive was escaped. + } + + # Strip the directive and its explanation (if any) from the test + # description. + result_obj["description"] = substr(line, 1, pos - 1) + # Now remove the test description from the line, that has been dealt + # with already. + line = substr(line, pos) + # Strip the directive, and save its value (normalized to upper case). + sub("^[ \t]*#[ \t]*", "", line) + result_obj["directive"] = toupper(substr(line, 1, 4)) + line = substr(line, 5) + # Now get the explanation for the directive (if any), with leading + # and trailing whitespace removed. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + result_obj["explanation"] = line +} + +function get_test_exit_message(status) +{ + if (status == 0) + return "" + if (status !~ /^[1-9][0-9]*$/) + abort("getting exit status") + if (status < 127) + exit_details = "" + else if (status == 127) + exit_details = " (command not found?)" + else if (status >= 128 && status <= 255) + exit_details = sprintf(" (terminated by signal %d?)", status - 128) + else if (status > 256 && status <= 384) + # We used to report an "abnormal termination" here, but some Korn + # shells, when a child process die due to signal number n, can leave + # in $? an exit status of 256+n instead of the more standard 128+n. + # Apparently, both behaviours are allowed by POSIX (2008), so be + # prepared to handle them both. See also Austing Group report ID + # 0000051 + exit_details = sprintf(" (terminated by signal %d?)", status - 256) + else + # Never seen in practice. + exit_details = " (abnormal termination)" + return sprintf("exited with status %d%s", status, exit_details) +} + +function write_test_results() +{ + print ":global-test-result: " get_global_test_result() > trs_file + print ":recheck: " yn(must_recheck()) > trs_file + print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file + for (i = 0; i < test_results_index; i += 1) + print ":test-result: " test_results_list[i] > trs_file + close(trs_file); +} + +BEGIN { + +## ------- ## +## SETUP ## +## ------- ## + +'"$init_colors"' + +# Properly initialized once the TAP plan is seen. +planned_tests = 0 + +COOKED_PASS = expect_failure ? "XPASS": "PASS"; +COOKED_FAIL = expect_failure ? "XFAIL": "FAIL"; + +# Enumeration-like constants to remember which kind of plan (if any) +# has been seen. It is important that NO_PLAN evaluates "false" as +# a boolean. +NO_PLAN = 0 +EARLY_PLAN = 1 +LATE_PLAN = 2 + +testno = 0 # Number of test results seen so far. +bailed_out = 0 # Whether a "Bail out!" directive has been seen. + +# Whether the TAP plan has been seen or not, and if yes, which kind +# it is ("early" is seen before any test result, "late" otherwise). +plan_seen = NO_PLAN + +## --------- ## +## PARSING ## +## --------- ## + +is_first_read = 1 + +while (1) + { + # Involutions required so that we are able to read the exit status + # from the last input line. + st = getline + if (st < 0) # I/O error. + fatal("I/O error while reading from input stream") + else if (st == 0) # End-of-input + { + if (is_first_read) + abort("in input loop: only one input line") + break + } + if (is_first_read) + { + is_first_read = 0 + nextline = $0 + continue + } + else + { + curline = nextline + nextline = $0 + $0 = curline + } + # Copy any input line verbatim into the log file. + print | "cat >&3" + # Parsing of TAP input should stop after a "Bail out!" directive. + if (bailed_out) + continue + + # TAP test result. + if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/) + { + testno += 1 + setup_result_obj($0) + handle_tap_result() + } + # TAP plan (normal or "SKIP" without explanation). + else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/) + { + # The next two lines will put the number of planned tests in $0. + sub("^1\\.\\.", "") + sub("[^0-9]*$", "") + handle_tap_plan($0, "") + continue + } + # TAP "SKIP" plan, with an explanation. + else if ($0 ~ /^1\.\.0+[ \t]*#/) + { + # The next lines will put the skip explanation in $0, stripping + # any leading and trailing whitespace. This is a little more + # tricky in truth, since we want to also strip a potential leading + # "SKIP" string from the message. + sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "") + sub("[ \t]*$", ""); + handle_tap_plan(0, $0) + } + # "Bail out!" magic. + # Older versions of prove and TAP::Harness (e.g., 3.17) did not + # recognize a "Bail out!" directive when preceded by leading + # whitespace, but more modern versions (e.g., 3.23) do. So we + # emulate the latter, "more modern" behaviour. + else if ($0 ~ /^[ \t]*Bail out!/) + { + bailed_out = 1 + # Get the bailout message (if any), with leading and trailing + # whitespace stripped. The message remains stored in `$0`. + sub("^[ \t]*Bail out![ \t]*", ""); + sub("[ \t]*$", ""); + # Format the error message for the + bailout_message = "Bail out!" + if (length($0)) + bailout_message = bailout_message " " $0 + testsuite_error(bailout_message) + } + # Maybe we have too look for dianogtic comments too. + else if (comments != 0) + { + comment = extract_tap_comment($0); + if (length(comment)) + report("#", comment); + } + } + +## -------- ## +## FINISH ## +## -------- ## + +# A "Bail out!" directive should cause us to ignore any following TAP +# error, as well as a non-zero exit status from the TAP producer. +if (!bailed_out) + { + if (!plan_seen) + { + testsuite_error("missing test plan") + } + else if (planned_tests != testno) + { + bad_amount = testno > planned_tests ? "many" : "few" + testsuite_error(sprintf("too %s tests run (expected %d, got %d)", + bad_amount, planned_tests, testno)) + } + if (!ignore_exit) + { + # Fetch exit status from the last line. + exit_message = get_test_exit_message(nextline) + if (exit_message) + testsuite_error(exit_message) + } + } + +write_test_results() + +exit 0 + +} # End of "BEGIN" block. +' + +# TODO: document that we consume the file descriptor 3 :-( +} 3>"$log_file" + +test $? -eq 0 || fatal "I/O or internal error" + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/utils/tap-test b/utils/tap-test new file mode 100755 index 00000000..481e333e --- /dev/null +++ b/utils/tap-test @@ -0,0 +1,5 @@ +#! /bin/sh + +# run a GTest in tap mode. The test binary is passed as $1 + +$1 -k --tap From 43d06369bf8e5c5e470dc2b00656ddcdb9ee0480 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Sun, 26 Nov 2017 21:10:07 +0100 Subject: [PATCH 3/8] move fixtures to outer scope --- tests/irc/core/Makefile.am | 16 +- tests/irc/core/test-irc.c | 372 ++++++++++++++++++------------------- 2 files changed, 190 insertions(+), 198 deletions(-) diff --git a/tests/irc/core/Makefile.am b/tests/irc/core/Makefile.am index b5345067..ccc6aa97 100644 --- a/tests/irc/core/Makefile.am +++ b/tests/irc/core/Makefile.am @@ -1,5 +1,7 @@ include $(top_srcdir)/utils/glib-tap.mk +PACKAGE_STRING=irc/core + AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/core \ @@ -17,21 +19,11 @@ test_irc_DEPENDENCIES = \ ../../../src/lib-config/libirssi_config.a test_irc_LDADD = \ + ../../../src/irc/core/libirc_core.a \ ../../../src/core/libcore.a \ ../../../src/lib-config/libirssi_config.a \ @GLIB_LIBS@ \ @OPENSSL_LIBS@ test_irc_SOURCES = \ - test-irc.c \ - ../../../src/irc/core/irc-cap.c \ - ../../../src/irc/core/irc-nicklist.c \ - ../../../src/irc/core/irc-queries.c \ - ../../../src/irc/core/irc-servers-reconnect.c \ - ../../../src/irc/core/irc-servers-setup.c \ - ../../../src/irc/core/irc-servers.c \ - ../../../src/irc/core/irc.c \ - ../../../src/irc/core/mode-lists.c \ - ../../../src/irc/core/modes.c \ - ../../../src/irc/core/servers-idle.c \ - ../../../src/irc/core/servers-redirect.c + test-irc.c diff --git a/tests/irc/core/test-irc.c b/tests/irc/core/test-irc.c index 4c62e6a7..90ce856b 100644 --- a/tests/irc/core/test-irc.c +++ b/tests/irc/core/test-irc.c @@ -22,210 +22,210 @@ #include #include -static void test_event_get_param(void); -static void test_event_get_params(void); +typedef struct { + char const *const description; + char const *const input; + char const *const input_after; + char const *const output; +} event_get_param_test_case; + +event_get_param_test_case const event_get_param_fixtures[] = { + { + .description = "Zero parameters", + .input = "", + .input_after = "", + .output = "", + }, + { + .description = "One parameter", + .input = "#test", + .input_after = "", + .output = "#test", + }, + { + .description = "One parameter, trailing space", + .input = "#test ", + .input_after = "", + .output = "#test", + }, + { + .description = "One parameter, more trailing space", + .input = "#test ", + .input_after = " ", + .output = "#test", + }, + { + .description = "Two parameters", + .input = "#test +o", + .input_after = "+o", + .output = "#test", + }, + { + .description = "Two parameters continued", + .input = "+o", + .input_after = "", + .output = "+o", + }, + { + .description = "Two parameters with trailing space", + .input = "#test +o ", + .input_after = "+o ", + .output = "#test", + }, + { + .description = "Two parameters with trailing space continued", + .input = "+o ", + .input_after = "", + .output = "+o", + }, + { + .description = "Two parameters with inline and trailing space", + .input = "#test +o ", + .input_after = " +o ", + .output = "#test", + }, + /* TODO: It seems not ideal that the caller has to deal with inline space. + */ + { + .description = "Two parameters with inline and trailing space continued", + .input = " +o ", + .input_after = "+o ", + .output = "", + }, +}; + +static void test_event_get_param(const event_get_param_test_case *test); + +typedef struct { + char const *const description; + char const *const input; + char const *const output0; + char const *const output1; +} event_get_params_test_case; + +event_get_params_test_case const event_get_params_fixtures[] = { + { + .description = "Only a channel", + .input = "#test", + .output0 = "#test", + .output1 = "", + }, + { + .description = "Only a channel with trailing space", + .input = "#test ", + .output0 = "#test", + .output1 = "", + }, + { + .description = "No :, channel mode with one parameter after channel name", + .input = "#test +i", + .output0 = "#test", + .output1 = "+i", + }, + { + .description = "No :, channel mode with two parameters after channel name", + .input = "#test +o tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "No :, channel mode with three parameters afer channel name", + .input = "#test +ov tester tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "No :, channel mode with three parameters afer channel name, bunch of extra space", + .input = "#test +ov tester tester2 ", + .output0 = "#test", + .output1 = " +ov tester tester2 ", + }, + { + .description = "Channel mode with one parameter after channel name, : at the start of modes", + .input = "#test :+i", + .output0 = "#test", + .output1 = "+i", + }, + { + .description = "Channel mode with two parameters after channel name, : at the start of modes", + .input = "#test :+o tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "Channel mode with three parameters after channel name, : at the start of modes", + .input = "#test :+ov tester tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "Channel mode with two parameters after channel name, : on the final parameter", + .input = "#test +o :tester", + .output0 = "#test", + .output1 = "+o tester", + }, + { + .description = "Channel mode with three parameters after channel name, : on the final parameter", + .input = "#test +ov tester :tester2", + .output0 = "#test", + .output1 = "+ov tester tester2", + }, + { + .description = "Channel mode with three parameters after channel name, : on the final parameter, also a second : present", + .input = "#test +ov tester :tester2 hi:there", + .output0 = "#test", + .output1 = "+ov tester tester2 hi:there", + }, +}; + +static void test_event_get_params(const event_get_params_test_case *test); int main(int argc, char **argv) { + int i; + g_test_init(&argc, &argv, NULL); - g_test_add_func("/test/event_get_param", test_event_get_param); - g_test_add_func("/test/event_get_params", test_event_get_params); + for (i = 0; i < G_N_ELEMENTS(event_get_param_fixtures); i++) { + char *name = g_strdup_printf("/test/event_get_params/%d", i); + g_test_add_data_func(name, &event_get_params_fixtures[i], (GTestDataFunc)test_event_get_params); + g_free(name); + } + for (i = 0; i < G_N_ELEMENTS(event_get_param_fixtures); i++) { + char *name = g_strdup_printf("/test/event_get_param/%d", i); + g_test_add_data_func(name, &event_get_param_fixtures[i], (GTestDataFunc)test_event_get_param); + g_free(name); + } g_test_set_nonfatal_assertions(); return g_test_run(); } -static void test_event_get_param(void) +static void test_event_get_param(const event_get_param_test_case *test) { - struct test_case { - char const *const description; - char const *const input; - char const *const input_after; - char const *const output; - }; + char *buf, *input, *output; - struct test_case const tests[] = { - { - .description = "Zero parameters", - .input = "", - .input_after = "", - .output = "", - }, - { - .description = "One parameter", - .input = "#test", - .input_after = "", - .output = "#test", - }, - { - .description = "One parameter, trailing space", - .input = "#test ", - .input_after = "", - .output = "#test", - }, - { - .description = "One parameter, more trailing space", - .input = "#test ", - .input_after = " ", - .output = "#test", - }, - { - .description = "Two parameters", - .input = "#test +o", - .input_after = "+o", - .output = "#test", - }, - { - .description = "Two parameters continued", - .input = "+o", - .input_after = "", - .output = "+o", - }, - { - .description = "Two parameters with trailing space", - .input = "#test +o ", - .input_after = "+o ", - .output = "#test", - }, - { - .description = "Two parameters with trailing space continued", - .input = "+o ", - .input_after = "", - .output = "+o", - }, - { - .description = "Two parameters with inline and trailing space", - .input = "#test +o ", - .input_after = " +o ", - .output = "#test", - }, - /* TODO: It seems not ideal that the caller has to deal with inline space. - */ - { - .description = "Two parameters with inline and trailing space continued", - .input = " +o ", - .input_after = "+o ", - .output = "", - }, - }; + input = buf = g_strdup(test->input); + output = event_get_param(&input); - char *buf = g_malloc0(1024); - - int i = 0; - for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - struct test_case const test = tests[i]; - - memcpy(buf, test.input, strlen(test.input)+1); - char *input = buf; - - char *const output = event_get_param(&input); - - g_assert_cmpstr(input, ==, test.input_after); - g_assert_cmpstr(output, ==, test.output); - } + g_assert_cmpstr(input, ==, test->input_after); + g_assert_cmpstr(output, ==, test->output); g_free(buf); } -static void test_event_get_params(void) +static void test_event_get_params(const event_get_params_test_case *test) { - struct test_case { - char const *const description; - char const *const input; - char const *const output0; - char const *const output1; - }; + char *output0, *output1, *params; + output0 = NULL; + output1 = NULL; + params = event_get_params(test->input, 2 | PARAM_FLAG_GETREST, + &output0, &output1); - struct test_case const tests[] = { - { - .description = "Only a channel", - .input = "#test", - .output0 = "#test", - .output1 = "", - }, - { - .description = "Only a channel with trailing space", - .input = "#test ", - .output0 = "#test", - .output1 = "", - }, - { - .description = "No :, channel mode with one parameter after channel name", - .input = "#test +i", - .output0 = "#test", - .output1 = "+i", - }, - { - .description = "No :, channel mode with two parameters after channel name", - .input = "#test +o tester", - .output0 = "#test", - .output1 = "+o tester", - }, - { - .description = "No :, channel mode with three parameters afer channel name", - .input = "#test +ov tester tester2", - .output0 = "#test", - .output1 = "+ov tester tester2", - }, - { - .description = "No :, channel mode with three parameters afer channel name, bunch of extra space", - .input = "#test +ov tester tester2 ", - .output0 = "#test", - .output1 = " +ov tester tester2 ", - }, - { - .description = "Channel mode with one parameter after channel name, : at the start of modes", - .input = "#test :+i", - .output0 = "#test", - .output1 = "+i", - }, - { - .description = "Channel mode with two parameters after channel name, : at the start of modes", - .input = "#test :+o tester", - .output0 = "#test", - .output1 = "+o tester", - }, - { - .description = "Channel mode with three parameters after channel name, : at the start of modes", - .input = "#test :+ov tester tester2", - .output0 = "#test", - .output1 = "+ov tester tester2", - }, - { - .description = "Channel mode with two parameters after channel name, : on the final parameter", - .input = "#test +o :tester", - .output0 = "#test", - .output1 = "+o tester", - }, - { - .description = "Channel mode with three parameters after channel name, : on the final parameter", - .input = "#test +ov tester :tester2", - .output0 = "#test", - .output1 = "+ov tester tester2", - }, - { - .description = "Channel mode with three parameters after channel name, : on the final parameter, also a second : present", - .input = "#test +ov tester :tester2 hi:there", - .output0 = "#test", - .output1 = "+ov tester tester2 hi:there", - }, - }; + /* params happens to always point at the first output */ + g_assert_cmpstr(params, ==, test->output0); + g_assert_cmpstr(output0, ==, test->output0); + g_assert_cmpstr(output1, ==, test->output1); - int i = 0; - for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - struct test_case const test = tests[i]; - - char *output0 = NULL; - char *output1 = NULL; - char *const params = event_get_params(test.input, 2 | PARAM_FLAG_GETREST, - &output0, &output1); - - /* params happens to always point at the first output */ - g_assert_cmpstr(params, ==, test.output0); - g_assert_cmpstr(output0, ==, test.output0); - g_assert_cmpstr(output1, ==, test.output1); - - g_free(params); - } + g_free(params); } From d932e6e4b78383e0874721a76a8480a9a7e03667 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Sun, 26 Nov 2017 21:10:49 +0100 Subject: [PATCH 4/8] add test case for format_real_length --- configure.ac | 2 ++ tests/Makefile.am | 2 +- tests/fe-common/Makefile.am | 1 + tests/fe-common/core/Makefile.am | 28 ++++++++++++++++ tests/fe-common/core/test-formats.c | 50 +++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/fe-common/Makefile.am create mode 100644 tests/fe-common/core/Makefile.am create mode 100644 tests/fe-common/core/test-formats.c diff --git a/configure.ac b/configure.ac index c780b9b8..76ada09f 100644 --- a/configure.ac +++ b/configure.ac @@ -661,6 +661,8 @@ src/perl/textui/Makefile.PL scripts/Makefile scripts/examples/Makefile tests/Makefile +tests/fe-common/Makefile +tests/fe-common/core/Makefile tests/irc/Makefile tests/irc/core/Makefile docs/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am index 58c348df..e16d190e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS = irc +SUBDIRS = fe-common irc diff --git a/tests/fe-common/Makefile.am b/tests/fe-common/Makefile.am new file mode 100644 index 00000000..52770885 --- /dev/null +++ b/tests/fe-common/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = core diff --git a/tests/fe-common/core/Makefile.am b/tests/fe-common/core/Makefile.am new file mode 100644 index 00000000..070b6052 --- /dev/null +++ b/tests/fe-common/core/Makefile.am @@ -0,0 +1,28 @@ +include $(top_srcdir)/utils/glib-tap.mk + +PACKAGE_STRING=fe-common/core + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/core \ + $(GLIB_CFLAGS) + +test_programs = test-formats + +test_formats_CPPFLAGS = \ + -I$(top_srcdir)/src/fe-common/core \ + $(AM_CPPFLAGS) + +test_formats_DEPENDENCIES = \ + ../../../src/core/libcore.a \ + ../../../src/lib-config/libirssi_config.a + +test_formats_LDADD = \ + ../../../src/fe-common/core/libfe_common_core.a \ + ../../../src/core/libcore.a \ + ../../../src/lib-config/libirssi_config.a \ + @GLIB_LIBS@ \ + @OPENSSL_LIBS@ + +test_formats_SOURCES = \ + test-formats.c diff --git a/tests/fe-common/core/test-formats.c b/tests/fe-common/core/test-formats.c new file mode 100644 index 00000000..9ef23fd6 --- /dev/null +++ b/tests/fe-common/core/test-formats.c @@ -0,0 +1,50 @@ +#include "common.h" +#include "formats.h" + +#define MAX_LENGTH 5 + +typedef struct { + char const *const description; + char const *const input; + int const result[ MAX_LENGTH ]; +} format_real_length_test_case; + +static void test_format_real_length(const format_real_length_test_case *test); + +format_real_length_test_case const format_real_length_fixtures[] = { + { + .description = "", + .input = "%4%w ", + .result = { 0, 5, 5, -1 }, + }, +}; + +int main(int argc, char **argv) +{ + int i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < G_N_ELEMENTS(format_real_length_fixtures); i++) { + char *name = g_strdup_printf("/test/format_real_length/%d", i); + g_test_add_data_func(name, &format_real_length_fixtures[i], (GTestDataFunc)test_format_real_length); + g_free(name); + } + + g_test_set_nonfatal_assertions(); + return g_test_run(); +} + +static void test_format_real_length(const format_real_length_test_case *test) +{ + int j, len; + + g_test_message("Testing format %s", test->input); + + for (j = 0; test->result[j] != -1; j++) { + len = format_real_length(test->input, j); + g_assert_cmpint(len, ==, test->result[j]); + } + + return; +} From d6458304d7dba0644fb4b682e09baf0acebdbb97 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Sun, 26 Nov 2017 21:23:51 +0100 Subject: [PATCH 5/8] mess with travis --- .travis.yml | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e04d943..a6ff601f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,13 @@ perl: # - "5.18-shrplib" - "system-perl" env: - - CC=clang - - CC=gcc + - CC=clang UNITTESTS=false + - CC=gcc UNITTESTS=false + - CC=clang UNITTESTS=true +matrix: + exclude: + - env: CC=clang UNITTESTS=true + perl: "system-perl" addons: apt: @@ -31,11 +36,12 @@ before_install: install: - ./configure --with-proxy --with-bot --with-perl=module --prefix=$HOME/irssi-build + $( $UNITTESTS && echo --enable-always-build-tests ) - make CFLAGS="-Wall -Werror -Werror=declaration-after-statement" - make install before_script: - - cd + - pushd ~ - mkdir irssi-test - echo echo automated irssi launch test > irssi-test/startup; echo ^set settings_autosave off >> irssi-test/startup; @@ -47,9 +53,12 @@ before_script: - echo load perl >> irssi-test/startup - echo load proxy >> irssi-test/startup - echo ^quit >> irssi-test/startup - - irssi-build/bin/irssi --home irssi-test - - cat irc.log.* - - cd $TRAVIS_BUILD_DIR script: - - make check + - irssi-build/bin/irssi --home irssi-test + - popd + - if $UNITTESTS; then make -C tests -sk check; fi + +after_script: + - cat ~/irc.log.*; + find -name test-suite.log -exec cat {} + From eb9e2ed6fdacc3fa262b4907de51dea3f12be5fe Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Tue, 28 Nov 2017 11:00:46 +0100 Subject: [PATCH 6/8] Update test-irc.c Fix wrong array (missing an s) --- tests/irc/core/test-irc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/irc/core/test-irc.c b/tests/irc/core/test-irc.c index 90ce856b..c96956df 100644 --- a/tests/irc/core/test-irc.c +++ b/tests/irc/core/test-irc.c @@ -186,7 +186,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); - for (i = 0; i < G_N_ELEMENTS(event_get_param_fixtures); i++) { + for (i = 0; i < G_N_ELEMENTS(event_get_params_fixtures); i++) { char *name = g_strdup_printf("/test/event_get_params/%d", i); g_test_add_data_func(name, &event_get_params_fixtures[i], (GTestDataFunc)test_event_get_params); g_free(name); From 8b34871ea67c420b045ead9e317b67a247c02aae Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Wed, 29 Nov 2017 14:40:40 +0100 Subject: [PATCH 7/8] make travis pass despite failures --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a6ff601f..b0bc78e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,8 @@ matrix: exclude: - env: CC=clang UNITTESTS=true perl: "system-perl" + allow_failures: + - env: CC=clang UNITTESTS=true addons: apt: From 58557d18c49c11cd4a4de44c5a9e7c00f2d8f880 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Thu, 7 Dec 2017 12:08:20 +0100 Subject: [PATCH 8/8] add separator in travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b0bc78e8..e2b3f57c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,5 +62,5 @@ script: - if $UNITTESTS; then make -C tests -sk check; fi after_script: - - cat ~/irc.log.*; - find -name test-suite.log -exec cat {} + + - cat ~/irc.log.* + - find -name test-suite.log -exec cat {} +