#!/bin/bash

001_start_ssh-agent() {
    run_kc

    [[ $kc_out == *Starting\ ssh-agent* ]] || fail "failed to start ssh-agent"
    count ssh 1

    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID does not exist"
}

002_start_gpg-agent() {
    which gpg-agent || skip "gpg-agent not available"
    run_kc

    [[ $kc_out == *Starting\ gpg-agent* ]] || fail "failed to start gpg-agent"
    count gpg 1

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"
    IFS=: ; set -- $GPG_AGENT_INFO ; unset IFS
    kill -0 $2 || fail "GPG_AGENT_INFO pid does not exist"
}

003_start_ssh-agent_only() {
    run_kc --agents ssh

    [[ $kc_out == *Starting\ ssh-agent* ]] || fail "failed to start ssh-agent"
    [[ $kc_out == *Starting\ gpg-agent* ]] && fail "keychain started gpg-agent"
    count ssh 1 
    count gpg 0

    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID does not exist"
}

004_start_gpg-agent_only() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    run_kc --agents gpg

    [[ $kc_out == *Starting\ gpg-agent* ]] || fail "failed to start gpg-agent"
    [[ $kc_out == *Starting\ ssh-agent* ]] && fail "keychain started ssh-agent"
    count gpg 1
    count ssh 0

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"
    IFS=: ; set -- $GPG_AGENT_INFO ; unset IFS
    kill -0 $2 || fail "GPG_AGENT_INFO pid does not exist"
}

005_stop() {
    which gpg-agent || skip "gpg-agent not available"
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null

    local num_gpg=$(count gpg)
    local num_ssh=$(count ssh)

    run_kc
    run_kc --stop

    grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
    grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
    grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
    grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
    count gpg 0
    count ssh 0
}

    005.1_stop_ssh-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        run_kc --stop --agents ssh

        grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
        grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
        count gpg $(( num_gpg + 1 ))
        count ssh 0
    }

    005.2_stop_gpg-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        run_kc --stop --agents gpg

        grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
        grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
        count ssh $(( num_ssh + 1 ))
        count gpg 0
    }

006_stop_all() {
    which gpg-agent || skip "gpg-agent not available"
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null

    local num_gpg=$(count gpg)
    local num_ssh=$(count ssh)

    run_kc
    run_kc --stop all

    grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
    grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
    grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
    grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
    count gpg 0
    count ssh 0
}

    006.1_stop_all_ssh-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        run_kc --stop --agents ssh

        grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
        grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
        count gpg $(( num_gpg + 1 ))
        count ssh 0
    }

    005.2_stop_gpg-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        run_kc --stop --agents gpg

        grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
        grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
        count ssh $(( num_ssh + 1 ))
        count gpg 0
    }

007_stop_mine() {
    which gpg-agent || skip "gpg-agent not available"
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    gpg-agent --daemon >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null
    ssh-agent >/dev/null

    local num_gpg=$(count gpg)
    local num_ssh=$(count ssh)

    run_kc
    load
    run_kc --stop mine

    grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
    grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
    grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
    grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
    count gpg $num_gpg
    count ssh $num_ssh
    stopped $SSH_AGENT_PID
    stopped $GPG_AGENT_PID
}

    007.1_stop_mine_ssh-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        load
        run_kc --stop mine --agents ssh

        grep -q 'ssh-agent.*found running' <<<"$kc_out" && fail "no ssh-agent found running"
        grep -q 'ssh-agents stopped' <<<"$kc_out" || fail "couldn't stop ssh-agent"
        count gpg $(( num_gpg + 1 ))
        count ssh $num_ssh
        stopped $GPG_AGENT_PID
    }

    007.2_stop_mine_gpg-agent_only() {
        which gpg-agent || skip "gpg-agent not available"
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        gpg-agent --daemon >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null
        ssh-agent >/dev/null

        local num_gpg=$(count gpg)
        local num_ssh=$(count ssh)

        run_kc
        load
        run_kc --stop mine --agents gpg

        grep -q 'gpg-agent.*found running' <<<"$kc_out" && fail "no gpg-agent found running"
        grep -q 'gpg-agents stopped' <<<"$kc_out" || fail "couldn't stop gpg-agent"
        count ssh $(( num_ssh + 1 ))
        count gpg $num_gpg
        stopped $SSH_AGENT_PID
    }

