#!/bin/bash
# Usage:
# [DMG2IMG=path/to/dmg2img] [QEMU_IMG=path/to/qemu-img] $0 [file.dmg ...]
# If no files are given, dmg-images/*.dmg is assumed (relative to working dir)
#
# On success, 0 is returned. On failure, the number of failed dmg files are
# returned.
set -u

_lastmsg=
msg() {
    local color code msg
    code=$1
    msg=$2
    case $code in
    info)   color="\e[35;1m" ;;
    warn)   color="\e[33;1m" ;;
    error)  color="\e[31;1m" ;;
    ok)     color="\e[32;1m" ;;
    esac
    printf "$color%s\e[m\n" "$msg"
    _lastmsg="$msg"
}
check_result() {
    local rc=$?
    if [ $rc -eq 0 ]; then
        msg ok "$_lastmsg - OK"
    else
        msg error "$_lastmsg - Failed with $rc"
    fi
    return $rc
}

test_file() {
    local dmg raw img
    dmg=$1
    raw=$2
    img=$3

    msg info "qemu-img info $dmg"
    "$QEMU_IMG" info "$dmg"
    check_result || return 1

    msg info "qemu-img convert $dmg"
    "$QEMU_IMG" convert -p -f dmg -O raw "$dmg" "$raw"
    check_result || return 2

    msg info "dmg2img $dmg"
    "$DMG2IMG" -i "$dmg" -o "$img"
    check_result || return 3

    ls -l "$dmg" "$raw" "$img"
    cmp "$raw" "$img" || return 4

    return 0
}

# Locate test programs
QEMU_IMG=${QEMU_IMG:-qemu-img}
DMG2IMG=${DMG2IMG:-dmg2img}
if ! "$QEMU_IMG" --version &>/dev/null; then
    msg error "qemu-img not found"
    exit 1
fi
if ! "$DMG2IMG" &>/dev/null; then
    msg error "dmg2img not found"
    exit 1
fi

# Default images are relative to the current working directory
if [ $# -eq 0 ]; then
    set -- dmg-images/*.dmg
fi

images=()
for file; do
    case $file in
    *.dmg)
        if [ -s "$file" ]; then
            images+=("$file")
        else
            msg warn "$file: not a non-empty file"
        fi
        ;;
    *)
        msg warn "$file: not a dmg file? skipped"
        ;;
    esac
done

if [ $# -ne ${#images[@]} ]; then
    msg warn "Check above warnings!"
    sleep 3
fi

### MAIN

tmpdir=$(mktemp -d)
tmpfile() {
    echo "$tmpdir/${1##*/}"
}
cleanup() { rm -rf "$tmpdir"; }
trap cleanup EXIT

image_no=0
failures=()
for dmg_file in "${images[@]}"; do
    ((image_no++))
    echo
    msg info "Testing image $image_no/${#images[@]}: $dmg_file"
    raw_file=$(tmpfile "${dmg_file#.dmg}.raw")
    img_file=$(tmpfile "${dmg_file#.dmg}.img")
    test_file "$dmg_file" "$raw_file" "$img_file" || failures+=("$dmg_file")
    rm -f "$raw_file" "$img_file"
    echo
done

if [ ${#failures[@]} -gt 0 ]; then
    msg error "Failures: ${#failures[@]}/${#images[@]}"
    for dmg_file in "${failures[@]}"; do
        msg warn "Failed: $dmg_file"
    done
else
    msg ok "All ${#images[@]} images passed!"
fi
exit ${#failures[@]}
