#!/bin/bash
#
# Test Framework for update-systemd-resolved.
# Copyright (C) 2016, Jonathan Wright <jon@than.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# Set colour escape sequences
RED='\033[0;31m'
YELLOW='\033[1;33m'
ORANGE='\033[0;33m'
GREEN='\033[0;32m'
DARK='\033[1;30m'
RESET='\033[0m'
# Set Pass/Fail signatures
PASS="✓"
FAIL="✗"
# Counters
COUNT_PASS=0
COUNT_FAIL=0
# Flag for determining whether a test script called the `runtest' function
RUNTEST_CALLED=0

AUTOMATED_TESTING=1

function busctl {
  shift 4
  _log "busctl called with: ${@}"
  # Set that busctl has been called
  busctl_called=1

  case "${1}" in
    SetLinkDNS)
      shift 2
      if [[ "${TEST_BUSCTL_DNS}" == "" ]]; then
        [[ "${ip_ifindex} ${TEST_BUSCTL_DNS}" == "${@}" ]] || \
          _fail "SetLinkDNS was called and should not be: '${@}'"
      else
        [[ "${ip_ifindex} ${TEST_BUSCTL_DNS}" == "${@}" ]] && \
          _pass "SetLinkDNS was called correctly" || \
          _fail "SetLinkDNS was not given the correct arguments:\n" \
                "     Expected: '${ip_ifindex} ${TEST_BUSCTL_DNS}'\n" \
                "     Received: '${@}'"
      fi
      ;;
    SetLinkDomains)
      shift 2
      if [[ "${TEST_BUSCTL_DOMAINS}" == "" ]]; then
        [[ "${ip_ifindex} ${TEST_BUSCTL_DOMAINS}" == "${@}" ]] || \
          _fail "SetLinkDomains was called and should not be: '${@}'"
      else
        [[ "${ip_ifindex} ${TEST_BUSCTL_DOMAINS}" == "${@}" ]] && \
          _pass "SetLinkDomains was called correctly" || \
          _fail "SetLinkDomains was not given the correct arguments:\n" \
                "     Expected: '${ip_ifindex} ${TEST_BUSCTL_DOMAINS}'\n" \
                "     Received: '${@}'"
      fi
      ;;
    SetLinkDNSSEC)
      shift 2
      [[ "${ip_ifindex} ${TEST_BUSCTL_DNSSEC}x" == "${@}x" ]] && \
        _pass "SetLinkDNSSEC was called correctly" || \
        _fail "SetLinkDNSSEC was not given the correct arguments:\n" \
              "     Expected: '${ip_ifindex} ${TEST_BUSCTL_DNSSEC}'\n" \
              "     Received: '${@}'"
      ;;
    *)
      _fail "Unknown command called on busctl: ${1}"
      ;;
  esac
}

function ip {
  _log "ip called with: ${@}"

  [[ "${1} ${2} ${3} ${4}" == "link show dev ${dev}" ]] && \
    _pass "ip was called correctly" || \
    _fail "ip was called with incorrect or unknown arguments"

  # Return fake ip statement
  echo -e "${ip_ifindex}: ${dev}: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>" \
    " mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen" \
    " 100\n    link/none"
}

function logger {
  # Remove standard options
  local message="$*"
  _log "-- ${message##* -- }"
}

function exit {
  # Override
  _log "exit called with status ${1}"
}

function _log {
  ( >&2 echo -e "    ${DARK}${@}${RESET}" )
}

function _pass {
  COUNT_PASS=$((COUNT_PASS+1))
  ( >&2 echo -e "  ${GREEN}${PASS}${RESET} ${@}" )
}

function _fail {
  COUNT_FAIL=$((COUNT_FAIL+1))
  ( >&2 echo -e "  ${RED}${FAIL} ${@}${RESET}" )
}

function runtest {
  # Increment counter so that we don't double-execute if a test script calls
  # this function.
  : ${RUNTEST_CALLED:=0}
  (( RUNTEST_CALLED += 1 ))

  echo -e "${GREEN}- Testing ${TEST_TITLE:-a nameless test}${RESET}"

  # Source, don't run, so we don't need to export and internal functions override
  # external calls out to system commands
  source update-systemd-resolved
  exit_status="$?"
  exit_message="script exited with a ${exit_status} exit status"

  if [[ "$(( exit_status > 0 ))" == "${EXPECT_FAILURE:-0}" ]]; then
      _pass "$exit_message"
  else
      _fail "$exit_message"
  fi

  if [[ ${TEST_BUSCTL_CALLED} -eq 0 ]]; then
    [[ ${busctl_called} -eq 0 ]] && \
      _pass "busctl was not called, as expected" || \
      _fail "busctl was called, not expected"
  else
    [[ ${busctl_called} -eq 0 ]] && \
      _fail "busctl was not called, not expected"
  fi

  echo
}

echo "update-systemd-resolved Test Suite"
echo

for TEST in tests/*.sh; do
  # Set/Reset loop variables
  RUNTEST_CALLED=0
  EXPECT_FAILURE=0
  busctl_called=0
  # Set/Reset expected results
  TEST_BUSCTL_DNS=""
  TEST_BUSCTL_DOMAINS=""
  TEST_BUSCTL_DNSSEC=""
  # Keep this random, as we will never know the ifindex up-front
  ip_ifindex=$((RANDOM%=64))
  # Clear foreign_option_*
  foreign_option_1=""
  foreign_option_2=""
  foreign_option_3=""
  foreign_option_4=""
  foreign_option_5=""
  foreign_option_6=""

  # Import the test configuration
  source "${TEST}"

  (( RUNTEST_CALLED > 0 )) || runtest
done

echo -e "  ${GREEN}${PASS} ${COUNT_PASS} Passed${RESET}"
echo -e "  ${RED}${FAIL} ${COUNT_FAIL} Failed${RESET}"

# Make sure we fail if there are failed tests
[[ ${COUNT_FAIL} -eq 0 ]]
