# Copyright 2014 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# * Neither the name of Google Inc. nor the names of its contributors
#   may be used to endorse or promote products derived from this software
#   without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

shtk_import cli
#shtk_import unittest  # unittest imports us, so we can assume it is present.


# Verifies if a file conforms to a specification.
#
# This is a helper function for _shtk_unittest_check_command only and should not
# be seen as generic.  This is why, for example, this also handles the "save"
# specification which, strictly speaking, is not a verification; it is an
# action.
#
# wrapper: Name of the calling function for error reporting purposes.
# fail_function: Name of the function to use to report a failure.
# spec: The expectations that the file must match.
# file: The file to be checked.
#
# Returns true if the file matches the specification; false otherwise.
#
# Errors out if the specification is broken or if some other unexpected
# error (like missing files) is detected.
_shtk_unittest_check_file() {
    local wrapper="${1}"; shift
    local fail_function="${1}"; shift
    local spec="${1}"; shift
    local file="${1}"; shift

    if [ ! -e "${file}" ]; then
        "${fail_function}" "Cannot find ${file} in call to ${wrapper}"
        return 1
    fi

    local failed=no
    case "${spec}" in
        empty)
            if [ -s "${file}" ]; then
                echo "Expected ${file} to be empty; found:"
                cat "${file}"
                failed=yes
            fi
            ;;

        ignore)
            ;;

        file:*)
            local golden_file="$(echo "${spec}" | cut -d : -f 2-)"
            [ -e "${golden_file}" ] || shtk_cli_error "Cannot find golden" \
                "file ${golden_file} given to ${wrapper}"
            if ! cmp -s "${file}" "${golden_file}"; then
                echo "${file} did not match golden contents:"
                diff -u "${golden_file}" "${file}"
                failed=yes
            fi
            ;;

        inline:*)
            local golden_file="${wrapper}.inline"
            # Use printf instead of echo because it has more predictable
            # behavior when evaluating escape sequences.
            printf "$(printf "%s\n" "${spec}" | cut -d : -f 2-)" \
                >"${golden_file}"
            if ! cmp -s "${file}" "${golden_file}"; then
                echo "${file} did not match golden contents:"
                diff -u "${golden_file}" "${file}"
                rm -f "${golden_file}"
                failed=yes
            else
                rm -f "${golden_file}"
            fi
            ;;

        match:*)
            local match_regexp="$(echo "${spec}" | cut -d : -f 2-)"
            if ! grep -E "${match_regexp}" "${file}" >/dev/null; then
                echo "Expected regexp '${match_regexp}' not found in ${file}:"
                cat "${file}"
                failed=yes
            fi
            ;;

        not-empty)
            if [ ! -s "${file}" ]; then
                echo "Expected ${file} to not be empty"
                failed=yes
            fi
            ;;

        not-match:*)
            local match_regexp="$(echo "${spec}" | cut -d : -f 2-)"
            if grep -E "${match_regexp}" "${file}" >/dev/null; then
                echo "Expected regexp '${match_regexp}' found in ${file}:"
                cat "${file}"
                failed=yes
            fi
            ;;

        save:*)
            local output_file="$(echo "${spec}" | cut -d : -f 2-)"
            cp "${file}" "${output_file}" 2>/dev/null \
                || shtk_cli_error "Failed to save output to ${output_file} in" \
                "call to ${wrapper}"
            ;;

        stdin)
            local golden_file="${wrapper}.stdin"
            cat >"${golden_file}"
            if ! cmp -s "${file}" "${golden_file}"; then
                echo "${file} did not match golden contents from stdin:"
                diff -u "${golden_file}" "${file}"
                rm -f "${golden_file}"
                failed=yes
            else
                rm -f "${golden_file}"
            fi
            ;;

        *)
            shtk_cli_error "Invalid file check specification in ${wrapper};" \
                "got ${spec}"
            ;;
    esac
    [ "${failed}" = no ] || \
        "${fail_function}" "Failed to validate contents of file ${file}"
}
_shtk_unittest_register_check file
