#!/bin/sh
# Regression test for winetricks

set -x

# verbs known to not work in -q mode yet
BLACKLIST="cygwin|kde|psdk2003|psdkwin7|dotnet20sp2"
# verbs that hang in -q because of simple problem we should work around soon
BLACKLIST="$BLACKLIST|vc2005trial"
# verbs that are too slow
BLACKLIST="$BLACKLIST|bfbc2"
# verbs that are too flaky
BLACKLIST="$BLACKLIST|amnesia_tdd_demo|wowtrial|mfsxde"
# steam verbs I don't have
BLACKLIST="$BLACKLIST|borderlands|supermeatboy|trine"
# broken http://bugs.winehq.org/show_bug.cgi?id=26411:
BLACKLIST="$BLACKLIST|mfsxde|mfsx_demo"
# only support older versions of wine
BLACKLIST="$BLACKLIST|gecko110"
# hang lately, probably ui changes in install process
BLACKLIST="$BLACKLIST|bioshock2|audibledm"

# Verbs known to update frequently
QUICKCHECK="flash spotify utorrent utorrent3 hegemonygold_demo"

# Check for programs this script (or winetricks) uses.  
# Better to find out they're missing now than in the
# middle of a two day run.
for tool in time cabextract unzip 7z
do
    if test "`which $tool`" = ""
    then
        echo "Please install $tool."
        exit 1
    fi
done

errors=0
fail()
{
    echo FAIL: $@
    errors=`expr $errors + 1`
}

case "$LANG" in
""|"C") echo "Some games won't install in the Posix locale; doing 'export LANG=en_US.UTF-8'" ; export LANG=en_US.UTF-8;;
esac

case "$OS" in
 "Windows_NT")
    # Mostly unimplemented...
    # Cheezy fix for getting rid of double slashes when running cygwin in wine
    case "$HOME" in
      /) HOME="" ;;
    esac
    WINE=""
    WINESERVER=true
    DRIVE_C="C:/"
    ;;
 *)
    export WINE=${WINE:-wine}
    export WINESERVER=${WINESERVER:-wineserver}
    ;;
esac

srcdir=`dirname $0`
srcdir=`cd $srcdir; pwd`

test_speed()
{
    if ! /usr/bin/time -p --output=time.log sh winetricks $1 > foo.log
    then
        fail "winetricks $1 returned status $?"
    fi
    if test `wc -l < foo.log` -lt 5
    then
        fail "winetricks $1 returned too few lines"
    fi
    seconds=`awk '/real/ {print $2}' < time.log | sed 's/\..*//'`
    echo test_speed: winetricks $1 took $seconds seconds
    # Longest runtime as of 11 Dec 2010 is 5 seconds on an e8400 with cygwin
    if test $seconds -gt 7
    then
        fail "test_speed: winetricks $1 took $seconds seconds"
    fi
}

test_app_checksums()
{
    # Verify the installation
    if [ -f "$srcdir/winetricksverify.d/$app.sha1sum" ]
    then
        windir="`$WINE cmd /c echo "%windir%" | cut -c 4- | tr -d '\015'`"
        progdir="`$WINE cmd /c echo "%ProgramFiles%" | cut -c 4- | tr -d '\015'`"

        cd "$DRIVE_C"
        # Fix up the filenames, which can differ between Windows versions/Wine:
        # FIXME: we need a way to guarantee that all _original_ .sha1sums are the same.
        # Preferably generated under 32-bit wine, so that we don't need a really complex sed
        # substitution here...
        sed -e "s|/Program\ Files/|/$progdir/|" -e "s|/windows/|/$windir/|" < "$srcdir/winetricksverify.d/$app.sha1sum" > $app.sha1sum.tmp
        if ! sha1sum -c $app.sha1sum.tmp 
        then
            fail "test_app_checksum $app !" 
        fi
        rm $app.sha1sum.tmp
        cd $srcdir
    fi
}

# Return the number of blocks available in the system
total_df()
{
    df | grep -v /dev/loop | awk '/^\// { sum += $4 } END { print sum }'
}

