internal_spec.sh (9378B)
1 # pashage - age-backed POSIX password manager 2 # Copyright (C) 2024 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 covers all internal helper functions, 19 # These functions are fundemantal so there is no need for mocking, 20 # except for the interactive path in `yesno`. 21 22 Describe 'Internal Helper Functions' 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 Describe 'check_sneaky_path' 31 It 'accept an empty path' 32 When run check_sneaky_path '' 33 The status should be success 34 The error should be blank 35 The output should be blank 36 End 37 38 It 'accepts a file name' 39 When run check_sneaky_path 'a' 40 The status should be success 41 The error should be blank 42 The output should be blank 43 End 44 45 It 'accepts an absolute path' 46 When run check_sneaky_path '/a/b/c' 47 The status should be success 48 The error should be blank 49 The output should be blank 50 End 51 52 It 'accepts a relative path' 53 When run check_sneaky_path 'a/b/c/' 54 The status should be success 55 The error should be blank 56 The output should be blank 57 End 58 59 It 'aborts when .. is a path component' 60 When run check_sneaky_path 'a/../b' 61 The error should equal 'Encountered path considered sneaky: "a/../b"' 62 The output should be blank 63 The status should equal 1 64 End 65 66 It 'aborts when .. is a path prefix' 67 When run check_sneaky_path '../a/b' 68 The error should equal 'Encountered path considered sneaky: "../a/b"' 69 The output should be blank 70 The status should equal 1 71 End 72 73 It 'aborts when .. is a path suffix' 74 When run check_sneaky_path '/a/..' 75 The error should equal 'Encountered path considered sneaky: "/a/.."' 76 The output should be blank 77 The status should equal 1 78 End 79 80 It 'aborts when .. is the whole path' 81 When run check_sneaky_path '..' 82 The error should equal 'Encountered path considered sneaky: ".."' 83 The output should be blank 84 The status should equal 1 85 End 86 End 87 88 Describe 'check_sneaky_paths' 89 It 'aborts when all paths are bad' 90 When run check_sneaky_paths ../a b/../c 91 The error should equal 'Encountered path considered sneaky: "../a"' 92 The output should be blank 93 The status should equal 1 94 End 95 96 It 'accepts several good paths' 97 When run check_sneaky_paths a b/c /d/e/f 98 The status should be success 99 The error should be blank 100 The output should be blank 101 End 102 103 It 'accepts an empty argument list' 104 When run check_sneaky_paths 105 The status should be success 106 The error should be blank 107 The output should be blank 108 End 109 110 It 'aborts when a single path is bad' 111 When run check_sneaky_paths a b/../c /d/e/f 112 The error should equal 'Encountered path considered sneaky: "b/../c"' 113 The output should be blank 114 The status should equal 1 115 End 116 End 117 118 Describe 'checked' 119 echo_ret() { printf '%s\n' "$1"; return $2; } 120 121 It 'aborts on command failure and reports it' 122 When run checked echo_ret 'it runs' 42 123 The output should equal 'it runs' 124 The error should equal 'Fatal(42): echo_ret it runs 42' 125 The status should equal 42 126 End 127 128 It 'continues silently when the command is successful' 129 When run checked echo_ret 'it runs' 0 130 The status should be success 131 The output should equal 'it runs' 132 The error should be blank 133 End 134 End 135 136 Specify 'die' 137 When run die Message Word 138 The error should equal 'Message Word' 139 The output should be blank 140 The status should equal 1 141 End 142 143 Describe 'set_LOCAL_RECIPIENT_FILE' 144 PREFIX="${SHELLSPEC_WORKDIR}/prefix/store" 145 setup() { 146 @mkdir -p "${PREFIX}/subdir/subsub" "${PREFIX}/special" 147 echo "Outside recipient" >"${PREFIX}/../.age-recipients" 148 echo "Toplevel recipient" >"${PREFIX}/.age-recipients" 149 echo "Subdir recipient" >"${PREFIX}/subdir/.age-recipients" 150 } 151 cat() { @cat "$@"; } 152 cleanup() { @rm -rf "${PREFIX}"; } 153 154 BeforeEach 'setup' 155 AfterEach 'cleanup' 156 157 It 'returns root from root' 158 When call set_LOCAL_RECIPIENT_FILE foo 159 The status should be success 160 The variable LOCAL_RECIPIENT_FILE should equal \ 161 "${PREFIX}/.age-recipients" 162 The variable LOCAL_RECIPIENTS should equal 'Toplevel recipient' 163 End 164 165 It 'returns root from unmarked subdirectory' 166 When call set_LOCAL_RECIPIENT_FILE special/foo 167 The status should be success 168 The variable LOCAL_RECIPIENT_FILE should equal \ 169 "${PREFIX}/.age-recipients" 170 The variable LOCAL_RECIPIENTS should equal 'Toplevel recipient' 171 End 172 173 It 'returns subdirectory from itself' 174 When call set_LOCAL_RECIPIENT_FILE subdir/foo 175 The status should be success 176 The variable LOCAL_RECIPIENT_FILE should equal \ 177 "${PREFIX}/subdir/.age-recipients" 178 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 179 End 180 181 It 'returns subdirectory from sub-subdirectory' 182 When call set_LOCAL_RECIPIENT_FILE subdir/subsub/foo 183 The status should be success 184 The variable LOCAL_RECIPIENT_FILE should equal \ 185 "${PREFIX}/subdir/.age-recipients" 186 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 187 End 188 189 setup() { 190 @mkdir -p "${PREFIX}/subdir/subsub" "${PREFIX}/special" 191 echo "Outside recipient" >"${PREFIX}/../.age-recipients" 192 echo "Subdir recipient" >"${PREFIX}/subdir/.age-recipients" 193 } 194 195 It 'returns nothing from empty root' 196 When call set_LOCAL_RECIPIENT_FILE foo 197 The status should be success 198 The variable LOCAL_RECIPIENT_FILE should equal '' 199 The variable LOCAL_RECIPIENTS should equal '' 200 End 201 202 It 'returns nothing from unmarked subdirectory below empty root' 203 When call set_LOCAL_RECIPIENT_FILE special/foo 204 The status should be success 205 The variable LOCAL_RECIPIENT_FILE should equal '' 206 The variable LOCAL_RECIPIENTS should equal '' 207 End 208 209 It 'returns subdirectory from itself even under empty root' 210 When call set_LOCAL_RECIPIENT_FILE subdir/foo 211 The status should be success 212 The variable LOCAL_RECIPIENT_FILE should equal \ 213 "${PREFIX}/subdir/.age-recipients" 214 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 215 End 216 217 It 'returns subdirectory from sub-subdirectory even under empty root' 218 When call set_LOCAL_RECIPIENT_FILE subdir/subsub/foo 219 The status should be success 220 The variable LOCAL_RECIPIENT_FILE should equal \ 221 "${PREFIX}/subdir/.age-recipients" 222 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 223 End 224 End 225 226 Describe 'strlen' 227 It 'accepts an ASCII and returns its length' 228 When call strlen 'abc def' 229 The output should equal 7 230 End 231 232 It 'accepts an empty string and returns 0' 233 When call strlen '' 234 The output should equal 0 235 End 236 End 237 238 Describe 'yesno' 239 Describe 'Without stty' 240 It 'accepts an uppercase N' 241 Data 'N' 242 When call yesno 'prompt' 243 The status should be success 244 The output should equal 'prompt [y/n]' 245 The variable ANSWER should equal 'N' 246 End 247 248 It 'accepts an uppercase Y' 249 Data 'YES' 250 When call yesno 'prompt' 251 The status should be success 252 The output should equal 'prompt [y/n]' 253 The variable ANSWER should equal 'y' 254 End 255 End 256 257 Describe 'Dumb terminal with stty' 258 stty() { false; } 259 260 It 'accepts a lowercase N' 261 Data 'no' 262 When call yesno 'prompt' 263 The status should be success 264 The output should equal 'prompt [y/n]' 265 The variable ANSWER should equal 'n' 266 End 267 268 It 'accepts an uppercase Y' 269 Data 'Y' 270 When call yesno 'prompt' 271 The status should be success 272 The output should equal 'prompt [y/n]' 273 The variable ANSWER should equal 'y' 274 End 275 End 276 277 Describe 'Mocking a terminal' 278 setup() { 279 %putsn x >|"${SHELLSPEC_WORKDIR}/first-dd" 280 } 281 stty() { :; } 282 dd() { 283 if [ -f "${SHELLSPEC_WORKDIR}/first-dd" ]; then 284 %puts x 285 @rm "${SHELLSPEC_WORKDIR}/first-dd" 286 else 287 %puts y 288 fi 289 } 290 291 BeforeEach setup 292 293 It 'accepts a lowercase Y after bad input' 294 When call yesno 'prompt' 295 The status should be success 296 The output should equal 'prompt [y/n]' 297 The variable ANSWER should equal 'y' 298 End 299 End 300 End 301 End