#!/bin/bash # ------------------------------------------------------------------------------ # (C) British Crown Copyright 2006-17 Met Office. # # This file is part of FCM, tools for managing and building source code. # # FCM is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # FCM 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 FCM. If not, see . # ------------------------------------------------------------------------------ # NAME # test_header # # SYNOPSIS # . $FCM_HOME/t/lib/bash/test_header # # DESCRIPTION # Provide bash shell functions for writing tests for "fcm" commands to # output in Perl's TAP format. Add "set -eu". Create a temporary working # directory $TEST_DIR and change to it. Automatically increment test number. # If $FCM_HOME is not specified, set it to point to the "fcm" source tree # containing this script. Add $FCM_HOME/bin to the front of $PATH. # # FUNCTIONS # tests N # echo "1..$N". # skip N REASON # echo "ok $((++T)) # skip REASON" N times, where T is the test number. # skip_all REASON # echo "1..0 # SKIP $REASON" and exit. # pass TEST_KEY # echo "ok $T - $TEST_KEY" where T is the current test number. # fail TEST_KEY # echo "not ok $T - $TEST_KEY" where T is the current test number. # run_pass TEST_KEY COMMAND ... # Run $COMMAND. pass/fail $TEST_KEY if $COMMAND returns true/false. # Write STDOUT and STDERR in $TEST_KEY.out and $TEST_KEY.err. # run_fail TEST_KEY COMMAND ... # Run $COMMAND. pass/fail $TEST_KEY if $COMMAND returns false/true. # Write STDOUT and STDERR in $TEST_KEY.out and $TEST_KEY.err. # file_cmp TEST_KEY FILE_ACTUAL [$FILE_EXPECT] # Compare contents in $FILE_ACTUAL and $FILE_EXPECT. pass/fail # $TEST_KEY if contents are identical/different. If $FILE_EXPECT is "-" # or not defined, compare $FILE_ACTUAL with STDIN to this function. # file_test TEST_KEY FILE [OPTION] # pass/fail $TEST_KEY if "test $OPTION $FILE" returns 0/1. $OPTION is # -e if not specified. # file_grep TEST_KEY PATTERN FILE # Run "grep -q PATTERN FILE". pass/fail $TEST_KEY accordingly. # branch_tidy INPUT_FILE # Standardise branch-create output between Subversion 1.8 and 1.9. # commit_sort INPUT_FILE OUTPUT_FILE # Sort status and transmitting info within the commit output. # diff_sort INPUT_FILE OUTPUT_FILE # Sort Subversion diff output by filename. # diff_svn_version_filter # Preprocess stdin to stdout based on relevant '#IF SVN1.X' prefixes. # status_sort INPUT_FILE OUTPUT_FILE # Sort Subversion status lines. # merge_sort INPUT_FILE OUTPUT_FILE # Sort Subversion merge status lines. # check_svn_version # Check Subversion version and skip tests if not compatible. # FINALLY # This is run on EXIT or INT to remove the temporary working directory # for the test. Call FINALLY_MORE if it is declared. # # VARIABLES # FCM_HOME # Root of FCM's installation. (Exported.) # SIGNALS # List of signals trapped by FINALLY, currently EXIT and INT. # TEST_DIR # Temporary directory that is also the working directory for this test. # TEST_KEY_BASE # Base root name of current test file. # TEST_NUMBER # Test number of latest test. # TEST_SOURCE_DIR # Directory containing the current test file. #------------------------------------------------------------------------------- set -eu SIGNALS="EXIT INT" TEST_DIR= function FINALLY() { for S in $SIGNALS; do trap '' $S done if [[ -n $TEST_DIR ]]; then cd ~ rm -rf $TEST_DIR fi if declare -F FINALLY_MORE >/dev/null; then FINALLY_MORE fi } for S in $SIGNALS; do trap "FINALLY $S" $S done TEST_NUMBER=0 function tests() { echo "1..$1" } function skip() { local N_SKIPS=$1 shift 1 local I=0 while ((I++ < N_SKIPS)); do echo "ok $((++TEST_NUMBER)) # skip $@" done } function skip_all() { echo "1..0 # SKIP $@" exit } function pass() { echo "ok $((++TEST_NUMBER)) - $@" } function fail() { echo "not ok $((++TEST_NUMBER)) - $@" } function run_pass() { local TEST_KEY=$1 shift 1 if ! "$@" 1>$TEST_KEY.out 2>$TEST_KEY.err; then fail $TEST_KEY return fi pass $TEST_KEY } function run_fail() { local TEST_KEY=$1 shift 1 if "$@" 1>$TEST_KEY.out 2>$TEST_KEY.err; then fail $TEST_KEY return fi pass $TEST_KEY } function file_cmp() { local TEST_KEY=$1 local FILE_ACTUAL=$2 local FILE_EXPECT=${3:--} if diff -u $FILE_EXPECT $FILE_ACTUAL >&2; then pass $TEST_KEY return fi fail $TEST_KEY } function file_test() { local TEST_KEY=$1 local FILE=$2 local OPTION=${3:--e} if test $OPTION $FILE; then pass $TEST_KEY else fail $TEST_KEY fi } function file_grep() { local TEST_KEY=$1 local PATTERN=$2 local FILE=$3 if grep -q -e "$PATTERN" $FILE; then pass $TEST_KEY return fi fail $TEST_KEY } function branch_tidy() { local INPUT_FILE=$TEST_DIR/$1 sed -i "/^Committing transaction/d; /^$/d" "$INPUT_FILE" } function commit_sort() { local INPUT_FILE=$1 local OUTPUT_FILE=$2 local TMP_OUTPUT_FILE=$(mktemp) # Sort the svn status part of the message status_sort $INPUT_FILE $TMP_OUTPUT_FILE # Sort the 'Adding/Deleting', etc part of the message python -c 'import re, sys text = sys.stdin.read() sending_lines = re.findall("^\w+ing +.*$", text, re.M) prefix = text[:text.index(sending_lines[0])] suffix = text[(text.index(sending_lines[-1]) + len(sending_lines[-1])):] sending_lines.sort() print prefix + "\n".join(sending_lines) + suffix.rstrip() ' <"$TMP_OUTPUT_FILE" >"$OUTPUT_FILE" rm "$TMP_OUTPUT_FILE" # Remove 1.8 to 1.9 specific changes (transmitting, transaction lines). sed -i "/^Transmitting file data/d; /^Committing transaction/d; /^$/d" \ "$OUTPUT_FILE" } function diff_sort() { local INPUT_FILE=$1 local OUTPUT_FILE=$2 # Sort the diff file order. python -c 'import re, sys text = sys.stdin.read() print "\nIndex: ".join( [l.strip() for l in sorted(re.compile("^Index: ", re.M).split(text))]) ' <"$INPUT_FILE" >"$OUTPUT_FILE" # In 1.9, new files are (nonexistent) rather than (working copy). sed -i "s/(nonexistent)/(working copy)/" "$OUTPUT_FILE" } function diff_svn_version_filter() { if "$SVN_VERSION_IS_19"; then sed "s/^#IF SVN1.9 //g; /^#IF SVN1.8 /d" else sed "s/^#IF SVN1.8 //g; /^#IF SVN1.9 /d" fi } function status_sort() { local INPUT_FILE=$1 local OUTPUT_FILE=$2 python -c 'import re, sys text = sys.stdin.read() status_lines = re.findall("^.{7} [\w./].*$", text, re.M) prefix = text[:text.index(status_lines[0])] suffix = text[(text.index(status_lines[-1]) + len(status_lines[-1])):] status_lines.sort() print prefix + "\n".join(status_lines) + suffix.rstrip() ' <"$INPUT_FILE" >"$OUTPUT_FILE" } function merge_sort() { local INPUT_FILE=$1 local OUTPUT_FILE=$2 python -c 'import re, sys text = sys.stdin.read() status_lines = [] for line in text.splitlines(): if line.startswith("Enter \"y\"") and ": " in line: head, tail = line.split(": ", 1) if status_lines: print "\n".join(sorted(status_lines)) status_lines = [] print head + ": " if tail: line = tail if re.search("^.{4} [\w./].*$", line): status_lines.append(line) elif status_lines: print "\n".join(sorted(status_lines)) print line status_lines = [] else: print line if status_lines: print "\n".join(sorted(status_lines)) ' <"$INPUT_FILE" >"$OUTPUT_FILE" } function check_svn_version() { if ! svn --version | head -1 | grep -q "^svn, version 1\.\(8\|9\)"; then skip_all "Tests require Subversion 1.8 or 1.9" exit 0 fi } function fcm_make_build_hello_tests() { local TEST_KEY=$1 local HELLO_EXT=${2:-} shift 2 rm -fr \ .fcm-make \ build \ fcm-make-as-parsed.cfg \ fcm-make-on-success.cfg \ fcm-make.log run_pass "$TEST_KEY" fcm make "$@" file_test "$TEST_KEY.hello$HELLO_EXT" "$PWD/build/bin/hello$HELLO_EXT" "$PWD/build/bin/hello$HELLO_EXT" >"$TEST_KEY.hello$HELLO_EXT.out" file_cmp "$TEST_KEY.hello$HELLO_EXT.out" \ "$TEST_KEY.hello$HELLO_EXT.out" <<'__OUT__' Hello World! __OUT__ } FCM_HOME=${FCM_HOME:-$(cd $(dirname $(readlink -f $BASH_SOURCE))/../../.. && pwd)} export FCM_HOME PATH=$FCM_HOME/bin:$PATH SVN_VERSION_IS_19=false if svn --version 1>/dev/null 2>&1; then SVN_VERSION=$(svn --version | \ sed -n "s/^svn, version \([0-9.]\+\) .*/\1/p") if [[ $SVN_VERSION =~ "1.9." ]]; then SVN_VERSION_IS_19=true fi fi TEST_KEY_BASE=$(basename $0 .t) TEST_SOURCE_DIR=$(cd $(dirname $0) && pwd) TEST_DIR=$(mktemp -d) export LC_ALL=C export LANG=C cd $TEST_DIR set +e