test_app()
{
    app=$1

    export WINE_PREFIXES=$HOME/winetrickstest-prefixes
    export WINEPREFIX=$WINE_PREFIXES/$app
    DRIVE_C="$WINEPREFIX/dosdevices/c:"

    # change if you don't want to skip ones already installed
    if test -d $HOME/winetrickstest-prefixes/$app
    then
        echo "Skipping $app, already installed"
        return 0
        #rm -rf $WINEPREFIX
    fi
    mkdir -p $WINEPREFIX

    # Watch transient disk space
    DF_START=`total_df`
    if test -d ~/.cache/winetricks/$app
    then
        DU_CACHE_START=`du -s ~/.cache/winetricks/$app | awk '{print $1}'`
    else
        DU_CACHE_START=0
    fi
    touch df-daemon
    (set +x; while test -f df-daemon; do total_df; sleep 1; done ) > df-during.log &

    # Isolate us from the user's home directory
    sh -x winetricks sandbox

    echo "Installing $app"
    if ! /usr/bin/time -p --output=time.log sh winetricks --no-isolate -q $app
    then
        rm df-daemon
        fail "test_app $app failed!"
        return
    fi
    rm df-daemon
    seconds=`awk '/real/ {print $2}' < time.log | sed 's/\..*//'`
    echo "test_app: ${app}: install_time $seconds seconds."

    sh winetricks -q list-installed > list-installed.out
    if ! grep -w $app list-installed.out
    then
        fail "test app $app not installed after install?"
    fi

    # Total max disk usage = max df change plus any initial blocks in cache
    DF_MIN=`cat df-during.log | awk '{ if (min == "" || $1 < min) min=$1; } END {print min}' `
    DF_DIFF=`expr $DF_START - $DF_MIN`
    TOTAL=`expr $DF_DIFF + $DU_CACHE_START`
    echo "test_app: ${app}: max_disk $TOTAL blocks."

    TOTAL_MB=`expr $TOTAL / 1024`
    mkdir -p measurements
    echo "${app}:size_MB=${TOTAL_MB},time_sec=${seconds}" >> measurements/$app.dat

    # Work around dangling processes (whether normal or the fault of wine or the verb script)
    case $app in
    dotnet*)
        killall wineconsole ;;   # bug in wine?  the wineconsoles are for the langpacks, and seem empty.
    wmi)
        killall WinMgmt.exe ;;   # wmi starts a service
    fontxplorer)
        killall winefile.exe ;;  # a number of apps open a folder on the desktop
    hegemony*)
        killall Launcher.exe ;;  # or should this be in the verb?
    esac
    killall notepad.exe          # Arcania-Gothic4 and others

    ps augxw | grep exe
    $WINESERVER -w
    echo "Wineserver done."

    test_app_checksums
}

test_dlls()
{
    sh winetricks dlls list | awk '{print $1}' > dlls.log
    if grep .------------------- dlls.log
    then
        fail "output of dlls list contained garbage"
        exit 1
    fi
    sort -u < dlls.log | egrep -v "$BLACKLIST" > dlls.verbs
    for a in `cat dlls.verbs`
    do
        test_app $a
    done
}

test_manual_dlls()
{
    sh winetricks list-manual-download > manual.log
    sh winetricks dlls list | awk '{print $1}' > dlls.log
    if grep .------------------- dlls.log
    then
        fail "output of dlls list contained garbage"
        exit 1
    fi
    cat dlls.log manual.log | sort | uniq -c | awk '$1 == 2 {print $2}' | egrep -v "$BLACKLIST" > dlls.verbs
    for a in `cat dlls.verbs`
    do
        test_app $a
    done
}

test_install_cached_or_download()
{
    sh winetricks list-cached list-download > ticd.log
    if grep .------------------- ticd.log
    then
        fail "output of list-cached list-download contained garbage"
        exit 1
    fi
    sort -u < ticd.log | egrep -v "$BLACKLIST" > ticd.verbs

    if true
    then
        # Split into two, only do half
        nverbs=`cat ticd.verbs | wc -l`
        firsthalf=`expr $nverbs / 2 + 1`
        sed ${firsthalf}',$d' < ticd.verbs > ticd-1.verbs 
        sed '1,'${firsthalf}d   < ticd.verbs > ticd-2.verbs 
        VERBS=`cat ticd-1.verbs`
    else
        VERBS=`cat ticd.verbs`
    fi

    for a in $VERBS
    do
        test_app $a
    done
    sh winetricks list-cached | sort > cached.txt
    # Verbs that are just wrappers around others don't detect cache/install
    # state yet.  
    # Verbs that are just informative placeholders don't ever download (gecko).
    # And some verbs (gecko110) don't usually install for other reasons.
    BLACKLIST_CACHE="allfonts|cjkfonts|allcodecs|gecko|gecko110|fontfix"
    cat ticd.verbs | egrep -vw "$BLACKLIST_CACHE" > download.txt
    comm -23 download.txt cached.txt > download-but-not-cached.txt
    echo "Supposedly downloadable"
    cat download.txt
    echo "Cached"
    cat cached.txt
    echo "Downloadable but not cached"
    cat download-but-not-cached.txt
    if test `wc -l < download-but-not-cached.txt` != 0
    then
        fail "test_install_cached_or_download: asked to install all downloadable apps, but some not listed as cached afterwards"
        cat download-but-not-cached.txt
    fi
}

# Test the frequent download-changes-checksum offenders first
true || (
cache="$HOME/winetricks-quickcheck-cache"
rm -rf "$cache"
export W_CACHE="$cache" 
for a in $QUICKCHECK
do
   rm -rf $HOME/winetrickstest-prefixes/$a
   test_app $a
done
)

test_speed list
test_speed list-download
# three tries to preload cache
# FIXME: check cache to see if we need to do this
for try in `seq 1 3`
do
    test_manual_dlls
    echo press enter
    read x
done
test_dlls
#test_install_cached_or_download
test_speed list-cached
test_speed list-installed

echo "Test over, $errors failures."
test $errors = 0
