#!/bin/sh
# $Id$

# --verify tests

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

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

    REPO="$ORIGREPO/src"
    rm -rf $REPO

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

    RAW_POLDEK="$POLDEK_NOCONF"
    POLDEK="$RAW_POLDEK --st pndir -s $REPO"
}

build() {
   build_package $REPO $@
}

build2() {
   build_package $REPO2 $@
}

make_index() {
    $RAW_POLDEK --st dir -s $REPO --index
}

testVerifySuccess()
{
    build a -r "foo" -r "bar" -f /etc/foo.conf
    build b -p "foo" -p "bar" -r "baz" -f /etc/bar.conf
    build c -p "baz"
    build sh -p /bin/sh
    make_index

    msgn "deps"
    $POLDEK --verify a
    assertEquals "verify  failed" "$?" "0"

    msgn "order"
    $POLDEK --verify=order a
    assertEquals "verify=order failed" "$?" "0"

    msgn "conflicts"
    $POLDEK --verify=conflicts a
    assertEquals "verify=conflicts failed" "$?" "0"

    msgn "file conflicts"
    $POLDEK --verify=file-conflicts a
    assertEquals "verify=file-conflicts failed" "$?" "0"

    msgn "file orphans"
    $POLDEK --verify=file-orphans a
    assertEquals "verify=file-orphans failed" "$?" "0"

    msgn "file missing deps"
    $POLDEK --verify=file-missing-deps a
    assertEquals "verify=missing-deps failed" "$?" "0"
}

testVerifyDepsFail()
{
    build a -r "foo" -r "bar.so"
    build b -p "foo" -p "bar" -r "baz"
    build c -p "baz" -r "foo.so"
    build d -r "baz.so"
    build sh -p /bin/sh
    make_index

    msg "# selected: $POLDEK --verify a"
    $POLDEK --verify a >$TMP/verify-log.log
    assertEquals "poldek succeed, but should fail", "$?" "1"

    n=$(grep "error:" $TMP/verify-log.log | grep -P 'req.+not found' | wc -l)
    assertEquals "should report 2 dependency errors" "$n" "2"


    msg "# all: $POLDEK --verify"
    $POLDEK --verify >$TMP/verify-log.log
    assertEquals "poldek succeed, but should fail", "$?" "1"

    n=$(grep "error:" $TMP/verify-log.log | grep -P 'req.+not found' | wc -l)
    assertEquals "should report 3 dependency errors" "$n" "3"
}

# a boolean requirement is satisfied by the packages it comes down to
testVerifyDepsBooleanSuccess()
{
    build a -r "'(b or c)'"
    build b
    build x -r "'(y with ycap)'"
    build y -p ycap
    # s provides y itself, y provides both
    build s -p y -r "'(y with ycap)'"
    # o owns the file, e only provides its path
    build f -r "'(/usr/bin/foo with bar)'"
    build o -p bar -f /usr/bin/foo
    build e -p /usr/bin/foo
    # t meets its own requirement
    build t -p u -p ucap -r "'(u with ucap)'"
    build sh -p /bin/sh
    make_index

    msg "# $POLDEK --verify"
    $POLDEK --verify >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error: " $TMP/verify-log.log | wc -l)
    assertEquals "should not report errors" "$n" "0"
}

# without takes away every provider of its right side, the requiring package too
testVerifyDepsBooleanFail()
{
    build a -p y -r "'(x without y)'"
    build b -p x -p y
    # the only z comes with the file, kept in the pndir index
    build c -r "'(z without /opt/zzbool/tool)'"
    build d -p z -f /opt/zzbool/tool
    build sh -p /bin/sh
    make_index

    msg "# $POLDEK --verify"
    $POLDEK --verify >$TMP/verify-log.log
    assertEquals "poldek succeed, but should fail" "$?" "1"
    n=$(grep "error: a-1-1" $TMP/verify-log.log | grep -c 'x without y')
    assertEquals "should report a's requirement" "$n" "1"
    n=$(grep "error: c-1-1" $TMP/verify-log.log | grep -c 'z without /opt/zzbool/tool')
    assertEquals "should report c's requirement" "$n" "1"
}

