#!/bin/sh

set -e

# path to the flash-kernel script to test
flash_kernel="./flash-kernel"

self="$(basename "$0")"

# space separated list of tests
all_tests=""
add_test() {
    all_tests="${all_tests:+$all_tests }$*"
}

run_tests() {
    local passed_count=0
    local skipped_count=0
    local failed_count=0
    # space separated lists of skipped and failed tests
    local skipped_tests=""
    local failed_tests=""

    for t; do
        count=$(($count + 1))
        # look for skip_test_foo which tells us whether dependencies for this
        # test are satisfied
        if type skip_$t 2>&1 >/dev/null && skip_$t; then
            skipped="$skipped_tests $t"
            skipped_count="$(($skipped_count + 1))"
            continue
        fi
        if ($t); then
            passed_count=$(($passed_count + 1))
        else
            failed_tests="$failed_tests $t"
            failed_count=$(($failed_count + 1))
        fi
    done
    echo "passed: $passed_count; skipped: $skipped_count; failed: $failed_count" >&2
    if [ -n "$skipped_tests" ]; then
        for t in $skipped_tests; do
            echo "skipped: $t" >&2
        done
    fi
    if [ -n "$failed_tests" ]; then
        for t in $failed_tests; do
            echo "failed: $t" >&2
        done
        return 1
    fi
    return 0
}

# space separated list of tempfiles; XXX doesn't support spaces in pathnames
tempfiles=""
last_tempfile=""
cleanup_tempfiles(){
    for t in $tempfiles "$last_tempfile"; do
        if [ -n "$t" ]; then
            rm -f "$t"
        fi
    done
}
trap cleanup_tempfiles EXIT HUP INT QUIT ILL KILL SEGV PIPE TERM

get_tempfile() {
    last_tempfile="$(mktemp -t "$self.XXXXXXXX")"
    tempfiles="$tempfiles $last_tempfile"
}


test_syntax() {
    sh -n "$flash_kernel"
}
add_test test_syntax

skip_test_bashisms() {
    if which checkbashisms 2>&1 >/dev/null; then
        return 1
    fi
    return 0
}

test_bashisms() {
    checkbashisms "$flash_kernel"
}
add_test test_bashisms

test_mtdblock() {
    get_tempfile
    mock_proc_mtd="$last_tempfile"
    cat >"$mock_proc_mtd" <<EOF
dev:    size   erasesize  name
mtd0: 00580000 00020000 "root"
mtd1: 00100000 00020000 "kernel"
mtd2: 00160000 00020000 "initrd"
mtd3: 00020000 00020000 "reset"
mtd4: 00800000 00020000 "jffs2"
EOF
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        PROC_MTD="$mock_proc_mtd"
        root_mtd=$(mtdblock "root")
        if [ "$root_mtd" != "/dev/mtdblock0" ]; then
            echo "Expected root mtd to be /dev/mtdblock0 but got $root_mtd" >&2
            exit 1
        fi
        jffs2_mtd=$(mtdblock "jffs2")
        if [ "$jffs2_mtd" != "/dev/mtdblock4" ]; then
            echo "Expected jffs2 mtd to be /dev/mtdblock4 but got $jffs2_mtd" >&2
            exit 1
        fi
    )
}
add_test test_mtdblock

test_mtdsize() {
    get_tempfile
    mock_proc_mtd="$last_tempfile"
    cat >"$mock_proc_mtd" <<EOF
dev:    size   erasesize  name
mtd0: 00580000 00020000 "root"
mtd1: 00100000 00020000 "kernel"
mtd2: 00160000 00020000 "initrd"
mtd3: 00020000 00020000 "reset"
mtd4: 00800000 00020000 "jffs2"
EOF
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        PROC_MTD="$mock_proc_mtd"
        root_size=$(mtdsize "root")
        if [ "$root_size" != 5767168 ]; then
            echo "Expected root size of 5767168 but got $root_size" >&2
            exit 1
        fi
        jffs2_size=$(mtdsize "jffs2")
        if [ "$jffs2_size" != 8388608 ]; then
            echo "Expected jffs2 size of 8388608 but got $jffs2_size" >&2
            exit 1
        fi
    )
}
add_test test_mtdsize