008_start_ssh-agent_with_one_key() {
    run_kc ${sshkeys[0]}

    [[ $kc_out == *Identities\ added* ]] || fail "failed to start ssh-agent"

    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    ssh-add -l | grep -q ${sshkeys[0]##*/} || fail "ssh-agent isn't aware of ${sshkeys[0]##*/}"
}

009_start_ssh-agent_with_multiple_keys() {
    run_kc "${sshkeys[@]}"

    [ "`count_ident "$kc_out"`" != "${#sshkeys[@]}" ] && fail "keychain didn't report ${#sshkeys[@]} keys"
    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    for x in "${sshkeys[@]}"; do
        ssh-add -l | grep -q ${x##*/} || fail "ssh-agent isn't aware of ${x##*/}"
    done
}

010_start_gpg-agent_with_one_key() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    run_kc ${gpgkeys[0]}

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"
    grep -q ${gpgkeys[0]} <<<"$kc_out" || fail "keychain didn't add the key"

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"
    echo | gpg --no-tty --sign --local-user "${gpgkeys[0]}" -o - >/dev/null \
        || fail "couldn't encrypt with ${gpgkeys[0]}"
}

011_start_gpg-agent_with_multiple_keys() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    run_kc "${gpgkeys[@]}"

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"

    for x in "${gpgkeys[@]}"; do
        grep -q "$x" <<<"$kc_out" || fail "keychain didn't add $x"
        echo | gpg --no-tty --sign --local-user "$x" -o - >/dev/null \
            || fail "couldn't encrypt with $x"
    done
}

012_start_keychain_with_ssh_and_gpg_keys() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    run_kc "${sshkeys[@]}" "${gpgkeys[@]}"

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"


    [ "`count_ident "$kc_out"`" != "${#sshkeys[@]}" ] && fail "keychain didn't report ${#sshkeys[@]} ssh keys"
    [ "`count_gpg "$kc_out"`" != "${#gpgkeys[@]}" ] && fail "keychain didn't report ${#gpgkeys[@]} gpg keys"

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"
    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"

    for x in "${sshkeys[@]}"; do
        ssh-add -l | grep -q "${x##*/}" || fail "ssh-agent doesn't know about ${x##*/}"
    done
    for x in "${gpgkeys[@]}"; do
        echo | gpg --no-tty --sign --local-user "$x" -o - >/dev/null \
            || fail "couldn't encrypt with $x"
    done
}

013_add_a_key_to_ssh-agent() {
    run_kc ${sshkeys[0]}
    run_kc ${sshkeys[1]}

    [[ $kc_out == *Identities\ added* ]] || fail "failed to add key"

    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    ssh-add -l | grep -q ${sshkeys[1]##*/} || fail "ssh-agent isn't aware of ${sshkeys[0]##*/}"
}

014_add_a_key_to_gpg-agent() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    run_kc ${gpgkeys[0]}
    run_kc ${gpgkeys[1]}

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"
    grep -q ${gpgkeys[1]} <<<"$kc_out" || fail "keychain didn't add the key"

    source $keydir/$HOSTNAME-sh-gpg || fail "couldn't source $keydir/$HOSTNAME-sh-gpg"
    echo | gpg --no-tty --sign --local-user "${gpgkeys[1]}" -o - >/dev/null \
        || fail "couldn't encrypt with ${gpgkeys[1]}"
}

015_add_a_missing_key() {
    run_kc no_such_key

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"
    grep -q 'Warning.*no_such_key' <<<"$kc_out" \
        || fail "keychain didn't warn about no_such_key"
}

016_missing_key_with_--ignore-missing() {
    run_kc --ignore-missing no_such_key

    [[ $? == 0 ]] || fail "keychain exited with non-zero status"
    grep -q 'Warning.*no_such_key' <<<"$kc_out" \
        && fail "keychain warned about no_such_key"
}

