Commit 8a2cec3c authored by Ondřej Surý's avatar Ondřej Surý

Start using C TAP Harness and convert journal tests to the new system

parent 1413ac86
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src samples doc man
EXTRA_DIST = resource.sh
include $(srcdir)/tests/Makefile.inc
......@@ -318,7 +318,6 @@ AC_CONFIG_FILES([Makefile
man/Makefile
src/Makefile
samples/Makefile
src/tests/Makefile
src/zscanner/Makefile
src/zscanner/test/cases/06-3_INCLUDE.in:src/zscanner/test/cases/06-3_INCLUDE.inin
src/zscanner/test/cases/06-4_INCLUDE.in:src/zscanner/test/cases/06-4_INCLUDE.inin
......
ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
SUBDIRS = zscanner . tests
SUBDIRS = zscanner .
sbin_PROGRAMS = knotc knotd
bin_PROGRAMS = kdig khost knsupdate knsec3hash
......
check_PROGRAMS = tests/runtests tests/journal
check_LIBRARIES = tests/tap/libtap.a
AM_CPPFLAGS = -I$(top_srcdir)/src \
-DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"'
tests_runtests_CPPFLAGS = \
-DSOURCE='"$(abs_top_srcdir)/tests"' \
-DBUILD='"$(abs_top_builddir)/tests"'
tests_tap_libtap_a_CPPFLAGS = -I$(abs_top_srcdir)/t
tests_tap_libtap_a_SOURCES = \
tests/tap/basic.c tests/tap/basic.h \
tests/tap/float.c tests/tap/float.h \
tests/tap/macros.h
check-local: $(check_PROGRAMS)
cd tests && ./runtests -l $(abs_top_srcdir)/tests/TESTS
tests_journal_LDADD = \
tests/tap/libtap.a \
src/libknotd.la src/libknots.la \
@LIBOBJS@
This diff is collapsed.
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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 3 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/>.
*/
#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include <tests/tap/basic.h>
#include "knot/server/journal.h"
#include "knot/knot.h"
static int journal_tests_count(int argc, char *argv[]);
static int journal_tests_run(int argc, char *argv[]);
/*! \brief Generate random string with given length. */
static int randstr(char* dst, size_t len)
{
for (int i = 0; i < len - 1; ++i) {
dst[i] = '0' + (int) (('Z'-'0') * (rand() / (RAND_MAX + 1.0)));
}
dst[len - 1] = '\0';
return 0;
}
/*! \brief Walk journal of chars into buffer. */
static int _wbi = 0;
static char _walkbuf[7];
static int walkchars_cmp(uint64_t k1, uint64_t k2) {
return k1 - k2;
}
static int walkchars(journal_t *j, journal_node_t *n) {
journal_read(j, n->id, walkchars_cmp, _walkbuf + _wbi);
++_wbi;
return 0;
}
int main(int argc, char *argv[])
{
plan(21);
/* Create tmpdir */
int fsize = 8092;
int jsize = 6;
char *tmpdir = test_tmpdir();
char jfn_buf[4096];
snprintf(jfn_buf, 4096 - 1, "%s/%s", tmpdir, "journal.XXXXXX");
/* Test 1: Create tmpfile. */
int tmp_fd = mkstemp(jfn_buf);
ok(tmp_fd >= 0, "journal: create temporary file");
if (tmp_fd < 0) {
skip_block(20, "journal: create temporary file failed");
}
close(tmp_fd);
/* Test 2: Create journal. */
const char *jfilename = jfn_buf;
int ret = journal_create(jfilename, jsize);
ok(ret == KNOT_EOK, "journal: create journal '%s'", jfilename);
/* Test 3: Open journal. */
journal_t *journal = journal_open(jfilename, fsize, JOURNAL_LAZY, 0);
ok(journal != 0, "journal: open");
/* Retain journal. */
journal_t *j = journal_retain(journal);
/* Test 4: Write entry to log. */
const char *sample = "deadbeef";
ret = journal_write(j, 0x0a, sample, strlen(sample));
ok(ret == KNOT_EOK, "journal: write");
/* Test 5: Read entry from log. */
char tmpbuf[64] = {'\0'};
ret = journal_read(j, 0x0a, 0, tmpbuf);
ok(ret == KNOT_EOK, "journal: read entry");
/* Test 6: Compare read data. */
ret = strncmp(sample, tmpbuf, strlen(sample));
ok(ret == 0, "journal: read data integrity check");
/* Append several characters. */
journal_write(j, 0, "X", 1); /* Dummy */
char word[7] = { 'w', 'o', 'r', 'd', '0', '\0', '\0' };
for (int i = 0; i < strlen(word); ++i) {
journal_write(j, i, word+i, 1);
}
/* Test 7: Compare journal_walk() result. */
_wbi = 0;
journal_walk(j, walkchars);
_walkbuf[_wbi] = '\0';
ret = strcmp(word, _walkbuf);
ok(ret == 0, "journal: read data integrity check 2 '%s'", _walkbuf);
_wbi = 0;
/* Test 8: Change single letter and compare. */
word[5] = 'X';
journal_write(j, 5, word+5, 1); /* append 'X', shifts out 'w' */
journal_walk(j, walkchars);
_walkbuf[_wbi] = '\0';
ret = strcmp(word + 1, _walkbuf);
ok(ret == 0, "journal: read data integrity check 3 '%s'", _walkbuf);
_wbi = 0;
/* Test 9: Attempt to retain and release. */
journal_t *tmp = journal_retain(j);
ok(tmp == j, "journal: tested journal retaining");
journal_release(tmp);
/* Release journal. */
journal_release(j);
/* Close journal. */
journal_close(journal);
/* Recreate journal = NORMAL mode. */
if (remove(jfilename) < 0) {
diag("journal: couldn't remove filename");
}
fsize = 8092;
jsize = 512;
ret = journal_create(jfilename, jsize);
j = journal_open(jfilename, fsize, 0, 0);
/* Test 10: Write random data. */
int chk_key = 0;
char chk_buf[64] = {'\0'};
ret = 0;
const int itcount = jsize * 5 + 5;
for (int i = 0; i < itcount; ++i) {
int key = rand() % 65535;
randstr(tmpbuf, sizeof(tmpbuf));
if (journal_write(j, key, tmpbuf, sizeof(tmpbuf)) != KNOT_EOK) {
ret = -1;
break;
}
/* Store some key on the end. */
if (i == itcount - 2) {
chk_key = key;
memcpy(chk_buf, tmpbuf, sizeof(chk_buf));
}
}
ok(j && ret == 0, "journal: sustained looped writes");
/* Test 11: Check data integrity. */
memset(tmpbuf, 0, sizeof(tmpbuf));
journal_read(j, chk_key, 0, tmpbuf);
ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
ok(j && ret == 0, "journal: read data integrity check");
/* Test 12: Reopen log and re-read value. */
memset(tmpbuf, 0, sizeof(tmpbuf));
journal_close(j);
j = journal_open(jfilename, fsize, 0, 0);
journal_read(j, chk_key, 0, tmpbuf);
ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
ok(j && ret == 0, "journal: read data integrity check after close/open");
/* Test 13: Map journal entry. */
char *mptr = NULL;
memset(chk_buf, 0xde, sizeof(chk_buf));
ret = journal_map(j, 0x12345, &mptr, sizeof(chk_buf));
ok(j && mptr && ret == 0, "journal: mapped journal entry");
if (ret != 0) {
skip_block(2, NULL);
}
/* Test 14: Write to mmaped entry and unmap. */
memcpy(mptr, chk_buf, sizeof(chk_buf));
ret = journal_unmap(j, 0x12345, mptr, 1);
ok(j && mptr && ret == 0, "journal: written to mapped entry and finished");
/* Test 15: Compare mmaped entry. */
memset(tmpbuf, 0, sizeof(tmpbuf));
journal_read(j, 0x12345, NULL, tmpbuf);
ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
ok(j && ret == 0, "journal: mapped entry data integrity check");
/* Test 16: Make a transaction. */
uint64_t tskey = 0x75750000;
ret = journal_trans_begin(j);
ok(j && ret == 0, "journal: TRANS begin");
for (int i = 0; i < 16; ++i) {
memset(tmpbuf, i, sizeof(tmpbuf));
journal_write(j, tskey + i, tmpbuf, sizeof(tmpbuf));
}
/* Test 17: Check if uncommited node exists. */
ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf);
ok(j && ret != 0, "journal: check for uncommited node");
/* Test 18: Commit transaction. */
ret = journal_trans_commit(j);
int read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf);
ok(j && ret == 0 && read_ret == 0, "journal: transaction commit");
/* Test 19: Rollback transaction. */
tskey = 0x6B6B0000;
journal_trans_begin(j);
for (int i = 0; i < 16; ++i) {
memset(tmpbuf, i, sizeof(tmpbuf));
journal_write(j, tskey + i, tmpbuf, sizeof(tmpbuf));
}
ret = journal_trans_rollback(j);
read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf);
ok(j && ret == 0 && read_ret != 0, "journal: transaction rollback");
/* Test 20: Write random data. */
ret = 0;
for (int i = 0; i < 512; ++i) {
int key = i;
randstr(tmpbuf, sizeof(tmpbuf));
ret = journal_map(j, key, &mptr, sizeof(tmpbuf));
if (ret != KNOT_EOK) {
diag("journal_map failed: %s", knot_strerror(ret));
break;
}
memcpy(mptr, tmpbuf, sizeof(tmpbuf));
if ((ret = journal_unmap(j, key, mptr, 1)) != KNOT_EOK) {
diag("journal_unmap failed: %s", knot_strerror(ret));
break;
}
/* Store some key on the end. */
memset(chk_buf, 0, sizeof(chk_buf));
ret = journal_read(j, key, 0, chk_buf);
if (ret != 0) {
diag("journal_map integrity check failed %s",
knot_strerror(ret));
break;
}
ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf));
if (ret != 0) {
diag("journal_map integrity check failed");
break;
}
}
ok(j && ret == 0, "journal: sustained mmap r/w");
/* Test 21: Open + create journal. */
journal_close(j);
remove(jfilename);
j = journal_open(jfilename, fsize, 0, 0);
ok(j != NULL, "journal: open+create from scratch");
/* Close journal. */
journal_close(j);
/* Delete journal. */
remove(jfilename);
return 0;
}
This diff is collapsed.
This diff is collapsed.
/*
* Basic utility routines for the TAP protocol.
*
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
* Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu>
* Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012
* The Board of Trustees of the Leland Stanford Junior University
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef TAP_BASIC_H
#define TAP_BASIC_H 1
#include <tests/tap/macros.h>
#include <stdarg.h> /* va_list */
#include <sys/types.h> /* size_t */
/*
* Used for iterating through arrays. ARRAY_SIZE returns the number of
* elements in the array (useful for a < upper bound in a for loop) and
* ARRAY_END returns a pointer to the element past the end (ISO C99 makes it
* legal to refer to such a pointer as long as it's never dereferenced).
*/
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)])
BEGIN_DECLS
/*
* The test count. Always contains the number that will be used for the next
* test status.
*/
extern unsigned long testnum;
/* Print out the number of tests and set standard output to line buffered. */
void plan(unsigned long count);
/*
* Prepare for lazy planning, in which the plan will be printed automatically
* at the end of the test program.
*/
void plan_lazy(void);
/* Skip the entire test suite. Call instead of plan. */
void skip_all(const char *format, ...)
__attribute__((__noreturn__, __format__(printf, 1, 2)));
/*
* Basic reporting functions. The okv() function is the same as ok() but
* takes the test description as a va_list to make it easier to reuse the
* reporting infrastructure when writing new tests.
*/
void ok(int success, const char *format, ...)
__attribute__((__format__(printf, 2, 3)));
void okv(int success, const char *format, va_list args);
void skip(const char *reason, ...)
__attribute__((__format__(printf, 1, 2)));
/* Report the same status on, or skip, the next count tests. */
void ok_block(unsigned long count, int success, const char *format, ...)
__attribute__((__format__(printf, 3, 4)));
void skip_block(unsigned long count, const char *reason, ...)
__attribute__((__format__(printf, 2, 3)));
/* Check an expected value against a seen value. */
void is_int(long wanted, long seen, const char *format, ...)
__attribute__((__format__(printf, 3, 4)));
void is_string(const char *wanted, const char *seen, const char *format, ...)
__attribute__((__format__(printf, 3, 4)));
void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
__attribute__((__format__(printf, 3, 4)));
/* Bail out with an error. sysbail appends strerror(errno). */
void bail(const char *format, ...)
__attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2)));
void sysbail(const char *format, ...)
__attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2)));
/* Report a diagnostic to stderr prefixed with #. */
void diag(const char *format, ...)
__attribute__((__nonnull__, __format__(printf, 1, 2)));
void sysdiag(const char *format, ...)
__attribute__((__nonnull__, __format__(printf, 1, 2)));
/* Allocate memory, reporting a fatal error with bail on failure. */
void *bcalloc(size_t, size_t)
__attribute__((__alloc_size__(1, 2), __malloc__));
void *bmalloc(size_t)
__attribute__((__alloc_size__(1), __malloc__));
void *brealloc(void *, size_t)
__attribute__((__alloc_size__(2), __malloc__));
char *bstrdup(const char *)
__attribute__((__malloc__, __nonnull__));
char *bstrndup(const char *, size_t)
__attribute__((__malloc__, __nonnull__));
/*
* Find a test file under BUILD or SOURCE, returning the full path. The
* returned path should be freed with test_file_path_free().
*/
char *test_file_path(const char *file)
__attribute__((__malloc__, __nonnull__));
void test_file_path_free(char *path);
/*
* Create a temporary directory relative to BUILD and return the path. The
* returned path should be freed with test_tmpdir_free.
*/
char *test_tmpdir(void)
__attribute__((__malloc__));
void test_tmpdir_free(char *path);
END_DECLS
#endif /* TAP_BASIC_H */
/*
* Utility routines for writing floating point tests.
*
* Currently provides only one function, which checks whether a double is
* equal to an expected value within a given epsilon. This is broken into a
* separate source file from the rest of the basic C TAP library because it
* may require linking with -lm on some platforms, and the package may not
* otherwise care about floating point.
*
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
* Copyright 2008, 2010, 2012 Russ Allbery <rra@stanford.edu>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* Required for isnan() and isinf(). */
#if defined(__STRICT_ANSI__) || defined(PEDANTIC)
# ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE 600
# endif
#endif
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <tests/tap/basic.h>
#include <tests/tap/float.h>
/*
* Takes an expected double and a seen double and assumes the test passes if
* those two numbers are within delta of each other.
*/
void
is_double(double wanted, double seen, double epsilon, const char *format, ...)
{
va_list args;
va_start(args, format);
fflush(stderr);
if ((isnan(wanted) && isnan(seen))
|| (isinf(wanted) && isinf(seen) && wanted == seen)
|| fabs(wanted - seen) <= epsilon)
okv(1, format, args);
else {
printf("# wanted: %g\n# seen: %g\n", wanted, seen);
okv(0, format, args);
}
}
/*
* Floating point check function for the TAP protocol.
*
* This file is part of C TAP Harness. The current version plus supporting
* documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
*
* Copyright 2008, 2010, 2012 Russ Allbery <rra@stanford.edu>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef TAP_FLOAT_H
#define TAP_FLOAT_H 1
#include <tests/tap/macros.h>
BEGIN_DECLS
/* Check an expected value against a seen value within epsilon. */
void is_double(double wanted, double seen, double epsilon,
const char *format, ...)
__attribute__((__format__(printf, 4, 5)));
END_DECLS
#endif /* TAP_FLOAT_H */
# Shell function library for test cases.
#
# Note that while many of the functions in this library could benefit from
# using "local" to avoid possibly hammering global variables, Solaris /bin/sh
# doesn't support local and this library aspires to be portable to Solaris
# Bourne shell. Instead, all private variables are prefixed with "tap_".
#
# This file provides a TAP-compatible shell function library useful for
# writing test cases. It is part of C TAP Harness, which can be found at
# <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
#
# Written by Russ Allbery <rra@stanford.edu>
# Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu>
# Copyright 2006, 2007, 2008, 2013
# The Board of Trustees of the Leland Stanford Junior University
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# Print out the number of test cases we expect to run.
plan () {
count=1
planned="$1"
failed=0
echo "1..$1"
trap finish 0
}
# Prepare for lazy planning.
plan_lazy () {
count=1
planned=0
failed=0
trap finish 0
}
# Report the test status on exit.
finish () {
tap_highest=`expr "$count" - 1`
if [ "$planned" = 0 ] ; then
echo "1..$tap_highest"
planned="$tap_highest"
fi
tap_looks='# Looks like you'
if [ "$planned" -gt 0 ] ; then
if [ "$planned" -gt "$tap_highest" ] ; then
if [ "$planned" -gt 1 ] ; then
echo "$tap_looks planned $planned tests but only ran" \
"$tap_highest"
else
echo "$tap_looks planned $planned test but only ran" \
"$tap_highest"
fi
elif [ "$planned" -lt "$tap_highest" ] ; then
tap_extra=`expr "$tap_highest" - "$planned"`
if [ "$planned" -gt 1 ] ; then
echo "$tap_looks planned $planned tests but ran" \
"$tap_extra extra"
else
echo "$tap_looks planned $planned test but ran" \
"$tap_extra extra"
fi
elif [ "$failed" -gt 0 ] ; then
if [ "$failed" -gt 1 ] ; then
echo "$tap_looks failed $failed tests of $planned"
else
echo "$tap_looks failed $failed test of $planned"
fi
elif [ "$planned" -gt 1 ] ; then
echo "# All $planned tests successful or skipped"
else
echo "# $planned test successful or skipped"
fi
fi
}
# Skip the entire test suite. Should be run instead of plan.
skip_all () {
tap_desc="$1"
if [ -n "$tap_desc" ] ; then
echo "1..0 # skip $tap_desc"
else
echo "1..0 # skip"
fi
exit 0
}
# ok takes a test description and a command to run and prints success if that
# command is successful, false otherwise. The count starts at 1 and is
# updated each time ok is printed.
ok () {
tap_desc="$1"
if [ -n "$tap_desc" ] ; then
tap_desc=" - $tap_desc"
fi
shift
if "$@" ; then
echo ok "$count$tap_desc"
else
echo not ok "$count$tap_desc"
failed=`expr $failed + 1`
fi
count=`expr $count + 1`
}
# Skip the next test. Takes the reason why the test is skipped.
skip () {
echo "ok $count # skip $*"
count=`expr $count + 1`
}
# Report the same status on a whole set of tests. Takes the count of tests,
# the description, and then the command to run to determine the status.
ok_block () {
tap_i=$count
tap_end=`expr $count + $1`
shift
while [ "$tap_i" -lt "$tap_end" ] ; do
ok "$@"
tap_i=`expr $tap_i + 1`
done
}
# Skip a whole set of tests. Takes the count and then the reason for skipping
# the test.
skip_block () {
tap_i=$count
tap_end=`expr $count + $1`
shift
while [ "$tap_i" -lt "$tap_end" ] ; do
skip "$@"
tap_i=`expr $tap_i + 1`
done
}
# Portable variant of printf '%s\n' "$*". In the majority of cases, this
# function is slower than printf, because the latter is often implemented
# as a builtin command. The value of the variable IFS is ignored.
#
# This macro must not be called via backticks inside double quotes, since this
# will result in bizarre escaping behavior and lots of extra backslashes on
# Solaris.
puts () {
cat << EOH
$@
EOH
}
# Run a program expected to succeed, and print ok if it does and produces the
# correct output. Takes the description, expected exit status, the expected
# output, the command to run, and then any arguments for that command.
# Standard output and standard error are combined when analyzing the output of
# the command.
#
# If the command may contain system-specific error messages in its output,
# add strip_colon_error before the command to post-process its output.
ok_program () {