pashage

Yet Another Opinionated Re-engineering of the Unix Password Store
git clone https://git.instinctive.eu/pashage.git
Log | Files | Refs | README | LICENSE

usage_spec.sh (67393B)


      1 # pashage - age-backed POSIX password manager
      2 # Copyright (C) 2024-2025  Natasha Kerensikova
      3 #
      4 # This program is free software; you can redistribute it and/or
      5 # modify it under the terms of the GNU General Public License
      6 # as published by the Free Software Foundation; either version 2
      7 # of the License, or (at your option) any later version.
      8 #
      9 # This program is distributed in the hope that it will be useful,
     10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 # GNU General Public License for more details.
     13 #
     14 # You should have received a copy of the GNU General Public License
     15 # along with this program; if not, write to the Free Software
     16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     17 
     18 # This test file fully covers all command functions in isolation,
     19 # using mocks for all action and helper functions.
     20 # It mostly tests command-line parsing and environment transmission to actions.
     21 
     22 Describe 'Command-Line Parsing'
     23   Include src/pashage.sh
     24   if [ "${SHELLSPEC_SHELL_TYPE}" = sh ]; then
     25     Set 'errexit:on' 'nounset:on'
     26   else
     27     Set 'errexit:on' 'nounset:on' 'pipefail:on'
     28   fi
     29 
     30   PREFIX=/prefix
     31   PROGRAM=prg
     32 
     33   CHARACTER_SET='[:punct:][:alnum:]'
     34   CHARACTER_SET_NO_SYMBOLS='[:alnum:]'
     35 
     36   # mocks
     37   platform_tmpdir() {
     38     SECURE_TMPDIR=/tmp/secure
     39   }
     40 
     41   check_sneaky_path() { mocklog check_sneaky_path "$@"; }
     42   git() { mocklog git "$@"; }
     43   scm_add() { mocklog scm_add "$@"; }
     44   scm_begin() { mocklog scm_begin "$@"; }
     45   scm_commit() { mocklog scm_commit "$@"; }
     46 
     47   do_copy_move() {
     48     mocklog do_copy_move "$@"
     49     %text:expand >&2
     50     #|ACTION=${ACTION}
     51     #|DECISION=${DECISION}
     52     #|OVERWRITE=${OVERWRITE}
     53     #|SCM_ACTION=${SCM_ACTION}
     54   }
     55   do_decrypt() {
     56     mocklog do_decrypt "$@"
     57   }
     58   do_decrypt_gpg() {
     59     mocklog do_decrypt_gpg "$@"
     60   }
     61   do_deinit() {
     62     mocklog do_deinit "$@"
     63     %text:expand >&2
     64     #|DECISION=${DECISION}
     65   }
     66   do_delete() {
     67     mocklog do_delete "$@"
     68     %text:expand >&2
     69     #|DECISION=${DECISION}
     70     #|RECURSIVE=${RECURSIVE}
     71   }
     72   do_edit() {
     73     mocklog do_edit "$@"
     74     %text:expand >&2
     75     #|EDITOR=${EDITOR}
     76     #|SECURE_TMPDIR=${SECURE_TMPDIR}
     77     #|TERM=${TERM}
     78     #|VISUAL=${VISUAL}
     79   }
     80   do_encrypt() {
     81     mocklog do_encrypt "$@"
     82     %text:expand >&2
     83     #|IDENTITIES_FILE=${IDENTITIES_FILE}
     84     #|LOCAL_RECIPIENT_FILE=${LOCAL_RECIPIENT_FILE}
     85     #|PASHAGE_RECIPIENTS=${PASHAGE_RECIPIENTS}
     86     #|PASHAGE_RECIPIENTS_FILE=${PASHAGE_RECIPIENTS_FILE}
     87     #|PASSAGE_RECIPIENTS=${PASSAGE_RECIPIENTS}
     88     #|PASSAGE_RECIPIENTS_FILE=${PASSAGE_RECIPIENTS_FILE}
     89   }
     90   do_generate() {
     91     mocklog do_generate "$@"
     92     %text:expand >&2
     93     #|DECISION=${DECISION}
     94     #|MULTILINE=${MULTILINE}
     95     #|OVERWRITE=${OVERWRITE}
     96     #|SELECTED_LINE=${SELECTED_LINE}
     97     #|SHOW=${SHOW}
     98   }
     99   do_grep() {
    100     mocklog do_grep "$@"
    101   }
    102   do_init() {
    103     mocklog do_init "$@"
    104     %text:expand >&2
    105     #|DECISION=${DECISION}
    106     #|OVERWRITE=${OVERWRITE}
    107   }
    108   do_insert() {
    109     mocklog do_insert "$@"
    110     %text:expand >&2
    111     #|ECHO=${ECHO}
    112     #|MULTILINE=${MULTILINE}
    113     #|OVERWRITE=${OVERWRITE}
    114   }
    115   do_list() {
    116     mocklog do_list "$@"
    117   }
    118   do_list_or_show() {
    119     mocklog do_list_or_show "$@"
    120     %text:expand >&2
    121     #|LIST_VIEW=${LIST_VIEW}
    122     #|SELECTED_LINE=${SELECTED_LINE}
    123     #|SHOW=${SHOW}
    124   }
    125   do_reencrypt() {
    126     mocklog do_reencrypt "$@"
    127     %text:expand >&2
    128     #|DECISION=${DECISION}
    129     #|RECURSIVE=${RECURSIVE}
    130   }
    131   do_reencrypt_dir() {
    132     mocklog do_reencrypt_dir "$@"
    133     %text:expand >&2
    134     #|DECISION=${DECISION}
    135   }
    136   do_reencrypt_file() {
    137     mocklog do_reencrypt_file "$@"
    138     %text:expand >&2
    139     #|DECISION=${DECISION}
    140   }
    141   do_show() {
    142     mocklog do_show "$@"
    143     %text:expand >&2
    144     #|SELECTED_LINE=${SELECTED_LINE}
    145     #|SHOW=${SHOW}
    146   }
    147   do_tree() {
    148     mocklog do_tree "$@"
    149   }
    150 
    151   Describe 'cmd_copy'
    152     COMMAND=copy
    153 
    154     It 'copies multiple files'
    155       result() {
    156         %text
    157         #|$ check_sneaky_path src1
    158         #|$ check_sneaky_path src2
    159         #|$ check_sneaky_path src3
    160         #|$ check_sneaky_path dest
    161         #|$ do_copy_move src1 dest/
    162         #|ACTION=Copy
    163         #|DECISION=default
    164         #|OVERWRITE=no
    165         #|SCM_ACTION=scm_cp
    166         #|$ do_copy_move src2 dest/
    167         #|ACTION=Copy
    168         #|DECISION=default
    169         #|OVERWRITE=no
    170         #|SCM_ACTION=scm_cp
    171         #|$ do_copy_move src3 dest/
    172         #|ACTION=Copy
    173         #|DECISION=default
    174         #|OVERWRITE=no
    175         #|SCM_ACTION=scm_cp
    176       }
    177       When call cmd_copy src1 src2 src3 dest
    178       The status should be success
    179       The output should be blank
    180       The error should equal "$(result)"
    181     End
    182 
    183     It 'copies forcefully with a long option'
    184       result() {
    185         %text
    186         #|$ check_sneaky_path src
    187         #|$ check_sneaky_path dest
    188         #|$ do_copy_move src dest
    189         #|ACTION=Copy
    190         #|DECISION=default
    191         #|OVERWRITE=yes
    192         #|SCM_ACTION=scm_cp
    193       }
    194       When call cmd_copy --force src dest
    195       The status should be success
    196       The output should be blank
    197       The error should equal "$(result)"
    198     End
    199 
    200     It 'copies forcefully with a short option'
    201       result() {
    202         %text
    203         #|$ check_sneaky_path src
    204         #|$ check_sneaky_path dest
    205         #|$ do_copy_move src dest
    206         #|ACTION=Copy
    207         #|DECISION=default
    208         #|OVERWRITE=yes
    209         #|SCM_ACTION=scm_cp
    210       }
    211       When call cmd_copy -f src dest
    212       The status should be success
    213       The output should be blank
    214       The error should equal "$(result)"
    215     End
    216 
    217     It 'always reencrypts with a long option'
    218       result() {
    219         %text
    220         #|$ check_sneaky_path src
    221         #|$ check_sneaky_path dest
    222         #|$ do_copy_move src dest
    223         #|ACTION=Copy
    224         #|DECISION=force
    225         #|OVERWRITE=no
    226         #|SCM_ACTION=scm_cp
    227       }
    228       When call cmd_copy --reencrypt src dest
    229       The status should be success
    230       The output should be blank
    231       The error should equal "$(result)"
    232     End
    233 
    234     It 'always reencrypts with a short option'
    235       result() {
    236         %text
    237         #|$ check_sneaky_path src
    238         #|$ check_sneaky_path dest
    239         #|$ do_copy_move src dest
    240         #|ACTION=Copy
    241         #|DECISION=force
    242         #|OVERWRITE=no
    243         #|SCM_ACTION=scm_cp
    244       }
    245       When call cmd_copy -e src dest
    246       The status should be success
    247       The output should be blank
    248       The error should equal "$(result)"
    249     End
    250 
    251     It 'interactively reencrypts with a long option'
    252       result() {
    253         %text
    254         #|$ check_sneaky_path src
    255         #|$ check_sneaky_path dest
    256         #|$ do_copy_move src dest
    257         #|ACTION=Copy
    258         #|DECISION=interactive
    259         #|OVERWRITE=no
    260         #|SCM_ACTION=scm_cp
    261       }
    262       When call cmd_copy --interactive src dest
    263       The status should be success
    264       The output should be blank
    265       The error should equal "$(result)"
    266     End
    267 
    268     It 'interactively reencrypts with a short option'
    269       result() {
    270         %text
    271         #|$ check_sneaky_path src
    272         #|$ check_sneaky_path dest
    273         #|$ do_copy_move src dest
    274         #|ACTION=Copy
    275         #|DECISION=interactive
    276         #|OVERWRITE=no
    277         #|SCM_ACTION=scm_cp
    278       }
    279       When call cmd_copy -i src dest
    280       The status should be success
    281       The output should be blank
    282       The error should equal "$(result)"
    283     End
    284 
    285     It 'never reencrypts with a long option'
    286       result() {
    287         %text
    288         #|$ check_sneaky_path src
    289         #|$ check_sneaky_path dest
    290         #|$ do_copy_move src dest
    291         #|ACTION=Copy
    292         #|DECISION=keep
    293         #|OVERWRITE=no
    294         #|SCM_ACTION=scm_cp
    295       }
    296       When call cmd_copy --keep src dest
    297       The status should be success
    298       The output should be blank
    299       The error should equal "$(result)"
    300     End
    301 
    302     It 'never reencrypts with a short option'
    303       result() {
    304         %text
    305         #|$ check_sneaky_path src
    306         #|$ check_sneaky_path dest
    307         #|$ do_copy_move src dest
    308         #|ACTION=Copy
    309         #|DECISION=keep
    310         #|OVERWRITE=no
    311         #|SCM_ACTION=scm_cp
    312       }
    313       When call cmd_copy -k src dest
    314       The status should be success
    315       The output should be blank
    316       The error should equal "$(result)"
    317     End
    318 
    319     It 'copies a file named like a flag'
    320       result() {
    321         %text
    322         #|$ check_sneaky_path -s
    323         #|$ check_sneaky_path dest
    324         #|$ do_copy_move -s dest
    325         #|ACTION=Copy
    326         #|DECISION=default
    327         #|OVERWRITE=no
    328         #|SCM_ACTION=scm_cp
    329       }
    330       When call cmd_copy -- -s dest
    331       The status should be success
    332       The output should be blank
    333       The error should equal "$(result)"
    334     End
    335 
    336     usage_text() { %text
    337       #|Usage: prg copy [--reencrypt,-e | --interactive,-i | --keep,-k ]
    338       #|                [--force,-f] old-path new-path
    339     }
    340 
    341     It 'reports a bad option'
    342       cat() { @cat; }
    343       When run cmd_copy -s arg
    344       The output should be blank
    345       The error should equal "$(usage_text)"
    346       The status should equal 1
    347     End
    348 
    349     It 'reports incompatible re-encryption options (-e and -i)'
    350       cat() { @cat; }
    351       When run cmd_copy -ei src dest
    352       The output should be blank
    353       The error should equal "$(usage_text)"
    354       The status should equal 1
    355     End
    356 
    357     It 'reports incompatible re-encryption options (-i and -k)'
    358       cat() { @cat; }
    359       When run cmd_copy -ik src dest
    360       The output should be blank
    361       The error should equal "$(usage_text)"
    362       The status should equal 1
    363     End
    364 
    365     It 'reports incompatible re-encryption options (-k and -e)'
    366       cat() { @cat; }
    367       When run cmd_copy -ke src dest
    368       The output should be blank
    369       The error should equal "$(usage_text)"
    370       The status should equal 1
    371     End
    372 
    373     It 'reports a lack of argument'
    374       cat() { @cat; }
    375       When run cmd_copy src
    376       The output should be blank
    377       The error should equal "$(usage_text)"
    378       The status should equal 1
    379     End
    380   End
    381 
    382   Describe 'cmd_copy_move'
    383     COMMAND=wrong
    384 
    385     It 'reports both commands when confused'
    386       cat() { @cat; }
    387       result() { %text
    388         #|Usage: prg copy [--reencrypt,-e | --interactive,-i | --keep,-k ]
    389         #|                [--force,-f] old-path new-path
    390         #|       prg move [--reencrypt,-e | --interactive,-i | --keep,-k ]
    391         #|                [--force,-f] old-path new-path
    392       }
    393       When run cmd_copy src
    394       The output should be blank
    395       The error should equal "$(result)"
    396       The status should equal 1
    397     End
    398   End
    399 
    400   Describe 'cmd_delete'
    401     COMMAND=delete
    402 
    403     It 'removes a file forcefully with a long option'
    404       result() {
    405         %text
    406         #|$ check_sneaky_path arg1
    407         #|$ do_delete arg1
    408         #|DECISION=force
    409         #|RECURSIVE=no
    410       }
    411       When call cmd_delete --force arg1
    412       The status should be success
    413       The output should be blank
    414       The error should equal "$(result)"
    415     End
    416 
    417     It 'removes a file forcefully with a short option'
    418       result() {
    419         %text
    420         #|$ check_sneaky_path arg1
    421         #|$ do_delete arg1
    422         #|DECISION=force
    423         #|RECURSIVE=no
    424       }
    425       When call cmd_delete -f arg1
    426       The status should be success
    427       The output should be blank
    428       The error should equal "$(result)"
    429     End
    430 
    431     It 'removes a directory recursively with a long option'
    432       result() {
    433         %text
    434         #|$ check_sneaky_path arg1
    435         #|$ do_delete arg1
    436         #|DECISION=default
    437         #|RECURSIVE=yes
    438       }
    439       When call cmd_delete --recursive arg1
    440       The status should be success
    441       The output should be blank
    442       The error should equal "$(result)"
    443     End
    444 
    445     It 'removes a directory recursively with a short option'
    446       result() {
    447         %text
    448         #|$ check_sneaky_path arg1
    449         #|$ do_delete arg1
    450         #|DECISION=default
    451         #|RECURSIVE=yes
    452       }
    453       When call cmd_delete -r arg1
    454       The status should be success
    455       The output should be blank
    456       The error should equal "$(result)"
    457     End
    458 
    459     It 'removes a directory recursively and forcefully with long options'
    460       result() {
    461         %text
    462         #|$ check_sneaky_path arg1
    463         #|$ do_delete arg1
    464         #|DECISION=force
    465         #|RECURSIVE=yes
    466       }
    467       When call cmd_delete --recursive --force arg1
    468       The status should be success
    469       The output should be blank
    470       The error should equal "$(result)"
    471     End
    472 
    473     It 'removes a directory recursively and forcefully with short options'
    474       result() {
    475         %text
    476         #|$ check_sneaky_path arg1
    477         #|$ do_delete arg1
    478         #|DECISION=force
    479         #|RECURSIVE=yes
    480       }
    481       When call cmd_delete -rf arg1
    482       The status should be success
    483       The output should be blank
    484       The error should equal "$(result)"
    485     End
    486 
    487     It 'removes a directory forcefully and recursively with short options'
    488       result() {
    489         %text
    490         #|$ check_sneaky_path arg1
    491         #|$ do_delete arg1
    492         #|DECISION=force
    493         #|RECURSIVE=yes
    494       }
    495       When call cmd_delete -fr arg1
    496       The status should be success
    497       The output should be blank
    498       The error should equal "$(result)"
    499     End
    500 
    501     It 'removes multiple files'
    502       result() {
    503         %text
    504         #|$ check_sneaky_path arg1
    505         #|$ check_sneaky_path arg2
    506         #|$ check_sneaky_path arg3
    507         #|$ do_delete arg1
    508         #|DECISION=default
    509         #|RECURSIVE=no
    510         #|$ do_delete arg2
    511         #|DECISION=default
    512         #|RECURSIVE=no
    513         #|$ do_delete arg3
    514         #|DECISION=default
    515         #|RECURSIVE=no
    516       }
    517       When call cmd_delete arg1 arg2 arg3
    518       The status should be success
    519       The output should be blank
    520       The error should equal "$(result)"
    521     End
    522 
    523     It 'removes a file named like a flag'
    524       result() {
    525         %text
    526         #|$ check_sneaky_path -f
    527         #|$ check_sneaky_path arg2
    528         #|$ do_delete -f
    529         #|DECISION=default
    530         #|RECURSIVE=no
    531         #|$ do_delete arg2
    532         #|DECISION=default
    533         #|RECURSIVE=no
    534       }
    535       When call cmd_delete -- -f arg2
    536       The status should be success
    537       The output should be blank
    538       The error should equal "$(result)"
    539     End
    540 
    541     It 'reports a bad option'
    542       cat() { @cat; }
    543       When run cmd_delete -u arg
    544       The output should be blank
    545       The error should equal \
    546         'Usage: prg delete [--recursive,-r] [--force,-f] pass-name'
    547       The status should equal 1
    548     End
    549 
    550     It 'reports a lack of argument'
    551       cat() { @cat; }
    552       When run cmd_delete
    553       The output should be blank
    554       The error should equal \
    555         'Usage: prg delete [--recursive,-r] [--force,-f] pass-name'
    556       The status should equal 1
    557     End
    558   End
    559 
    560   Describe 'cmd_edit'
    561     COMMAND=edit
    562     EDITOR=ed
    563     TERM=dumb
    564     VISUAL=vi
    565 
    566     It 'edits multiple files succesively'
    567       result() {
    568         %text
    569         #|$ check_sneaky_path arg1
    570         #|$ check_sneaky_path arg2
    571         #|$ check_sneaky_path arg3
    572         #|$ do_edit arg1
    573         #|EDITOR=ed
    574         #|SECURE_TMPDIR=/tmp/secure
    575         #|TERM=dumb
    576         #|VISUAL=vi
    577         #|$ do_edit arg2
    578         #|EDITOR=ed
    579         #|SECURE_TMPDIR=/tmp/secure
    580         #|TERM=dumb
    581         #|VISUAL=vi
    582         #|$ do_edit arg3
    583         #|EDITOR=ed
    584         #|SECURE_TMPDIR=/tmp/secure
    585         #|TERM=dumb
    586         #|VISUAL=vi
    587       }
    588       When call cmd_edit arg1 arg2 arg3
    589       The status should be success
    590       The output should be blank
    591       The error should equal "$(result)"
    592     End
    593 
    594     It 'reports a lack of argument'
    595       cat() { @cat; }
    596       When run cmd_edit
    597       The output should be blank
    598       The error should equal 'Usage: prg edit pass-name'
    599       The status should equal 1
    600     End
    601   End
    602 
    603   Describe 'cmd_find'
    604     COMMAND=find
    605 
    606     It 'uses the argument list directly'
    607       When call cmd_find -i pattern
    608       The status should be success
    609       The output should equal 'Search pattern: -i pattern'
    610       The error should equal '$ do_tree  -i pattern'
    611     End
    612 
    613     It 'interprets the raw list flag'
    614       When call cmd_find -r pattern
    615       The status should be success
    616       The output should be blank
    617       The error should equal '$ do_list  pattern'
    618     End
    619 
    620     It 'reports a lack of argument'
    621       cat() { @cat; }
    622       When run cmd_find
    623       The output should be blank
    624       The error should equal 'Usage: prg find [--raw,-r] [GREP_OPTIONS] regex'
    625       The status should equal 1
    626     End
    627 
    628     It 'reports a lack of argument for grep'
    629       cat() { @cat; }
    630       When run cmd_find -r
    631       The output should be blank
    632       The error should equal 'Usage: prg find [--raw,-r] [GREP_OPTIONS] regex'
    633       The status should equal 1
    634     End
    635   End
    636 
    637   Describe 'cmd_generate'
    638     COMMAND=generate
    639     GENERATED_LENGTH=25
    640 
    641     usage_text() { %text
    642       #|Usage: prg generate [--no-symbols,-n] [--clip,-c | --qrcode,-q]
    643       #|                    [--in-place,-i | --force,-f] [--multiline,-m]
    644       #|                    [--try,-t] pass-name [pass-length [character-set]]
    645     }
    646 
    647     It 'generates a new entry with default length'
    648       result() {
    649         %text
    650         #|$ check_sneaky_path secret
    651         #|$ do_generate secret 25 [:punct:][:alnum:]
    652         #|DECISION=default
    653         #|MULTILINE=no
    654         #|OVERWRITE=no
    655         #|SELECTED_LINE=1
    656         #|SHOW=text
    657       }
    658       When call cmd_generate secret
    659       The status should be success
    660       The output should be blank
    661       The error should equal "$(result)"
    662     End
    663 
    664     It 'generates a new entry with explicit length'
    665       result() {
    666         %text
    667         #|$ check_sneaky_path secret
    668         #|$ do_generate secret 12 [:punct:][:alnum:]
    669         #|DECISION=default
    670         #|MULTILINE=no
    671         #|OVERWRITE=no
    672         #|SELECTED_LINE=1
    673         #|SHOW=text
    674       }
    675       When call cmd_generate secret 12
    676       The status should be success
    677       The output should be blank
    678       The error should equal "$(result)"
    679     End
    680 
    681     It 'generates a new entry with explicit length and character set'
    682       result() {
    683         %text
    684         #|$ check_sneaky_path secret
    685         #|$ do_generate secret 12 [A-Z]
    686         #|DECISION=default
    687         #|MULTILINE=no
    688         #|OVERWRITE=no
    689         #|SELECTED_LINE=1
    690         #|SHOW=text
    691       }
    692       When call cmd_generate secret 12 '[A-Z]'
    693       The status should be success
    694       The output should be blank
    695       The error should equal "$(result)"
    696     End
    697 
    698     It 'generates a new flag-like entry'
    699       result() {
    700         %text
    701         #|$ check_sneaky_path -f
    702         #|$ do_generate -f 25 [:punct:][:alnum:]
    703         #|DECISION=default
    704         #|MULTILINE=no
    705         #|OVERWRITE=no
    706         #|SELECTED_LINE=1
    707         #|SHOW=text
    708       }
    709       When call cmd_generate -- -f
    710       The status should be success
    711       The output should be blank
    712       The error should equal "$(result)"
    713     End
    714 
    715     It 'generates a new entry and copies it into the clipboard (long)'
    716       result() {
    717         %text
    718         #|$ check_sneaky_path secret
    719         #|$ do_generate secret 25 [:punct:][:alnum:]
    720         #|DECISION=default
    721         #|MULTILINE=no
    722         #|OVERWRITE=no
    723         #|SELECTED_LINE=1
    724         #|SHOW=clip
    725       }
    726       When call cmd_generate --clip secret
    727       The status should be success
    728       The output should be blank
    729       The error should equal "$(result)"
    730     End
    731 
    732     It 'generates a new entry and copies it into the clipboard (short)'
    733       result() {
    734         %text
    735         #|$ check_sneaky_path secret
    736         #|$ do_generate secret 25 [:punct:][:alnum:]
    737         #|DECISION=default
    738         #|MULTILINE=no
    739         #|OVERWRITE=no
    740         #|SELECTED_LINE=1
    741         #|SHOW=clip
    742       }
    743       When call cmd_generate -c secret
    744       The status should be success
    745       The output should be blank
    746       The error should equal "$(result)"
    747     End
    748 
    749     It 'generates a new entry and shows it as a QR-code (long)'
    750       result() {
    751         %text
    752         #|$ check_sneaky_path secret
    753         #|$ do_generate secret 25 [:punct:][:alnum:]
    754         #|DECISION=default
    755         #|MULTILINE=no
    756         #|OVERWRITE=no
    757         #|SELECTED_LINE=1
    758         #|SHOW=qrcode
    759       }
    760       When call cmd_generate --qrcode secret
    761       The status should be success
    762       The output should be blank
    763       The error should equal "$(result)"
    764     End
    765 
    766     It 'generates a new entry and shows it as a QR-code (short)'
    767       result() {
    768         %text
    769         #|$ check_sneaky_path secret
    770         #|$ do_generate secret 25 [:punct:][:alnum:]
    771         #|DECISION=default
    772         #|MULTILINE=no
    773         #|OVERWRITE=no
    774         #|SELECTED_LINE=1
    775         #|SHOW=qrcode
    776       }
    777       When call cmd_generate -q secret
    778       The status should be success
    779       The output should be blank
    780       The error should equal "$(result)"
    781     End
    782 
    783     It 'generates a new alphanumeric entry and copies it into the clipboard (long)'
    784       result() {
    785         %text
    786         #|$ check_sneaky_path secret
    787         #|$ do_generate secret 25 [:alnum:]
    788         #|DECISION=default
    789         #|MULTILINE=no
    790         #|OVERWRITE=no
    791         #|SELECTED_LINE=1
    792         #|SHOW=clip
    793       }
    794       When call cmd_generate --clip --no-symbols secret
    795       The status should be success
    796       The output should be blank
    797       The error should equal "$(result)"
    798     End
    799 
    800     It 'generates a new alphanumeric entry and copies it into the clipboard (short)'
    801       result() {
    802         %text
    803         #|$ check_sneaky_path secret
    804         #|$ do_generate secret 25 [:alnum:]
    805         #|DECISION=default
    806         #|MULTILINE=no
    807         #|OVERWRITE=no
    808         #|SELECTED_LINE=1
    809         #|SHOW=clip
    810       }
    811       When call cmd_generate -cn secret
    812       The status should be success
    813       The output should be blank
    814       The error should equal "$(result)"
    815     End
    816 
    817     It 'generates a new alphanumeric entry and shows it as a QR-code (long)'
    818       result() {
    819         %text
    820         #|$ check_sneaky_path secret
    821         #|$ do_generate secret 25 [:alnum:]
    822         #|DECISION=default
    823         #|MULTILINE=no
    824         #|OVERWRITE=no
    825         #|SELECTED_LINE=1
    826         #|SHOW=qrcode
    827       }
    828       When call cmd_generate --no-symbols --qrcode secret
    829       The status should be success
    830       The output should be blank
    831       The error should equal "$(result)"
    832     End
    833 
    834     It 'generates a new alphanumeric entry and shows it as a QR-code (short)'
    835       result() {
    836         %text
    837         #|$ check_sneaky_path secret
    838         #|$ do_generate secret 25 [:alnum:]
    839         #|DECISION=default
    840         #|MULTILINE=no
    841         #|OVERWRITE=no
    842         #|SELECTED_LINE=1
    843         #|SHOW=qrcode
    844       }
    845       When call cmd_generate -nq secret
    846       The status should be success
    847       The output should be blank
    848       The error should equal "$(result)"
    849     End
    850 
    851     It 'generates a new entry in place (long)'
    852       result() {
    853         %text
    854         #|$ check_sneaky_path secret
    855         #|$ do_generate secret 25 [:punct:][:alnum:]
    856         #|DECISION=default
    857         #|MULTILINE=no
    858         #|OVERWRITE=reuse
    859         #|SELECTED_LINE=1
    860         #|SHOW=text
    861       }
    862       When call cmd_generate --in-place secret
    863       The status should be success
    864       The output should be blank
    865       The error should equal "$(result)"
    866     End
    867 
    868     It 'generates a new entry in place (short)'
    869       result() {
    870         %text
    871         #|$ check_sneaky_path secret
    872         #|$ do_generate secret 25 [:punct:][:alnum:]
    873         #|DECISION=default
    874         #|MULTILINE=no
    875         #|OVERWRITE=reuse
    876         #|SELECTED_LINE=1
    877         #|SHOW=text
    878       }
    879       When call cmd_generate -i secret
    880       The status should be success
    881       The output should be blank
    882       The error should equal "$(result)"
    883     End
    884 
    885     It 'overwrites an existing entry (long)'
    886       result() {
    887         %text
    888         #|$ check_sneaky_path secret
    889         #|$ do_generate secret 25 [:punct:][:alnum:]
    890         #|DECISION=default
    891         #|MULTILINE=no
    892         #|OVERWRITE=yes
    893         #|SELECTED_LINE=1
    894         #|SHOW=text
    895       }
    896       When call cmd_generate --force secret
    897       The status should be success
    898       The output should be blank
    899       The error should equal "$(result)"
    900     End
    901 
    902     It 'overwrites an existing entry (short)'
    903       result() {
    904         %text
    905         #|$ check_sneaky_path secret
    906         #|$ do_generate secret 25 [:punct:][:alnum:]
    907         #|DECISION=default
    908         #|MULTILINE=no
    909         #|OVERWRITE=yes
    910         #|SELECTED_LINE=1
    911         #|SHOW=text
    912       }
    913       When call cmd_generate -f secret
    914       The status should be success
    915       The output should be blank
    916       The error should equal "$(result)"
    917     End
    918 
    919     It 'asks for confirmation before saving the generated password (long)'
    920       result() {
    921         %text
    922         #|$ check_sneaky_path secret
    923         #|$ do_generate secret 25 [:punct:][:alnum:]
    924         #|DECISION=interactive
    925         #|MULTILINE=no
    926         #|OVERWRITE=no
    927         #|SELECTED_LINE=1
    928         #|SHOW=text
    929       }
    930       When call cmd_generate --try secret
    931       The status should be success
    932       The output should be blank
    933       The error should equal "$(result)"
    934     End
    935 
    936     It 'asks for confirmation before saving the generated password (short)'
    937       result() {
    938         %text
    939         #|$ check_sneaky_path secret
    940         #|$ do_generate secret 25 [:punct:][:alnum:]
    941         #|DECISION=interactive
    942         #|MULTILINE=no
    943         #|OVERWRITE=no
    944         #|SELECTED_LINE=1
    945         #|SHOW=text
    946       }
    947       When call cmd_generate -t secret
    948       The status should be success
    949       The output should be blank
    950       The error should equal "$(result)"
    951     End
    952 
    953     It 'accepts extra lines after the generated secret (long)'
    954       result() {
    955         %text
    956         #|$ check_sneaky_path secret
    957         #|$ do_generate secret 25 [:punct:][:alnum:]
    958         #|DECISION=default
    959         #|MULTILINE=yes
    960         #|OVERWRITE=no
    961         #|SELECTED_LINE=1
    962         #|SHOW=text
    963       }
    964       When call cmd_generate --multiline secret
    965       The status should be success
    966       The output should be blank
    967       The error should equal "$(result)"
    968     End
    969 
    970     It 'accepts extra lines after the generated secret (short)'
    971       result() {
    972         %text
    973         #|$ check_sneaky_path secret
    974         #|$ do_generate secret 25 [:punct:][:alnum:]
    975         #|DECISION=default
    976         #|MULTILINE=yes
    977         #|OVERWRITE=no
    978         #|SELECTED_LINE=1
    979         #|SHOW=text
    980       }
    981       When call cmd_generate -m secret
    982       The status should be success
    983       The output should be blank
    984       The error should equal "$(result)"
    985     End
    986 
    987     It 'reports incompatible generation long options'
    988       cat() { @cat; }
    989       When run cmd_generate --in-place --force secret
    990       The output should be blank
    991       The error should equal "$(usage_text)"
    992       The status should equal 1
    993     End
    994 
    995     It 'reports incompatible generation short options'
    996       cat() { @cat; }
    997       When run cmd_generate -fi secret
    998       The output should be blank
    999       The error should equal "$(usage_text)"
   1000       The status should equal 1
   1001     End
   1002 
   1003     It 'reports incompatible show long options'
   1004       cat() { @cat; }
   1005       When run cmd_generate --qrcode --clip secret
   1006       The output should be blank
   1007       The error should equal "$(usage_text)"
   1008       The status should equal 1
   1009     End
   1010 
   1011     It 'reports incompatible show short options'
   1012       cat() { @cat; }
   1013       When run cmd_generate -cq secret
   1014       The output should be blank
   1015       The error should equal "$(usage_text)"
   1016       The status should equal 1
   1017     End
   1018 
   1019     It 'reports a bad option'
   1020       cat() { @cat; }
   1021       When run cmd_generate --bad secret
   1022       The output should be blank
   1023       The error should equal "$(usage_text)"
   1024       The status should equal 1
   1025     End
   1026 
   1027     It 'reports a lack of argument'
   1028       cat() { @cat; }
   1029       When run cmd_generate
   1030       The output should be blank
   1031       The error should equal "$(usage_text)"
   1032       The status should equal 1
   1033     End
   1034   End
   1035 
   1036   Describe 'cmd_git'
   1037     COMMAND=git
   1038 
   1039     cmd_gitconfig() { mocklog cmd_gitconfig "$@"; }
   1040     mkdir() { mocklog mkdir "$@"; @mkdir "$@"; }
   1041 
   1042     setup() {
   1043       @mkdir -p "${SHELLSPEC_WORKDIR}/repo/.git"
   1044       @mkdir -p "${SHELLSPEC_WORKDIR}/repo/sub"
   1045     }
   1046 
   1047     cleanup() {
   1048       @rm -rf "${SHELLSPEC_WORKDIR}/repo"
   1049     }
   1050 
   1051     BeforeEach setup
   1052     AfterEach cleanup
   1053 
   1054     It 'initializes a new repository'
   1055       PREFIX="${SHELLSPEC_WORKDIR}/repo/sub"
   1056       result() {
   1057         %text:expand
   1058         #|$ mkdir -p -- ${PREFIX}
   1059         #|$ git -C ${PREFIX} init
   1060         #|$ scm_add .
   1061         #|$ scm_commit Add current contents of password store.
   1062         #|$ cmd_gitconfig
   1063       }
   1064       When call cmd_git init
   1065       The status should be success
   1066       The output should be blank
   1067       The error should equal "$(result)"
   1068     End
   1069 
   1070     It 'clones a new repository'
   1071       PREFIX="${SHELLSPEC_WORKDIR}/repo/sub"
   1072       result() {
   1073         %text:expand
   1074         #|$ git clone origin ${PREFIX}
   1075         #|$ cmd_gitconfig
   1076       }
   1077       When call cmd_git clone origin
   1078       The status should be success
   1079       The output should be blank
   1080       The error should equal "$(result)"
   1081     End
   1082 
   1083     It 'runs the git command into the store'
   1084       PREFIX="${SHELLSPEC_WORKDIR}/repo"
   1085       When call cmd_git log --oneline
   1086       The status should be success
   1087       The output should be blank
   1088       The error should equal "$ git -C ${PREFIX} log --oneline"
   1089     End
   1090 
   1091     It 'transmits an empty argument list to git'
   1092       PREFIX="${SHELLSPEC_WORKDIR}/repo"
   1093       When run cmd_git
   1094       The status should be success
   1095       The output should be blank
   1096       The error should equal "$ git -C ${PREFIX}"
   1097     End
   1098 
   1099     It 'aborts without a git repository'
   1100       PREFIX="${SHELLSPEC_WORKDIR}/repo/sub"
   1101       When run cmd_git log
   1102       The output should be blank
   1103       The error should equal 'Error: the password store is not a git repository. Try "prg git init".'
   1104       The status should equal 1
   1105     End
   1106   End
   1107 
   1108   Describe 'cmd_gitconfig'
   1109     COMMAND=gitconfig
   1110     AGE=age
   1111     IDENTITIES_FILE=id
   1112 
   1113     grep() { @grep "$@"; }
   1114 
   1115     setup() {
   1116       @mkdir -p "${SHELLSPEC_WORKDIR}/repo/.git"
   1117       @mkdir -p "${SHELLSPEC_WORKDIR}/repo/sub-1/.git"
   1118       %putsn data >"${SHELLSPEC_WORKDIR}/repo/sub-1/.gitattributes"
   1119       @mkdir -p "${SHELLSPEC_WORKDIR}/repo/sub-2/.git"
   1120       %putsn '*.age diff=age' >"${SHELLSPEC_WORKDIR}/repo/sub-2/.gitattributes"
   1121     }
   1122 
   1123     cleanup() {
   1124       @rm -rf "${SHELLSPEC_WORKDIR}/repo"
   1125     }
   1126 
   1127     BeforeEach setup
   1128     AfterEach cleanup
   1129 
   1130     It 'configures a new repository'
   1131       PREFIX="${SHELLSPEC_WORKDIR}/repo"
   1132       result() {
   1133         %text:expand
   1134         #|$ scm_begin
   1135         #|$ scm_add .gitattributes
   1136         #|$ scm_commit Configure git repository for age file diff.
   1137         #|$ git -C ${PREFIX} config --local diff.age.binary true
   1138         #|$ git -C ${PREFIX} config --local diff.age.textconv age -d -i id
   1139       }
   1140       When call cmd_gitconfig
   1141       The status should be success
   1142       The output should be blank
   1143       The error should equal "$(result)"
   1144       The contents of file "${PREFIX}/.gitattributes" should equal '*.age diff=age'
   1145     End
   1146 
   1147     It 'expands an existing .gitattributes'
   1148       PREFIX="${SHELLSPEC_WORKDIR}/repo/sub-1"
   1149       result() {
   1150         %text:expand
   1151         #|$ scm_begin
   1152         #|$ scm_add .gitattributes
   1153         #|$ scm_commit Configure git repository for age file diff.
   1154         #|$ git -C ${PREFIX} config --local diff.age.binary true
   1155         #|$ git -C ${PREFIX} config --local diff.age.textconv age -d -i id
   1156       }
   1157       attrs() {
   1158         %text
   1159         #|data
   1160         #|*.age diff=age
   1161       }
   1162       When call cmd_gitconfig
   1163       The status should be success
   1164       The output should be blank
   1165       The error should equal "$(result)"
   1166       The contents of file "${PREFIX}/.gitattributes" should equal "$(attrs)"
   1167     End
   1168 
   1169     It 'configures a repository with a valid .gitattributes'
   1170       PREFIX="${SHELLSPEC_WORKDIR}/repo/sub-2"
   1171       result() {
   1172         %text:expand
   1173         #|$ git -C ${PREFIX} config --local diff.age.binary true
   1174         #|$ git -C ${PREFIX} config --local diff.age.textconv age -d -i id
   1175       }
   1176       When call cmd_gitconfig
   1177       The status should be success
   1178       The output should be blank
   1179       The error should equal "$(result)"
   1180       The contents of file "${PREFIX}/.gitattributes" should equal '*.age diff=age'
   1181     End
   1182 
   1183     It 'aborts without a git repository'
   1184       PREFIX="${SHELLSPEC_WORKDIR}/repo/prefix"
   1185       When run cmd_gitconfig
   1186       The output should be blank
   1187       The error should equal  'The store is not a git repository.'
   1188       The status should equal 1
   1189     End
   1190   End
   1191 
   1192   Describe 'cmd_grep'
   1193     COMMAND=grep
   1194     PREFIX="${SHELLSPEC_WORKDIR}"
   1195 
   1196     It 'uses the argument list directly'
   1197       When call cmd_grep -i pattern
   1198       The status should be success
   1199       The output should be blank
   1200       The error should equal "$ do_grep ${PREFIX} -i pattern"
   1201     End
   1202 
   1203     It 'reports a lack of argument'
   1204       cat() { @cat; }
   1205       When run cmd_grep
   1206       The output should be blank
   1207       The error should equal 'Usage: prg grep [GREP_OPTIONS] search-regex'
   1208       The status should equal 1
   1209     End
   1210   End
   1211 
   1212   Describe 'cmd_help'
   1213     COMMAND=help
   1214 
   1215     It 'displays version and usage without arguments'
   1216       cmd_usage() { mocklog cmd_usage "$@"; }
   1217       cmd_version() { mocklog cmd_version "$@"; }
   1218       expected_output() { %text
   1219         #|
   1220         #|Usage:
   1221       }
   1222       result() {
   1223         %text | @sed 's/\$$//'
   1224         #|$ cmd_version
   1225         #|$ cmd_usage yes     $
   1226       }
   1227       When call cmd_help
   1228       The status should be success
   1229       The output should equal "$(expected_output)"
   1230       The error should equal "$(result)"
   1231     End
   1232 
   1233     It 'displays only usage with arguments'
   1234       cmd_usage() { mocklog cmd_usage "$@"; }
   1235       cmd_version() { mocklog cmd_version "$@"; }
   1236       When call cmd_help foo bar
   1237       The status should be success
   1238       The output should be blank
   1239       The error should equal '$ cmd_usage yes  foo bar'
   1240     End
   1241   End
   1242 
   1243   Describe 'cmd_init'
   1244     COMMAND=init
   1245 
   1246     It 'initializes the whole store'
   1247       result() {
   1248         %text | @sed 's/\$$//'
   1249         #|$ check_sneaky_path $
   1250         #|$ do_init  recipient-1 recipient-2
   1251         #|DECISION=default
   1252         #|OVERWRITE=yes
   1253       }
   1254       When call cmd_init recipient-1 recipient-2
   1255       The status should be success
   1256       The output should be blank
   1257       The error should equal "$(result)"
   1258     End
   1259 
   1260     It 'initializes the whole store conservatively with a long option'
   1261       result() {
   1262         %text | @sed 's/\$$//'
   1263         #|$ check_sneaky_path $
   1264         #|$ do_init  recipient-1 recipient-2
   1265         #|DECISION=keep
   1266         #|OVERWRITE=yes
   1267       }
   1268       When call cmd_init --keep recipient-1 recipient-2
   1269       The status should be success
   1270       The output should be blank
   1271       The error should equal "$(result)"
   1272     End
   1273 
   1274     It 'initializes the whole store conservatively with a short option'
   1275       result() {
   1276         %text | @sed 's/\$$//'
   1277         #|$ check_sneaky_path $
   1278         #|$ do_init  recipient-1 recipient-2
   1279         #|DECISION=keep
   1280         #|OVERWRITE=yes
   1281       }
   1282       When call cmd_init -k recipient-1 recipient-2
   1283       The status should be success
   1284       The output should be blank
   1285       The error should equal "$(result)"
   1286     End
   1287 
   1288     It 'initializes the whole store interactively with a long option'
   1289       result() {
   1290         %text | @sed 's/\$$//'
   1291         #|$ check_sneaky_path $
   1292         #|$ do_init  recipient-1 recipient-2
   1293         #|DECISION=interactive
   1294         #|OVERWRITE=yes
   1295       }
   1296       When call cmd_init --interactive recipient-1 recipient-2
   1297       The status should be success
   1298       The output should be blank
   1299       The error should equal "$(result)"
   1300     End
   1301 
   1302     It 'initializes the whole store interactively with a short option'
   1303       result() {
   1304         %text | @sed 's/\$$//'
   1305         #|$ check_sneaky_path $
   1306         #|$ do_init  recipient-1 recipient-2
   1307         #|DECISION=interactive
   1308         #|OVERWRITE=yes
   1309       }
   1310       When call cmd_init -i recipient-1 recipient-2
   1311       The status should be success
   1312       The output should be blank
   1313       The error should equal "$(result)"
   1314     End
   1315 
   1316     It 'initializes a subdirectory with a collapsed long option'
   1317       result() {
   1318         %text
   1319         #|$ check_sneaky_path sub
   1320         #|$ do_init sub recipient
   1321         #|DECISION=default
   1322         #|OVERWRITE=yes
   1323       }
   1324       When call cmd_init --path=sub recipient
   1325       The status should be success
   1326       The output should be blank
   1327       The error should equal "$(result)"
   1328     End
   1329 
   1330     It 'initializes a subdirectory with an expanded long option'
   1331       result() {
   1332         %text
   1333         #|$ check_sneaky_path sub
   1334         #|$ do_init sub recipient
   1335         #|DECISION=default
   1336         #|OVERWRITE=yes
   1337       }
   1338       When call cmd_init --path sub recipient
   1339       The status should be success
   1340       The output should be blank
   1341       The error should equal "$(result)"
   1342     End
   1343 
   1344     It 'initializes a subdirectory with a collapsed short option'
   1345       result() {
   1346         %text
   1347         #|$ check_sneaky_path sub
   1348         #|$ do_init sub recipient
   1349         #|DECISION=default
   1350         #|OVERWRITE=yes
   1351       }
   1352       When call cmd_init -psub recipient
   1353       The status should be success
   1354       The output should be blank
   1355       The error should equal "$(result)"
   1356     End
   1357 
   1358     It 'initializes a subdirectory with an expanded short option'
   1359       result() {
   1360         %text
   1361         #|$ check_sneaky_path sub
   1362         #|$ do_init sub recipient
   1363         #|DECISION=default
   1364         #|OVERWRITE=yes
   1365       }
   1366       When call cmd_init -p sub recipient
   1367       The status should be success
   1368       The output should be blank
   1369       The error should equal "$(result)"
   1370     End
   1371 
   1372     It 'interactively initializes a directory with collapsed short options'
   1373       result() {
   1374         %text
   1375         #|$ check_sneaky_path sub
   1376         #|$ do_init sub recipient
   1377         #|DECISION=interactive
   1378         #|OVERWRITE=yes
   1379       }
   1380       When call cmd_init -ipsub recipient
   1381       The status should be success
   1382       The output should be blank
   1383       The error should equal "$(result)"
   1384     End
   1385 
   1386     It 'conservatively initializes a directory with long options'
   1387       result() {
   1388         %text
   1389         #|$ check_sneaky_path sub
   1390         #|$ do_init sub recipient
   1391         #|DECISION=keep
   1392         #|OVERWRITE=yes
   1393       }
   1394       When call cmd_init --path sub --keep recipient
   1395       The status should be success
   1396       The output should be blank
   1397       The error should equal "$(result)"
   1398     End
   1399 
   1400     It 'de-initializes a subdirectory'
   1401       result() {
   1402         %text
   1403         #|$ check_sneaky_path sub
   1404         #|$ do_deinit sub
   1405         #|DECISION=default
   1406       }
   1407       When call cmd_init -p sub ''
   1408       The status should be success
   1409       The output should be blank
   1410       The error should equal "$(result)"
   1411     End
   1412 
   1413     It 'supports recipients starting with dash'
   1414       result() {
   1415         %text | @sed 's/\$$//'
   1416         #|$ check_sneaky_path $
   1417         #|$ do_init  -recipient
   1418         #|DECISION=default
   1419         #|OVERWRITE=yes
   1420       }
   1421       When call cmd_init -- -recipient
   1422       The status should be success
   1423       The output should be blank
   1424       The error should equal "$(result)"
   1425     End
   1426 
   1427     usage_text() { %text
   1428       #|Usage: prg init [--interactive,-i | --keep,-k ]
   1429       #|                [--path=subfolder,-p subfolder] age-recipient ...
   1430     }
   1431 
   1432     It 'reports a bad option'
   1433       cat() { @cat; }
   1434       When run cmd_init -q arg
   1435       The output should be blank
   1436       The error should equal "$(usage_text)"
   1437       The status should equal 1
   1438     End
   1439 
   1440     It 'reports conflicting options (`-i` then `-k`)'
   1441       cat() { @cat; }
   1442       When run cmd_init -ik arg
   1443       The output should be blank
   1444       The error should equal "$(usage_text)"
   1445       The status should equal 1
   1446     End
   1447 
   1448     It 'reports conflicting options (`-k` then `-i`)'
   1449       cat() { @cat; }
   1450       When run cmd_init --keep --interactive arg
   1451       The output should be blank
   1452       The error should equal "$(usage_text)"
   1453       The status should equal 1
   1454     End
   1455 
   1456     It 'reports a missing recipient'
   1457       cat() { @cat; }
   1458       When run cmd_init -p sub
   1459       The output should be blank
   1460       The error should equal "$(usage_text)"
   1461       The status should equal 1
   1462     End
   1463 
   1464     It 'reports a missing path'
   1465       cat() { @cat; }
   1466       When run cmd_init -p
   1467       The output should be blank
   1468       The error should equal "$(usage_text)"
   1469       The status should equal 1
   1470     End
   1471 
   1472     It 'reports a lack of argument'
   1473       cat() { @cat; }
   1474       When run cmd_init
   1475       The output should be blank
   1476       The error should equal "$(usage_text)"
   1477       The status should equal 1
   1478     End
   1479   End
   1480 
   1481   Describe 'cmd_insert'
   1482     COMMAND=insert
   1483 
   1484     It 'inserts a few new entries'
   1485       result() {
   1486         %text
   1487         #|$ check_sneaky_path secret1
   1488         #|$ check_sneaky_path secret2
   1489         #|$ do_insert secret1
   1490         #|ECHO=no
   1491         #|MULTILINE=no
   1492         #|OVERWRITE=no
   1493         #|$ do_insert secret2
   1494         #|ECHO=no
   1495         #|MULTILINE=no
   1496         #|OVERWRITE=no
   1497       }
   1498       When call cmd_insert secret1 secret2
   1499       The status should be success
   1500       The output should be blank
   1501       The error should equal "$(result)"
   1502     End
   1503 
   1504     It 'inserts a new flag-like entry'
   1505       result() {
   1506         %text
   1507         #|$ check_sneaky_path -c
   1508         #|$ do_insert -c
   1509         #|ECHO=no
   1510         #|MULTILINE=no
   1511         #|OVERWRITE=no
   1512       }
   1513       When call cmd_insert -- -c
   1514       The status should be success
   1515       The output should be blank
   1516       The error should equal "$(result)"
   1517     End
   1518 
   1519     It 'inserts a new entry with echo (short option)'
   1520       result() {
   1521         %text
   1522         #|$ check_sneaky_path secret
   1523         #|$ do_insert secret
   1524         #|ECHO=yes
   1525         #|MULTILINE=no
   1526         #|OVERWRITE=no
   1527       }
   1528       When call cmd_insert -e secret
   1529       The status should be success
   1530       The output should be blank
   1531       The error should equal "$(result)"
   1532     End
   1533 
   1534     It 'inserts a new entry with echo (long option)'
   1535       result() {
   1536         %text
   1537         #|$ check_sneaky_path secret
   1538         #|$ do_insert secret
   1539         #|ECHO=yes
   1540         #|MULTILINE=no
   1541         #|OVERWRITE=no
   1542       }
   1543       When call cmd_insert --echo secret
   1544       The status should be success
   1545       The output should be blank
   1546       The error should equal "$(result)"
   1547     End
   1548 
   1549     It 'forcefully inserts a new entry with echo (short option)'
   1550       result() {
   1551         %text
   1552         #|$ check_sneaky_path secret
   1553         #|$ do_insert secret
   1554         #|ECHO=yes
   1555         #|MULTILINE=no
   1556         #|OVERWRITE=yes
   1557       }
   1558       When call cmd_insert -fe secret
   1559       The status should be success
   1560       The output should be blank
   1561       The error should equal "$(result)"
   1562     End
   1563 
   1564     It 'forcefully inserts a new entry with echo (short options)'
   1565       result() {
   1566         %text
   1567         #|$ check_sneaky_path secret
   1568         #|$ do_insert secret
   1569         #|ECHO=yes
   1570         #|MULTILINE=no
   1571         #|OVERWRITE=yes
   1572       }
   1573       When call cmd_insert -e -f secret
   1574       The status should be success
   1575       The output should be blank
   1576       The error should equal "$(result)"
   1577     End
   1578 
   1579     It 'forcefully inserts a new entry with echo (long option)'
   1580       result() {
   1581         %text
   1582         #|$ check_sneaky_path secret
   1583         #|$ do_insert secret
   1584         #|ECHO=yes
   1585         #|MULTILINE=no
   1586         #|OVERWRITE=yes
   1587       }
   1588       When call cmd_insert --force --echo secret
   1589       The status should be success
   1590       The output should be blank
   1591       The error should equal "$(result)"
   1592     End
   1593 
   1594     It 'inserts a new multiline entry (short option)'
   1595       result() {
   1596         %text
   1597         #|$ check_sneaky_path secret
   1598         #|$ do_insert secret
   1599         #|ECHO=no
   1600         #|MULTILINE=yes
   1601         #|OVERWRITE=no
   1602       }
   1603       When call cmd_insert -m secret
   1604       The status should be success
   1605       The output should be blank
   1606       The error should equal "$(result)"
   1607     End
   1608 
   1609     It 'inserts a new multiline entry (long option)'
   1610       result() {
   1611         %text
   1612         #|$ check_sneaky_path secret
   1613         #|$ do_insert secret
   1614         #|ECHO=no
   1615         #|MULTILINE=yes
   1616         #|OVERWRITE=no
   1617       }
   1618       When call cmd_insert --multiline secret
   1619       The status should be success
   1620       The output should be blank
   1621       The error should equal "$(result)"
   1622     End
   1623 
   1624     It 'forcefully inserts a new multiline entry (short option)'
   1625       result() {
   1626         %text
   1627         #|$ check_sneaky_path secret
   1628         #|$ do_insert secret
   1629         #|ECHO=no
   1630         #|MULTILINE=yes
   1631         #|OVERWRITE=yes
   1632       }
   1633       When call cmd_insert -mf secret
   1634       The status should be success
   1635       The output should be blank
   1636       The error should equal "$(result)"
   1637     End
   1638 
   1639     It 'forcefully inserts a new multiline entry (short options)'
   1640       result() {
   1641         %text
   1642         #|$ check_sneaky_path secret
   1643         #|$ do_insert secret
   1644         #|ECHO=no
   1645         #|MULTILINE=yes
   1646         #|OVERWRITE=yes
   1647       }
   1648       When call cmd_insert -m -f secret
   1649       The status should be success
   1650       The output should be blank
   1651       The error should equal "$(result)"
   1652     End
   1653 
   1654     It 'forcefully inserts a new multiline entry (long option)'
   1655       result() {
   1656         %text
   1657         #|$ check_sneaky_path secret
   1658         #|$ do_insert secret
   1659         #|ECHO=no
   1660         #|MULTILINE=yes
   1661         #|OVERWRITE=yes
   1662       }
   1663       When call cmd_insert --force --multiline secret
   1664       The status should be success
   1665       The output should be blank
   1666       The error should equal "$(result)"
   1667     End
   1668 
   1669     It 'reports a bad option'
   1670       cat() { @cat; }
   1671       When run cmd_insert -u secret
   1672       The output should be blank
   1673       The error should equal \
   1674         'Usage: prg insert [--echo,-e | --multiline,-m] [--force,-f] pass-name'
   1675       The status should equal 1
   1676     End
   1677 
   1678     It 'reports incompatible long options'
   1679       cat() { @cat; }
   1680       When run cmd_insert --multiline --echo secret
   1681       The output should be blank
   1682       The error should equal \
   1683         'Usage: prg insert [--echo,-e | --multiline,-m] [--force,-f] pass-name'
   1684       The status should equal 1
   1685     End
   1686 
   1687     It 'reports incompatible short options'
   1688       cat() { @cat; }
   1689       When run cmd_insert -em secret
   1690       The output should be blank
   1691       The error should equal \
   1692         'Usage: prg insert [--echo,-e | --multiline,-m] [--force,-f] pass-name'
   1693       The status should equal 1
   1694     End
   1695 
   1696     It 'reports a lack of argument'
   1697       cat() { @cat; }
   1698       When run cmd_insert
   1699       The output should be blank
   1700       The error should equal \
   1701         'Usage: prg insert [--echo,-e | --multiline,-m] [--force,-f] pass-name'
   1702       The status should equal 1
   1703     End
   1704   End
   1705 
   1706   Describe 'cmd_list_or_show'
   1707     COMMAND=
   1708 
   1709     It 'lists the whole store as a list'
   1710       result() {
   1711         %text | @sed 's/\$$//'
   1712         #|$ do_list_or_show $
   1713         #|LIST_VIEW=yes
   1714         #|SELECTED_LINE=1
   1715         #|SHOW=text
   1716       }
   1717       When call cmd_list_or_show -r
   1718       The status should be success
   1719       The output should be blank
   1720       The error should equal "$(result)"
   1721     End
   1722 
   1723     It 'lists the whole store as a tree'
   1724       result() {
   1725         %text | @sed 's/\$$//'
   1726         #|$ do_list_or_show $
   1727         #|LIST_VIEW=no
   1728         #|SELECTED_LINE=1
   1729         #|SHOW=text
   1730       }
   1731       When call cmd_list_or_show
   1732       The status should be success
   1733       The output should be blank
   1734       The error should equal "$(result)"
   1735     End
   1736 
   1737     It 'shows multiple entries'
   1738       result() {
   1739         %text
   1740         #|$ check_sneaky_path arg1
   1741         #|$ check_sneaky_path arg2
   1742         #|$ check_sneaky_path arg3
   1743         #|$ do_list_or_show arg1
   1744         #|LIST_VIEW=no
   1745         #|SELECTED_LINE=1
   1746         #|SHOW=text
   1747         #|$ do_list_or_show arg2
   1748         #|LIST_VIEW=no
   1749         #|SELECTED_LINE=1
   1750         #|SHOW=text
   1751         #|$ do_list_or_show arg3
   1752         #|LIST_VIEW=no
   1753         #|SELECTED_LINE=1
   1754         #|SHOW=text
   1755       }
   1756       When call cmd_list_or_show arg1 arg2 arg3
   1757       The status should be success
   1758       The output should be blank
   1759       The error should equal "$(result)"
   1760     End
   1761 
   1762     It 'shows a flag-like entry'
   1763       result() {
   1764         %text
   1765         #|$ check_sneaky_path -c
   1766         #|$ do_list_or_show -c
   1767         #|LIST_VIEW=no
   1768         #|SELECTED_LINE=1
   1769         #|SHOW=text
   1770       }
   1771       When call cmd_list_or_show -- -c
   1772       The status should be success
   1773       The output should be blank
   1774       The error should equal "$(result)"
   1775     End
   1776 
   1777     It 'copies an entry into the clipboard (short option)'
   1778       result() {
   1779         %text
   1780         #|$ check_sneaky_path arg
   1781         #|$ do_list_or_show arg
   1782         #|LIST_VIEW=no
   1783         #|SELECTED_LINE=1
   1784         #|SHOW=clip
   1785       }
   1786       When call cmd_list_or_show -c arg
   1787       The status should be success
   1788       The output should be blank
   1789       The error should equal "$(result)"
   1790     End
   1791 
   1792     It 'copies an entry into the clipboard (long option)'
   1793       result() {
   1794         %text
   1795         #|$ check_sneaky_path arg
   1796         #|$ do_list_or_show arg
   1797         #|LIST_VIEW=no
   1798         #|SELECTED_LINE=1
   1799         #|SHOW=clip
   1800       }
   1801       When call cmd_list_or_show --clip arg
   1802       The status should be success
   1803       The output should be blank
   1804       The error should equal "$(result)"
   1805     End
   1806 
   1807     It 'copies a line of an entry into the clipboard (short option)'
   1808       result() {
   1809         %text
   1810         #|$ check_sneaky_path arg
   1811         #|$ do_list_or_show arg
   1812         #|LIST_VIEW=no
   1813         #|SELECTED_LINE=2
   1814         #|SHOW=clip
   1815       }
   1816       When call cmd_list_or_show -c2 arg
   1817       The status should be success
   1818       The output should be blank
   1819       The error should equal "$(result)"
   1820     End
   1821 
   1822     It 'copies a line of an entry into the clipboard (short option)'
   1823       result() {
   1824         %text
   1825         #|$ check_sneaky_path arg
   1826         #|$ do_list_or_show arg
   1827         #|LIST_VIEW=no
   1828         #|SELECTED_LINE=2
   1829         #|SHOW=clip
   1830       }
   1831       When call cmd_list_or_show --clip=2 arg
   1832       The status should be success
   1833       The output should be blank
   1834       The error should equal "$(result)"
   1835     End
   1836 
   1837     It 'shows an entry as a QR-code (short option)'
   1838       result() {
   1839         %text
   1840         #|$ check_sneaky_path arg
   1841         #|$ do_list_or_show arg
   1842         #|LIST_VIEW=no
   1843         #|SELECTED_LINE=1
   1844         #|SHOW=qrcode
   1845       }
   1846       When call cmd_list_or_show -q arg
   1847       The status should be success
   1848       The output should be blank
   1849       The error should equal "$(result)"
   1850     End
   1851 
   1852     It 'shows an entry as a QR-code (long option)'
   1853       result() {
   1854         %text
   1855         #|$ check_sneaky_path arg
   1856         #|$ do_list_or_show arg
   1857         #|LIST_VIEW=no
   1858         #|SELECTED_LINE=1
   1859         #|SHOW=qrcode
   1860       }
   1861       When call cmd_list_or_show --qrcode arg
   1862       The status should be success
   1863       The output should be blank
   1864       The error should equal "$(result)"
   1865     End
   1866 
   1867     It 'shows the line of an entry as a QR-code (short option)'
   1868       result() {
   1869         %text
   1870         #|$ check_sneaky_path arg
   1871         #|$ do_list_or_show arg
   1872         #|LIST_VIEW=no
   1873         #|SELECTED_LINE=3
   1874         #|SHOW=qrcode
   1875       }
   1876       When call cmd_list_or_show -q3 arg
   1877       The status should be success
   1878       The output should be blank
   1879       The error should equal "$(result)"
   1880     End
   1881 
   1882     It 'shows the line of an entry as a QR-code (long option)'
   1883       result() {
   1884         %text
   1885         #|$ check_sneaky_path arg
   1886         #|$ do_list_or_show arg
   1887         #|LIST_VIEW=no
   1888         #|SELECTED_LINE=3
   1889         #|SHOW=qrcode
   1890       }
   1891       When call cmd_list_or_show --qrcode=3 arg
   1892       The status should be success
   1893       The output should be blank
   1894       The error should equal "$(result)"
   1895     End
   1896 
   1897     It 'shows an entry as a raw list (shot option)'
   1898       result() {
   1899         %text
   1900         #|$ check_sneaky_path arg
   1901         #|$ do_list_or_show arg
   1902         #|LIST_VIEW=yes
   1903         #|SELECTED_LINE=1
   1904         #|SHOW=text
   1905       }
   1906       When call cmd_list_or_show -r arg
   1907       The status should be success
   1908       The output should be blank
   1909       The error should equal "$(result)"
   1910     End
   1911 
   1912     It 'shows an entry as a raw list (long option)'
   1913       result() {
   1914         %text
   1915         #|$ check_sneaky_path arg
   1916         #|$ do_list_or_show arg
   1917         #|LIST_VIEW=yes
   1918         #|SELECTED_LINE=1
   1919         #|SHOW=text
   1920       }
   1921       When call cmd_list_or_show --raw arg
   1922       The status should be success
   1923       The output should be blank
   1924       The error should equal "$(result)"
   1925     End
   1926 
   1927     It 'reports incompatible show options'
   1928       cat() { @cat; }
   1929       result() { %text
   1930         #|Usage: prg [list] [--raw,-r] [subfolder]
   1931         #|       prg [show] [--clip[=line-number],-c[line-number] |
   1932         #|                   --qrcode[=line-number],-q[line-number]] pass-name
   1933       }
   1934       When run cmd_list_or_show -q -c arg
   1935       The output should be blank
   1936       The error should equal "$(result)"
   1937       The status should equal 1
   1938     End
   1939 
   1940     It 'reports a bad option for both commands'
   1941       cat() { @cat; }
   1942       result() { %text
   1943         #|Usage: prg [list] [--raw,-r] [subfolder]
   1944         #|       prg [show] [--clip[=line-number],-c[line-number] |
   1945         #|                   --qrcode[=line-number],-q[line-number]] pass-name
   1946       }
   1947       When run cmd_list_or_show -f arg
   1948       The output should be blank
   1949       The error should equal "$(result)"
   1950       The status should equal 1
   1951     End
   1952 
   1953     It 'reports a bad option for list command'
   1954       COMMAND=list
   1955       cat() { @cat; }
   1956       result() { %text
   1957         #|Usage: prg [list] [--raw,-r] [subfolder]
   1958       }
   1959       When run cmd_list_or_show -f arg
   1960       The output should be blank
   1961       The error should equal "$(result)"
   1962       The status should equal 1
   1963     End
   1964 
   1965     It 'reports a bad option for show command'
   1966       COMMAND=show
   1967       cat() { @cat; }
   1968       result() { %text
   1969         #|Usage: prg [show] [--clip[=line-number],-c[line-number] |
   1970         #|                   --qrcode[=line-number],-q[line-number]] pass-name
   1971       }
   1972       When run cmd_list_or_show -f arg
   1973       The output should be blank
   1974       The error should equal "$(result)"
   1975       The status should equal 1
   1976     End
   1977   End
   1978 
   1979   Describe 'cmd_move'
   1980     COMMAND=move
   1981 
   1982     It 'moves multiple files'
   1983       result() {
   1984         %text
   1985         #|$ check_sneaky_path src1
   1986         #|$ check_sneaky_path src2
   1987         #|$ check_sneaky_path src3
   1988         #|$ check_sneaky_path dest
   1989         #|$ do_copy_move src1 dest/
   1990         #|ACTION=Move
   1991         #|DECISION=default
   1992         #|OVERWRITE=no
   1993         #|SCM_ACTION=scm_mv
   1994         #|$ do_copy_move src2 dest/
   1995         #|ACTION=Move
   1996         #|DECISION=default
   1997         #|OVERWRITE=no
   1998         #|SCM_ACTION=scm_mv
   1999         #|$ do_copy_move src3 dest/
   2000         #|ACTION=Move
   2001         #|DECISION=default
   2002         #|OVERWRITE=no
   2003         #|SCM_ACTION=scm_mv
   2004       }
   2005       When call cmd_move src1 src2 src3 dest
   2006       The status should be success
   2007       The output should be blank
   2008       The error should equal "$(result)"
   2009     End
   2010 
   2011     It 'moves forcefully with a long option'
   2012       result() {
   2013         %text
   2014         #|$ check_sneaky_path src
   2015         #|$ check_sneaky_path dest
   2016         #|$ do_copy_move src dest
   2017         #|ACTION=Move
   2018         #|DECISION=default
   2019         #|OVERWRITE=yes
   2020         #|SCM_ACTION=scm_mv
   2021       }
   2022       When call cmd_move --force src dest
   2023       The status should be success
   2024       The output should be blank
   2025       The error should equal "$(result)"
   2026     End
   2027 
   2028     It 'moves forcefully with a short option'
   2029       result() {
   2030         %text
   2031         #|$ check_sneaky_path src
   2032         #|$ check_sneaky_path dest
   2033         #|$ do_copy_move src dest
   2034         #|ACTION=Move
   2035         #|DECISION=default
   2036         #|OVERWRITE=yes
   2037         #|SCM_ACTION=scm_mv
   2038       }
   2039       When call cmd_move -f src dest
   2040       The status should be success
   2041       The output should be blank
   2042       The error should equal "$(result)"
   2043     End
   2044 
   2045     It 'always reencrypts with a long option'
   2046       result() {
   2047         %text
   2048         #|$ check_sneaky_path src
   2049         #|$ check_sneaky_path dest
   2050         #|$ do_copy_move src dest
   2051         #|ACTION=Move
   2052         #|DECISION=force
   2053         #|OVERWRITE=no
   2054         #|SCM_ACTION=scm_mv
   2055       }
   2056       When call cmd_move --reencrypt src dest
   2057       The status should be success
   2058       The output should be blank
   2059       The error should equal "$(result)"
   2060     End
   2061 
   2062     It 'always reencrypts with a short option'
   2063       result() {
   2064         %text
   2065         #|$ check_sneaky_path src
   2066         #|$ check_sneaky_path dest
   2067         #|$ do_copy_move src dest
   2068         #|ACTION=Move
   2069         #|DECISION=force
   2070         #|OVERWRITE=no
   2071         #|SCM_ACTION=scm_mv
   2072       }
   2073       When call cmd_move -e src dest
   2074       The status should be success
   2075       The output should be blank
   2076       The error should equal "$(result)"
   2077     End
   2078 
   2079     It 'interactively reencrypts with a long option'
   2080       result() {
   2081         %text
   2082         #|$ check_sneaky_path src
   2083         #|$ check_sneaky_path dest
   2084         #|$ do_copy_move src dest
   2085         #|ACTION=Move
   2086         #|DECISION=interactive
   2087         #|OVERWRITE=no
   2088         #|SCM_ACTION=scm_mv
   2089       }
   2090       When call cmd_move --interactive src dest
   2091       The status should be success
   2092       The output should be blank
   2093       The error should equal "$(result)"
   2094     End
   2095 
   2096     It 'interactively reencrypts with a short option'
   2097       result() {
   2098         %text
   2099         #|$ check_sneaky_path src
   2100         #|$ check_sneaky_path dest
   2101         #|$ do_copy_move src dest
   2102         #|ACTION=Move
   2103         #|DECISION=interactive
   2104         #|OVERWRITE=no
   2105         #|SCM_ACTION=scm_mv
   2106       }
   2107       When call cmd_move -i src dest
   2108       The status should be success
   2109       The output should be blank
   2110       The error should equal "$(result)"
   2111     End
   2112 
   2113     It 'never reencrypts with a long option'
   2114       result() {
   2115         %text
   2116         #|$ check_sneaky_path src
   2117         #|$ check_sneaky_path dest
   2118         #|$ do_copy_move src dest
   2119         #|ACTION=Move
   2120         #|DECISION=keep
   2121         #|OVERWRITE=no
   2122         #|SCM_ACTION=scm_mv
   2123       }
   2124       When call cmd_move --keep src dest
   2125       The status should be success
   2126       The output should be blank
   2127       The error should equal "$(result)"
   2128     End
   2129 
   2130     It 'never reencrypts with a short option'
   2131       result() {
   2132         %text
   2133         #|$ check_sneaky_path src
   2134         #|$ check_sneaky_path dest
   2135         #|$ do_copy_move src dest
   2136         #|ACTION=Move
   2137         #|DECISION=keep
   2138         #|OVERWRITE=no
   2139         #|SCM_ACTION=scm_mv
   2140       }
   2141       When call cmd_move -k src dest
   2142       The status should be success
   2143       The output should be blank
   2144       The error should equal "$(result)"
   2145     End
   2146 
   2147     It 'moves a file named like a flag'
   2148       result() {
   2149         %text
   2150         #|$ check_sneaky_path -s
   2151         #|$ check_sneaky_path dest
   2152         #|$ do_copy_move -s dest
   2153         #|ACTION=Move
   2154         #|DECISION=default
   2155         #|OVERWRITE=no
   2156         #|SCM_ACTION=scm_mv
   2157       }
   2158       When call cmd_move -- -s dest
   2159       The status should be success
   2160       The output should be blank
   2161       The error should equal "$(result)"
   2162     End
   2163 
   2164     usage_text() { %text
   2165       #|Usage: prg move [--reencrypt,-e | --interactive,-i | --keep,-k ]
   2166       #|                [--force,-f] old-path new-path
   2167     }
   2168 
   2169     It 'reports a bad option'
   2170       cat() { @cat; }
   2171       When run cmd_move -s arg
   2172       The output should be blank
   2173       The error should equal "$(usage_text)"
   2174       The status should equal 1
   2175     End
   2176 
   2177     It 'reports incompatible re-encryption options (-e and -i)'
   2178       cat() { @cat; }
   2179       When run cmd_move -ei src dest
   2180       The output should be blank
   2181       The error should equal "$(usage_text)"
   2182       The status should equal 1
   2183     End
   2184 
   2185     It 'reports incompatible re-encryption options (-i and -k)'
   2186       cat() { @cat; }
   2187       When run cmd_move -ik src dest
   2188       The output should be blank
   2189       The error should equal "$(usage_text)"
   2190       The status should equal 1
   2191     End
   2192 
   2193     It 'reports incompatible re-encryption options (-k and -e)'
   2194       cat() { @cat; }
   2195       When run cmd_move -ke src dest
   2196       The output should be blank
   2197       The error should equal "$(usage_text)"
   2198       The status should equal 1
   2199     End
   2200 
   2201     It 'reports a lack of argument'
   2202       cat() { @cat; }
   2203       When run cmd_move src
   2204       The output should be blank
   2205       The error should equal "$(usage_text)"
   2206       The status should equal 1
   2207     End
   2208   End
   2209 
   2210   Describe 'cmd_random'
   2211     COMMAND=generate
   2212     GENERATED_LENGTH=25
   2213 
   2214     random_chars() { mocklog random_chars "$@"; }
   2215 
   2216     It 'generates random characters with default parameters'
   2217       When run cmd_random
   2218       The status should be success
   2219       The error should equal \
   2220         "$ random_chars ${GENERATED_LENGTH} ${CHARACTER_SET}"
   2221     End
   2222 
   2223     It 'generates random characters with default character set'
   2224       When run cmd_random 8
   2225       The status should be success
   2226       The error should equal "$ random_chars 8 ${CHARACTER_SET}"
   2227     End
   2228 
   2229     It 'generates random characters with the given arguments'
   2230       When run cmd_random 8 a-z
   2231       The status should be success
   2232       The error should equal "$ random_chars 8 a-z"
   2233     End
   2234 
   2235     It 'reports too many arguments'
   2236       cat() { @cat; }
   2237       When run cmd_random 1 2 3
   2238       The output should be blank
   2239       The error should equal 'Usage: prg random [pass-length [character-set]]'
   2240       The status should equal 1
   2241     End
   2242   End
   2243 
   2244   Describe 'cmd_reencrypt'
   2245     COMMAND=reencrypt
   2246 
   2247     It 're-encrypts multiple files and directories'
   2248       result() {
   2249         %text
   2250         #|$ check_sneaky_path file-1
   2251         #|$ check_sneaky_path dir/
   2252         #|$ check_sneaky_path sub/file-2
   2253         #|$ do_reencrypt file-1
   2254         #|DECISION=default
   2255         #|RECURSIVE=no
   2256         #|$ do_reencrypt dir/
   2257         #|DECISION=default
   2258         #|RECURSIVE=no
   2259         #|$ do_reencrypt sub/file-2
   2260         #|DECISION=default
   2261         #|RECURSIVE=no
   2262       }
   2263       When call cmd_reencrypt file-1 dir/ sub/file-2
   2264       The status should be success
   2265       The output should be blank
   2266       The error should equal "$(result)"
   2267     End
   2268 
   2269     It 'deeply re-encrypts with a long option'
   2270       result() {
   2271         %text
   2272         #|$ check_sneaky_path arg
   2273         #|$ do_reencrypt arg
   2274         #|DECISION=default
   2275         #|RECURSIVE=yes
   2276       }
   2277       When call cmd_reencrypt --deep arg
   2278       The status should be success
   2279       The output should be blank
   2280       The error should equal "$(result)"
   2281     End
   2282 
   2283     It 'deeply re-encrypts with a short option'
   2284       result() {
   2285         %text
   2286         #|$ check_sneaky_path arg
   2287         #|$ do_reencrypt arg
   2288         #|DECISION=default
   2289         #|RECURSIVE=yes
   2290       }
   2291       When call cmd_reencrypt -d arg
   2292       The status should be success
   2293       The output should be blank
   2294       The error should equal "$(result)"
   2295     End
   2296 
   2297     It 'deeply and interactively re-encrypts with short options'
   2298       result() {
   2299         %text
   2300         #|$ check_sneaky_path arg
   2301         #|$ do_reencrypt arg
   2302         #|DECISION=interactive
   2303         #|RECURSIVE=yes
   2304       }
   2305       When call cmd_reencrypt -di arg
   2306       The status should be success
   2307       The output should be blank
   2308       The error should equal "$(result)"
   2309     End
   2310 
   2311     It 'interactively re-encrypts with a long option'
   2312       result() {
   2313         %text
   2314         #|$ check_sneaky_path arg
   2315         #|$ do_reencrypt arg
   2316         #|DECISION=interactive
   2317         #|RECURSIVE=no
   2318       }
   2319       When call cmd_reencrypt --interactive arg
   2320       The status should be success
   2321       The output should be blank
   2322       The error should equal "$(result)"
   2323     End
   2324 
   2325     It 'interactively re-encrypts with a short option'
   2326       result() {
   2327         %text
   2328         #|$ check_sneaky_path arg
   2329         #|$ do_reencrypt arg
   2330         #|DECISION=interactive
   2331         #|RECURSIVE=no
   2332       }
   2333       When call cmd_reencrypt -i arg
   2334       The status should be success
   2335       The output should be blank
   2336       The error should equal "$(result)"
   2337     End
   2338 
   2339     It 'interactively and deeply re-encrypts with short options'
   2340       result() {
   2341         %text
   2342         #|$ check_sneaky_path arg
   2343         #|$ do_reencrypt arg
   2344         #|DECISION=interactive
   2345         #|RECURSIVE=yes
   2346       }
   2347       When call cmd_reencrypt -id arg
   2348       The status should be success
   2349       The output should be blank
   2350       The error should equal "$(result)"
   2351     End
   2352 
   2353     It 're-encrypts a file named like a flag'
   2354       result() {
   2355         %text
   2356         #|$ check_sneaky_path -s
   2357         #|$ do_reencrypt -s
   2358         #|DECISION=default
   2359         #|RECURSIVE=no
   2360       }
   2361       When call cmd_reencrypt -- -s
   2362       The status should be success
   2363       The output should be blank
   2364       The error should equal "$(result)"
   2365     End
   2366 
   2367     usage_text() { %text
   2368       #|Usage: prg reencrypt [--deep,-d] [--interactive,-i] pass-name|subfolder ...
   2369     }
   2370 
   2371     It 'reports a bad option'
   2372       cat() { @cat; }
   2373       When run cmd_reencrypt -s arg
   2374       The status should equal 1
   2375       The output should be blank
   2376       The error should equal "$(usage_text)"
   2377     End
   2378 
   2379     It 'reports a lack of argument'
   2380       cat() { @cat; }
   2381       When run cmd_reencrypt
   2382       The status should equal 1
   2383       The output should be blank
   2384       The error should equal "$(usage_text)"
   2385     End
   2386   End
   2387 
   2388   Describe 'cmd_usage'
   2389     COMMAND=usage
   2390     CLIP_TIME='$CLIP_TIME'
   2391     GENERATED_LENGTH='$GENERATED_LENGTH'
   2392     cat() { @cat; }
   2393 
   2394     It 'includes help about all commands'
   2395       When call cmd_usage
   2396       The status should be success
   2397       The output should include 'prg copy'
   2398       The output should include 'prg delete'
   2399       The output should include 'prg edit'
   2400       The output should include 'prg find'
   2401       The output should include 'prg generate'
   2402       The output should include 'prg git'
   2403       The output should include 'prg gitconfig'
   2404       The output should include 'prg grep'
   2405       The output should include 'prg help'
   2406       The output should include 'prg init'
   2407       The output should include 'prg insert'
   2408       The output should include 'prg [list]'
   2409       The output should include 'prg move'
   2410       The output should include 'prg random'
   2411       The output should include 'prg reencrypt'
   2412       The output should include 'prg [show]'
   2413       The output should include 'prg version'
   2414     End
   2415 
   2416     It 'displays terse help about the given commands'
   2417       When call cmd_usage no '> ' version edit version
   2418       The status should be success
   2419       The output should match pattern '*prg version*prg edit*prg version*'
   2420       The lines of output should equal 3
   2421     End
   2422 
   2423     It 'displays verbose help about the given commands'
   2424       When call cmd_usage yes '> ' version edit version
   2425       The status should be success
   2426       The output should match pattern \
   2427         '*prg version*Show*prg edit*Insert*prg version*Show*'
   2428       The lines of output should equal 6
   2429     End
   2430 
   2431     It 'rejects unknown commands'
   2432       When run cmd_usage no '> ' foo
   2433       The output should be blank
   2434       The error should equal 'cmd_usage: unknown command "foo"'
   2435       The status should equal 1
   2436     End
   2437   End
   2438 
   2439   Describe 'cmd_version'
   2440     COMMAND=version
   2441 
   2442     It 'shows the version box'
   2443       cat() { @cat; }
   2444       result() {
   2445         %text
   2446         #|==============================================
   2447         #|= pashage: age-backed POSIX password manager =
   2448         #|=                                            =
   2449         #|=                   v*
   2450         #|=                                            =
   2451         #|=            Natasha Kerensikova             =
   2452         #|=                                            =
   2453         #|=                 Based on:                  =
   2454         #|=   password-store  by Jason A. Donenfeld    =
   2455         #|=          passage  by Filippo Valsorda      =
   2456         #|=             pash  by Dylan Araps           =
   2457         #|==============================================
   2458       }
   2459       When call cmd_version
   2460       The status should be success
   2461       The output should match pattern "$(result)"
   2462     End
   2463   End
   2464 End