017_start_keychain_with_password_ssh() {
    # create a password generator
    askpass=$(mktemp -t tmp.XXXXXXXXXX) || fail "mktemp failed"
    trap 'rm -f $askpass' 0 1 2 15
    echo "echo keychain" > $askpass
    chmod +x $askpass
    DISPLAY=needthis SSH_ASKPASS=$askpass run_kc ${sshkeys_passwd[0]} </dev/null

    [[ $kc_out == *Identities\ added* ]] || fail "failed to start ssh-agent"

    source $keydir/$HOSTNAME-sh || fail "couldn't source $keydir/$HOSTNAME-sh"
    ssh-add -l | grep -q ${sshkeys_passwd[0]##*/} \
    || fail "ssh-agent isn't aware of ${sshkeys_passwd[0]##*/}"
}

030_default_inherit_ssh-agent() {
    eval $(ssh-agent) >/dev/null
    run_kc

    [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent"
    count ssh 1
    kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID has changed"
}

    030.1_inherit_local_ssh-agent() {
        eval $(ssh-agent) >/dev/null
        run_kc --inherit local

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (1)"
        count ssh 1
        kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID has changed"

        eval $(ssh-agent) >/dev/null
        run_kc --inherit local

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (2)"
        count ssh 2

        unset SSH_AGENT_PID
        run_kc --inherit local

        [[ $kc_out == *Inheriting?ssh* ]] && fail "inherited forwarded agent"
        count ssh 3
    }

    030.2_inherit_any_ssh-agent() {
        eval $(ssh-agent) >/dev/null
        old_pid=$SSH_AGENT_PID; unset SSH_AGENT_PID
        run_kc --inherit any

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (1)"
        count ssh 1
        [[ -n $SSH_AGENT_PID ]] && fail "SSH_AGENT_PID should not be known"
        kill -0 $old_pid || fail "agent pid has changed"

        eval $(ssh-agent) >/dev/null
        unset SSH_AGENT_PID
        run_kc --inherit any

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (2)"
        count ssh 2
    }

    030.3_inherit_local_once_ssh-agent() {
        eval $(ssh-agent) >/dev/null
        run_kc --inherit local-once

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent"
        count ssh 1
        kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID has changed"

        eval $(ssh-agent) >/dev/null
        run_kc --inherit local-once

        [[ $kc_out == *Inheriting?ssh* ]] && fail "should not have inherited"
        count ssh 2
    }

    030.4_inherit_any_once_ssh-agent() {
        eval $(ssh-agent) >/dev/null
        old_pid=$SSH_AGENT_PID; unset SSH_AGENT_PID
        run_kc --inherit any-once
        load

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (1)"
        count ssh 1
        [[ -n $SSH_AGENT_PID ]] && fail "SSH_AGENT_PID should not be known"
        kill -0 $old_pid || fail "agent pid has changed"

        eval $(ssh-agent) >/dev/null
        run_kc --inherit any-once

        [[ $kc_out == *Inheriting?ssh* ]] || fail "failed to inherit ssh-agent (2)"
        count ssh 2

        eval $(ssh-agent) >/dev/null
        run_kc --inherit any-once

        [[ $kc_out == *Inheriting?ssh* ]] && fail "should not have inherited"
        count ssh 3
    }

031_noinherit_ssh-agent() {
    eval $(ssh-agent) >/dev/null
    run_kc --noinherit

    [[ $kc_out == *Inheriting?ssh* ]] && fail "should not have inherited"
    count ssh 2
}

032_default_inherit_gpg-agent() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    eval $(gpg-agent --daemon)
    run_kc

    [[ $kc_out == *Inheriting?gpg* ]] || fail "failed to inherit gpg-agent"
    count gpg 1

    info=$GPG_AGENT_INFO
    load
    [[ $info == "$GPG_AGENT_INFO" ]] || fail "GPG_AGENT_INFO has changed"
}

    _inherit_gpg-agent() {
        eval $(gpg-agent --daemon) >/dev/null
        info=$GPG_AGENT_INFO
        run_kc "$@"
        load

        [[ $kc_out == *Inheriting?gpg* ]] || fail "failed to inherit gpg-agent (1)"
        count gpg 1
        [[ $info == "$GPG_AGENT_INFO" ]] || fail "GPG_AGENT_INFO has changed"

        eval $(gpg-agent --daemon) >/dev/null
        run_kc "$@"

        [[ $kc_out == *Inheriting?gpg* ]] || fail "failed to inherit gpg-agent (2)"
        count gpg 2

        eval $(gpg-agent --daemon) >/dev/null
        unset GPG_AGENT_INFO
        run_kc "$@"

        [[ $kc_out == *Inheriting?gpg* ]] && fail "should not have inherited"
        count gpg 4
    }

    032.1_inherit_local_gpg-agent() {
        _inherit_gpg-agent --inherit local
    }

    032.2_inherit_any_gpg-agent() {
        _inherit_gpg-agent --inherit any
    }

    _inherit_once_gpg-agent() {
        eval $(gpg-agent --daemon) >/dev/null
        info=$GPG_AGENT_INFO
        run_kc "$@"
        load

        [[ $kc_out == *Inheriting?gpg* ]] || fail "failed to inherit gpg-agent (1)"
        count gpg 1
        [[ $info == "$GPG_AGENT_INFO" ]] || fail "GPG_AGENT_INFO has changed"

        eval $(gpg-agent --daemon) >/dev/null
        run_kc "$@"

        [[ $kc_out == *Inheriting?gpg* ]] && fail "should not have inherited"
        count gpg 2
    }

    032.3_inherit_local_once_gpg-agent() {
        _inherit_once_gpg-agent --inherit local-once
    }

    032.4_inherit_any_once_gpg-agent() {
        _inherit_once_gpg-agent --inherit any-once
    }

040_noinherit_gpg-agent() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    eval $(gpg-agent --daemon) >/dev/null
    run_kc --noinherit

    [[ $kc_out == *Inheriting?gpg* ]] && fail "should not have inherited"
    count gpg 2
}

