#!/bin/sh
# $Id$

. ./sh/lib/setup
. ./sh/lib/repo-setup
. ./sh/lib/solver-setup

ORIGREPO=
DESTINATION_REPO=
DEPENDENCY_SOLVER=3

#tearDown() {
#    [ -n "$REPO" ] && rm -f $REPO/*.*
#}

setUp() {
    [ -z "$ORIGREPO" ] && ORIGREPO=$REPO
    [ -z "$ORIGREPO" ] && fail "empty REPO env variable"
    $SUDO rm -rf $ORIGREPO/*

    REPO="$ORIGREPO/src"
    REPO2="$ORIGREPO/src2"
    DESTINATION_REPO="$ORIGREPO/dest";

    $SUDO rm -rf $REPO $REPO2 $DESTINATION_REPO

    mkdir -p $REPO || fail "mkdir $REPO failed"
    mkdir -p $REPO2 || fail "mkdir $REPO2 failed"
    mkdir -p $DESTINATION_REPO || fail "mkdir $DESTINATION_REPO failed"

    RAW_POLDEK="$POLDEK_NOCONF"
    POLDEK_INSTALL="$RAW_POLDEK --st dir -s $REPO --st dir -s $REPO2 --install-dist=$DESTINATION_REPO"
}

build() {
   build_package $REPO $@
}

build2() {
   build_package $REPO2 $@
}

# try to install package and check result
# usage: try_install <mode> <poldek switches> <package> <expected installed> [<extra_poldek_switches>]
try_install_dist() {
    typeset eec="$1"; shift;
    typeset mode="$1"; shift
    typeset poldek_opts="$1"; shift
    typeset package="$1"; shift
    typeset expected="$1"; shift

    [ "$expected" == "none" ] && expected=""
    typeset regexp=$(echo $expected | sed 's/,/|/g')
    typeset n_expected=$(echo $expected | sed 's|,|\n|g' | wc -l)

    typeset cmd="$poldek_opts $package"
    if [ $# -gt 0 ]; then
        cmd="$1 $cmd"
        shift
    fi

    if is_verbose_mode; then
        GDB=${GDB:-""}
        if [ -n "$GDB" ]; then
            gdb --ex run --args $POLDEK_INSTALL $cmd --test
        else
            $POLDEK_INSTALL $cmd --test
        fi
    fi

    if [ "$mode" != "rpm" ]; then
        do_runpoldek $eec $cmd --test
    fi
    if [ -n "$expected" ]; then
        # run again to check installation results
        msg "# executing $POLDEK_INSTALL $cmd --parsable-tr-summary"
        typeset out=$($POLDEK_INSTALL $cmd --parsable-tr-summary | grep -E "^%[IDR]")
        typeset n_all=$(echo $out | sed 's|%|\n%|g' | grep -E '^%[ID]' | wc -l)
        typeset n=$(echo $out | sed 's|%|\n%|g' | grep -E "^%[ID] ($regexp)" | wc -l)
        assertEquals "unexpected ($n_all) number of packages (expected $n)" "$n_all" "$n"
        assertEquals "not all or non expected packages installed (expected $expected)" "$n" "$n_expected"
    fi
}


# try to install package and check result
# usage: try_install <package> <expected installed> [<expected removed>] [<extra poldek switches>]
try_install() {
    local pkg=$1
    local eec="success"
    if [ "$pkg" = "--failok" ]; then
        eec="fail"
        shift;
        pkg=$1
    fi

    try_install_dist $eec "dir" "-v" "$@"
}

testInstallDist() {
    skip_if_rpm_testing_off && return

    build a -r "foo" -r "bar"
    build b -p "foo" -p "bar" -r "baz"
    build c -p "baz"
    build sh -p /bin/sh -f /bin/sh

    msgn "Install"
    try_install a "a,b,c,sh"
}

# install-dist for real (rpm database only): rpm must find every dependency met
assert_dist_db() {
    $POLDEK_INSTALL --justdb "$@" >/dev/null 2>&1
    assertEquals "install-dist $* failed" "$?" "0"
    typeset out=$(rpm --root $DESTINATION_REPO -Va --nofiles --nodigest --nosignature 2>&1)
    assertEquals "rpm reports: $out" "" "$out"
}

# install-dist refused: nothing may be installed
assert_dist_none() {
    $POLDEK_INSTALL --justdb "$@" >/dev/null 2>&1
    typeset out=$(rpm --root $DESTINATION_REPO -qa 2>/dev/null)
    assertEquals "installed: $out" "" "$out"
}

# boolean requirements come down to the packages they need
testInstallDistBoolean() {
    skip_if_rpm_testing_off && return

    build a -r "'(b or c)'" -r "'(y with ycap)'" -r "'(x with xcap)'" -p "'zzp = 1-1'"
    build b
    build c
    build y -p ycap
    build z -p y
    # provides y's name and version, but not ycap
    build q -p "'y = 1-1'"
    # a provides zzp's name and version, zzp provides x and xcap
    build zzp -p x -p xcap
    build sh -p /bin/sh

    try_install a "a,b,y,zzp,sh"
    assert_dist_db a
}

# rpm meets an rpmlib() it supports itself, with no package; one it lacks
# leaves the other alternative
testInstallDistBooleanRpmlib() {
    skip_if_rpm_testing_off && return

    build a -r "'(rpmlib(CompressedFileNames) <= 3.0.4-1 or b)'"
    build b
    build c -r "'(rpmlib(NoSuchFeatureZz) <= 1 or d)'"
    build d
    build sh -p /bin/sh

    try_install "a c" "a,c,d,sh"
    assert_dist_db a c
}

# paths in boolean requirements, read from a pndir index
testInstallDistBooleanPath() {
    skip_if_rpm_testing_off && return

    build a -r "'(x without /opt/zzbool/tool)'" -r "'(z with /opt/zzbool/tool2)'"
    build px -p x -f /opt/zzbool/tool
    build qx -p x
    build pz -p z -f /opt/zzbool/tool2
    # provides the path, not z
    build e -p /opt/zzbool/tool2
    build sh -p /bin/sh
    $RAW_POLDEK --st dir -s $REPO --index >/dev/null 2>&1

    POLDEK_INSTALL="$RAW_POLDEK --st pndir -s $REPO --install-dist=$DESTINATION_REPO"
    try_install a "a,qx,pz,sh"
    assert_dist_db a
}

# an index made without a's requirement keeps no /opt/zzbool files, so
# who owns /opt/zzbool/tool can't be told and the requirement is reported
testInstallDistBooleanPathUnlisted() {
    skip_if_rpm_testing_off && return

    build px -p x -f /opt/zzbool/tool
    build sh -p /bin/sh
    $RAW_POLDEK --st dir -s $REPO --index >/dev/null 2>&1
    build2 a -r "'(x without /opt/zzbool/tool)'"

    POLDEK_INSTALL="$RAW_POLDEK --st pndir -s $REPO --st dir -s $REPO2 --install-dist=$DESTINATION_REPO"
    try_install --failok a ""
    assert_dist_none a
}

# whether b or d is needed depends on c, which install-dist may not install,
# so the requirement is reported instead of resolved
testInstallDistBooleanConditional() {
    skip_if_rpm_testing_off && return

    build a -r "'(b if c else d)'"
    build b
    build c
    build d
    build sh -p /bin/sh

    try_install --failok a ""
    $POLDEK_INSTALL a | grep -q "error: a-1-1.noarch: req (b if c else d) not found"
    assertEquals "poldek should report the conditional requirement" "$?" "0"
    assert_dist_none a
}

# install-dist cannot resolve this (by picking c) as regular install do
# and it simply report unmet dep here
testInstallDistMissingDepAlt() {
    skip_if_rpm_testing_off && return

    build a -r "foo" -r "bar"
    build b -p "foo" -p "bar" -r "baz"
    build c -p "foo" -p "bar"
    build sh -p /bin/sh

    try_install --failok a ""
    if is_verbose_mode; then
        msg "THE ERROR ABOVE (1 unresolved dependency) is EXPECTED"
    fi
    $POLDEK_INSTALL a | grep -q "error: b-1-1.noarch: req baz not found"
    assertEquals "poldek should report 1 dependency error" "$?" "0"
    # TODO try_install a "a,c,sh"
}

testInstallDistDepError() {
    skip_if_rpm_testing_off && return

    build a -r "b"
    build b -r "c"
    build c -r "unmetreq" -r "d"
    build d
    build sh -p /bin/sh

    try_install --failok a ""
    if is_verbose_mode; then
        msg "THE ERROR ABOVE (1 unresolved dependency) is EXPECTED"
    fi
    $POLDEK_INSTALL a | grep -q "error: c-1-1.noarch: req unmetreq not found"
    assertEquals "poldek should report 1 dependency error" "$?" "0"
}

testInstallDistDepErrorNoDeps() {
    skip_if_rpm_testing_off && return

    build a -r "b"
    build b -r "c"
    build c -r "unmetreq" -r "d"
    build d
    build sh -p /bin/sh

    msgn "Install"
    try_install a "a,b,c,d,sh" --nodeps
    #try_install_dist "success" "dir" "-vt --nodeps" a "a,b,c,d,sh"
}

# install-dist cannot resolve this conflict (by picking c) as regular install do
# and it simply report conflict here
testInstallDistConflictError() {
    skip_if_rpm_testing_off && return

    build a -r "foo" -r "bar"
    build b -p "foo" -p "bar" -c "a"
    build c -p "foo" -p "bar"
    build sh -p /bin/sh

    try_install --failok a ""
    if is_verbose_mode; then
        msg "THE ERROR ABOVE (1 unresolved dependency) is EXPECTED"
    fi
    $POLDEK_INSTALL a | grep -qP "error: b-1-1.*conflicts with a-1-1"
    assertEquals "poldek should report 1 conflict" "$?" "0"
}

testInstallDistConflictErrorForce() {
    skip_if_rpm_testing_off && return

    build a -r "foo" -r "bar"
    build b -p "foo" -p "bar" -c "a"
    build c -p "foo" -p "bar"
    build sh -p /bin/sh

    msgn "Install"
    try_install a "a,b,sh" --force
}


. ./sh/lib/shunit2
