You've already forked bash-ini-parser
mirror of
https://github.com/albfan/bash-ini-parser.git
synced 2025-08-04 19:42:06 +03:00
Add continuous integration
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "t/sharness"]
|
||||
path = t/sharness
|
||||
url = https://github.com/mlafeldt/sharness.git
|
10
.travis.yml
10
.travis.yml
@@ -5,12 +5,12 @@ compiler:
|
||||
|
||||
before_install:
|
||||
|
||||
script: cd t && make SHELL=/bin/bash
|
||||
script: cd t && make
|
||||
|
||||
## whitelist
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- cd t
|
||||
- make check
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
4
Makefile.am
Normal file
4
Makefile.am
Normal file
@@ -0,0 +1,4 @@
|
||||
bin_SCRIPTS = bash-ini-parser
|
||||
CLEAN_FILES = $(bin_SCRIPTS)
|
||||
|
||||
SUBDIRS = t
|
4
autogen.sh
Executable file
4
autogen.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
autoreconf -ivf
|
||||
./configure
|
6
bash-ini-parser
Normal file → Executable file
6
bash-ini-parser
Normal file → Executable file
@@ -203,5 +203,9 @@ function cfg_update {
|
||||
eval "function $item"
|
||||
}
|
||||
|
||||
|
||||
#Test harness
|
||||
if [ $# != 0 ]
|
||||
then
|
||||
$@
|
||||
fi
|
||||
# vim: filetype=sh
|
||||
|
651
build-aux/tap-driver.sh
Executable file
651
build-aux/tap-driver.sh
Executable file
@@ -0,0 +1,651 @@
|
||||
#! /bin/sh
|
||||
# Copyright (C) 2011-2017 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# 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 <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
scriptversion=2013-12-23.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 <<END
|
||||
Usage:
|
||||
tap-driver.sh --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--ignore-exit]
|
||||
[--diagnostic-string=STRING] [--merge|--no-merge]
|
||||
[--comments|--no-comments] [--] TEST-COMMAND
|
||||
The '--test-name', '-log-file' and '--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
# TODO: better error handling in option parsing (in particular, ensure
|
||||
# TODO: $log_file, $trs_file and $test_name are defined).
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the result and output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=0
|
||||
color_tests=0
|
||||
merge=0
|
||||
ignore_exit=0
|
||||
comments=0
|
||||
diag_string='#'
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "$me $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) shift;; # No-op.
|
||||
--merge) merge=1;;
|
||||
--no-merge) merge=0;;
|
||||
--ignore-exit) ignore_exit=1;;
|
||||
--comments) comments=1;;
|
||||
--no-comments) comments=0;;
|
||||
--diagnostic-string) diag_string=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
test $# -gt 0 || usage_error "missing test command"
|
||||
|
||||
case $expect_failure in
|
||||
yes) expect_failure=1;;
|
||||
*) expect_failure=0;;
|
||||
esac
|
||||
|
||||
if test $color_tests = yes; then
|
||||
init_colors='
|
||||
color_map["red"]="[0;31m" # Red.
|
||||
color_map["grn"]="[0;32m" # Green.
|
||||
color_map["lgn"]="[1;32m" # Light green.
|
||||
color_map["blu"]="[1;34m" # Blue.
|
||||
color_map["mgn"]="[0;35m" # Magenta.
|
||||
color_map["std"]="[m" # No color.
|
||||
color_for_result["ERROR"] = "mgn"
|
||||
color_for_result["PASS"] = "grn"
|
||||
color_for_result["XPASS"] = "red"
|
||||
color_for_result["FAIL"] = "red"
|
||||
color_for_result["XFAIL"] = "lgn"
|
||||
color_for_result["SKIP"] = "blu"'
|
||||
else
|
||||
init_colors=''
|
||||
fi
|
||||
|
||||
# :; is there to work around a bug in bash 3.2 (and earlier) which
|
||||
# does not always set '$?' properly on redirection failure.
|
||||
# See the Autoconf manual for more details.
|
||||
:;{
|
||||
(
|
||||
# Ignore common signals (in this subshell only!), to avoid potential
|
||||
# problems with Korn shells. Some Korn shells are known to propagate
|
||||
# to themselves signals that have killed a child process they were
|
||||
# waiting for; this is done at least for SIGINT (and usually only for
|
||||
# it, in truth). Without the `trap' below, such a behaviour could
|
||||
# cause a premature exit in the current subshell, e.g., in case the
|
||||
# test command it runs gets terminated by a SIGINT. Thus, the awk
|
||||
# script we are piping into would never seen the exit status it
|
||||
# expects on its last input line (which is displayed below by the
|
||||
# last `echo $?' statement), and would thus die reporting an internal
|
||||
# error.
|
||||
# For more information, see the Autoconf manual and the threads:
|
||||
# <http://lists.gnu.org/archive/html/bug-autoconf/2011-09/msg00004.html>
|
||||
# <http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/004121.html>
|
||||
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" \
|
||||
'
|
||||
# TODO: the usages of "cat >&3" below could be optimized when using
|
||||
# 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
|
||||
}
|
||||
|
||||
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 <http://www.austingroupbugs.net/view.php?id=51>
|
||||
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: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
23
configure.ac
Normal file
23
configure.ac
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT([bash-ini-parser], [1.0], [albertofanjul@gmail.com])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([foreign 1.11])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
# Checks for header files.
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
|
||||
# Checks for library functions.
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
t/Makefile])
|
||||
AC_REQUIRE_AUX_FILE([tap-driver.sh])
|
||||
AC_OUTPUT
|
1
t/.simplecov
Normal file
1
t/.simplecov
Normal file
@@ -0,0 +1 @@
|
||||
Bashcov.root_directory(File.expand_path('../../', Dir.getwd))
|
52
t/Makefile
52
t/Makefile
@@ -1,52 +0,0 @@
|
||||
SHELL_PATH ?= $(SHELL)
|
||||
PROVE ?= prove
|
||||
DEFAULT_TEST_TARGET ?= test
|
||||
TAP_OUT ?= tapout
|
||||
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
|
||||
T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
|
||||
|
||||
all: $(DEFAULT_TEST_TARGET)
|
||||
|
||||
test: pre-clean
|
||||
@$(MAKE) aggregate-results-and-cleanup
|
||||
|
||||
prove: pre-clean
|
||||
@echo '*** prove ***'; prove --exec '$(SHELL_PATH_SQ)' $(PROVE_OPTS) $(T) :: $(TEST_OPTS)
|
||||
@$(MAKE) clean-except-prove-cache
|
||||
|
||||
tap: pre-clean clean-tap
|
||||
mkdir $(TAP_OUT)
|
||||
@$(MAKE) aggregate-results-and-cleanup
|
||||
|
||||
clean-tap:
|
||||
@$(RM) -r $(TAP_OUT)
|
||||
|
||||
aggregate-results:
|
||||
@for f in test-results/t*-*.counts; do \
|
||||
echo "$$f"; \
|
||||
done | '$(SHELL_PATH_SQ)' ./sharness/aggregate-results.sh
|
||||
|
||||
pre-clean:
|
||||
@$(RM) -r test-results
|
||||
|
||||
clean-except-prove-cache:
|
||||
@$(RM) -r 'trash directory'.* test-results
|
||||
|
||||
clean: clean-except-prove-cache
|
||||
@$(RM) .prove
|
||||
|
||||
aggregate-results-and-cleanup: $(T)
|
||||
@$(MAKE) aggregate-results
|
||||
@$(MAKE) clean
|
||||
|
||||
$(T):
|
||||
ifeq ($(DEFAULT_TEST_TARGET),tap)
|
||||
@echo '*** $@ ***'; '$(SHELL_PATH_SQ)' $@ > $(TAP_OUT)/$@
|
||||
else
|
||||
@echo '*** $@ ***'; '$(SHELL_PATH_SQ)' $@
|
||||
endif
|
||||
|
||||
.PHONY: all test prove tap aggregate-results $(T)
|
||||
.PHONY: pre-clean clean-except-prove-cache clean clean-tap aggregate-results-and-cleanup
|
4
t/Makefile.am
Normal file
4
t/Makefile.am
Normal file
@@ -0,0 +1,4 @@
|
||||
TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||
$(top_srcdir)/build-aux/tap-driver.sh
|
||||
TESTS = t0001-parse.sh t0002-invalid.sh t0003-sections.sh t0004-comments.sh
|
||||
EXTRA_DIST = $(TESTS)
|
17
t/setup.sh
Executable file
17
t/setup.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
. sharness/sharness.sh
|
||||
|
||||
SHARNESS_TEST_EXTENSION="bash"
|
||||
|
||||
export GEM_PATH=$GEM_PATH:/home/alberto/.gem/ruby/2.2.0
|
||||
|
||||
if test "$COVERAGE" = "yes"
|
||||
then
|
||||
COMMAND="$COV_PROGRAM ../../bash-ini-parser"
|
||||
else
|
||||
. ../../bash-ini-parser
|
||||
COMMAND=""
|
||||
fi
|
||||
|
||||
export COMMAND
|
||||
|
||||
DIR_TEST=$SHARNESS_TEST_DIRECTORY/${0%%-*}
|
1
t/sharness
Submodule
1
t/sharness
Submodule
Submodule t/sharness added at 2298d6a491
@@ -1,16 +0,0 @@
|
||||
language: erlang # no shell language support; use least-loaded worker(s)
|
||||
|
||||
env:
|
||||
- TEST_OPTS=-v
|
||||
- DEFAULT_TEST_TARGET=prove
|
||||
|
||||
install:
|
||||
- sudo make install prefix=/usr/local
|
||||
|
||||
script:
|
||||
- make test
|
||||
- sudo make -C /usr/local/share/doc/sharness/examples
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
@@ -1,302 +0,0 @@
|
||||
# Sharness API
|
||||
|
||||
### SHARNESS_VERSION
|
||||
|
||||
Public: Current version of Sharness.
|
||||
|
||||
### SHARNESS_TEST_EXTENSION
|
||||
|
||||
Public: The file extension for tests. By default, it is set to "t".
|
||||
|
||||
### test_set_prereq()
|
||||
|
||||
Public: Define that a test prerequisite is available.
|
||||
|
||||
The prerequisite can later be checked explicitly using test_have_prereq or
|
||||
implicitly by specifying the prerequisite name in calls to test_expect_success
|
||||
or test_expect_failure.
|
||||
|
||||
$1 - Name of prerequiste (a simple word, in all capital letters by convention)
|
||||
|
||||
Examples
|
||||
|
||||
# Set PYTHON prerequisite if interpreter is available.
|
||||
command -v python >/dev/null && test_set_prereq PYTHON
|
||||
|
||||
# Set prerequisite depending on some variable.
|
||||
test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
|
||||
|
||||
Returns nothing.
|
||||
|
||||
### test_have_prereq()
|
||||
|
||||
Public: Check if one or more test prerequisites are defined.
|
||||
|
||||
The prerequisites must have previously been set with test_set_prereq.
|
||||
The most common use of this is to skip all the tests if some essential
|
||||
prerequisite is missing.
|
||||
|
||||
$1 - Comma-separated list of test prerequisites.
|
||||
|
||||
Examples
|
||||
|
||||
# Skip all remaining tests if prerequisite is not set.
|
||||
if ! test_have_prereq PERL; then
|
||||
skip_all='skipping perl interface tests, perl not available'
|
||||
test_done
|
||||
fi
|
||||
|
||||
Returns 0 if all prerequisites are defined or 1 otherwise.
|
||||
|
||||
### test_debug()
|
||||
|
||||
Public: Execute commands in debug mode.
|
||||
|
||||
Takes a single argument and evaluates it only when the test script is started
|
||||
with --debug. This is primarily meant for use during the development of test
|
||||
scripts.
|
||||
|
||||
$1 - Commands to be executed.
|
||||
|
||||
Examples
|
||||
|
||||
test_debug "cat some_log_file"
|
||||
|
||||
Returns the exit code of the last command executed in debug mode or 0
|
||||
otherwise.
|
||||
|
||||
### test_expect_success()
|
||||
|
||||
Public: Run test commands and expect them to succeed.
|
||||
|
||||
When the test passed, an "ok" message is printed and the number of successful
|
||||
tests is incremented. When it failed, a "not ok" message is printed and the
|
||||
number of failed tests is incremented.
|
||||
|
||||
With --immediate, exit test immediately upon the first failed test.
|
||||
|
||||
Usually takes two arguments:
|
||||
$1 - Test description
|
||||
$2 - Commands to be executed.
|
||||
|
||||
With three arguments, the first will be taken to be a prerequisite:
|
||||
$1 - Comma-separated list of test prerequisites. The test will be skipped if
|
||||
not all of the given prerequisites are set. To negate a prerequisite,
|
||||
put a "!" in front of it.
|
||||
$2 - Test description
|
||||
$3 - Commands to be executed.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success \
|
||||
'git-write-tree should be able to write an empty tree.' \
|
||||
'tree=$(git-write-tree)'
|
||||
|
||||
# Test depending on one prerequisite.
|
||||
test_expect_success TTY 'git --paginate rev-list uses a pager' \
|
||||
' ... '
|
||||
|
||||
# Multiple prerequisites are separated by a comma.
|
||||
test_expect_success PERL,PYTHON 'yo dawg' \
|
||||
' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
|
||||
|
||||
Returns nothing.
|
||||
|
||||
### test_expect_failure()
|
||||
|
||||
Public: Run test commands and expect them to fail. Used to demonstrate a known
|
||||
breakage.
|
||||
|
||||
This is NOT the opposite of test_expect_success, but rather used to mark a
|
||||
test that demonstrates a known breakage.
|
||||
|
||||
When the test passed, an "ok" message is printed and the number of fixed tests
|
||||
is incremented. When it failed, a "not ok" message is printed and the number
|
||||
of tests still broken is incremented.
|
||||
|
||||
Failures from these tests won't cause --immediate to stop.
|
||||
|
||||
Usually takes two arguments:
|
||||
$1 - Test description
|
||||
$2 - Commands to be executed.
|
||||
|
||||
With three arguments, the first will be taken to be a prerequisite:
|
||||
$1 - Comma-separated list of test prerequisites. The test will be skipped if
|
||||
not all of the given prerequisites are set. To negate a prerequisite,
|
||||
put a "!" in front of it.
|
||||
$2 - Test description
|
||||
$3 - Commands to be executed.
|
||||
|
||||
Returns nothing.
|
||||
|
||||
### test_must_fail()
|
||||
|
||||
Public: Run command and ensure that it fails in a controlled way.
|
||||
|
||||
Use it instead of "! <command>". For example, when <command> dies due to a
|
||||
segfault, test_must_fail diagnoses it as an error, while "! <command>" would
|
||||
mistakenly be treated as just another expected failure.
|
||||
|
||||
This is one of the prefix functions to be used inside test_expect_success or
|
||||
test_expect_failure.
|
||||
|
||||
$1.. - Command to be executed.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success 'complain and die' '
|
||||
do something &&
|
||||
do something else &&
|
||||
test_must_fail git checkout ../outerspace
|
||||
'
|
||||
|
||||
Returns 1 if the command succeeded (exit code 0).
|
||||
Returns 1 if the command died by signal (exit codes 130-192)
|
||||
Returns 1 if the command could not be found (exit code 127).
|
||||
Returns 0 otherwise.
|
||||
|
||||
### test_might_fail()
|
||||
|
||||
Public: Run command and ensure that it succeeds or fails in a controlled way.
|
||||
|
||||
Similar to test_must_fail, but tolerates success too. Use it instead of
|
||||
"<command> || :" to catch failures caused by a segfault, for instance.
|
||||
|
||||
This is one of the prefix functions to be used inside test_expect_success or
|
||||
test_expect_failure.
|
||||
|
||||
$1.. - Command to be executed.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success 'some command works without configuration' '
|
||||
test_might_fail git config --unset all.configuration &&
|
||||
do something
|
||||
'
|
||||
|
||||
Returns 1 if the command died by signal (exit codes 130-192)
|
||||
Returns 1 if the command could not be found (exit code 127).
|
||||
Returns 0 otherwise.
|
||||
|
||||
### test_expect_code()
|
||||
|
||||
Public: Run command and ensure it exits with a given exit code.
|
||||
|
||||
This is one of the prefix functions to be used inside test_expect_success or
|
||||
test_expect_failure.
|
||||
|
||||
$1 - Expected exit code.
|
||||
$2.. - Command to be executed.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success 'Merge with d/f conflicts' '
|
||||
test_expect_code 1 git merge "merge msg" B master
|
||||
'
|
||||
|
||||
Returns 0 if the expected exit code is returned or 1 otherwise.
|
||||
|
||||
### test_cmp()
|
||||
|
||||
Public: Compare two files to see if expected output matches actual output.
|
||||
|
||||
The TEST_CMP variable defines the command used for the comparision; it
|
||||
defaults to "diff -u". Only when the test script was started with --verbose,
|
||||
will the command's output, the diff, be printed to the standard output.
|
||||
|
||||
This is one of the prefix functions to be used inside test_expect_success or
|
||||
test_expect_failure.
|
||||
|
||||
$1 - Path to file with expected output.
|
||||
$2 - Path to file with actual output.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success 'foo works' '
|
||||
echo expected >expected &&
|
||||
foo >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
Returns the exit code of the command set by TEST_CMP.
|
||||
|
||||
### test_when_finished()
|
||||
|
||||
Public: Schedule cleanup commands to be run unconditionally at the end of a
|
||||
test.
|
||||
|
||||
If some cleanup command fails, the test will not pass. With --immediate, no
|
||||
cleanup is done to help diagnose what went wrong.
|
||||
|
||||
This is one of the prefix functions to be used inside test_expect_success or
|
||||
test_expect_failure.
|
||||
|
||||
$1.. - Commands to prepend to the list of cleanup commands.
|
||||
|
||||
Examples
|
||||
|
||||
test_expect_success 'test core.capslock' '
|
||||
git config core.capslock true &&
|
||||
test_when_finished "git config --unset core.capslock" &&
|
||||
do_something
|
||||
'
|
||||
|
||||
Returns the exit code of the last cleanup command executed.
|
||||
|
||||
### test_done()
|
||||
|
||||
Public: Summarize test results and exit with an appropriate error code.
|
||||
|
||||
Must be called at the end of each test script.
|
||||
|
||||
Can also be used to stop tests early and skip all remaining tests. For this,
|
||||
set skip_all to a string explaining why the tests were skipped before calling
|
||||
test_done.
|
||||
|
||||
Examples
|
||||
|
||||
# Each test script must call test_done at the end.
|
||||
test_done
|
||||
|
||||
# Skip all remaining tests if prerequisite is not set.
|
||||
if ! test_have_prereq PERL; then
|
||||
skip_all='skipping perl interface tests, perl not available'
|
||||
test_done
|
||||
fi
|
||||
|
||||
Returns 0 if all tests passed or 1 if there was a failure.
|
||||
|
||||
### cleanup()
|
||||
|
||||
Public: Schedule cleanup commands to be run unconditionally when all tests
|
||||
have run.
|
||||
|
||||
This can be used to clean up things like test databases. It is not needed to
|
||||
clean up temporary files, as test_done already does that.
|
||||
|
||||
Examples:
|
||||
|
||||
cleanup mysql -e "DROP DATABASE mytest"
|
||||
|
||||
Returns the exit code of the last cleanup command executed.
|
||||
|
||||
### SHARNESS_TEST_DIRECTORY
|
||||
|
||||
Public: Root directory containing tests. Tests can override this variable,
|
||||
e.g. for testing Sharness itself.
|
||||
|
||||
### SHARNESS_BUILD_DIRECTORY
|
||||
|
||||
Public: Build directory that will be added to PATH. By default, it is set to
|
||||
the parent directory of SHARNESS_TEST_DIRECTORY.
|
||||
|
||||
### SHARNESS_TEST_FILE
|
||||
|
||||
Public: Path to test script currently executed.
|
||||
|
||||
### SHARNESS_TRASH_DIRECTORY
|
||||
|
||||
Public: Empty trash directory, the test area, provided for each test. The HOME
|
||||
variable is set to that directory too.
|
||||
|
||||
Generated by tomdoc.sh version 0.1.4
|
@@ -1,116 +0,0 @@
|
||||
v0.3.0 (2013-04-03)
|
||||
-------------------
|
||||
|
||||
This release is all about bringing upstream fixes and improvements from Git to
|
||||
Sharness ([GH-7]).
|
||||
|
||||
List of merged upstream changes:
|
||||
|
||||
* Make test number come first in `not ok $count - $message`.
|
||||
* Paint known breakages in yellow.
|
||||
* Paint unexpectedly fixed known breakages in bold red.
|
||||
* Paint skipped tests in blue.
|
||||
* Change info messages from yellow/brown to cyan.
|
||||
* Fix `say_color()` to not interpret `\a\b\c` in the message.
|
||||
* Add check for invalid use of `skip_all` facility.
|
||||
* Rename `$satisfied` to `$satisfied_prereq`.
|
||||
* Allow negation of prerequisites with "!".
|
||||
* Retain cache file `test/.prove` across prove runs.
|
||||
* Replace `basic.t` with `sharness.t` which is an adapted version of
|
||||
`t0000-basic.sh` from upstream.
|
||||
* Update `README.git` with upstream changes.
|
||||
|
||||
Other changes:
|
||||
|
||||
* Add [git-integration] to the list of projects using Sharness. Also pay tribute
|
||||
to Git's test suite.
|
||||
* Let Travis only test the master branch (and pull requests).
|
||||
|
||||
[GH-7]: https://github.com/mlafeldt/sharness/pull/7
|
||||
[git-integration]: https://github.com/johnkeeping/git-integration
|
||||
|
||||
v0.2.5 (2013-03-29)
|
||||
-------------------
|
||||
|
||||
* Allow to install Sharness via `make install` and to uninstall it via
|
||||
`make uninstall`. See brand-new installation instructions in README. ([GH-5])
|
||||
* Allow users to override the test extension via `SHARNESS_TEST_EXTENSION` if
|
||||
they wish to. ([GH-6])
|
||||
* Don't set a variable and export it at the same time. ([GH-6])
|
||||
* Remove `TEST_INSTALLED` -- use `SHARNESS_BUILD_DIRECTORY` instead.
|
||||
* Add vi modeline to `sharness.sh`.
|
||||
* Add `AGGREGATE_SCRIPT` variable to `test/Makefile`.
|
||||
* Remove superfluous `SHARNESS_TEST_DIRECTORY` assignments from `test/basic.t`.
|
||||
* Add [timedb] to the list of projects using Sharness.
|
||||
* Add Sharness alternatives to README.
|
||||
* Rename HISTORY.md to CHANGELOG.md.
|
||||
|
||||
[GH-5]: https://github.com/mlafeldt/sharness/pull/5
|
||||
[GH-6]: https://github.com/mlafeldt/sharness/pull/6
|
||||
[timedb]: http://git.cryptoism.org/cgit.cgi/timedb.git
|
||||
|
||||
v0.2.4 (2012-07-13)
|
||||
-------------------
|
||||
|
||||
* Add `simple.t` to tests and README.
|
||||
* Provide `SHARNESS_TEST_FILE` which is the path to the test script currently
|
||||
being executed.
|
||||
* Add [dabba] to the list of projects using Sharness.
|
||||
|
||||
[dabba]: https://github.com/eroullit/dabba
|
||||
|
||||
v0.2.3 (2012-06-20)
|
||||
-------------------
|
||||
|
||||
* Make `.t` the new test file extension, which is the default extension used by
|
||||
`prove(1)`. (You can still use the `t????-*` scheme, but you need to rename
|
||||
the `.sh` ending of all tests.)
|
||||
* Rename, export, and document public variables `SHARNESS_TEST_DIRECTORY`,
|
||||
`SHARNESS_BUILD_DIRECTORY`, and `SHARNESS_TRASH_DIRECTORY`.
|
||||
* TomDoc `SHARNESS_TEST_EXTENSION`.
|
||||
|
||||
v0.2.2 (2012-04-27)
|
||||
-------------------
|
||||
|
||||
* Document all public API functions using [TomDoc] and let [tomdoc.sh] generate
|
||||
documentation in markdown format from it, see `API.md`.
|
||||
* Rename `test_skip` to `test_skip_` as it is internal.
|
||||
* Clean up `test/Makefile`.
|
||||
* Sync Git README with upstream.
|
||||
|
||||
[TomDoc]: http://tomdoc.org/
|
||||
[tomdoc.sh]: https://github.com/mlafeldt/tomdoc.sh
|
||||
|
||||
v0.2.1 (2012-03-01)
|
||||
-------------------
|
||||
|
||||
* Fix: Redirect stdin of tests (by @peff).
|
||||
* Unify coding style across all shell scripts.
|
||||
* Remove superfluous functions `sane_unset` and `test_declared_prereq`.
|
||||
* Get rid of variables `DIFF` and `TEST_CMP_USE_COPIED_CONTEXT`.
|
||||
* Remove dysfunctional smoke testing targets from `test/Makefile`.
|
||||
* Add Travis CI config.
|
||||
* Add top-level Makefile to say `make test`.
|
||||
* Add GPL header to all files from Git.
|
||||
|
||||
v0.2.0 (2011-12-13)
|
||||
-------------------
|
||||
|
||||
* Rename `test-lib.sh` to `sharness.sh`.
|
||||
* Strip more Git-specific functionality.
|
||||
* Add variable `SHARNESS_VERSION`.
|
||||
* Move self-tests to `test` folder; keep essential files in root.
|
||||
* Update README.
|
||||
* Add this history file.
|
||||
|
||||
v0.1.1 (2011-11-02)
|
||||
-------------------
|
||||
|
||||
* Merge changes to test harness library from Git v1.7.8-rc0
|
||||
|
||||
v0.1.0 (2011-05-02)
|
||||
-------------------
|
||||
|
||||
* First version based on test harness library from Git v1.7.5
|
||||
* Remove Git-specific functions, variables, prerequisites, make targets, etc.
|
||||
* Remove `GIT_` prefix from global variables.
|
@@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
@@ -1,36 +0,0 @@
|
||||
prefix = $(HOME)
|
||||
|
||||
INSTALL_DIR = $(prefix)/share/sharness
|
||||
DOC_DIR = $(prefix)/share/doc/sharness
|
||||
EXAMPLE_DIR = $(DOC_DIR)/examples
|
||||
|
||||
INSTALL_FILES = aggregate-results.sh sharness.sh
|
||||
DOC_FILES = API.md CHANGELOG.md COPYING README.git README.md
|
||||
EXAMPLE_FILES = test/Makefile test/simple.t
|
||||
|
||||
INSTALL = install
|
||||
RM = rm -f
|
||||
SED = sed
|
||||
TOMDOCSH = tomdoc.sh
|
||||
|
||||
all:
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(INSTALL_DIR) $(DOC_DIR) $(EXAMPLE_DIR)
|
||||
$(INSTALL) -m 644 $(INSTALL_FILES) $(INSTALL_DIR)
|
||||
$(INSTALL) -m 644 $(DOC_FILES) $(DOC_DIR)
|
||||
$(SED) -e "s!aggregate-results.sh!$(INSTALL_DIR)/aggregate-results.sh!" test/Makefile > $(EXAMPLE_DIR)/Makefile
|
||||
$(SED) -e "s!. ./sharness.sh!. $(INSTALL_DIR)/sharness.sh!" test/simple.t > $(EXAMPLE_DIR)/simple.t
|
||||
|
||||
uninstall:
|
||||
$(RM) -r $(INSTALL_DIR) $(DOC_DIR) $(EXAMPLE_DIR)
|
||||
|
||||
doc: all
|
||||
{ printf "# Sharness API\n\n"; \
|
||||
$(TOMDOCSH) -m -a Public sharness.sh; \
|
||||
printf "Generated by "; $(TOMDOCSH) --version; } >API.md
|
||||
|
||||
test: all
|
||||
$(MAKE) -C test
|
||||
|
||||
.PHONY: all install uninstall doc test
|
@@ -1,709 +0,0 @@
|
||||
Core GIT Tests
|
||||
==============
|
||||
|
||||
This directory holds many test scripts for core GIT tools. The
|
||||
first part of this short document describes how to run the tests
|
||||
and read their output.
|
||||
|
||||
When fixing the tools or adding enhancements, you are strongly
|
||||
encouraged to add tests in this directory to cover what you are
|
||||
trying to fix or enhance. The later part of this short document
|
||||
describes how your test scripts should be organized.
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
The easiest way to run tests is to say "make". This runs all
|
||||
the tests.
|
||||
|
||||
*** t0000-basic.sh ***
|
||||
ok 1 - .git/objects should be empty after git init in an empty repo.
|
||||
ok 2 - .git/objects should have 3 subdirectories.
|
||||
ok 3 - success is reported like this
|
||||
...
|
||||
ok 43 - very long name in the index handled sanely
|
||||
# fixed 1 known breakage(s)
|
||||
# still have 1 known breakage(s)
|
||||
# passed all remaining 42 test(s)
|
||||
1..43
|
||||
*** t0001-init.sh ***
|
||||
ok 1 - plain
|
||||
ok 2 - plain with GIT_WORK_TREE
|
||||
ok 3 - plain bare
|
||||
|
||||
Since the tests all output TAP (see http://testanything.org) they can
|
||||
be run with any TAP harness. Here's an example of parallel testing
|
||||
powered by a recent version of prove(1):
|
||||
|
||||
$ prove --timer --jobs 15 ./t[0-9]*.sh
|
||||
[19:17:33] ./t0005-signals.sh ................................... ok 36 ms
|
||||
[19:17:33] ./t0022-crlf-rename.sh ............................... ok 69 ms
|
||||
[19:17:33] ./t0024-crlf-archive.sh .............................. ok 154 ms
|
||||
[19:17:33] ./t0004-unwritable.sh ................................ ok 289 ms
|
||||
[19:17:33] ./t0002-gitfile.sh ................................... ok 480 ms
|
||||
===( 102;0 25/? 6/? 5/? 16/? 1/? 4/? 2/? 1/? 3/? 1... )===
|
||||
|
||||
prove and other harnesses come with a lot of useful options. The
|
||||
--state option in particular is very useful:
|
||||
|
||||
# Repeat until no more failures
|
||||
$ prove -j 15 --state=failed,save ./t[0-9]*.sh
|
||||
|
||||
You can give DEFAULT_TEST_TARGET=prove on the make command (or define it
|
||||
in config.mak) to cause "make test" to run tests under prove.
|
||||
GIT_PROVE_OPTS can be used to pass additional options, e.g.
|
||||
|
||||
$ make DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS='--timer --jobs 16' test
|
||||
|
||||
You can also run each test individually from command line, like this:
|
||||
|
||||
$ sh ./t3010-ls-files-killed-modified.sh
|
||||
ok 1 - git update-index --add to add various paths.
|
||||
ok 2 - git ls-files -k to show killed files.
|
||||
ok 3 - validate git ls-files -k output.
|
||||
ok 4 - git ls-files -m to show modified files.
|
||||
ok 5 - validate git ls-files -m output.
|
||||
# passed all 5 test(s)
|
||||
1..5
|
||||
|
||||
You can pass --verbose (or -v), --debug (or -d), and --immediate
|
||||
(or -i) command line argument to the test, or by setting GIT_TEST_OPTS
|
||||
appropriately before running "make".
|
||||
|
||||
--verbose::
|
||||
This makes the test more verbose. Specifically, the
|
||||
command being run and their output if any are also
|
||||
output.
|
||||
|
||||
--debug::
|
||||
This may help the person who is developing a new test.
|
||||
It causes the command defined with test_debug to run.
|
||||
The "trash" directory (used to store all temporary data
|
||||
during testing) is not deleted even if there are no
|
||||
failed tests so that you can inspect its contents after
|
||||
the test finished.
|
||||
|
||||
--immediate::
|
||||
This causes the test to immediately exit upon the first
|
||||
failed test.
|
||||
|
||||
--long-tests::
|
||||
This causes additional long-running tests to be run (where
|
||||
available), for more exhaustive testing.
|
||||
|
||||
--valgrind::
|
||||
Execute all Git binaries with valgrind and exit with status
|
||||
126 on errors (just like regular tests, this will only stop
|
||||
the test script when running under -i). Valgrind errors
|
||||
go to stderr, so you might want to pass the -v option, too.
|
||||
|
||||
Since it makes no sense to run the tests with --valgrind and
|
||||
not see any output, this option implies --verbose. For
|
||||
convenience, it also implies --tee.
|
||||
|
||||
Note that valgrind is run with the option --leak-check=no,
|
||||
as the git process is short-lived and some errors are not
|
||||
interesting. In order to run a single command under the same
|
||||
conditions manually, you should set GIT_VALGRIND to point to
|
||||
the 't/valgrind/' directory and use the commands under
|
||||
't/valgrind/bin/'.
|
||||
|
||||
--tee::
|
||||
In addition to printing the test output to the terminal,
|
||||
write it to files named 't/test-results/$TEST_NAME.out'.
|
||||
As the names depend on the tests' file names, it is safe to
|
||||
run the tests with this option in parallel.
|
||||
|
||||
--with-dashes::
|
||||
By default tests are run without dashed forms of
|
||||
commands (like git-commit) in the PATH (it only uses
|
||||
wrappers from ../bin-wrappers). Use this option to include
|
||||
the build directory (..) in the PATH, which contains all
|
||||
the dashed forms of commands. This option is currently
|
||||
implied by other options like --valgrind and
|
||||
GIT_TEST_INSTALLED.
|
||||
|
||||
--root=<directory>::
|
||||
Create "trash" directories used to store all temporary data during
|
||||
testing under <directory>, instead of the t/ directory.
|
||||
Using this option with a RAM-based filesystem (such as tmpfs)
|
||||
can massively speed up the test suite.
|
||||
|
||||
--chain-lint::
|
||||
--no-chain-lint::
|
||||
If --chain-lint is enabled, the test harness will check each
|
||||
test to make sure that it properly "&&-chains" all commands (so
|
||||
that a failure in the middle does not go unnoticed by the final
|
||||
exit code of the test). This check is performed in addition to
|
||||
running the tests themselves.
|
||||
|
||||
You can also set the GIT_TEST_INSTALLED environment variable to
|
||||
the bindir of an existing git installation to test that installation.
|
||||
You still need to have built this git sandbox, from which various
|
||||
test-* support programs, templates, and perl libraries are used.
|
||||
If your installed git is incomplete, it will silently test parts of
|
||||
your built version instead.
|
||||
|
||||
When using GIT_TEST_INSTALLED, you can also set GIT_TEST_EXEC_PATH to
|
||||
override the location of the dashed-form subcommands (what
|
||||
GIT_EXEC_PATH would be used for during normal operation).
|
||||
GIT_TEST_EXEC_PATH defaults to `$GIT_TEST_INSTALLED/git --exec-path`.
|
||||
|
||||
|
||||
Skipping Tests
|
||||
--------------
|
||||
|
||||
In some environments, certain tests have no way of succeeding
|
||||
due to platform limitation, such as lack of 'unzip' program, or
|
||||
filesystem that do not allow arbitrary sequence of non-NUL bytes
|
||||
as pathnames.
|
||||
|
||||
You should be able to say something like
|
||||
|
||||
$ GIT_SKIP_TESTS=t9200.8 sh ./t9200-git-cvsexport-commit.sh
|
||||
|
||||
and even:
|
||||
|
||||
$ GIT_SKIP_TESTS='t[0-4]??? t91?? t9200.8' make
|
||||
|
||||
to omit such tests. The value of the environment variable is a
|
||||
SP separated list of patterns that tells which tests to skip,
|
||||
and either can match the "t[0-9]{4}" part to skip the whole
|
||||
test, or t[0-9]{4} followed by ".$number" to say which
|
||||
particular test to skip.
|
||||
|
||||
Note that some tests in the existing test suite rely on previous
|
||||
test item, so you cannot arbitrarily disable one and expect the
|
||||
remainder of test to check what the test originally was intended
|
||||
to check.
|
||||
|
||||
|
||||
Naming Tests
|
||||
------------
|
||||
|
||||
The test files are named as:
|
||||
|
||||
tNNNN-commandname-details.sh
|
||||
|
||||
where N is a decimal digit.
|
||||
|
||||
First digit tells the family:
|
||||
|
||||
0 - the absolute basics and global stuff
|
||||
1 - the basic commands concerning database
|
||||
2 - the basic commands concerning the working tree
|
||||
3 - the other basic commands (e.g. ls-files)
|
||||
4 - the diff commands
|
||||
5 - the pull and exporting commands
|
||||
6 - the revision tree commands (even e.g. merge-base)
|
||||
7 - the porcelainish commands concerning the working tree
|
||||
8 - the porcelainish commands concerning forensics
|
||||
9 - the git tools
|
||||
|
||||
Second digit tells the particular command we are testing.
|
||||
|
||||
Third digit (optionally) tells the particular switch or group of switches
|
||||
we are testing.
|
||||
|
||||
If you create files under t/ directory (i.e. here) that is not
|
||||
the top-level test script, never name the file to match the above
|
||||
pattern. The Makefile here considers all such files as the
|
||||
top-level test script and tries to run all of them. Care is
|
||||
especially needed if you are creating a common test library
|
||||
file, similar to test-lib.sh, because such a library file may
|
||||
not be suitable for standalone execution.
|
||||
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
The test script is written as a shell script. It should start
|
||||
with the standard "#!/bin/sh" with copyright notices, and an
|
||||
assignment to variable 'test_description', like this:
|
||||
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2005 Junio C Hamano
|
||||
#
|
||||
|
||||
test_description='xxx test (option --frotz)
|
||||
|
||||
This test registers the following structure in the cache
|
||||
and tries to run git-ls-files with option --frotz.'
|
||||
|
||||
|
||||
Source 'test-lib.sh'
|
||||
--------------------
|
||||
|
||||
After assigning test_description, the test script should source
|
||||
test-lib.sh like this:
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
This test harness library does the following things:
|
||||
|
||||
- If the script is invoked with command line argument --help
|
||||
(or -h), it shows the test_description and exits.
|
||||
|
||||
- Creates an empty test directory with an empty .git/objects database
|
||||
and chdir(2) into it. This directory is 't/trash
|
||||
directory.$test_name_without_dotsh', with t/ subject to change by
|
||||
the --root option documented above.
|
||||
|
||||
- Defines standard test helper functions for your scripts to
|
||||
use. These functions are designed to make all scripts behave
|
||||
consistently when command line arguments --verbose (or -v),
|
||||
--debug (or -d), and --immediate (or -i) is given.
|
||||
|
||||
Do's, don'ts & things to keep in mind
|
||||
-------------------------------------
|
||||
|
||||
Here are a few examples of things you probably should and shouldn't do
|
||||
when writing tests.
|
||||
|
||||
Do:
|
||||
|
||||
- Put all code inside test_expect_success and other assertions.
|
||||
|
||||
Even code that isn't a test per se, but merely some setup code
|
||||
should be inside a test assertion.
|
||||
|
||||
- Chain your test assertions
|
||||
|
||||
Write test code like this:
|
||||
|
||||
git merge foo &&
|
||||
git push bar &&
|
||||
test ...
|
||||
|
||||
Instead of:
|
||||
|
||||
git merge hla
|
||||
git push gh
|
||||
test ...
|
||||
|
||||
That way all of the commands in your tests will succeed or fail. If
|
||||
you must ignore the return value of something, consider using a
|
||||
helper function (e.g. use sane_unset instead of unset, in order
|
||||
to avoid unportable return value for unsetting a variable that was
|
||||
already unset), or prepending the command with test_might_fail or
|
||||
test_must_fail.
|
||||
|
||||
- Check the test coverage for your tests. See the "Test coverage"
|
||||
below.
|
||||
|
||||
Don't blindly follow test coverage metrics; if a new function you added
|
||||
doesn't have any coverage, then you're probably doing something wrong,
|
||||
but having 100% coverage doesn't necessarily mean that you tested
|
||||
everything.
|
||||
|
||||
Tests that are likely to smoke out future regressions are better
|
||||
than tests that just inflate the coverage metrics.
|
||||
|
||||
- When a test checks for an absolute path that a git command generated,
|
||||
construct the expected value using $(pwd) rather than $PWD,
|
||||
$TEST_DIRECTORY, or $TRASH_DIRECTORY. It makes a difference on
|
||||
Windows, where the shell (MSYS bash) mangles absolute path names.
|
||||
For details, see the commit message of 4114156ae9.
|
||||
|
||||
Don't:
|
||||
|
||||
- exit() within a <script> part.
|
||||
|
||||
The harness will catch this as a programming error of the test.
|
||||
Use test_done instead if you need to stop the tests early (see
|
||||
"Skipping tests" below).
|
||||
|
||||
- use '! git cmd' when you want to make sure the git command exits
|
||||
with failure in a controlled way by calling "die()". Instead,
|
||||
use 'test_must_fail git cmd'. This will signal a failure if git
|
||||
dies in an unexpected way (e.g. segfault).
|
||||
|
||||
- use perl without spelling it as "$PERL_PATH". This is to help our
|
||||
friends on Windows where the platform Perl often adds CR before
|
||||
the end of line, and they bundle Git with a version of Perl that
|
||||
does not do so, whose path is specified with $PERL_PATH.
|
||||
|
||||
- use sh without spelling it as "$SHELL_PATH", when the script can
|
||||
be misinterpreted by broken platform shell (e.g. Solaris).
|
||||
|
||||
- chdir around in tests. It is not sufficient to chdir to
|
||||
somewhere and then chdir back to the original location later in
|
||||
the test, as any intermediate step can fail and abort the test,
|
||||
causing the next test to start in an unexpected directory. Do so
|
||||
inside a subshell if necessary.
|
||||
|
||||
- Break the TAP output
|
||||
|
||||
The raw output from your test may be interpreted by a TAP harness. TAP
|
||||
harnesses will ignore everything they don't know about, but don't step
|
||||
on their toes in these areas:
|
||||
|
||||
- Don't print lines like "$x..$y" where $x and $y are integers.
|
||||
|
||||
- Don't print lines that begin with "ok" or "not ok".
|
||||
|
||||
TAP harnesses expect a line that begins with either "ok" and "not
|
||||
ok" to signal a test passed or failed (and our harness already
|
||||
produces such lines), so your script shouldn't emit such lines to
|
||||
their output.
|
||||
|
||||
You can glean some further possible issues from the TAP grammar
|
||||
(see http://search.cpan.org/perldoc?TAP::Parser::Grammar#TAP_Grammar)
|
||||
but the best indication is to just run the tests with prove(1),
|
||||
it'll complain if anything is amiss.
|
||||
|
||||
Keep in mind:
|
||||
|
||||
- Inside <script> part, the standard output and standard error
|
||||
streams are discarded, and the test harness only reports "ok" or
|
||||
"not ok" to the end user running the tests. Under --verbose, they
|
||||
are shown to help debugging the tests.
|
||||
|
||||
|
||||
Skipping tests
|
||||
--------------
|
||||
|
||||
If you need to skip tests you should do so by using the three-arg form
|
||||
of the test_* functions (see the "Test harness library" section
|
||||
below), e.g.:
|
||||
|
||||
test_expect_success PERL 'I need Perl' '
|
||||
"$PERL_PATH" -e "hlagh() if unf_unf()"
|
||||
'
|
||||
|
||||
The advantage of skipping tests like this is that platforms that don't
|
||||
have the PERL and other optional dependencies get an indication of how
|
||||
many tests they're missing.
|
||||
|
||||
If the test code is too hairy for that (i.e. does a lot of setup work
|
||||
outside test assertions) you can also skip all remaining tests by
|
||||
setting skip_all and immediately call test_done:
|
||||
|
||||
if ! test_have_prereq PERL
|
||||
then
|
||||
skip_all='skipping perl interface tests, perl not available'
|
||||
test_done
|
||||
fi
|
||||
|
||||
The string you give to skip_all will be used as an explanation for why
|
||||
the test was skipped.
|
||||
|
||||
End with test_done
|
||||
------------------
|
||||
|
||||
Your script will be a sequence of tests, using helper functions
|
||||
from the test harness library. At the end of the script, call
|
||||
'test_done'.
|
||||
|
||||
|
||||
Test harness library
|
||||
--------------------
|
||||
|
||||
There are a handful helper functions defined in the test harness
|
||||
library for your script to use.
|
||||
|
||||
- test_expect_success [<prereq>] <message> <script>
|
||||
|
||||
Usually takes two strings as parameters, and evaluates the
|
||||
<script>. If it yields success, test is considered
|
||||
successful. <message> should state what it is testing.
|
||||
|
||||
Example:
|
||||
|
||||
test_expect_success \
|
||||
'git-write-tree should be able to write an empty tree.' \
|
||||
'tree=$(git-write-tree)'
|
||||
|
||||
If you supply three parameters the first will be taken to be a
|
||||
prerequisite; see the test_set_prereq and test_have_prereq
|
||||
documentation below:
|
||||
|
||||
test_expect_success TTY 'git --paginate rev-list uses a pager' \
|
||||
' ... '
|
||||
|
||||
You can also supply a comma-separated list of prerequisites, in the
|
||||
rare case where your test depends on more than one:
|
||||
|
||||
test_expect_success PERL,PYTHON 'yo dawg' \
|
||||
' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
|
||||
|
||||
- test_expect_failure [<prereq>] <message> <script>
|
||||
|
||||
This is NOT the opposite of test_expect_success, but is used
|
||||
to mark a test that demonstrates a known breakage. Unlike
|
||||
the usual test_expect_success tests, which say "ok" on
|
||||
success and "FAIL" on failure, this will say "FIXED" on
|
||||
success and "still broken" on failure. Failures from these
|
||||
tests won't cause -i (immediate) to stop.
|
||||
|
||||
Like test_expect_success this function can optionally use a three
|
||||
argument invocation with a prerequisite as the first argument.
|
||||
|
||||
- test_debug <script>
|
||||
|
||||
This takes a single argument, <script>, and evaluates it only
|
||||
when the test script is started with --debug command line
|
||||
argument. This is primarily meant for use during the
|
||||
development of a new test script.
|
||||
|
||||
- test_done
|
||||
|
||||
Your test script must have test_done at the end. Its purpose
|
||||
is to summarize successes and failures in the test script and
|
||||
exit with an appropriate error code.
|
||||
|
||||
- test_tick
|
||||
|
||||
Make commit and tag names consistent by setting the author and
|
||||
committer times to defined state. Subsequent calls will
|
||||
advance the times by a fixed amount.
|
||||
|
||||
- test_commit <message> [<filename> [<contents>]]
|
||||
|
||||
Creates a commit with the given message, committing the given
|
||||
file with the given contents (default for both is to reuse the
|
||||
message string), and adds a tag (again reusing the message
|
||||
string as name). Calls test_tick to make the SHA-1s
|
||||
reproducible.
|
||||
|
||||
- test_merge <message> <commit-or-tag>
|
||||
|
||||
Merges the given rev using the given message. Like test_commit,
|
||||
creates a tag and calls test_tick before committing.
|
||||
|
||||
- test_set_prereq <prereq>
|
||||
|
||||
Set a test prerequisite to be used later with test_have_prereq. The
|
||||
test-lib will set some prerequisites for you, see the
|
||||
"Prerequisites" section below for a full list of these.
|
||||
|
||||
Others you can set yourself and use later with either
|
||||
test_have_prereq directly, or the three argument invocation of
|
||||
test_expect_success and test_expect_failure.
|
||||
|
||||
- test_have_prereq <prereq>
|
||||
|
||||
Check if we have a prerequisite previously set with
|
||||
test_set_prereq. The most common use of this directly is to skip
|
||||
all the tests if we don't have some essential prerequisite:
|
||||
|
||||
if ! test_have_prereq PERL
|
||||
then
|
||||
skip_all='skipping perl interface tests, perl not available'
|
||||
test_done
|
||||
fi
|
||||
|
||||
- test_external [<prereq>] <message> <external> <script>
|
||||
|
||||
Execute a <script> with an <external> interpreter (like perl). This
|
||||
was added for tests like t9700-perl-git.sh which do most of their
|
||||
work in an external test script.
|
||||
|
||||
test_external \
|
||||
'GitwebCache::*FileCache*' \
|
||||
"$PERL_PATH" "$TEST_DIRECTORY"/t9503/test_cache_interface.pl
|
||||
|
||||
If the test is outputting its own TAP you should set the
|
||||
test_external_has_tap variable somewhere before calling the first
|
||||
test_external* function. See t9700-perl-git.sh for an example.
|
||||
|
||||
# The external test will outputs its own plan
|
||||
test_external_has_tap=1
|
||||
|
||||
- test_external_without_stderr [<prereq>] <message> <external> <script>
|
||||
|
||||
Like test_external but fail if there's any output on stderr,
|
||||
instead of checking the exit code.
|
||||
|
||||
test_external_without_stderr \
|
||||
'Perl API' \
|
||||
"$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl
|
||||
|
||||
- test_expect_code <exit-code> <command>
|
||||
|
||||
Run a command and ensure that it exits with the given exit code.
|
||||
For example:
|
||||
|
||||
test_expect_success 'Merge with d/f conflicts' '
|
||||
test_expect_code 1 git merge "merge msg" B master
|
||||
'
|
||||
|
||||
- test_must_fail <git-command>
|
||||
|
||||
Run a git command and ensure it fails in a controlled way. Use
|
||||
this instead of "! <git-command>". When git-command dies due to a
|
||||
segfault, test_must_fail diagnoses it as an error; "! <git-command>"
|
||||
treats it as just another expected failure, which would let such a
|
||||
bug go unnoticed.
|
||||
|
||||
- test_might_fail <git-command>
|
||||
|
||||
Similar to test_must_fail, but tolerate success, too. Use this
|
||||
instead of "<git-command> || :" to catch failures due to segv.
|
||||
|
||||
- test_cmp <expected> <actual>
|
||||
|
||||
Check whether the content of the <actual> file matches the
|
||||
<expected> file. This behaves like "cmp" but produces more
|
||||
helpful output when the test is run with "-v" option.
|
||||
|
||||
- test_line_count (= | -lt | -ge | ...) <length> <file>
|
||||
|
||||
Check whether a file has the length it is expected to.
|
||||
|
||||
- test_path_is_file <path> [<diagnosis>]
|
||||
test_path_is_dir <path> [<diagnosis>]
|
||||
test_path_is_missing <path> [<diagnosis>]
|
||||
|
||||
Check if the named path is a file, if the named path is a
|
||||
directory, or if the named path does not exist, respectively,
|
||||
and fail otherwise, showing the <diagnosis> text.
|
||||
|
||||
- test_when_finished <script>
|
||||
|
||||
Prepend <script> to a list of commands to run to clean up
|
||||
at the end of the current test. If some clean-up command
|
||||
fails, the test will not pass.
|
||||
|
||||
Example:
|
||||
|
||||
test_expect_success 'branch pointing to non-commit' '
|
||||
git rev-parse HEAD^{tree} >.git/refs/heads/invalid &&
|
||||
test_when_finished "git update-ref -d refs/heads/invalid" &&
|
||||
...
|
||||
'
|
||||
|
||||
- test_pause
|
||||
|
||||
This command is useful for writing and debugging tests and must be
|
||||
removed before submitting. It halts the execution of the test and
|
||||
spawns a shell in the trash directory. Exit the shell to continue
|
||||
the test. Example:
|
||||
|
||||
test_expect_success 'test' '
|
||||
git do-something >actual &&
|
||||
test_pause &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
These are the prerequisites that the test library predefines with
|
||||
test_have_prereq.
|
||||
|
||||
See the prereq argument to the test_* functions in the "Test harness
|
||||
library" section above and the "test_have_prereq" function for how to
|
||||
use these, and "test_set_prereq" for how to define your own.
|
||||
|
||||
- PERL & PYTHON
|
||||
|
||||
Git wasn't compiled with NO_PERL=YesPlease or
|
||||
NO_PYTHON=YesPlease. Wrap any tests that need Perl or Python in
|
||||
these.
|
||||
|
||||
- POSIXPERM
|
||||
|
||||
The filesystem supports POSIX style permission bits.
|
||||
|
||||
- BSLASHPSPEC
|
||||
|
||||
Backslashes in pathspec are not directory separators. This is not
|
||||
set on Windows. See 6fd1106a for details.
|
||||
|
||||
- EXECKEEPSPID
|
||||
|
||||
The process retains the same pid across exec(2). See fb9a2bea for
|
||||
details.
|
||||
|
||||
- SYMLINKS
|
||||
|
||||
The filesystem we're on supports symbolic links. E.g. a FAT
|
||||
filesystem doesn't support these. See 704a3143 for details.
|
||||
|
||||
- SANITY
|
||||
|
||||
Test is not run by root user, and an attempt to write to an
|
||||
unwritable file is expected to fail correctly.
|
||||
|
||||
- LIBPCRE
|
||||
|
||||
Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests
|
||||
that use git-grep --perl-regexp or git-grep -P in these.
|
||||
|
||||
- CASE_INSENSITIVE_FS
|
||||
|
||||
Test is run on a case insensitive file system.
|
||||
|
||||
- UTF8_NFD_TO_NFC
|
||||
|
||||
Test is run on a filesystem which converts decomposed utf-8 (nfd)
|
||||
to precomposed utf-8 (nfc).
|
||||
|
||||
Tips for Writing Tests
|
||||
----------------------
|
||||
|
||||
As with any programming projects, existing programs are the best
|
||||
source of the information. However, do _not_ emulate
|
||||
t0000-basic.sh when writing your tests. The test is special in
|
||||
that it tries to validate the very core of GIT. For example, it
|
||||
knows that there will be 256 subdirectories under .git/objects/,
|
||||
and it knows that the object ID of an empty tree is a certain
|
||||
40-byte string. This is deliberately done so in t0000-basic.sh
|
||||
because the things the very basic core test tries to achieve is
|
||||
to serve as a basis for people who are changing the GIT internal
|
||||
drastically. For these people, after making certain changes,
|
||||
not seeing failures from the basic test _is_ a failure. And
|
||||
such drastic changes to the core GIT that even changes these
|
||||
otherwise supposedly stable object IDs should be accompanied by
|
||||
an update to t0000-basic.sh.
|
||||
|
||||
However, other tests that simply rely on basic parts of the core
|
||||
GIT working properly should not have that level of intimate
|
||||
knowledge of the core GIT internals. If all the test scripts
|
||||
hardcoded the object IDs like t0000-basic.sh does, that defeats
|
||||
the purpose of t0000-basic.sh, which is to isolate that level of
|
||||
validation in one place. Your test also ends up needing
|
||||
updating when such a change to the internal happens, so do _not_
|
||||
do it and leave the low level of validation to t0000-basic.sh.
|
||||
|
||||
Test coverage
|
||||
-------------
|
||||
|
||||
You can use the coverage tests to find code paths that are not being
|
||||
used or properly exercised yet.
|
||||
|
||||
To do that, run the coverage target at the top-level (not in the t/
|
||||
directory):
|
||||
|
||||
make coverage
|
||||
|
||||
That'll compile Git with GCC's coverage arguments, and generate a test
|
||||
report with gcov after the tests finish. Running the coverage tests
|
||||
can take a while, since running the tests in parallel is incompatible
|
||||
with GCC's coverage mode.
|
||||
|
||||
After the tests have run you can generate a list of untested
|
||||
functions:
|
||||
|
||||
make coverage-untested-functions
|
||||
|
||||
You can also generate a detailed per-file HTML report using the
|
||||
Devel::Cover module. To install it do:
|
||||
|
||||
# On Debian or Ubuntu:
|
||||
sudo aptitude install libdevel-cover-perl
|
||||
|
||||
# From the CPAN with cpanminus
|
||||
curl -L http://cpanmin.us | perl - --sudo --self-upgrade
|
||||
cpanm --sudo Devel::Cover
|
||||
|
||||
Then, at the top-level:
|
||||
|
||||
make cover_db_html
|
||||
|
||||
That'll generate a detailed cover report in the "cover_db_html"
|
||||
directory, which you can then copy to a webserver, or inspect locally
|
||||
in a browser.
|
@@ -1,164 +0,0 @@
|
||||
# Sharness
|
||||
|
||||
Sharness is a portable shell library to write, run, and analyze automated tests
|
||||
for Unix programs. Since all tests output TAP, the [Test Anything Protocol],
|
||||
they can be run with any TAP harness.
|
||||
|
||||
Each test is written as a shell script, for example:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
|
||||
test_description="Show basic features of Sharness"
|
||||
|
||||
. ./sharness.sh
|
||||
|
||||
test_expect_success "Success is reported like this" "
|
||||
echo hello world | grep hello
|
||||
"
|
||||
|
||||
test_expect_success "Commands are chained this way" "
|
||||
test x = 'x' &&
|
||||
test 2 -gt 1 &&
|
||||
echo success
|
||||
"
|
||||
|
||||
return_42() {
|
||||
echo "Will return soon"
|
||||
return 42
|
||||
}
|
||||
|
||||
test_expect_success "You can test for a specific exit code" "
|
||||
test_expect_code 42 return_42
|
||||
"
|
||||
|
||||
test_expect_failure "We expect this to fail" "
|
||||
test 1 = 2
|
||||
"
|
||||
|
||||
test_done
|
||||
```
|
||||
|
||||
Running the above test script returns the following (TAP) output:
|
||||
|
||||
$ ./simple.t
|
||||
ok 1 - Success is reported like this
|
||||
ok 2 - Commands are chained this way
|
||||
ok 3 - You can test for a specific exit code
|
||||
not ok 4 - We expect this to fail # TODO known breakage
|
||||
# still have 1 known breakage(s)
|
||||
# passed all remaining 3 test(s)
|
||||
1..4
|
||||
|
||||
Alternatively, you can run the test through [prove(1)]:
|
||||
|
||||
$ prove simple.t
|
||||
simple.t .. ok
|
||||
All tests successful.
|
||||
Files=1, Tests=4, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU)
|
||||
Result: PASS
|
||||
|
||||
Sharness was derived from the [Git] project - see [README.git] for the original
|
||||
documentation.
|
||||
|
||||
## Installation
|
||||
|
||||
First, clone the Git repository:
|
||||
|
||||
$ git clone git://github.com/mlafeldt/sharness.git
|
||||
|
||||
Then choose an installation method that works best for you:
|
||||
|
||||
### Per-project installation
|
||||
|
||||
If you like to add Sharness to the sources of a project you want to use it for,
|
||||
simply copy the files `sharness.sh`, `aggregate-results.sh`, and `test/Makefile`
|
||||
to a folder named `test` inside that project.
|
||||
|
||||
Alternatively, you can also add Sharness as a Git submodule to your project.
|
||||
|
||||
### Per-user installation
|
||||
|
||||
$ cd sharness
|
||||
$ make install
|
||||
|
||||
This will install Sharness to `$HOME/share/sharness`, and its documentation and
|
||||
examples to `$HOME/share/doc/sharness`.
|
||||
|
||||
### System-wide installation
|
||||
|
||||
$ cd sharness
|
||||
# make install prefix=/usr/local
|
||||
|
||||
This will install Sharness to `/usr/local/share/sharness`, and its documentation
|
||||
and examples to `/usr/local/share/doc/sharness`.
|
||||
|
||||
Of course, you can change the _prefix_ parameter to install Sharness to any
|
||||
other location.
|
||||
|
||||
### Installation via Chef
|
||||
|
||||
If you want to install Sharness with Opscode Chef, the [Sharness cookbook] is
|
||||
for you.
|
||||
|
||||
## Usage
|
||||
|
||||
The following files are essential to using Sharness:
|
||||
|
||||
* `sharness.sh` - core shell library providing test functionality, see separate
|
||||
[API documentation]
|
||||
* `aggregate-results.sh` - helper script to aggregate test results
|
||||
* `test/Makefile` - test driver
|
||||
|
||||
To learn how to write and run actual test scripts based on `sharness.sh`, please
|
||||
read [README.git] until I come up with more documentation myself.
|
||||
|
||||
## Projects using Sharness
|
||||
|
||||
See how Sharness is used in real-world projects:
|
||||
|
||||
* [cb2util](https://github.com/mlafeldt/cb2util/tree/master/test)
|
||||
* [dabba](https://github.com/eroullit/dabba/tree/master/dabba/test)
|
||||
* [git-integration](https://github.com/johnkeeping/git-integration/tree/master/t)
|
||||
* [go-ipfs](https://github.com/jbenet/go-ipfs/tree/master/test/sharness)
|
||||
* [go-multihash](https://github.com/jbenet/go-multihash/tree/master/test/sharness)
|
||||
* [rdd.py](https://github.com/mlafeldt/rdd.py/tree/master/test/integration)
|
||||
* [Sharness itself](/test)
|
||||
* [tomdoc.sh](https://github.com/mlafeldt/tomdoc.sh/tree/master/test)
|
||||
|
||||
Furthermore, as Sharness was derived from Git, [Git's test suite](https://github.com/git/git/tree/master/t)
|
||||
is worth examining as well, especially if you're interested in managing a big
|
||||
number of tests.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Here is a list of other shell testing libraries (sorted alphabetically):
|
||||
|
||||
* [Bats](https://github.com/sstephenson/bats)
|
||||
* [Cram](https://bitheap.org/cram)
|
||||
* [rnt](https://github.com/roman-neuhauser/rnt)
|
||||
* [roundup](https://github.com/bmizerany/roundup)
|
||||
* [shUnit2](https://code.google.com/p/shunit2/)
|
||||
* [shspec](https://github.com/shpec/shpec)
|
||||
* [testlib.sh](https://gist.github.com/3877539)
|
||||
* [ts](https://github.com/thinkerbot/ts)
|
||||
|
||||
## License
|
||||
|
||||
Sharness is licensed under the terms of the GNU General Public License version
|
||||
2 or higher. See file [COPYING] for full license text.
|
||||
|
||||
## Author
|
||||
|
||||
Sharness is being developed by [Mathias Lafeldt][twitter]. The library was
|
||||
derived from the [Git] project.
|
||||
|
||||
|
||||
[API documentation]: https://github.com/mlafeldt/sharness/blob/master/API.md
|
||||
[COPYING]: https://github.com/mlafeldt/sharness/blob/master/COPYING
|
||||
[Git]: http://git-scm.com/
|
||||
[prove(1)]: http://linux.die.net/man/1/prove
|
||||
[README.git]: https://github.com/mlafeldt/sharness/blob/master/README.git
|
||||
[Sharness cookbook]: https://github.com/mlafeldt/sharness-cookbook
|
||||
[Test Anything Protocol]: http://testanything.org/
|
||||
[twitter]: https://twitter.com/mlafeldt
|
@@ -1,57 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2008-2012 Git project
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/ .
|
||||
|
||||
failed_tests=
|
||||
fixed=0
|
||||
success=0
|
||||
failed=0
|
||||
broken=0
|
||||
total=0
|
||||
|
||||
while read file; do
|
||||
while read type value; do
|
||||
case $type in
|
||||
'')
|
||||
continue ;;
|
||||
fixed)
|
||||
fixed=$(($fixed + $value)) ;;
|
||||
success)
|
||||
success=$(($success + $value)) ;;
|
||||
failed)
|
||||
failed=$(($failed + $value))
|
||||
if test $value != 0; then
|
||||
test_name=$(expr "$file" : 'test-results/\(.*\)\.[0-9]*\.counts')
|
||||
failed_tests="$failed_tests $test_name"
|
||||
fi
|
||||
;;
|
||||
broken)
|
||||
broken=$(($broken + $value)) ;;
|
||||
total)
|
||||
total=$(($total + $value)) ;;
|
||||
esac
|
||||
done <"$file"
|
||||
done
|
||||
|
||||
if test -n "$failed_tests"; then
|
||||
printf "\nfailed test(s):$failed_tests\n\n"
|
||||
fi
|
||||
|
||||
printf "%-8s%d\n" fixed $fixed
|
||||
printf "%-8s%d\n" success $success
|
||||
printf "%-8s%d\n" failed $failed
|
||||
printf "%-8s%d\n" broken $broken
|
||||
printf "%-8s%d\n" total $total
|
@@ -1,741 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011-2012 Mathias Lafeldt
|
||||
# Copyright (c) 2005-2012 Git project
|
||||
# Copyright (c) 2005-2012 Junio C Hamano
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/ .
|
||||
|
||||
# Public: Current version of Sharness.
|
||||
SHARNESS_VERSION="0.3.0"
|
||||
export SHARNESS_VERSION
|
||||
|
||||
# Public: The file extension for tests. By default, it is set to "t".
|
||||
: ${SHARNESS_TEST_EXTENSION:=t}
|
||||
export SHARNESS_TEST_EXTENSION
|
||||
|
||||
# Keep the original TERM for say_color
|
||||
ORIGINAL_TERM=$TERM
|
||||
|
||||
# For repeatability, reset the environment to a known state.
|
||||
LANG=C
|
||||
LC_ALL=C
|
||||
PAGER=cat
|
||||
TZ=UTC
|
||||
TERM=dumb
|
||||
EDITOR=:
|
||||
export LANG LC_ALL PAGER TZ TERM EDITOR
|
||||
unset VISUAL CDPATH GREP_OPTIONS
|
||||
|
||||
# Line feed
|
||||
LF='
|
||||
'
|
||||
|
||||
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
|
||||
TERM=$ORIGINAL_TERM &&
|
||||
export TERM &&
|
||||
[ -t 1 ] &&
|
||||
tput bold >/dev/null 2>&1 &&
|
||||
tput setaf 1 >/dev/null 2>&1 &&
|
||||
tput sgr0 >/dev/null 2>&1
|
||||
) &&
|
||||
color=t
|
||||
|
||||
while test "$#" -ne 0; do
|
||||
case "$1" in
|
||||
-d|--d|--de|--deb|--debu|--debug)
|
||||
debug=t; shift ;;
|
||||
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
|
||||
immediate=t; shift ;;
|
||||
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
|
||||
TEST_LONG=t; export TEST_LONG; shift ;;
|
||||
-h|--h|--he|--hel|--help)
|
||||
help=t; shift ;;
|
||||
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
|
||||
verbose=t; shift ;;
|
||||
-q|--q|--qu|--qui|--quie|--quiet)
|
||||
# Ignore --quiet under a TAP::Harness. Saying how many tests
|
||||
# passed without the ok/not ok details is always an error.
|
||||
test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
|
||||
--chain-lint)
|
||||
chain_lint=t; shift ;;
|
||||
--no-chain-lint)
|
||||
chain_lint=; shift ;;
|
||||
--no-color)
|
||||
color=; shift ;;
|
||||
--root=*)
|
||||
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
|
||||
shift ;;
|
||||
*)
|
||||
echo "error: unknown test option '$1'" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test -n "$color"; then
|
||||
say_color() {
|
||||
(
|
||||
TERM=$ORIGINAL_TERM
|
||||
export TERM
|
||||
case "$1" in
|
||||
error)
|
||||
tput bold; tput setaf 1;; # bold red
|
||||
skip)
|
||||
tput setaf 4;; # blue
|
||||
warn)
|
||||
tput setaf 3;; # brown/yellow
|
||||
pass)
|
||||
tput setaf 2;; # green
|
||||
info)
|
||||
tput setaf 6;; # cyan
|
||||
*)
|
||||
test -n "$quiet" && return;;
|
||||
esac
|
||||
shift
|
||||
printf "%s" "$*"
|
||||
tput sgr0
|
||||
echo
|
||||
)
|
||||
}
|
||||
else
|
||||
say_color() {
|
||||
test -z "$1" && test -n "$quiet" && return
|
||||
shift
|
||||
printf "%s\n" "$*"
|
||||
}
|
||||
fi
|
||||
|
||||
error() {
|
||||
say_color error "error: $*"
|
||||
EXIT_OK=t
|
||||
exit 1
|
||||
}
|
||||
|
||||
say() {
|
||||
say_color info "$*"
|
||||
}
|
||||
|
||||
test -n "$test_description" || error "Test script did not set test_description."
|
||||
|
||||
if test "$help" = "t"; then
|
||||
echo "$test_description"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec 5>&1
|
||||
exec 6<&0
|
||||
if test "$verbose" = "t"; then
|
||||
exec 4>&2 3>&1
|
||||
else
|
||||
exec 4>/dev/null 3>/dev/null
|
||||
fi
|
||||
|
||||
test_failure=0
|
||||
test_count=0
|
||||
test_fixed=0
|
||||
test_broken=0
|
||||
test_success=0
|
||||
|
||||
die() {
|
||||
code=$?
|
||||
if test -n "$EXIT_OK"; then
|
||||
exit $code
|
||||
else
|
||||
echo >&5 "FATAL: Unexpected exit with code $code"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
EXIT_OK=
|
||||
trap 'die' EXIT
|
||||
|
||||
# Public: Define that a test prerequisite is available.
|
||||
#
|
||||
# The prerequisite can later be checked explicitly using test_have_prereq or
|
||||
# implicitly by specifying the prerequisite name in calls to test_expect_success
|
||||
# or test_expect_failure.
|
||||
#
|
||||
# $1 - Name of prerequiste (a simple word, in all capital letters by convention)
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # Set PYTHON prerequisite if interpreter is available.
|
||||
# command -v python >/dev/null && test_set_prereq PYTHON
|
||||
#
|
||||
# # Set prerequisite depending on some variable.
|
||||
# test -z "$NO_GETTEXT" && test_set_prereq GETTEXT
|
||||
#
|
||||
# Returns nothing.
|
||||
test_set_prereq() {
|
||||
satisfied_prereq="$satisfied_prereq$1 "
|
||||
}
|
||||
satisfied_prereq=" "
|
||||
|
||||
# Public: Check if one or more test prerequisites are defined.
|
||||
#
|
||||
# The prerequisites must have previously been set with test_set_prereq.
|
||||
# The most common use of this is to skip all the tests if some essential
|
||||
# prerequisite is missing.
|
||||
#
|
||||
# $1 - Comma-separated list of test prerequisites.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # Skip all remaining tests if prerequisite is not set.
|
||||
# if ! test_have_prereq PERL; then
|
||||
# skip_all='skipping perl interface tests, perl not available'
|
||||
# test_done
|
||||
# fi
|
||||
#
|
||||
# Returns 0 if all prerequisites are defined or 1 otherwise.
|
||||
test_have_prereq() {
|
||||
# prerequisites can be concatenated with ','
|
||||
save_IFS=$IFS
|
||||
IFS=,
|
||||
set -- $*
|
||||
IFS=$save_IFS
|
||||
|
||||
total_prereq=0
|
||||
ok_prereq=0
|
||||
missing_prereq=
|
||||
|
||||
for prerequisite; do
|
||||
case "$prerequisite" in
|
||||
!*)
|
||||
negative_prereq=t
|
||||
prerequisite=${prerequisite#!}
|
||||
;;
|
||||
*)
|
||||
negative_prereq=
|
||||
esac
|
||||
|
||||
total_prereq=$(($total_prereq + 1))
|
||||
case "$satisfied_prereq" in
|
||||
*" $prerequisite "*)
|
||||
satisfied_this_prereq=t
|
||||
;;
|
||||
*)
|
||||
satisfied_this_prereq=
|
||||
esac
|
||||
|
||||
case "$satisfied_this_prereq,$negative_prereq" in
|
||||
t,|,t)
|
||||
ok_prereq=$(($ok_prereq + 1))
|
||||
;;
|
||||
*)
|
||||
# Keep a list of missing prerequisites; restore
|
||||
# the negative marker if necessary.
|
||||
prerequisite=${negative_prereq:+!}$prerequisite
|
||||
if test -z "$missing_prereq"; then
|
||||
missing_prereq=$prerequisite
|
||||
else
|
||||
missing_prereq="$prerequisite,$missing_prereq"
|
||||
fi
|
||||
esac
|
||||
done
|
||||
|
||||
test $total_prereq = $ok_prereq
|
||||
}
|
||||
|
||||
# You are not expected to call test_ok_ and test_failure_ directly, use
|
||||
# the text_expect_* functions instead.
|
||||
|
||||
test_ok_() {
|
||||
test_success=$(($test_success + 1))
|
||||
say_color "" "ok $test_count - $@"
|
||||
}
|
||||
|
||||
test_failure_() {
|
||||
test_failure=$(($test_failure + 1))
|
||||
say_color error "not ok $test_count - $1"
|
||||
shift
|
||||
echo "$@" | sed -e 's/^/# /'
|
||||
test "$immediate" = "" || { EXIT_OK=t; exit 1; }
|
||||
}
|
||||
|
||||
test_known_broken_ok_() {
|
||||
test_fixed=$(($test_fixed + 1))
|
||||
say_color error "ok $test_count - $@ # TODO known breakage vanished"
|
||||
}
|
||||
|
||||
test_known_broken_failure_() {
|
||||
test_broken=$(($test_broken + 1))
|
||||
say_color warn "not ok $test_count - $@ # TODO known breakage"
|
||||
}
|
||||
|
||||
# Public: Execute commands in debug mode.
|
||||
#
|
||||
# Takes a single argument and evaluates it only when the test script is started
|
||||
# with --debug. This is primarily meant for use during the development of test
|
||||
# scripts.
|
||||
#
|
||||
# $1 - Commands to be executed.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_debug "cat some_log_file"
|
||||
#
|
||||
# Returns the exit code of the last command executed in debug mode or 0
|
||||
# otherwise.
|
||||
test_debug() {
|
||||
test "$debug" = "" || eval "$1"
|
||||
}
|
||||
|
||||
test_eval_() {
|
||||
# This is a separate function because some tests use
|
||||
# "return" to end a test_expect_success block early.
|
||||
eval </dev/null >&3 2>&4 "$*"
|
||||
}
|
||||
|
||||
test_run_() {
|
||||
test_cleanup=:
|
||||
expecting_failure=$2
|
||||
test_eval_ "$1"
|
||||
eval_ret=$?
|
||||
|
||||
if test "$chain_lint" = "t"; then
|
||||
test_eval_ "(exit 117) && $1"
|
||||
if test "$?" != 117; then
|
||||
error "bug in the test script: broken &&-chain: $1"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then
|
||||
test_eval_ "$test_cleanup"
|
||||
fi
|
||||
if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
|
||||
echo ""
|
||||
fi
|
||||
return "$eval_ret"
|
||||
}
|
||||
|
||||
test_skip_() {
|
||||
test_count=$(($test_count + 1))
|
||||
to_skip=
|
||||
for skp in $SKIP_TESTS; do
|
||||
case $this_test.$test_count in
|
||||
$skp)
|
||||
to_skip=t
|
||||
break
|
||||
esac
|
||||
done
|
||||
if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then
|
||||
to_skip=t
|
||||
fi
|
||||
case "$to_skip" in
|
||||
t)
|
||||
of_prereq=
|
||||
if test "$missing_prereq" != "$test_prereq"; then
|
||||
of_prereq=" of $test_prereq"
|
||||
fi
|
||||
|
||||
say_color skip >&3 "skipping test: $@"
|
||||
say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
|
||||
: true
|
||||
;;
|
||||
*)
|
||||
false
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Public: Run test commands and expect them to succeed.
|
||||
#
|
||||
# When the test passed, an "ok" message is printed and the number of successful
|
||||
# tests is incremented. When it failed, a "not ok" message is printed and the
|
||||
# number of failed tests is incremented.
|
||||
#
|
||||
# With --immediate, exit test immediately upon the first failed test.
|
||||
#
|
||||
# Usually takes two arguments:
|
||||
# $1 - Test description
|
||||
# $2 - Commands to be executed.
|
||||
#
|
||||
# With three arguments, the first will be taken to be a prerequisite:
|
||||
# $1 - Comma-separated list of test prerequisites. The test will be skipped if
|
||||
# not all of the given prerequisites are set. To negate a prerequisite,
|
||||
# put a "!" in front of it.
|
||||
# $2 - Test description
|
||||
# $3 - Commands to be executed.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success \
|
||||
# 'git-write-tree should be able to write an empty tree.' \
|
||||
# 'tree=$(git-write-tree)'
|
||||
#
|
||||
# # Test depending on one prerequisite.
|
||||
# test_expect_success TTY 'git --paginate rev-list uses a pager' \
|
||||
# ' ... '
|
||||
#
|
||||
# # Multiple prerequisites are separated by a comma.
|
||||
# test_expect_success PERL,PYTHON 'yo dawg' \
|
||||
# ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
|
||||
#
|
||||
# Returns nothing.
|
||||
test_expect_success() {
|
||||
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
|
||||
test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success"
|
||||
export test_prereq
|
||||
if ! test_skip_ "$@"; then
|
||||
say >&3 "expecting success: $2"
|
||||
if test_run_ "$2"; then
|
||||
test_ok_ "$1"
|
||||
else
|
||||
test_failure_ "$@"
|
||||
fi
|
||||
fi
|
||||
echo >&3 ""
|
||||
}
|
||||
|
||||
# Public: Run test commands and expect them to fail. Used to demonstrate a known
|
||||
# breakage.
|
||||
#
|
||||
# This is NOT the opposite of test_expect_success, but rather used to mark a
|
||||
# test that demonstrates a known breakage.
|
||||
#
|
||||
# When the test passed, an "ok" message is printed and the number of fixed tests
|
||||
# is incremented. When it failed, a "not ok" message is printed and the number
|
||||
# of tests still broken is incremented.
|
||||
#
|
||||
# Failures from these tests won't cause --immediate to stop.
|
||||
#
|
||||
# Usually takes two arguments:
|
||||
# $1 - Test description
|
||||
# $2 - Commands to be executed.
|
||||
#
|
||||
# With three arguments, the first will be taken to be a prerequisite:
|
||||
# $1 - Comma-separated list of test prerequisites. The test will be skipped if
|
||||
# not all of the given prerequisites are set. To negate a prerequisite,
|
||||
# put a "!" in front of it.
|
||||
# $2 - Test description
|
||||
# $3 - Commands to be executed.
|
||||
#
|
||||
# Returns nothing.
|
||||
test_expect_failure() {
|
||||
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
|
||||
test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure"
|
||||
export test_prereq
|
||||
if ! test_skip_ "$@"; then
|
||||
say >&3 "checking known breakage: $2"
|
||||
if test_run_ "$2" expecting_failure; then
|
||||
test_known_broken_ok_ "$1"
|
||||
else
|
||||
test_known_broken_failure_ "$1"
|
||||
fi
|
||||
fi
|
||||
echo >&3 ""
|
||||
}
|
||||
|
||||
# Public: Run command and ensure that it fails in a controlled way.
|
||||
#
|
||||
# Use it instead of "! <command>". For example, when <command> dies due to a
|
||||
# segfault, test_must_fail diagnoses it as an error, while "! <command>" would
|
||||
# mistakenly be treated as just another expected failure.
|
||||
#
|
||||
# This is one of the prefix functions to be used inside test_expect_success or
|
||||
# test_expect_failure.
|
||||
#
|
||||
# $1.. - Command to be executed.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success 'complain and die' '
|
||||
# do something &&
|
||||
# do something else &&
|
||||
# test_must_fail git checkout ../outerspace
|
||||
# '
|
||||
#
|
||||
# Returns 1 if the command succeeded (exit code 0).
|
||||
# Returns 1 if the command died by signal (exit codes 130-192)
|
||||
# Returns 1 if the command could not be found (exit code 127).
|
||||
# Returns 0 otherwise.
|
||||
test_must_fail() {
|
||||
"$@"
|
||||
exit_code=$?
|
||||
if test $exit_code = 0; then
|
||||
echo >&2 "test_must_fail: command succeeded: $*"
|
||||
return 1
|
||||
elif test $exit_code -gt 129 -a $exit_code -le 192; then
|
||||
echo >&2 "test_must_fail: died by signal: $*"
|
||||
return 1
|
||||
elif test $exit_code = 127; then
|
||||
echo >&2 "test_must_fail: command not found: $*"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Public: Run command and ensure that it succeeds or fails in a controlled way.
|
||||
#
|
||||
# Similar to test_must_fail, but tolerates success too. Use it instead of
|
||||
# "<command> || :" to catch failures caused by a segfault, for instance.
|
||||
#
|
||||
# This is one of the prefix functions to be used inside test_expect_success or
|
||||
# test_expect_failure.
|
||||
#
|
||||
# $1.. - Command to be executed.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success 'some command works without configuration' '
|
||||
# test_might_fail git config --unset all.configuration &&
|
||||
# do something
|
||||
# '
|
||||
#
|
||||
# Returns 1 if the command died by signal (exit codes 130-192)
|
||||
# Returns 1 if the command could not be found (exit code 127).
|
||||
# Returns 0 otherwise.
|
||||
test_might_fail() {
|
||||
"$@"
|
||||
exit_code=$?
|
||||
if test $exit_code -gt 129 -a $exit_code -le 192; then
|
||||
echo >&2 "test_might_fail: died by signal: $*"
|
||||
return 1
|
||||
elif test $exit_code = 127; then
|
||||
echo >&2 "test_might_fail: command not found: $*"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Public: Run command and ensure it exits with a given exit code.
|
||||
#
|
||||
# This is one of the prefix functions to be used inside test_expect_success or
|
||||
# test_expect_failure.
|
||||
#
|
||||
# $1 - Expected exit code.
|
||||
# $2.. - Command to be executed.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success 'Merge with d/f conflicts' '
|
||||
# test_expect_code 1 git merge "merge msg" B master
|
||||
# '
|
||||
#
|
||||
# Returns 0 if the expected exit code is returned or 1 otherwise.
|
||||
test_expect_code() {
|
||||
want_code=$1
|
||||
shift
|
||||
"$@"
|
||||
exit_code=$?
|
||||
if test $exit_code = $want_code; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Public: Compare two files to see if expected output matches actual output.
|
||||
#
|
||||
# The TEST_CMP variable defines the command used for the comparision; it
|
||||
# defaults to "diff -u". Only when the test script was started with --verbose,
|
||||
# will the command's output, the diff, be printed to the standard output.
|
||||
#
|
||||
# This is one of the prefix functions to be used inside test_expect_success or
|
||||
# test_expect_failure.
|
||||
#
|
||||
# $1 - Path to file with expected output.
|
||||
# $2 - Path to file with actual output.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success 'foo works' '
|
||||
# echo expected >expected &&
|
||||
# foo >actual &&
|
||||
# test_cmp expected actual
|
||||
# '
|
||||
#
|
||||
# Returns the exit code of the command set by TEST_CMP.
|
||||
test_cmp() {
|
||||
${TEST_CMP:-diff -u} "$@"
|
||||
}
|
||||
|
||||
# Public: Schedule cleanup commands to be run unconditionally at the end of a
|
||||
# test.
|
||||
#
|
||||
# If some cleanup command fails, the test will not pass. With --immediate, no
|
||||
# cleanup is done to help diagnose what went wrong.
|
||||
#
|
||||
# This is one of the prefix functions to be used inside test_expect_success or
|
||||
# test_expect_failure.
|
||||
#
|
||||
# $1.. - Commands to prepend to the list of cleanup commands.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# test_expect_success 'test core.capslock' '
|
||||
# git config core.capslock true &&
|
||||
# test_when_finished "git config --unset core.capslock" &&
|
||||
# do_something
|
||||
# '
|
||||
#
|
||||
# Returns the exit code of the last cleanup command executed.
|
||||
test_when_finished() {
|
||||
test_cleanup="{ $*
|
||||
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
|
||||
}
|
||||
|
||||
# Public: Schedule cleanup commands to be run unconditionally when all tests
|
||||
# have run.
|
||||
#
|
||||
# This can be used to clean up things like test databases. It is not needed to
|
||||
# clean up temporary files, as test_done already does that.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# cleanup mysql -e "DROP DATABASE mytest"
|
||||
#
|
||||
# Returns the exit code of the last cleanup command executed.
|
||||
final_cleanup=
|
||||
cleanup() {
|
||||
final_cleanup="{ $*
|
||||
} && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup"
|
||||
}
|
||||
|
||||
# Public: Summarize test results and exit with an appropriate error code.
|
||||
#
|
||||
# Must be called at the end of each test script.
|
||||
#
|
||||
# Can also be used to stop tests early and skip all remaining tests. For this,
|
||||
# set skip_all to a string explaining why the tests were skipped before calling
|
||||
# test_done.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# # Each test script must call test_done at the end.
|
||||
# test_done
|
||||
#
|
||||
# # Skip all remaining tests if prerequisite is not set.
|
||||
# if ! test_have_prereq PERL; then
|
||||
# skip_all='skipping perl interface tests, perl not available'
|
||||
# test_done
|
||||
# fi
|
||||
#
|
||||
# Returns 0 if all tests passed or 1 if there was a failure.
|
||||
test_done() {
|
||||
EXIT_OK=t
|
||||
|
||||
if test -z "$HARNESS_ACTIVE"; then
|
||||
test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results"
|
||||
mkdir -p "$test_results_dir"
|
||||
test_results_path="$test_results_dir/${SHARNESS_TEST_FILE%.$SHARNESS_TEST_EXTENSION}.$$.counts"
|
||||
|
||||
cat >>"$test_results_path" <<-EOF
|
||||
total $test_count
|
||||
success $test_success
|
||||
fixed $test_fixed
|
||||
broken $test_broken
|
||||
failed $test_failure
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if test "$test_fixed" != 0; then
|
||||
say_color error "# $test_fixed known breakage(s) vanished; please update test(s)"
|
||||
fi
|
||||
if test "$test_broken" != 0; then
|
||||
say_color warn "# still have $test_broken known breakage(s)"
|
||||
fi
|
||||
if test "$test_broken" != 0 || test "$test_fixed" != 0; then
|
||||
test_remaining=$(( $test_count - $test_broken - $test_fixed ))
|
||||
msg="remaining $test_remaining test(s)"
|
||||
else
|
||||
test_remaining=$test_count
|
||||
msg="$test_count test(s)"
|
||||
fi
|
||||
|
||||
case "$test_failure" in
|
||||
0)
|
||||
# Maybe print SKIP message
|
||||
if test -n "$skip_all" && test $test_count -gt 0; then
|
||||
error "Can't use skip_all after running some tests"
|
||||
fi
|
||||
[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
|
||||
|
||||
if test $test_remaining -gt 0; then
|
||||
say_color pass "# passed all $msg"
|
||||
fi
|
||||
say "1..$test_count$skip_all"
|
||||
|
||||
test_eval_ "$final_cleanup"
|
||||
|
||||
test -d "$remove_trash" &&
|
||||
cd "$(dirname "$remove_trash")" &&
|
||||
rm -rf "$(basename "$remove_trash")"
|
||||
|
||||
exit 0 ;;
|
||||
|
||||
*)
|
||||
say_color error "# failed $test_failure among $msg"
|
||||
say "1..$test_count"
|
||||
|
||||
exit 1 ;;
|
||||
|
||||
esac
|
||||
}
|
||||
|
||||
# Public: Root directory containing tests. Tests can override this variable,
|
||||
# e.g. for testing Sharness itself.
|
||||
: ${SHARNESS_TEST_DIRECTORY:=$(pwd)}
|
||||
export SHARNESS_TEST_DIRECTORY
|
||||
|
||||
# Public: Build directory that will be added to PATH. By default, it is set to
|
||||
# the parent directory of SHARNESS_TEST_DIRECTORY.
|
||||
: ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}
|
||||
PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
|
||||
export PATH SHARNESS_BUILD_DIRECTORY
|
||||
|
||||
# Public: Path to test script currently executed.
|
||||
SHARNESS_TEST_FILE="$0"
|
||||
export SHARNESS_TEST_FILE
|
||||
|
||||
# Prepare test area.
|
||||
test_dir="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
|
||||
test -n "$root" && test_dir="$root/$test_dir"
|
||||
case "$test_dir" in
|
||||
/*) SHARNESS_TRASH_DIRECTORY="$test_dir" ;;
|
||||
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$test_dir" ;;
|
||||
esac
|
||||
test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
|
||||
rm -rf "$test_dir" || {
|
||||
EXIT_OK=t
|
||||
echo >&5 "FATAL: Cannot prepare test area"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Public: Empty trash directory, the test area, provided for each test. The HOME
|
||||
# variable is set to that directory too.
|
||||
export SHARNESS_TRASH_DIRECTORY
|
||||
|
||||
HOME="$SHARNESS_TRASH_DIRECTORY"
|
||||
export HOME
|
||||
|
||||
mkdir -p "$test_dir" || exit 1
|
||||
# Use -P to resolve symlinks in our working directory so that the cwd
|
||||
# in subprocesses like git equals our $PWD (for pathname comparisons).
|
||||
cd -P "$test_dir" || exit 1
|
||||
|
||||
this_test=${SHARNESS_TEST_FILE##*/}
|
||||
this_test=${this_test%.$SHARNESS_TEST_EXTENSION}
|
||||
for skp in $SKIP_TESTS; do
|
||||
case "$this_test" in
|
||||
$skp)
|
||||
say_color info >&3 "skipping test $this_test altogether"
|
||||
skip_all="skip all tests in $this_test"
|
||||
test_done
|
||||
esac
|
||||
done
|
||||
|
||||
# vi: set ts=4 sw=4 noet :
|
3
t/sharness/test/.gitignore
vendored
3
t/sharness/test/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
/trash directory*
|
||||
/test-results
|
||||
/.prove
|
@@ -1,60 +0,0 @@
|
||||
# Run tests
|
||||
#
|
||||
# Copyright (c) 2011-2012 Mathias Lafeldt
|
||||
# Copyright (c) 2005-2012 Git project
|
||||
# Copyright (c) 2005-2012 Junio C Hamano
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/ .
|
||||
|
||||
SHELL_PATH ?= $(SHELL)
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
RM ?= rm -f
|
||||
PROVE ?= prove
|
||||
AGGREGATE_SCRIPT ?= aggregate-results.sh
|
||||
DEFAULT_TEST_TARGET ?= test
|
||||
|
||||
T = $(wildcard *.t)
|
||||
|
||||
all: $(DEFAULT_TEST_TARGET)
|
||||
|
||||
test: pre-clean
|
||||
$(MAKE) aggregate-results-and-cleanup
|
||||
|
||||
prove: pre-clean
|
||||
@echo "*** prove ***"; $(PROVE) --exec '$(SHELL_PATH_SQ)' $(PROVE_OPTS) $(T) :: $(TEST_OPTS)
|
||||
$(MAKE) clean-except-prove-cache
|
||||
|
||||
$(T):
|
||||
@echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(TEST_OPTS)
|
||||
|
||||
pre-clean:
|
||||
$(RM) -r test-results
|
||||
|
||||
clean-except-prove-cache:
|
||||
$(RM) -r 'trash directory'.* test-results
|
||||
|
||||
clean: clean-except-prove-cache
|
||||
$(RM) .prove
|
||||
|
||||
aggregate-results-and-cleanup: $(T)
|
||||
$(MAKE) aggregate-results
|
||||
$(MAKE) clean
|
||||
|
||||
aggregate-results:
|
||||
for f in test-results/*.counts; do \
|
||||
echo "$$f"; \
|
||||
done | '$(SHELL_PATH_SQ)' '$(AGGREGATE_SCRIPT)'
|
||||
|
||||
.PHONY: all test prove $(T) pre-clean clean
|
||||
.PHONY: aggregate-results-and-cleanup aggregate-results
|
@@ -1 +0,0 @@
|
||||
../aggregate-results.sh
|
@@ -1 +0,0 @@
|
||||
../sharness.sh
|
@@ -1,302 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011-2013 Mathias Lafeldt
|
||||
# Copyright (c) 2005-2013 Git project
|
||||
# Copyright (c) 2005-2013 Junio C Hamano
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/ .
|
||||
|
||||
test_description='Test Sharness itself'
|
||||
|
||||
. ./sharness.sh
|
||||
|
||||
test_expect_success 'success is reported like this' '
|
||||
:
|
||||
'
|
||||
test_expect_failure 'pretend we have a known breakage' '
|
||||
false
|
||||
'
|
||||
|
||||
run_sub_test_lib_test () {
|
||||
name="$1" descr="$2" # stdin is the body of the test code
|
||||
mkdir "$name" &&
|
||||
(
|
||||
cd "$name" &&
|
||||
cat >".$name.t" <<-EOF &&
|
||||
#!$SHELL_PATH
|
||||
|
||||
test_description='$descr (run in sub sharness)
|
||||
|
||||
This is run in a sub sharness so that we do not get incorrect
|
||||
passing metrics
|
||||
'
|
||||
|
||||
# Point to the test/sharness.sh, which isn't in ../ as usual
|
||||
. "\$SHARNESS_TEST_DIRECTORY"/sharness.sh
|
||||
EOF
|
||||
cat >>".$name.t" &&
|
||||
chmod +x ".$name.t" &&
|
||||
export SHARNESS_TEST_DIRECTORY &&
|
||||
./".$name.t" --chain-lint >out 2>err
|
||||
)
|
||||
}
|
||||
|
||||
check_sub_test_lib_test () {
|
||||
name="$1" # stdin is the expected output from the test
|
||||
(
|
||||
cd "$name" &&
|
||||
! test -s err &&
|
||||
sed -e 's/^> //' -e 's/Z$//' >expect &&
|
||||
test_cmp expect out
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success 'pretend we have a fully passing test suite' "
|
||||
run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF &&
|
||||
for i in 1 2 3
|
||||
do
|
||||
test_expect_success \"passing test #\$i\" 'true'
|
||||
done
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test full-pass <<-\\EOF
|
||||
> ok 1 - passing test #1
|
||||
> ok 2 - passing test #2
|
||||
> ok 3 - passing test #3
|
||||
> # passed all 3 test(s)
|
||||
> 1..3
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have a partially passing test suite' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
partial-pass '2/3 tests passing' <<-\\EOF &&
|
||||
test_expect_success 'passing test #1' 'true'
|
||||
test_expect_success 'failing test #2' 'false'
|
||||
test_expect_success 'passing test #3' 'true'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test partial-pass <<-\\EOF
|
||||
> ok 1 - passing test #1
|
||||
> not ok 2 - failing test #2
|
||||
# false
|
||||
> ok 3 - passing test #3
|
||||
> # failed 1 among 3 test(s)
|
||||
> 1..3
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have a known breakage' "
|
||||
run_sub_test_lib_test failing-todo 'A failing TODO test' <<-\\EOF &&
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_failure 'pretend we have a known breakage' 'false'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test failing-todo <<-\\EOF
|
||||
> ok 1 - passing test
|
||||
> not ok 2 - pretend we have a known breakage # TODO known breakage
|
||||
> # still have 1 known breakage(s)
|
||||
> # passed all remaining 1 test(s)
|
||||
> 1..2
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have fixed a known breakage' "
|
||||
run_sub_test_lib_test passing-todo 'A passing TODO test' <<-\\EOF &&
|
||||
test_expect_failure 'pretend we have fixed a known breakage' 'true'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test passing-todo <<-\\EOF
|
||||
> ok 1 - pretend we have fixed a known breakage # TODO known breakage vanished
|
||||
> # 1 known breakage(s) vanished; please update test(s)
|
||||
> 1..1
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have fixed one of two known breakages (run in sub sharness)' "
|
||||
run_sub_test_lib_test partially-passing-todos \
|
||||
'2 TODO tests, one passing' <<-\\EOF &&
|
||||
test_expect_failure 'pretend we have a known breakage' 'false'
|
||||
test_expect_success 'pretend we have a passing test' 'true'
|
||||
test_expect_failure 'pretend we have fixed another known breakage' 'true'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test partially-passing-todos <<-\\EOF
|
||||
> not ok 1 - pretend we have a known breakage # TODO known breakage
|
||||
> ok 2 - pretend we have a passing test
|
||||
> ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished
|
||||
> # 1 known breakage(s) vanished; please update test(s)
|
||||
> # still have 1 known breakage(s)
|
||||
> # passed all remaining 1 test(s)
|
||||
> 1..3
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have a pass, fail, and known breakage' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
mixed-results1 'mixed results #1' <<-\\EOF &&
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_success 'failing test' 'false'
|
||||
test_expect_failure 'pretend we have a known breakage' 'false'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test mixed-results1 <<-\\EOF
|
||||
> ok 1 - passing test
|
||||
> not ok 2 - failing test
|
||||
> # false
|
||||
> not ok 3 - pretend we have a known breakage # TODO known breakage
|
||||
> # still have 1 known breakage(s)
|
||||
> # failed 1 among remaining 2 test(s)
|
||||
> 1..3
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'pretend we have a mix of all possible results' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
mixed-results2 'mixed results #2' <<-\\EOF &&
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_success 'passing test' 'true'
|
||||
test_expect_success 'failing test' 'false'
|
||||
test_expect_success 'failing test' 'false'
|
||||
test_expect_success 'failing test' 'false'
|
||||
test_expect_failure 'pretend we have a known breakage' 'false'
|
||||
test_expect_failure 'pretend we have a known breakage' 'false'
|
||||
test_expect_failure 'pretend we have fixed a known breakage' 'true'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test mixed-results2 <<-\\EOF
|
||||
> ok 1 - passing test
|
||||
> ok 2 - passing test
|
||||
> ok 3 - passing test
|
||||
> ok 4 - passing test
|
||||
> not ok 5 - failing test
|
||||
> # false
|
||||
> not ok 6 - failing test
|
||||
> # false
|
||||
> not ok 7 - failing test
|
||||
> # false
|
||||
> not ok 8 - pretend we have a known breakage # TODO known breakage
|
||||
> not ok 9 - pretend we have a known breakage # TODO known breakage
|
||||
> ok 10 - pretend we have fixed a known breakage # TODO known breakage vanished
|
||||
> # 1 known breakage(s) vanished; please update test(s)
|
||||
> # still have 2 known breakage(s)
|
||||
> # failed 3 among remaining 7 test(s)
|
||||
> 1..10
|
||||
EOF
|
||||
"
|
||||
|
||||
test_set_prereq HAVEIT
|
||||
haveit=no
|
||||
test_expect_success HAVEIT 'test runs if prerequisite is satisfied' '
|
||||
test_have_prereq HAVEIT &&
|
||||
haveit=yes
|
||||
'
|
||||
donthaveit=yes
|
||||
test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' '
|
||||
donthaveit=no
|
||||
'
|
||||
if test $haveit$donthaveit != yesyes
|
||||
then
|
||||
say "bug in test framework: prerequisite tags do not work reliably"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_set_prereq HAVETHIS
|
||||
haveit=no
|
||||
test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' '
|
||||
test_have_prereq HAVEIT &&
|
||||
test_have_prereq HAVETHIS &&
|
||||
haveit=yes
|
||||
'
|
||||
donthaveit=yes
|
||||
test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' '
|
||||
donthaveit=no
|
||||
'
|
||||
donthaveiteither=yes
|
||||
test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' '
|
||||
donthaveiteither=no
|
||||
'
|
||||
if test $haveit$donthaveit$donthaveiteither != yesyesyes
|
||||
then
|
||||
say "bug in test framework: multiple prerequisite tags do not work reliably"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
clean=no
|
||||
test_expect_success 'tests clean up after themselves' '
|
||||
test_when_finished clean=yes
|
||||
'
|
||||
|
||||
if test $clean != yes
|
||||
then
|
||||
say "bug in test framework: basic cleanup command does not work reliably"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_expect_success 'tests clean up even on failures' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
failing-cleanup 'Failing tests with cleanup commands' <<-\\EOF &&
|
||||
test_expect_success 'tests clean up even after a failure' '
|
||||
touch clean-after-failure &&
|
||||
test_when_finished rm clean-after-failure &&
|
||||
(exit 1)
|
||||
'
|
||||
test_expect_success 'failure to clean up causes the test to fail' '
|
||||
test_when_finished \"(exit 2)\"
|
||||
'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test failing-cleanup <<-\\EOF
|
||||
> not ok 1 - tests clean up even after a failure
|
||||
> # Z
|
||||
> # touch clean-after-failure &&
|
||||
> # test_when_finished rm clean-after-failure &&
|
||||
> # (exit 1)
|
||||
> # Z
|
||||
> not ok 2 - failure to clean up causes the test to fail
|
||||
> # Z
|
||||
> # test_when_finished \"(exit 2)\"
|
||||
> # Z
|
||||
> # failed 2 among 2 test(s)
|
||||
> 1..2
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'cleanup functions tun at the end of the test' "
|
||||
run_sub_test_lib_test cleanup-function 'Empty test with cleanup function' <<-\\EOF &&
|
||||
cleanup 'echo cleanup-function-called >&5'
|
||||
test_done
|
||||
EOF
|
||||
check_sub_test_lib_test cleanup-function <<-\\EOF
|
||||
1..0
|
||||
cleanup-function-called
|
||||
EOF
|
||||
"
|
||||
|
||||
test_expect_success 'We detect broken && chains' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
broken-chain 'Broken && chain' <<-\\EOF
|
||||
test_expect_success 'Cannot fail' '
|
||||
true
|
||||
true
|
||||
'
|
||||
test_done
|
||||
EOF
|
||||
"
|
||||
|
||||
test_done
|
||||
|
||||
# vi: set ft=sh :
|
@@ -1,32 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description="Show basic features of Sharness"
|
||||
|
||||
. ./sharness.sh
|
||||
|
||||
test_expect_success "Success is reported like this" "
|
||||
echo hello world | grep hello
|
||||
"
|
||||
|
||||
test_expect_success "Commands are chained this way" "
|
||||
test x = 'x' &&
|
||||
test 2 -gt 1 &&
|
||||
echo success
|
||||
"
|
||||
|
||||
return_42() {
|
||||
echo "Will return soon"
|
||||
return 42
|
||||
}
|
||||
|
||||
test_expect_success "You can test for a specific exit code" "
|
||||
test_expect_code 42 return_42
|
||||
"
|
||||
|
||||
test_expect_failure "We expect this to fail" "
|
||||
test 1 = 2
|
||||
"
|
||||
|
||||
test_done
|
||||
|
||||
# vi: set ft=sh :
|
@@ -1,18 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
SHARNESS_TEST_EXTENSION="sh"
|
||||
#!/bin/bash
|
||||
|
||||
test_description="check parse"
|
||||
|
||||
. sharness/sharness.sh
|
||||
|
||||
. ../../bash-ini-parser
|
||||
|
||||
DIR_TEST=$SHARNESS_TEST_DIRECTORY/t0001
|
||||
. setup.sh
|
||||
|
||||
test_expect_success "Whitespace parse" "
|
||||
cfg_parser $DIR_TEST/whitespace.ini &&
|
||||
cfg_writer > whitespace.out &&
|
||||
export COVERAGE_NAME=whitespace_parser
|
||||
cp ../.simplecov .
|
||||
$COMMAND cfg_parser $DIR_TEST/whitespace.ini
|
||||
export COVERAGE_NAME=whitespace_writer
|
||||
$COMMAND cfg_writer > whitespace.out
|
||||
diff -u whitespace.out $DIR_TEST/whitespace.out.correct
|
||||
"
|
||||
|
||||
|
@@ -1,17 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
SHARNESS_TEST_EXTENSION="sh"
|
||||
#!/bin/bash
|
||||
|
||||
test_description="check invalid ini files"
|
||||
|
||||
. sharness/sharness.sh
|
||||
|
||||
. ../../bash-ini-parser
|
||||
|
||||
DIR_TEST=$SHARNESS_TEST_DIRECTORY/t0002
|
||||
. setup.sh
|
||||
|
||||
test_expect_success "Invalid line" "
|
||||
test_expect_code 1 cfg_parser $DIR_TEST/invalid.ini
|
||||
export COVERAGE_NAME=invalid_line
|
||||
cp ../.simplecov .
|
||||
test_expect_code 1 $COMMAND cfg_parser $DIR_TEST/invalid.ini
|
||||
"
|
||||
|
||||
test_done
|
||||
|
@@ -1,18 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
SHARNESS_TEST_EXTENSION="sh"
|
||||
#!/bin/bash
|
||||
|
||||
test_description="check sections"
|
||||
|
||||
. sharness/sharness.sh
|
||||
|
||||
. ../../bash-ini-parser
|
||||
|
||||
DIR_TEST=$SHARNESS_TEST_DIRECTORY/t0003
|
||||
. setup.sh
|
||||
|
||||
test_expect_success "Parse sections" "
|
||||
cfg_parser $DIR_TEST/sections.ini
|
||||
cfg_writer > sections.out
|
||||
export COVERAGE_NAME=sections_parser
|
||||
cp ../.simplecov .
|
||||
$COMMAND cfg_parser $DIR_TEST/sections.ini
|
||||
export COVERAGE_NAME=sections_writer
|
||||
$COMMAND cfg_writer > sections.out
|
||||
diff $DIR_TEST/sections.out.correct sections.out
|
||||
"
|
||||
|
||||
|
@@ -1,16 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
SHARNESS_TEST_EXTENSION="sh"
|
||||
#!/bin/bash
|
||||
|
||||
test_description="check comments"
|
||||
|
||||
. sharness/sharness.sh
|
||||
|
||||
. ../../bash-ini-parser
|
||||
. setup.sh
|
||||
|
||||
DIR_TEST=$SHARNESS_TEST_DIRECTORY/t0004
|
||||
|
||||
test_expect_success "Parse sections" "
|
||||
test_expect_success "Parse comments" "
|
||||
export COVERAGE_NAME=comments_parser
|
||||
cp ../.simplecov .
|
||||
cfg_parser $DIR_TEST/comments.ini
|
||||
cfg_writer > comments.out
|
||||
diff $DIR_TEST/comments.out.correct comments.out
|
||||
|
Reference in New Issue
Block a user