# the provider of a boolean prerequisite goes first
testVerifyOrderBoolean()
{
    build a -rpre "'(b or c)'"
    build b
    build sh -p /bin/sh
    make_index

    msg "# $POLDEK --verify=order"
    out=$($POLDEK --verify=order)
    assertEquals "verify=order failed" "$?" "0"
    na=$(echo "$out" | sed -n 's/^\([0-9]*\)\. a-1-1.*/\1/p')
    nb=$(echo "$out" | sed -n 's/^\([0-9]*\)\. b-1-1.*/\1/p')
    assertTrue "b ($nb) should go before a ($na)" "[ \"$nb\" -lt \"$na\" ]"
}

testVerifyConflictsFail()
{
    build a -r "foo" -r "bar" -p "foo.so"
    build b -p "foo" -p "bar" -r "baz"
    build c -p "baz" -c "foo.so"
    build sh -p /bin/sh
    make_index

    msg "# $POLDEK --verify=conflicts a"
    $POLDEK --verify=conflicts a >$TMP/verify-log.log
    assertEquals "poldek succeed, but should fail", "$?" "1"

    n=$(grep "error:" $TMP/verify-log.log | grep -P 'c-.+conflicts.+foo.so' | wc -l)
    assertEquals "should report 1 conflict" "$n" "1"
}

testVerifyFileOrphansSuccess()
{
    build a -r "foo" -r "bar" -p "foo.so" -f "/usr/bin/a"
    build b -p "foo" -p "bar" -r "baz" -fd '/usr' -f "/bin/b"
    make_index

    #msg "$POLDEK desc -ll a"
    #$POLDEK desc -ll a

    msg "# $POLDEK --verify=file-orphans"
    is_verbose_mode && $POLDEK --verify=file-orphans
    $POLDEK --verify=file-orphans >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error:" $TMP/verify-log.log | wc -l)
    assertEquals "should not report orphans" "$n" "0"
}

testVerifyFileOrphansFail()
{
    build a -r "foo" -r "bar" -p "foo.so" -f "/usr/bin/a"
    make_index

    #msg "$POLDEK desc -ll a"
    #$POLDEK desc -ll a

    msg "# $POLDEK --verify=file-orphans"
    is_verbose_mode && $POLDEK --verify=file-orphans
    $POLDEK --verify=file-orphans >$TMP/verify-log.log
    #assertEquals "poldek succeed, but should fail", "$?" "1"
    n=$(grep "error:" $TMP/verify-log.log | grep -P '/usr: orphaned directory from a-' | wc -l)
    assertEquals "should report 1 orphan" "$n" "1"
}


testVerifyFileMissingDepsSuccess()
{
    build a -r "foo" -f "/usr/bin/a"
    build b -p "foo" -fd '/usr' -f "/bin/b"
    make_index

    #msg "$POLDEK desc -ll a"
    #$POLDEK desc -ll a

    msg "# $POLDEK --verify=file-missing-deps"
    is_verbose_mode && $POLDEK --verify=file-missing-deps
    $POLDEK --verify=file-missing-deps >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error: " $TMP/verify-log.log | wc -l)
    assertEquals "should not report errors" "$n" "0"
}

testVerifyFileMissingDepsIndirectSuccess()
{
    build a -r "foo" -f "/usr/bin/a"
    build b -p "foo" -r "bar"
    build c -p "bar" -fd '/usr'
    make_index

    #msg "$POLDEK desc -ll a"
    #$POLDEK desc -ll a

    msg "# $POLDEK --verify=file-missing-deps"
    is_verbose_mode && $POLDEK --verify=file-missing-deps
    $POLDEK --verify=file-missing-deps >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error: " $TMP/verify-log.log | wc -l)
    assertEquals "should not report errors" "$n" "0"
}


testVerifyFileMissingDepsFail()
{
    build a -r "foo" -r "bar" -p "foo.so" -f "/usr/bin/a"
    build b -p "xfoo" -p "xbar" -fd '/usr' -f "/bin/b"
    make_index

    #msg "$POLDEK desc -ll a"
    #$POLDEK desc -ll a

    msg "# $POLDEK --verify=file-missing-deps"
    is_verbose_mode && $POLDEK --verify=file-missing-deps
    $POLDEK --verify=file-missing-deps >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error: a-1-1.noarch: /usr: directory not in required packages (missing Requires: b?)" $TMP/verify-log.log | wc -l)
    assertEquals "should report one missing dep" "$n" "1"
}

