internal_spec.sh (9761B)
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 'glob_exists' 144 It 'answers y when the glob matches something' 145 When call glob_exists /* 146 The status should be success 147 The variable ANSWER should equal y 148 End 149 150 It 'answers n when the glob does not match anything' 151 When call glob_exists non-existent/* 152 The status should be success 153 The variable ANSWER should equal n 154 End 155 End 156 157 Describe 'set_LOCAL_RECIPIENT_FILE' 158 PREFIX="${SHELLSPEC_WORKDIR}/prefix/store" 159 setup() { 160 @mkdir -p "${PREFIX}/subdir/subsub" "${PREFIX}/special" 161 echo "Outside recipient" >"${PREFIX}/../.age-recipients" 162 echo "Toplevel recipient" >"${PREFIX}/.age-recipients" 163 echo "Subdir recipient" >"${PREFIX}/subdir/.age-recipients" 164 } 165 cat() { @cat "$@"; } 166 cleanup() { @rm -rf "${PREFIX}"; } 167 168 BeforeEach 'setup' 169 AfterEach 'cleanup' 170 171 It 'returns root from root' 172 When call set_LOCAL_RECIPIENT_FILE foo 173 The status should be success 174 The variable LOCAL_RECIPIENT_FILE should equal \ 175 "${PREFIX}/.age-recipients" 176 The variable LOCAL_RECIPIENTS should equal 'Toplevel recipient' 177 End 178 179 It 'returns root from unmarked subdirectory' 180 When call set_LOCAL_RECIPIENT_FILE special/foo 181 The status should be success 182 The variable LOCAL_RECIPIENT_FILE should equal \ 183 "${PREFIX}/.age-recipients" 184 The variable LOCAL_RECIPIENTS should equal 'Toplevel recipient' 185 End 186 187 It 'returns subdirectory from itself' 188 When call set_LOCAL_RECIPIENT_FILE subdir/foo 189 The status should be success 190 The variable LOCAL_RECIPIENT_FILE should equal \ 191 "${PREFIX}/subdir/.age-recipients" 192 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 193 End 194 195 It 'returns subdirectory from sub-subdirectory' 196 When call set_LOCAL_RECIPIENT_FILE subdir/subsub/foo 197 The status should be success 198 The variable LOCAL_RECIPIENT_FILE should equal \ 199 "${PREFIX}/subdir/.age-recipients" 200 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 201 End 202 203 setup() { 204 @mkdir -p "${PREFIX}/subdir/subsub" "${PREFIX}/special" 205 echo "Outside recipient" >"${PREFIX}/../.age-recipients" 206 echo "Subdir recipient" >"${PREFIX}/subdir/.age-recipients" 207 } 208 209 It 'returns nothing from empty root' 210 When call set_LOCAL_RECIPIENT_FILE foo 211 The status should be success 212 The variable LOCAL_RECIPIENT_FILE should equal '' 213 The variable LOCAL_RECIPIENTS should equal '' 214 End 215 216 It 'returns nothing from unmarked subdirectory below empty root' 217 When call set_LOCAL_RECIPIENT_FILE special/foo 218 The status should be success 219 The variable LOCAL_RECIPIENT_FILE should equal '' 220 The variable LOCAL_RECIPIENTS should equal '' 221 End 222 223 It 'returns subdirectory from itself even under empty root' 224 When call set_LOCAL_RECIPIENT_FILE subdir/foo 225 The status should be success 226 The variable LOCAL_RECIPIENT_FILE should equal \ 227 "${PREFIX}/subdir/.age-recipients" 228 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 229 End 230 231 It 'returns subdirectory from sub-subdirectory even under empty root' 232 When call set_LOCAL_RECIPIENT_FILE subdir/subsub/foo 233 The status should be success 234 The variable LOCAL_RECIPIENT_FILE should equal \ 235 "${PREFIX}/subdir/.age-recipients" 236 The variable LOCAL_RECIPIENTS should equal 'Subdir recipient' 237 End 238 End 239 240 Describe 'strlen' 241 It 'accepts an ASCII and returns its length' 242 When call strlen 'abc def' 243 The output should equal 7 244 End 245 246 It 'accepts an empty string and returns 0' 247 When call strlen '' 248 The output should equal 0 249 End 250 End 251 252 Describe 'yesno' 253 Describe 'Without stty' 254 It 'accepts an uppercase N' 255 Data 'N' 256 When call yesno 'prompt' 257 The status should be success 258 The output should equal 'prompt [y/n]' 259 The variable ANSWER should equal 'N' 260 End 261 262 It 'accepts an uppercase Y' 263 Data 'YES' 264 When call yesno 'prompt' 265 The status should be success 266 The output should equal 'prompt [y/n]' 267 The variable ANSWER should equal 'y' 268 End 269 End 270 271 Describe 'Dumb terminal with stty' 272 stty() { false; } 273 274 It 'accepts a lowercase N' 275 Data 'no' 276 When call yesno 'prompt' 277 The status should be success 278 The output should equal 'prompt [y/n]' 279 The variable ANSWER should equal 'n' 280 End 281 282 It 'accepts an uppercase Y' 283 Data 'Y' 284 When call yesno 'prompt' 285 The status should be success 286 The output should equal 'prompt [y/n]' 287 The variable ANSWER should equal 'y' 288 End 289 End 290 291 Describe 'Mocking a terminal' 292 setup() { 293 %putsn x >|"${SHELLSPEC_WORKDIR}/first-dd" 294 } 295 stty() { :; } 296 dd() { 297 if [ -f "${SHELLSPEC_WORKDIR}/first-dd" ]; then 298 %puts x 299 @rm "${SHELLSPEC_WORKDIR}/first-dd" 300 else 301 %puts y 302 fi 303 } 304 305 BeforeEach setup 306 307 It 'accepts a lowercase Y after bad input' 308 When call yesno 'prompt' 309 The status should be success 310 The output should equal 'prompt [y/n]' 311 The variable ANSWER should equal 'y' 312 End 313 End 314 End 315 End