test_check_kflavors() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        if check_kflavors "ksuffix" "kflavor1" "kflavor2"; then
            echo "Expected check_kflavors to fail with kernel suffix not in expected flavors, but it succeeded" >&2
            exit 1
        fi
        if ! check_kflavors "foo" "kflavor1" "foo" "kflavor3"; then
            echo "Expected check_kflavors to succeed with kernel suffix in expected flavors, but it failed" >&2
            exit 1
        fi
        if ! check_kflavors "" "kflavor1" "kflavor2" "kflavor3"; then
            echo "Expected check_kflavors to succeed with empty kernel suffix, but it failed" >&2
            exit 1
        fi
    )
}
add_test test_check_kflavors

test_check_size() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        error() {
            return 1
        }
        if check_size "MTD" 2 1; then
            echo "Expected check_size to fail for too small size, but it succeeded" >&2
            exit 1
        fi
        if ! check_size "MTD" 1 1; then
            echo "Expected check_supported to succeed with large enough size, but it failed" >&2
            exit 1
        fi
    )
}
add_test test_check_size

test_check_supported() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        if check_supported "Dummy"; then
            echo "Expected check_supported to fail for non-existent board, but it succeeded" >&2
            exit 1
        fi
        machine="Marvell SheevaPlug Reference Board"
        if ! check_supported "$machine"; then
            echo "Expected check_supported to succeed with machine $machine, but it failed" >&2
            exit 1
        fi
    )
}
add_test test_check_supported

test_get_cpuinfo_hardware() {
    get_tempfile
    mock_proc_cpuinfo="$last_tempfile"
    cat >"$mock_proc_cpuinfo" <<EOF
Processor       : Feroceon 88FR131 rev 1 (v5l)
BogoMIPS        : 1192.75
Features        : swp half thumb fastmult edsp
CPU implementer : 0x56
CPU architecture: 5TE
CPU variant     : 0x2
CPU part        : 0x131
CPU revision    : 1

Hardware        : Marvell SheevaPlug Reference Board
Revision        : 0000
Serial          : 0000000000000000
EOF
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        PROC_CPUINFO="$mock_proc_cpuinfo"
        machine=$(get_cpuinfo_hardware)
        if [ "$machine" != "Marvell SheevaPlug Reference Board" ]; then
            echo "Expected machine to be Marvell SheevaPlug Reference Board but got $machine" >&2
            exit 1
        fi
    )
}
add_test test_get_cpuinfo_hardware

test_get_kfile_suffix() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        kfile_suffix=$(get_kfile_suffix "/boot/vmlinuz-2.6.32-5-kirkwood")
        if [ "$kfile_suffix" != "kirkwood" ]; then
            echo "Expected kernel file suffix to be kirkwood but got $kfile_suffix" >&2
            exit 1
        fi
    )
}
add_test test_get_kfile_suffix

test_get_machine_field() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        machine="Marvell SheevaPlug Reference Board"
        if machine_field="$(get_machine_field "$machine" "Machine")"; then
            if [ "$machine_field" != "$machine" ]; then
                echo "Expected Machine field to be $machine but got $machine_field" >&2
                exit 1
            fi
        else
            echo "Expected get_machine_field to succeed on Machine field but it failed" >&2
            exit 1
        fi
        kflavors="$(get_machine_field "$machine" "Kernel-Flavors")"
        if [ "$kflavors" != "kirkwood" ]; then
            echo "Expected Kernel-Flavors field to be kirkwood but got $kflavors" >&2
            exit 1
        fi
        if dummy_field="$(get_machine_field "$machine" "Dummy")"; then
            echo "Expected get_machine_field to fail on unknown field Dummy but it succeeded" >&2
            exit 1
        fi
    )
}
add_test test_get_machine_field

test_set_machine_id() {
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        arm_code="$(set_machine_id 2097 | od -x)"
        expected="0000000 1c08 e3a0 1031 e381
0000010"
        if [ "$arm_code" != "$expected" ]; then
            echo "Expected \"$expected\" for machine-id 2097 but got \"$arm_code\"" >&2
            exit 1
        fi
        arm_code="$(set_machine_id "" | od -x)"
        expected="0000000"
        if [ "$arm_code" != "$expected" ]; then
            echo "Expected \"$expected\" for empty machine-id but got \"$arm_code\"" >&2
            exit 1
        fi
    )
}
add_test test_set_machine_id