041_start_with_--host() {
    rm -f $keydir/*not_a_real_host*
    trap "rm -f $keydir/*not_a_real_host*" 0 1 2 15
    run_kc --host not_a_real_host

    [[ $kc_out == *Starting\ ssh-agent* ]] || fail "failed to start ssh-agent"
    count ssh 1

    source $keydir/not_a_real_host-sh \
        || fail "couldn't source $keydir/not_a_real_host-sh"
    kill -0 $SSH_AGENT_PID || fail "SSH_AGENT_PID does not exist"
}

042_start_with_--quiet() {
    run_kc --quiet

    [[ $kc_out != '' ]] && fail "started noisily"
    count ssh 1
}

043_help_with_--nocolor() {
    # fake out the tty check
    tty() { command tty "$@"; true; }
    run_kc --help
    [[ $kc_out == *''* ]] || fail "control output was uncolored"

    run_kc --nocolor --help
    [[ $kc_out == *''* ]] && fail "output was colored"
}

050_start_ssh-agent_with_--eval() {
    $opt_debug && set +x
    SHELL=/bin/bash run_kc --quiet --eval --agents ssh
    $opt_debug && set -x
    count ssh 1; count gpg 0

    eval "$kc_out" || fail "eval failed"
    set | grep -q '^GPG' && fail "settings contain GPG vars"
    esettings=$(env | grep SSH | sort)

    load
    lsettings=$(env | grep SSH | sort)

    [[ $esettings == "$lsettings" ]] || fail "variables don't match"
}

051_start_gpg-agent_with_--eval() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    $opt_debug && set +x
    SHELL=/bin/bash run_kc --quiet --eval --agents gpg
    $opt_debug && set -x
    count ssh 0; count gpg 1

    eval "$kc_out" || fail "eval failed"
    set | grep -q '^SSH' && fail "settings contain SSH vars"
    esettings=$(env | grep GPG | sort)

    load
    lsettings=$(env | grep GPG | sort)

    [[ $esettings == "$lsettings" ]] || fail "variables don't match"
}

052_start_with_--eval() {
    type -P gpg-agent &>/dev/null || skip "gpg-agent not available"
    $opt_debug && set +x
    SHELL=/bin/bash run_kc --quiet --eval
    $opt_debug && set -x
    count ssh 1; count gpg 1

    eval "$kc_out" || fail "eval failed"
    esettings=$(env | egrep 'GPG|SSH' | sort)

    load
    lsettings=$(env | egrep 'GPG|SSH' | sort)
    
    [[ $esettings == "$lsettings" ]] || fail "variables don't match"
}

053_start_with_--eval_ksh() {
    $opt_debug && set +x
    SHELL=/bin/ksh run_kc --quiet --eval --agents ssh
    $opt_debug && set -x
    count ssh 1; count gpg 0

    type -P ksh >&/dev/null || skip "ksh not available"
    ksh -c "$kc_out" || fail "ksh eval failed"
}

054_start_with_--eval_fish() {
    $opt_debug && set +x
    SHELL=/bin/fish run_kc --quiet --eval --agents ssh
    $opt_debug && set -x
    count ssh 1; count gpg 0

    type -P fish >&/dev/null || skip "fish not available"
    fish -c "$kc_out" || fail "fish eval failed"
}

055_start_with_--eval_csh() {
    $opt_debug && set +x
    SHELL=/bin/csh run_kc --quiet --eval --agents ssh
    $opt_debug && set -x
    count ssh 1; count gpg 0

    type -P csh &>/dev/null || skip "csh not available"
    csh -c "$kc_out" || fail "csh eval failed"
}

060_start_with_--timeout() {
    run_kc --timeout 2 "${sshkeys[0]}"
    [[ $kc_out == *'life=2m'* ]] || fail "msg not printed"
    count ssh 1
}

061_start_with_--timeout_no_arg() {
    run_kc "${sshkeys[0]}" --timeout
    [[ $kc_out == *Error* ]] || fail "error message not printed"
    count ssh 0
}

062_start_with_--timeout_bad_arg() {
    run_kc --timeout blah "${sshkeys[0]}"
    [[ $kc_out == *Error* ]] || fail "error message not printed"
    count ssh 0
}

070_start_with_--confirm() {
    run_kc --confirm "${sshkeys[0]}"
    [[ $kc_out == *'confirm'* ]] || fail "msg not printed"
    count ssh 1
}

100_lock_stale() {
    lockf=$keydir/$HOSTNAME-lockf
    trap "rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; echo stale > $lockf; )
    run_kc --lockwait 3
    [[ -f $keydir/$HOSTNAME-lockf && $(<$keydir/$HOSTNAME-lockf) == stale ]] && fail "stale lock remains"
    [[ $kc_out == *'removing stale lock'* ]] || fail "msg not printed"
}

101_lock_held() {
    lockf=$keydir/$HOSTNAME-lockf
    trap "rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; echo $$ > $lockf; )
    run_kc --lockwait 3
    [[ -f $lockf ]] || fail "lock was removed"
    [[ $(<$lockf) == $$ ]] || fail "lock was modified"
    [[ $kc_out == *"failed to get the lock, held by pid $$"* ]] || fail "msg not printed"
}

102_lock_empty() {
    lockf=$keydir/$HOSTNAME-lockf
    trap "rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; :> $lockf; )
    run_kc --lockwait 3
    [[ -f $lockf && ! -s $lockf ]] && fail "empty lock remains"
    [[ $kc_out == *'removing empty lock'* ]] || fail "msg not printed"
}

103_lock_empty_cant_remove() {
    lockf=$keydir/$HOSTNAME-lockf
    trap "unset -f rm; rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; :> $lockf; )
    # fake out the rm attempt
    rm() { [[ $* == *lockf ]] || command rm "$@"; }
    run_kc --lockwait 3
    [[ -f $lockf ]] || fail "lock removed"
    [[ $kc_out == *'failed to remove empty lock'* ]] || fail "msg not printed"
}

104_lock_lockwait_zero() {
    lockf=$keydir/$HOSTNAME-lockf
    trap "rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; echo $$ > $lockf; )
    run_kc --lockwait 0
    [[ -f $lockf ]] || fail "lock removed"
    [[ $kc_out == *Waiting* ]] && fail "msg == Waiting"
    [[ $kc_out == *'failed to get the lock'* ]] || fail "msg not printed"
}

# kinda weak, doesn't check output
105_lock_lockwait_forever() {
    lockf=$keydir/$HOSTNAME-lockf
    unset bgpid
    trap "kill \$bgpid; rm -f $lockf" 0 1 2 15
    rm -f $lockf
    ( umask 0377; echo $$ > $lockf; )
    run_kc --lockwait -1 &
    bgpid=$!
    sleep 3
    count ssh 0
    kill -0 $bgpid || fail "run_kc returned early"
    [[ -f $lockf ]] || fail "lock removed"
}

#
# helper functions
# 

count_ident() {
	cat << EOF | sed -n -e '/Identities.added/{s/^.*added://;p;}' | wc -w
$1
EOF
}

count_gpg() {
	cat << EOF | sed -n -e '/Adding.*gpg key(s)/{s/^.*key(s)://;p;}' | wc -w
$1
EOF
}


run_kc() {
    kc_args="$*"        # for fail()
    kc_out=$( source "$topdir/keychain" --dir "$keydir" "$@" 2>&1; )
    if $opt_verbose; then
        echo
        echo "keychain $*"
        echo "$kc_out"
    fi
}

count() {
    local ag=$1
    local num=$(ps x | grep -c "[${1:0:1}]${1:1}-agent")
    shift
    if [[ -z $1 ]]; then
        echo $num
    else 
        [[ -z $2 ]] && set -- -eq $1
        eval \[\[ \$num $1 \$2 \]\] || fail "wrong num of ${ag}-agents (have $num, want $1 $2)"
    fi
}

running() {
    local procs=" $(ps x | sed -n '2,$p' | awk '{print $1}' | xargs) "
    local n=1
    for pid; do
        [[ $procs == *" $pid "* ]] || fail "pid $pid is not running"
    done
}

stopped() {
    local procs=" $(ps x | sed -n '2,$p' | awk '{print $1}' | xargs) "
    local n=1
    for pid; do
        [[ $procs == *" $pid "* ]] && fail "pid $pid is not stopped"
    done
}

load() {
    local f
    for f in ${*:-$keydir/$HOSTNAME-sh{,-*}}; do
        [[ -f $f ]] && source $f
    done
    if [[ -n $GPG_AGENT_INFO ]]; then
        GPG_AGENT_PID=${GPG_AGENT_INFO%:*}
        GPG_AGENT_PID=${GPG_AGENT_PID##*:}
    fi
}

fail() {
    if ! $opt_verbose; then
        echo
        echo "keychain $*"
        echo "$kc_out"
    fi
    echo "fail -- $*"
    echo
    exit 125
}

skip() {
    echo "skip -- $*"
    exit 126
}

#
# main program
# 

topdir=$PWD
HOME=$topdir/testhome
keydir=$HOME/.keychain
sshdir=$HOME/.ssh
gpgdir=$HOME/.gnupg
sshkeys=( $sshdir/id_dsa $sshdir/id_rsa )
sshkeys_passwd=( $sshdir/id_dsa_passwd )        # password: keychain
gpgkeys=( 9977A767 603C3040 )
gpgkeys_passwd=( C8919193 )                     # password: keychain
passes=0
total=0

opt_debug=false
opt_list=false
opt_verbose=false

args=$(getopt -o dlv --long debug,list,verbose -n "$0" -- "$@") || exit
eval set -- "$args"

while true; do
    case $1 in
        -d|--debug)     opt_debug=true ; shift ;;
        -l|--list)      opt_list=true ; shift ;;
        -v|--verbose)   opt_verbose=true ; shift ;;
        --) shift ; break ;;
        *) echo "failed to process cmdline args" >&2 ; exit 1 ;;
    esac
done

tests=( $(set | sed -n -e '/[0-9][0-9][0-9].*\ ()/{s/^\(.*\) ()/\1/;p;}' | sort -n ) )
#if [[ $# -gt 0 ]]; then
#    newtests=()
#    for x; do 
#        for ((i = 0; i < ${#tests[@]}; )); do
#            if [[ ${tests[i]} == *${x}* ]]; then
#                newtests=( "${newtests[@]}" "${tests[i]}" )
#                tests=( "${tests[@]:0:i}" "${tests[@]:i+1}" )
#            else
#                let i++
#            fi
#        done
#    done
#    tests=( "${newtests[@]}" )
#    unset newtests
#fi

if $opt_list; then
    for t in "${tests[@]}"; do
        printf "%s\n" "$t"
    done
    exit 0
fi

# don't leak current settings
eval unset ${!SSH_*} ${!GPG_*}

# make sure ssh-add won't balk at the perms
chmod -R go-rwx $sshdir $gpgdir

for t in "${tests[@]}"; do
    run_kc --stop all >/dev/null
    printf "%-50s " "${t##*/}:" >&2
    ( $opt_debug && set -x; $t; true; )
    case $? in
        125)
            # failed, already announced.
            ;;
        126)
            # skipped, already announced.
            # treat this as a pass for stats
            (( passes++ ))
            $opt_verbose && echo
            ;;
        *)
            # passed, need to announce.
            (( passes++ ))
            echo "pass" >&2
            $opt_verbose && echo
            ;;
    esac
    (( total++ ))
done

echo
printf "%d of %d tests passed/skipped (%d%%)\n" \
    $passes $total $(( 100 * passes / total ))

# vim:sw=4 et:
