X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=tests%2Futils%2Ftap%2Ftap.c;h=687ea22f28a9adf7f787dc473b5313d1da129cf3;hb=83dc3923fa4b0fc2e0ad091392aea64cac046498;hp=a430951193328aca551e34dfa1f3622a9b23ef28;hpb=5d2e1e66a968d9e555f9b8b00d0589ebfaf3de32;p=lttng-tools.git diff --git a/tests/utils/tap/tap.c b/tests/utils/tap/tap.c index a43095119..687ea22f2 100644 --- a/tests/utils/tap/tap.c +++ b/tests/utils/tap/tap.c @@ -1,36 +1,23 @@ -/*- - * Copyright (c) 2004 Nik Clayton - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. +/* + * SPDX-License-Identifier: BSD-2-Clause * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * Copyright (C) 2004 Nik Clayton + * Copyright (C) 2017 Jérémie Galarneau */ -#define _GNU_SOURCE +#include "../utils.h" +#include "common/compat/time.hpp" +#include "tap.h" + +#include #include +#include +#include #include #include #include - -#include "tap.h" +#include +#include static int no_plan = 0; static int skip_all = 0; @@ -39,26 +26,40 @@ static unsigned int test_count = 0; /* Number of tests that have been run */ static unsigned int e_tests = 0; /* Expected number of tests to run */ static unsigned int failures = 0; /* Number of tests that failed */ static char *todo_msg = NULL; -static char *todo_msg_fixed = "libtap malloc issue"; +static const char *todo_msg_fixed = "libtap malloc issue"; static int todo = 0; static int test_died = 0; +static int time_tests = 1; +struct timespec last_time; /* Encapsulate the pthread code in a conditional. In the absence of libpthread the code does nothing */ #ifdef HAVE_LIBPTHREAD #include static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER; -# define LOCK pthread_mutex_lock(&M); -# define UNLOCK pthread_mutex_unlock(&M); +#define LOCK pthread_mutex_lock(&M); +#define UNLOCK pthread_mutex_unlock(&M); #else -# define LOCK -# define UNLOCK +#define LOCK +#define UNLOCK #endif static void _expected_tests(unsigned int); static void _tap_init(void); static void _cleanup(void); +#ifdef __MINGW32__ +static inline void flockfile(FILE *filehandle) +{ + return; +} + +static inline void funlockfile(FILE *filehandle) +{ + return; +} +#endif + /* * Generate a test result. * @@ -66,9 +67,8 @@ static void _cleanup(void); * test_name -- the name of the test, may be NULL * test_comment -- a comment to print afterwards, may be NULL */ -unsigned int -_gen_result(int ok, const char *func, char *file, unsigned int line, - char *test_name, ...) +unsigned int _gen_result( + int ok, const char *func, const char *file, unsigned int line, const char *test_name, ...) { va_list ap; char *local_test_name = NULL; @@ -81,51 +81,54 @@ _gen_result(int ok, const char *func, char *file, unsigned int line, /* Start by taking the test name and performing any printf() expansions on it */ - if(test_name != NULL) { + if (test_name != NULL) { va_start(ap, test_name); - vasprintf(&local_test_name, test_name, ap); + if (vasprintf(&local_test_name, test_name, ap) == -1) { + local_test_name = NULL; + } va_end(ap); /* Make sure the test name contains more than digits and spaces. Emit an error message and exit if it does */ - if(local_test_name) { + if (local_test_name) { name_is_digits = 1; - for(c = local_test_name; *c != '\0'; c++) { - if(!isdigit(*c) && !isspace(*c)) { + for (c = local_test_name; *c != '\0'; c++) { + if (!isdigit((unsigned char) *c) && !isspace((unsigned char) *c)) { name_is_digits = 0; break; } } - if(name_is_digits) { - diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); + if (name_is_digits) { + diag(" You named your test '%s'. You shouldn't use numbers for your test names.", + local_test_name); diag(" Very confusing."); } } } - if(!ok) { + if (!ok) { printf("not "); failures++; } printf("ok %d", test_count); - if(test_name != NULL) { + if (test_name != NULL) { printf(" - "); /* Print the test name, escaping any '#' characters it might contain */ - if(local_test_name != NULL) { + if (local_test_name != NULL) { flockfile(stdout); - for(c = local_test_name; *c != '\0'; c++) { - if(*c == '#') + for (c = local_test_name; *c != '\0'; c++) { + if (*c == '#') fputc('\\', stdout); - fputc((int)*c, stdout); + fputc((int) *c, stdout); } funlockfile(stdout); - } else { /* vasprintf() failed, use a fixed message */ + } else { /* vasprintf() failed, use a fixed message */ printf("%s", todo_msg_fixed); } } @@ -137,20 +140,24 @@ _gen_result(int ok, const char *func, char *file, unsigned int line, This is not counted as a failure, so decrement the counter if the test failed. */ - if(todo) { + if (todo) { printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); - if(!ok) + if (!ok) failures--; } printf("\n"); + _output_test_time(); - if(!ok) { - if(getenv("HARNESS_ACTIVE") != NULL) + if (!ok) { + if (getenv("HARNESS_ACTIVE") != NULL) fputs("\n", stderr); diag(" Failed %stest (%s:%s() at line %d)", - todo ? "(TODO) " : "", file, func, line); + todo ? "(TODO) " : "", + file, + func, + line); } free(local_test_name); @@ -165,34 +172,52 @@ _gen_result(int ok, const char *func, char *file, unsigned int line, * Initialise the TAP library. Will only do so once, however many times it's * called. */ -void -_tap_init(void) +void _tap_init(void) { static int run_once = 0; - if(!run_once) { + if (!run_once) { atexit(_cleanup); /* stdout needs to be unbuffered so that the output appears in the same place relative to stderr output as it does with Test::Harness */ setbuf(stdout, 0); + + /* + * Check if the LTTNG_TESTS_TAP_AUTOTIME environment variable + * is set and contains at least one byte. + */ + const char *autotime_env = getenv("LTTNG_TESTS_TAP_AUTOTIME"); + if (autotime_env != NULL && strnlen(autotime_env, 1)) { + int tap_autotime; + + /* + * Check if LTTNG_TESTS_TAP_AUTOTIME is '0', also check + * errno because strtol() can return '0' on error. + */ + errno = 0; + tap_autotime = strtol(autotime_env, NULL, 10); + if (tap_autotime == 0 && errno == 0) { + time_tests = 0; + } + } + run_once = 1; } + lttng_clock_gettime(CLOCK_MONOTONIC, &last_time); } /* * Note that there's no plan. */ -int -plan_no_plan(void) +int plan_no_plan(void) { - LOCK; _tap_init(); - if(have_plan != 0) { + if (have_plan != 0) { fprintf(stderr, "You tried to plan twice!\n"); test_died = 1; UNLOCK; @@ -210,10 +235,8 @@ plan_no_plan(void) /* * Note that the plan is to skip all tests */ -int -plan_skip_all(char *reason) +int plan_skip_all(const char *reason) { - LOCK; _tap_init(); @@ -222,7 +245,7 @@ plan_skip_all(char *reason) printf("1..0"); - if(reason != NULL) + if (reason != NULL) printf(" # Skip %s", reason); printf("\n"); @@ -235,22 +258,20 @@ plan_skip_all(char *reason) /* * Note the number of tests that will be run. */ -int -plan_tests(unsigned int tests) +int plan_tests(unsigned int tests) { - LOCK; _tap_init(); - if(have_plan != 0) { + if (have_plan != 0) { fprintf(stderr, "You tried to plan twice!\n"); test_died = 1; UNLOCK; exit(255); } - if(tests == 0) { + if (tests == 0) { fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); test_died = 1; UNLOCK; @@ -266,8 +287,7 @@ plan_tests(unsigned int tests) return e_tests; } -unsigned int -diag(char *fmt, ...) +unsigned int diag(const char *fmt, ...) { va_list ap; @@ -282,31 +302,52 @@ diag(char *fmt, ...) return 0; } -void -_expected_tests(unsigned int tests) +void diag_multiline(const char *val) { + size_t len, i, line_start_idx = 0; + + assert(val); + len = strlen(val); + + for (i = 0; i < len; i++) { + int line_length; + + if (val[i] != '\n') { + continue; + } + assert((i - line_start_idx + 1) <= INT_MAX); + line_length = i - line_start_idx + 1; + fprintf(stderr, "# %.*s", line_length, &val[line_start_idx]); + line_start_idx = i + 1; + } +} + +void _expected_tests(unsigned int tests) +{ printf("1..%d\n", tests); e_tests = tests; } -int -skip(unsigned int n, char *fmt, ...) +int skip(unsigned int n, const char *fmt, ...) { va_list ap; - char *skip_msg; + char *skip_msg = NULL; LOCK; va_start(ap, fmt); - asprintf(&skip_msg, fmt, ap); + if (vasprintf(&skip_msg, fmt, ap) == -1) { + skip_msg = NULL; + } va_end(ap); - while(n-- > 0) { + while (n-- > 0) { test_count++; - printf("ok %d # skip %s\n", test_count, - skip_msg != NULL ? - skip_msg : "libtap():malloc() failed"); + printf("ok %d # skip %s\n", + test_count, + skip_msg != NULL ? skip_msg : "libtap():malloc() failed"); + _output_test_time(); } free(skip_msg); @@ -316,15 +357,30 @@ skip(unsigned int n, char *fmt, ...) return 1; } -void -todo_start(char *fmt, ...) +void _output_test_time(void) +{ + struct timespec new_time; + int64_t time_ns; + if (time_tests) { + lttng_clock_gettime(CLOCK_MONOTONIC, &new_time); + time_ns = elapsed_time_ns(&last_time, &new_time); + printf(" ---\n duration_ms: %ld.%ld\n ...\n", + time_ns / 1000000, + time_ns % 1000000); + } + lttng_clock_gettime(CLOCK_MONOTONIC, &last_time); +} + +void todo_start(const char *fmt, ...) { va_list ap; LOCK; va_start(ap, fmt); - vasprintf(&todo_msg, fmt, ap); + if (vasprintf(&todo_msg, fmt, ap) == -1) { + todo_msg = NULL; + } va_end(ap); todo = 1; @@ -332,10 +388,8 @@ todo_start(char *fmt, ...) UNLOCK; } -void -todo_end(void) +void todo_end(void) { - LOCK; todo = 0; @@ -344,22 +398,21 @@ todo_end(void) UNLOCK; } -int -exit_status(void) +int exit_status(void) { int r; LOCK; /* If there's no plan, just return the number of failures */ - if(no_plan || !have_plan) { + if (no_plan || !have_plan) { UNLOCK; return failures; } /* Ran too many tests? Return the number of tests that were run that shouldn't have been */ - if(e_tests < test_count) { + if (e_tests < test_count) { r = test_count - e_tests; UNLOCK; return r; @@ -377,51 +430,54 @@ exit_status(void) * Cleanup at the end of the run, produce any final output that might be * required. */ -void -_cleanup(void) +void _cleanup(void) { - LOCK; /* If plan_no_plan() wasn't called, and we don't have a plan, and we're not skipping everything, then something happened before we could produce any output */ - if(!no_plan && !have_plan && !skip_all) { + if (!no_plan && !have_plan && !skip_all) { diag("Looks like your test died before it could output anything."); UNLOCK; return; } - if(test_died) { + if (test_died) { diag("Looks like your test died just after %d.", test_count); UNLOCK; return; } - /* No plan provided, but now we know how many tests were run, and can print the header at the end */ - if(!skip_all && (no_plan || !have_plan)) { + if (!skip_all && (no_plan || !have_plan)) { printf("1..%d\n", test_count); } - if((have_plan && !no_plan) && e_tests < test_count) { + if ((have_plan && !no_plan) && e_tests < test_count) { diag("Looks like you planned %d %s but ran %d extra.", - e_tests, e_tests == 1 ? "test" : "tests", test_count - e_tests); + e_tests, + e_tests == 1 ? "test" : "tests", + test_count - e_tests); UNLOCK; return; } - if((have_plan || !no_plan) && e_tests > test_count) { + if ((have_plan || !no_plan) && e_tests > test_count) { diag("Looks like you planned %d %s but only ran %d.", - e_tests, e_tests == 1 ? "test" : "tests", test_count); + e_tests, + e_tests == 1 ? "test" : "tests", + test_count); UNLOCK; return; } - if(failures) + if (failures) diag("Looks like you failed %d %s of %d.", - failures, failures == 1 ? "test" : "tests", test_count); + failures, + failures == 1 ? "test" : "tests", + test_count); UNLOCK; }