commit 6ef534d7ba55ef75b039a297962705061a83986f
parent b48f1852d537f50329ee152cfddee30641bef65a
Author: Natasha Kerensikova <natgh@instinctive.eu>
Date: Sun, 6 Oct 2024 13:02:59 +0000
command_spec.sh is redesigned
Diffstat:
M | spec/command_spec.sh | | | 238 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
1 file changed, 168 insertions(+), 70 deletions(-)
diff --git a/spec/command_spec.sh b/spec/command_spec.sh
@@ -1,86 +1,184 @@
-Describe 'Command Functions'
+# pashage - age-backed POSIX password manager
+# Copyright (C) 2024 Natasha Kerensikova
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This test file exercises the whole software through command functions,
+# using minimal mocking, limited to cryptography (to make it more robust
+# and easier to debug), like the `pass_usage.sh` suite.
+# It complements `pass_usage.sh` with pashage-specific behavior, aiming for
+# maximal coverage of normal code paths.
+
+Describe 'Integrated Command Functions'
Include src/pashage.sh
Set 'errexit:on' 'nounset:on' 'pipefail:on'
- age() {
- case "$1" in
- -e)
- shift
- MOCK_AGE_OUTPUT="$(@mktemp "${PREFIX}/mock-age-encrypt.XXXXXXXXX")"
- while [ $# -gt 0 ]; do
- case "$1" in
- -R|-i)
- @sed 's/^/ageRecipient:/' "$2" >>"${MOCK_AGE_OUTPUT}"
- shift 2 ;;
- -r)
- printf 'ageRecipient:%s\n' "$2" >>"${MOCK_AGE_OUTPUT}"
- shift 2 ;;
- -o)
- [ $# -eq 2 ] || printf 'Unexpected age -e [...] %s\n' "$*" >&2
- @sed 's/^/age:/' >>"${MOCK_AGE_OUTPUT}"
- @mv -f "${MOCK_AGE_OUTPUT}" "$2"
- shift 2 ;;
- *)
- printf 'Unexpected age -e [...] %s\n' "$*" >&2
- exit 1
- ;;
- esac
- done
- ;;
- -d)
- [ "$2" = '-i' ] || echo "Unexpected age -d \$2: \"$2\"" >&2
- [ "$4" = '--' ] || echo "Unexpected age -d \$4: \"$4\"" >&2
- @grep -v '^age' "$5" >&2 && echo "Bad encrypted file \"$4\"" >&2
- @grep -qFx "ageRecipient:$(@cat "$3")" "$5" \
- || echo "Bad identity \"$3\": $(@cat "$3")" >&2
- @sed -n 's/^age://p' "$5"
- ;;
- *)
- echo "Unexpected age \$1: \"$1\"" >&2
- ;;
- esac
+ GITLOG="${SHELLSPEC_WORKDIR}/git-log.txt"
+
+ AGE='mock-age'
+ IDENTITIES_FILE="${SHELLSPEC_WORKDIR}/age-identities"
+ PREFIX="${SHELLSPEC_WORKDIR}/store"
+
+ CHARACTER_SET='[:punct:][:alnum:]'
+ CHARACTER_SET_NO_SYMBOLS='[:alnum:]'
+ CLIP_TIME=45
+ GENERATED_LENGTH=25
+ X_SELECTION=clipboard
+
+ TREE__=' '
+ TREE_I='| '
+ TREE_T='|- '
+ TREE_L='`- '
+
+ BOLD_TEXT='(B)'
+ NORMAL_TEXT='(N)'
+ RED_TEXT='(R)'
+ BLUE_TEXT='(B)'
+ UNDERLINE_TEXT='(U)'
+ NO_UNDERLINE_TEXT='(!U)'
+
+ git_log() {
+ @git -C "${PREFIX}" log --format='%s' --stat >|"${GITLOG}"
}
- setup() {
- %putsn 'moi' >"${SHELLSPEC_WORKDIR}/.age-recipients"
- %putsn 'moi' >"${SHELLSPEC_WORKDIR}/identity"
- %text >"${SHELLSPEC_WORKDIR}/my-file.age"
- #|ageRecipient:moi
- #|age:foo
- #|age:bar
+ setup_log() { %text
+ #|Initial setup
+ #|
+ #| extra/subdir/file.age | 2 ++
+ #| fluff/.age-recipients | 2 ++
+ #| fluff/one.age | 3 +++
+ #| fluff/three.age | 5 +++++
+ #| fluff/two.age | 4 ++++
+ #| shared/.age-recipients | 2 ++
+ #| stale.age | 3 +++
+ #| subdir/file.age | 2 ++
+ #| 8 files changed, 23 insertions(+)
+ }
+
+ setup_id() {
+ @mkdir -p "${PREFIX}/$1"
+ @cat >"${PREFIX}/$1/.age-recipients"
}
- cleartext() {
- %text
- #|foo
- #|bar
+ setup_secret() {
+ [ "$1" = "${1%/*}" ] || @mkdir -p "${PREFIX}/${1%/*}"
+ @sed 's/^/age/' >"${PREFIX}/$1.age"
+ }
+
+ setup() {
+ @git init -q -b main "${PREFIX}"
+ @git -C "${PREFIX}" config --local user.name 'Test User'
+ @git -C "${PREFIX}" config --local user.email 'test@example.com'
+ %putsn 'myself' >"${IDENTITIES_FILE}"
+ %text | setup_secret 'subdir/file'
+ #|Recipient:myself
+ #|:p4ssw0rd
+ %text | setup_secret 'extra/subdir/file'
+ #|Recipient:myself
+ #|:Pa55worD
+ %text | setup_id 'shared'
+ #|myself
+ #|friend
+ %text | setup_id 'fluff'
+ #|master
+ #|myself
+ %text | setup_secret 'fluff/one'
+ #|Recipient:master
+ #|Recipient:myself
+ #|:1-password
+ %text | setup_secret 'fluff/two'
+ #|Recipient:master
+ #|Recipient:myself
+ #|:2-password
+ #|:URL: https://example.com/login
+ %text | setup_secret 'fluff/three'
+ #|Recipient:master
+ #|Recipient:myself
+ #|:3-password
+ #|:Username: 3Jane
+ #|:URL: https://example.com/login
+ %text | setup_secret 'stale'
+ #|Recipient:master
+ #|Recipient:myself
+ #|:0-password
+ @git -C "${PREFIX}" add .
+ @git -C "${PREFIX}" commit -m 'Initial setup' >/dev/null
+
+ # Check setup_log consistency
+ git_log
+ setup_log | @diff -u - "${GITLOG}"
}
cleanup() {
- @rm -f "${SHELLSPEC_WORKDIR}/.age-recipients"
- @rm -f "${SHELLSPEC_WORKDIR}/identity"
- @rm -f "${SHELLSPEC_WORKDIR}/my-file.age"
- @rm -f "${SHELLSPEC_WORKDIR}/my-file.txt"
- @rm -f "${SHELLSPEC_WORKDIR}/result.age"
+ @rm -rf "${PREFIX}"
+ @rm -f "${IDENTITIES_FILE}"
}
- BeforeEach 'setup'
- AfterEach 'cleanup'
+ BeforeEach setup
+ AfterEach cleanup
- Specify 'do_decrypt'
- AGE=age
- IDENTITIES_FILE="${SHELLSPEC_WORKDIR}/identity"
- When call do_decrypt "${SHELLSPEC_WORKDIR}/my-file.age"
- The output should equal "$(cleartext)"
- End
+ git() { @git "$@"; }
+ mktemp() { @mktemp "$@"; }
- Specify 'do_encrypt'
- AGE=age
- PREFIX="${SHELLSPEC_WORKDIR}"
- Data cleartext
- When call do_encrypt "result.age"
- The file "${SHELLSPEC_WORKDIR}/result.age" should be exist
- The contents of file "${SHELLSPEC_WORKDIR}/result.age" should equal \
- "$(@cat "${SHELLSPEC_WORKDIR}/my-file.age")"
+ platform_tmpdir() {
+ SECURE_TMPDIR="${PREFIX}/secure"
+ @mkdir -p "${SECURE_TMPDIR}"
+ }
+
+# Describe 'cmd_copy' is not needed (covered by 'cmd_copy_move')
+# Describe 'cmd_copy_move'
+# Describe 'cmd_delete'
+
+ Describe 'cmd_edit'
+ It 'allows lack of file creation without error'
+ EDITOR=true
+ When run cmd_edit subdir/new
+ The status should be success
+ The output should equal 'New password for subdir/new not saved.'
+ The error should be blank
+ The file "${PREFIX}/subdir/new.age" should not be exist
+ The file "${PREFIX}/subdir/new.gpg" should not be exist
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
+
+ It 'reports editor failure'
+ ret42() { return 42; }
+ EDITOR=ret42
+ When run cmd_edit subdir/new
+ The status should equal 42
+ The output should be blank
+ The error should equal 'Editor "ret42" exited with code 42'
+ The file "${PREFIX}/subdir/new.age" should not be exist
+ The file "${PREFIX}/subdir/new.gpg" should not be exist
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
End
+
+# Describe 'cmd_find'
+# Describe 'cmd_generate'
+# Describe 'cmd_git'
+# Describe 'cmd_grep'
+# Describe 'cmd_gitconfig'
+# Describe 'cmd_help'
+# Describe 'cmd_init'
+# Describe 'cmd_insert'
+# Describe 'cmd_list_or_show'
+# Describe 'cmd_move' is not needed (covered by 'cmd_copy_move')
+# Describe 'cmd_random'
+# Describe 'cmd_usage'
+# Describe 'cmd_version'
End