# a requires x itself; that must not hide a from b, which requires x too
testVerifyFileMissingDepsSelfRequirerSuccess()
{
    build a -p "x" -r "x" -fd '/usr' -f "/bin/a"
    build b -r "x" -f "/usr/bin/b"
    make_index

    msg "# $POLDEK --verify=file-missing-deps"
    is_verbose_mode && $POLDEK --verify=file-missing-deps
    $POLDEK --verify=file-missing-deps >$TMP/verify-log.log
    assertEquals "poldek fail, but should succeed" "$?" "0"
    n=$(grep "error: " $TMP/verify-log.log | wc -l)
    assertEquals "should not report errors" "$n" "0"
}

# required packages do not depend on the packages asked about before
testRequiredPackagesSelfRequirer()
{
    build a -p "x" -r "x"
    build b -r "x"
    make_index

    msg "# $POLDEK desc -R a b"
    out=$($POLDEK desc -R a b)
    echo "$out" | grep -A1 '^Package: *a-1-1' | grep -q '^Required(pkgs):'
    assertEquals "a should require no package" "$?" "1"
    echo "$out" | grep -A1 '^Package: *b-1-1' | grep -qE '^Required\(pkgs\): +a$'
    assertEquals "b should require a" "$?" "0"
}

# a file shared by two packages is reported wherever the index put it
testVerifyFileConflictsShared()
{
    build a -f /opt/x -f /opt/y
    build b -f /opt/x
    make_index

    msg "# $POLDEK --verify=file-conflicts"
    $POLDEK --verify=file-conflicts >$TMP/verify-log.log
    n=$(grep -A1 '^Path: /opt/x$' $TMP/verify-log.log | grep ' shr ' | grep -c 'a-1-1.* b-1-1')
    assertEquals "should report /opt/x shared by a and b" "$n" "1"
}

# each pair is reported, also for the last name of a directory
testVerifyFileConflictsSharedByThree()
{
    build a -f /opt/x
    build b -f /opt/x
    build c -f /opt/x
    make_index

    msg "# $POLDEK --verify=file-conflicts"
    $POLDEK --verify=file-conflicts >$TMP/verify-log.log
    n=$(sed -n '/^Path: \/opt\/x$/,/^$/p' $TMP/verify-log.log | grep -c ' shr ')
    assertEquals "should report 3 pairs sharing /opt/x" "$n" "3"
}

# with packages given, only files shared between them are reported
testVerifyFileConflictsGivenPackages()
{
    build a -f /opt/x
    build b -f /opt/x
    make_index

    for p in a b; do
        msg "# $POLDEK --verify=file-conflicts $p"
        $POLDEK --verify=file-conflicts $p >$TMP/verify-log.log
        n=$(grep -c '^Path: /opt/x$' $TMP/verify-log.log)
        assertEquals "$p alone should not report /opt/x" "$n" "0"
    done

    msg "# $POLDEK --verify=file-conflicts a b"
    $POLDEK --verify=file-conflicts a b >$TMP/verify-log.log
    n=$(grep -c '^Path: /opt/x$' $TMP/verify-log.log)
    assertEquals "a and b should report /opt/x" "$n" "1"
}

# every file a pair of packages has in conflict is reported, not only the first one
testVerifyFileConflictsDifferingFiles()
{
    build a -f /opt/x -f /opt/y
    build b -fd /opt/x -fd /opt/y
    make_index

    msg "# $POLDEK -Omultilib=no --verify=file-conflicts"
    $POLDEK -Omultilib=no --verify=file-conflicts >$TMP/verify-log.log
    n=$(grep -A1 -E '^Path: /opt/(x|y)$' $TMP/verify-log.log | grep -c ' cnfl .*a-1-1.*b-1-1')
    assertEquals "should report /opt/x and /opt/y" "$n" "2"
}

# a file in the root directory is printed as /name, not as //name
testVerifyFileConflictsTopLevelPath()
{
    build a -f /top -f /top2
    build b -f /top -f /top2
    make_index

    msg "# $POLDEK --verify=file-conflicts"
    $POLDEK --verify=file-conflicts >$TMP/verify-log.log
    n=$(grep -c '^Path: /top$' $TMP/verify-log.log)
    assertEquals "should report /top" "$n" "1"
    n=$(grep -c '^Path: /top2$' $TMP/verify-log.log)
    assertEquals "should report /top2" "$n" "1"
    n=$(grep -c '^Path: //' $TMP/verify-log.log)
    assertEquals "no path with two slashes" "$n" "0"
}


. ./sh/lib/shunit2
