#!/bin/bash

# TODO Test what happens when 'apt update' fails, backup files
# should be restored.

set -eu
#set-x
#VERBOSE=1

TEST_SUITE=
TEST_NAME=
tname() { TEST_NAME="$@"; }

DEFAULT_ONE_LINE="\
deb http://http.kali.org/kali kali-rolling main contrib non-free non-free-firmware"

DEFAULT_DEB822="\
Types: deb
URIs: http://http.kali.org/kali/
Suites: kali-rolling
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"

reset_one_line() {
    rm -fr /etc/apt/sources.list*
    mkdir /etc/apt/sources.list.d/
    [ $# -eq 0 ] && set -- "$DEFAULT_ONE_LINE"
    echo "$1" >/etc/apt/sources.list
#    echo "${1:-$DEFAULT_ONE_LINE}" >/etc/apt/sources.list
#    echo "$DEFAULT_ONE_LINE" >/etc/apt/sources.list
}

reset_deb822() {
    rm -fr /etc/apt/sources.list*
    mkdir /etc/apt/sources.list.d/
    [ $# -eq 0 ] && set -- "$DEFAULT_DEB822"
    echo "$1" >/etc/apt/sources.list.d/kali.sources
#    echo "${1:-$DEFAULT_DEB822}" >/etc/apt/sources.list.d/kali.sources
#    echo "$DEFAULT_DEB822" >/etc/apt/sources.list.d/kali.sources
}

apply() {
    if [ "${VERBOSE:-0}" -eq 0 ]; then
        debian/tests/apt-repos-apply "$1" >/dev/null
    else
        debian/tests/apt-repos-apply "$1"
    fi
}

check() {
    local filename=
    local expected=
    local content=
    local ignore_comments=0

    while [ $# -gt 1 ]; do
        case $1 in
            --ignore-comments) ignore_comments=1 ;;
            *)
                filename=/etc/apt/$1; shift
                expected=$1; shift
                break ;;
        esac
        shift
    done

    if [ "$expected" = null ]; then
        if [ ! -e "$filename" ]; then
            return 0
        fi
        ERR="File $filename exists, expected it NOT to exist"
        exit 1
    fi

    if [ ! -e "$filename" ]; then
        ERR="File $filename doesn't exist, expected it to exist"
        exit 1
    fi

    if [ $ignore_comments -eq 1 ]; then
        content=$(grep -v '^#' "$filename")
    else
        content=$(cat "$filename")
    fi

    if [ "$content" = "$expected" ]; then
        return 0
    fi

    # Test failed!

    ERR="\
Filename: $filename
Expected:
$(echo "$expected" | sed 's/^/  /')
Got:
$(echo "$content"  | sed 's/^/  /')"

    exit 1
}

cleanup() {
    echo "Test suite: ${TEST_SUITE:-undefined}"
    echo "Test name : ${TEST_NAME:-undefined}"
    echo "${ERR:-}"
}

trap cleanup EXIT

# One-Line-Style Tests --------------------------------------------------------

TEST_SUITE="One-Line-Style Tests"
DEFAULT=$DEFAULT_ONE_LINE
reset() { reset_one_line "$@"; }

tname "Change protocol and mirror"
reset
apply '{"protocol": "https", "mirror": "kali.download"}'
check sources.list \
    "deb https://kali.download/kali kali-rolling main contrib non-free non-free-firmware"

tname "Add an extra repository"
reset
apply '{"extra-repos": {"kali-experimental": true}}'
check sources.list "$DEFAULT"
check sources.list.d/kali-experimental.list \
    "deb http://http.kali.org/kali kali-experimental main contrib non-free non-free-firmware"

tname "Add an extra repository, the destination file already exists"
reset
echo "Foobar!" >/etc/apt/sources.list.d/kali-experimental.list
apply '{"extra-repos": {"kali-experimental": true}}'
check sources.list "$DEFAULT"
check sources.list.d/kali-experimental.list \
    "deb http://http.kali.org/kali kali-experimental main contrib non-free non-free-firmware"

tname "Remove an extra repository"
apply '{"extra-repos": {"kali-experimental": false}}'
check sources.list "$DEFAULT"
check sources.list.d/kali-experimental.list null

tname "Remove an extra repository that was in sources.list"
reset
sed "s/kali-rolling/kali-experimental/" /etc/apt/sources.list >>/etc/apt/sources.list
apply '{"extra-repos": {"kali-experimental": false}}'
check sources.list "$DEFAULT"

tname "Main suite, components and options are preserved"
reset "deb [ arch=amd64,i386 ] http://http.kali.org/kali kali-dev main"
apply '{"protocol": "https", "mirror": "kali.download"}'
check sources.list \
    "deb [ arch=amd64,i386 ] https://kali.download/kali kali-dev main"

# Deb822-Style Tests ----------------------------------------------------------

TEST_SUITE="Deb822-Style Tests"
DEFAULT=$DEFAULT_DEB822
reset() { reset_deb822 "$@"; }

tname "Change protocol and mirror"
reset
apply '{"protocol": "https", "mirror": "kali.download"}'
check sources.list.d/kali.sources "\
Types: deb
URIs: https://kali.download/kali/
Suites: kali-rolling
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"

tname "Add an extra repository"
reset
apply '{"extra-repos": {"kali-experimental": true}}'
check sources.list.d/kali.sources "\
Types: deb
URIs: http://http.kali.org/kali/
Suites: kali-rolling kali-experimental
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"

tname "Remove an extra repository"
apply '{"extra-repos": {"kali-experimental": false}}'
check sources.list.d/kali.sources "$DEFAULT"

tname "Main suite, components and options are preserved"
reset "\
Types: deb deb-src
Architectures: amd64 i386
URIs: http://http.kali.org/kali/
Suites: kali-dev
Components: main
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"
apply '{"protocol": "https", "mirror": "kali.download"}'
check sources.list.d/kali.sources "\
Types: deb deb-src
URIs: https://kali.download/kali/
Suites: kali-dev
Components: main
Architectures: amd64 i386
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"

# Modernize Tests -------------------------------------------------------------

TEST_SUITE="Modernize"
DEFAULT=$DEFAULT_DEB822
reset() { true; }  # we don't use reset() here

tname "Modernize sources, with extra suites "
reset_one_line
sed 's/kali-rolling/kali-bleeding-edge/' /etc/apt/sources.list \
    >/etc/apt/sources.list.d/kali-bleeding-edge.list
sed 's/kali-rolling/kali-experimental/'  /etc/apt/sources.list \
    >/etc/apt/sources.list.d/kali-experimental.list
apt update >/dev/null 2>&1
apt modernize-sources -y >/dev/null 2>&1
check --ignore-comments sources.list.d/kali.sources "$DEFAULT"
check --ignore-comments sources.list.d/kali-bleeding-edge.sources \
    "$(sed 's/kali-rolling/kali-bleeding-edge/' <<< $DEFAULT)"
check --ignore-comments sources.list.d/kali-experimental.sources \
    "$(sed 's/kali-rolling/kali-experimental/' <<< $DEFAULT)"

tname "Apply a change, and check that only kali.sources remains"
apply '{"protocol": "https"}'
check sources.list.d/kali.sources "\
Types: deb
URIs: https://http.kali.org/kali/
Suites: kali-rolling kali-bleeding-edge kali-experimental
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/kali-archive-keyring.gpg"
check sources.list.d/kali-bleeding-edge.sources null
check sources.list.d/kali-experimental.sources  null

trap - EXIT