test_mkimage_kernel() {
    (
        mkimage() {
            saved_args="$@"
        }
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        saved_args=""
        mkimage_kernel "0xdeadbeef" "desc" "input" "output" 2>/dev/null
        expected="-A arm -O linux -T kernel -C none -a 0xdeadbeef -e 0xdeadbeef -n desc -d input output"
        if [ "$expected" != "$saved_args" ]; then
            echo "Expected mkimage_kernel to be called with \"$expected\" but it was called with \"$saved_args\"" >&2
            exit 1
        fi
    )
}
add_test test_mkimage_kernel

test_mkimage_initrd() {
    (
        mkimage() {
            saved_args="$@"
        }
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        saved_args=""
        mkimage_initrd "0xdeadbeef" "desc" "input" "output" 2>/dev/null
        expected="-A arm -O linux -T ramdisk -C gzip -a 0xdeadbeef -e 0xdeadbeef -n desc -d input output"
        if [ "$expected" != "$saved_args" ]; then
            echo "Expected mkimage_initrd to be called with \"$expected\" but it was called with \"$saved_args\"" >&2
            exit 1
        fi
    )
}
add_test test_mkimage_initrd

test_mkimage_multi() {
    (
        mkimage() {
            saved_args="$@"
        }
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        saved_args=""
        mkimage_multi "0xdeadbeef" "desc" "kinput" "iinput" "output" 2>/dev/null
        expected="-A arm -O linux -T multi -C none -a 0xdeadbeef -e 0xdeadbeef -n desc -d kinput:iinput output"
        if [ "$expected" != "$saved_args" ]; then
            echo "Expected mkimage_multi to be called with \"$expected\" but it was called with \"$saved_args\"" >&2
            exit 1
        fi
    )
}
add_test test_mkimage_multi

test_gen_kernel() {
    get_tempfile
    kernel_input="$last_tempfile"
    echo "foo" >"$kernel_input"
    get_tempfile
    kernel_output="$last_tempfile"
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        gen_kernel "$kernel_input" "$kernel_output" 2097
        result="$(od -t x1 "$kernel_output")"
        expected="0000000 08 1c a0 e3 31 10 81 e3 66 6f 6f 0a
0000014"
        if [ "$result" != "$expected" ]; then
            echo "With machine id 2097, expected \"$expected\" but got \"$result\"" >&2
            exit 1
        fi
        gen_kernel "$kernel_input" "$kernel_output" ""
        result="$(od -t x1 "$kernel_output")"
        expected="0000000 66 6f 6f 0a
0000004"
        if [ "$result" != "$expected" ]; then
            echo "With no machine id, expected \"$expected\" but got \"$result\"" >&2
            exit 1
        fi
    )
}
add_test test_gen_kernel

test_flash_initrd() {
    get_tempfile
    initrd_input="$last_tempfile"
    echo "foo" >"$initrd_input"
    get_tempfile
    initrd_output="$last_tempfile"
    (
        TEST_FLASH_KERNEL=1
        . "$flash_kernel"
        flash_initrd "$initrd_input" "$initrd_output" 3 2>/dev/null
        result="$(od -t x1 "$initrd_output")"
        expected="0000000 66 6f 6f 0a 00 00 00
0000007"
        if [ "$result" != "$expected" ]; then
            echo "With 3 bytes of padding, expected \"$expected\" but got \"$result\"" >&2
            exit 1
        fi
        flash_initrd "$initrd_input" "$initrd_output" 0 2>/dev/null
        result="$(od -t x1 "$initrd_output")"
        expected="0000000 66 6f 6f 0a
0000004"
        if [ "$result" != "$expected" ]; then
            echo "With no padding, expected \"$expected\" but got \"$result\"" >&2
            exit 1
        fi
    )
}
add_test test_flash_initrd

if [ $# = 0 ]; then
    run_tests $all_tests
else
    run_tests "$@"
fi

