|  | # Copyright 2020 The Bazel Authors. All rights reserved. | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | # Support for unittest.bash | 
|  |  | 
|  | #### Set up the test environment. | 
|  |  | 
|  | set -euo pipefail | 
|  |  | 
|  | cat_jvm_log () { | 
|  | if [[ "$log_content" =~ \ | 
|  | "(error code:".*", error message: '".*"', log file: '"(.*)"')" ]]; then | 
|  | echo >&2 | 
|  | echo "Content of ${BASH_REMATCH[1]}:" >&2 | 
|  | cat "${BASH_REMATCH[1]}" >&2 | 
|  | fi | 
|  | } | 
|  |  | 
|  | # Print message in "$1" then exit with status "$2" | 
|  | die () { | 
|  | # second argument is optional, defaulting to 1 | 
|  | local status_code=${2:-1} | 
|  | # Stop capturing stdout/stderr, and dump captured output | 
|  | if [[ "$CAPTURED_STD_ERR" -ne 0 || "$CAPTURED_STD_OUT" -ne 0 ]]; then | 
|  | restore_outputs | 
|  | if [[ "$CAPTURED_STD_OUT" -ne 0 ]]; then | 
|  | cat "${TEST_TMPDIR}/captured.out" | 
|  | CAPTURED_STD_OUT=0 | 
|  | fi | 
|  | if [[ "$CAPTURED_STD_ERR" -ne 0 ]]; then | 
|  | cat "${TEST_TMPDIR}/captured.err" 1>&2 | 
|  | cat_jvm_log "$(cat "${TEST_TMPDIR}/captured.err")" | 
|  | CAPTURED_STD_ERR=0 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | if [[ -n "${1-}" ]] ; then | 
|  | echo "$1" 1>&2 | 
|  | fi | 
|  | if [[ -n "${BASH-}" ]]; then | 
|  | local caller_n=0 | 
|  | while [[ $caller_n -lt 4 ]] && \ | 
|  | caller_out=$(caller $caller_n 2>/dev/null); do | 
|  | test $caller_n -eq 0 && echo "CALLER stack (max 4):" | 
|  | echo "  $caller_out" | 
|  | let caller_n=caller_n+1 | 
|  | done 1>&2 | 
|  | fi | 
|  | if [[ -n "${status_code}" && "${status_code}" -ne 0 ]]; then | 
|  | exit "$status_code" | 
|  | else | 
|  | exit 1 | 
|  | fi | 
|  | } | 
|  |  | 
|  | # Print message in "$1" then record that a non-fatal error occurred in | 
|  | # ERROR_COUNT | 
|  | ERROR_COUNT="${ERROR_COUNT:-0}" | 
|  | error () { | 
|  | if [[ -n "$1" ]] ; then | 
|  | echo "$1" 1>&2 | 
|  | fi | 
|  | ERROR_COUNT=$(($ERROR_COUNT + 1)) | 
|  | } | 
|  |  | 
|  | # Die if "$1" != "$2", print $3 as death reason | 
|  | check_eq () { | 
|  | [[ "$1" = "$2" ]] || die "Check failed: '$1' == '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Die if "$1" == "$2", print $3 as death reason | 
|  | check_ne () { | 
|  | [[ "$1" != "$2" ]] || die "Check failed: '$1' != '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # The structure of the following if statements is such that if '[[' fails | 
|  | # (e.g., a non-number was passed in) then the check will fail. | 
|  |  | 
|  | # Die if "$1" > "$2", print $3 as death reason | 
|  | check_le () { | 
|  | [[ "$1" -gt "$2" ]] || die "Check failed: '$1' <= '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Die if "$1" >= "$2", print $3 as death reason | 
|  | check_lt () { | 
|  | [[ "$1" -lt "$2" ]] || die "Check failed: '$1' < '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Die if "$1" < "$2", print $3 as death reason | 
|  | check_ge () { | 
|  | [[ "$1" -ge "$2" ]] || die "Check failed: '$1' >= '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Die if "$1" <= "$2", print $3 as death reason | 
|  | check_gt () { | 
|  | [[ "$1" -gt "$2" ]] || die "Check failed: '$1' > '$2' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Die if $2 !~ $1; print $3 as death reason | 
|  | check_match () | 
|  | { | 
|  | expr match "$2" "$1" >/dev/null || \ | 
|  | die "Check failed: '$2' does not match regex '$1' ${3:+ ($3)}" | 
|  | } | 
|  |  | 
|  | # Run command "$1" at exit. Like "trap" but multiple atexits don't | 
|  | # overwrite each other. Will break if someone does call trap | 
|  | # directly. So, don't do that. | 
|  | ATEXIT="${ATEXIT-}" | 
|  | atexit () { | 
|  | if [[ -z "$ATEXIT" ]]; then | 
|  | ATEXIT="$1" | 
|  | else | 
|  | ATEXIT="$1 ; $ATEXIT" | 
|  | fi | 
|  | trap "$ATEXIT" EXIT | 
|  | } | 
|  |  | 
|  | ## TEST_TMPDIR | 
|  | if [[ -z "${TEST_TMPDIR:-}" ]]; then | 
|  | export TEST_TMPDIR="$(mktemp -d ${TMPDIR:-/tmp}/bazel-test.XXXXXXXX)" | 
|  | fi | 
|  | if [[ ! -e "${TEST_TMPDIR}" ]]; then | 
|  | mkdir -p -m 0700 "${TEST_TMPDIR}" | 
|  | # Clean TEST_TMPDIR on exit | 
|  | atexit "rm -fr ${TEST_TMPDIR}" | 
|  | fi | 
|  |  | 
|  | # Functions to compare the actual output of a test to the expected | 
|  | # (golden) output. | 
|  | # | 
|  | # Usage: | 
|  | #   capture_test_stdout | 
|  | #   ... do something ... | 
|  | #   diff_test_stdout "$TEST_SRCDIR/path/to/golden.out" | 
|  |  | 
|  | # Redirect a file descriptor to a file. | 
|  | CAPTURED_STD_OUT="${CAPTURED_STD_OUT:-0}" | 
|  | CAPTURED_STD_ERR="${CAPTURED_STD_ERR:-0}" | 
|  |  | 
|  | capture_test_stdout () { | 
|  | exec 3>&1 # Save stdout as fd 3 | 
|  | exec 4>"${TEST_TMPDIR}/captured.out" | 
|  | exec 1>&4 | 
|  | CAPTURED_STD_OUT=1 | 
|  | } | 
|  |  | 
|  | capture_test_stderr () { | 
|  | exec 6>&2 # Save stderr as fd 6 | 
|  | exec 7>"${TEST_TMPDIR}/captured.err" | 
|  | exec 2>&7 | 
|  | CAPTURED_STD_ERR=1 | 
|  | } | 
|  |  | 
|  | # Force XML_OUTPUT_FILE to an existing path | 
|  | if [[ -z "${XML_OUTPUT_FILE:-}" ]]; then | 
|  | XML_OUTPUT_FILE=${TEST_TMPDIR}/output.xml | 
|  | fi | 
|  |  | 
|  | # Functions to provide easy access to external repository outputs in the sibling | 
|  | # repository layout. | 
|  | # | 
|  | # Usage: | 
|  | #   bin_dir <repository name> | 
|  | #   genfiles_dir <repository name> | 
|  | #   testlogs_dir <repository name> | 
|  |  | 
|  | testlogs_dir() { | 
|  | echo $(bazel info bazel-testlogs | sed "s|bazel-out|bazel-out/$1|") | 
|  | } |