simplefiles

A lightweight C CGI web application for managing files.
git clone https://scm.kuandu.systems/git-raw/simplefiles.git
Log | Files | Refs | README | LICENSE

testlib.sh (4982B)


      1 #!/bin/sh
      2 
      3 PASS=0
      4 FAIL=0
      5 
      6 TESTROOT=${TESTROOT:-testroot}
      7 TEST_LOCK_DIR="$TESTROOT/run/simplefiles/lock"
      8 TEST_UPLOAD_DIR="$TESTROOT/run/simplefiles/uploads"
      9 TEST_CONFIG="$TESTROOT/etc/simplefiles.conf"
     10 TEST_CSRF_ORIGIN=${TEST_CSRF_ORIGIN:-http://localhost:8000}
     11 
     12 #
     13 # Reporting
     14 #
     15 
     16 ok() {
     17   printf '%-60s ok\n' "$1"
     18   PASS=$((PASS + 1))
     19 }
     20 
     21 not_ok() {
     22   printf '%-60s failed\n' "$1"
     23   printf '  %s\n' "$2"
     24   FAIL=$((FAIL + 1))
     25 }
     26 
     27 #
     28 # Run a command and capture its output.
     29 #
     30 # These are globals deliberately. POSIX sh has no local variables,
     31 # and keeping command execution in one place makes the assertions
     32 # simpler and safer with "set -e".
     33 #
     34 
     35 run() {
     36   TEST_OUTPUT=
     37   TEST_RC=0
     38 
     39   if TEST_OUTPUT=$("$@" 2>&1); then
     40     TEST_RC=0
     41   else
     42     TEST_RC=$?
     43   fi
     44 
     45   return 0
     46 }
     47 
     48 #
     49 # HTTP helpers
     50 #
     51 
     52 status_from_output() {
     53   printf '%s\n' "$1" |
     54     sed -n 's/^Status: //p' |
     55     sed -n '1p' |
     56     tr -d '\r'
     57 }
     58 
     59 header_from_output() {
     60   header_name=$1
     61   output=$2
     62 
     63   printf '%s\n' "$output" |
     64     sed -n "s/^${header_name}: //p" |
     65     sed -n '1p' |
     66     tr -d '\r'
     67 }
     68 
     69 #
     70 # Assertions
     71 #
     72 
     73 check_status() {
     74   name=$1
     75   expected=$2
     76   shift 2
     77 
     78   run "$@"
     79 
     80   got=$(status_from_output "$TEST_OUTPUT")
     81 
     82   if [ "$got" = "$expected" ]; then
     83     ok "$name"
     84   else
     85     not_ok "$name" \
     86       "expected status: $expected (got: ${got:-none})"
     87     printf '%s\n' "$TEST_OUTPUT"
     88   fi
     89 }
     90 
     91 check_body() {
     92   name=$1
     93   expected=$2
     94   shift 2
     95 
     96   run "$@"
     97 
     98   if printf '%s' "$TEST_OUTPUT" | grep -F "$expected" > /dev/null; then
     99     ok "$name"
    100   else
    101     not_ok "$name" "missing body: $expected"
    102   fi
    103 }
    104 
    105 check_not_body() {
    106   name=$1
    107   unexpected=$2
    108   shift 2
    109 
    110   run "$@"
    111 
    112   if printf '%s' "$TEST_OUTPUT" | grep -F "$unexpected" > /dev/null; then
    113     not_ok "$name" "unexpected body: $unexpected"
    114   else
    115     ok "$name"
    116   fi
    117 }
    118 
    119 check_header() {
    120   name=$1
    121   header_name=$2
    122   expected=$3
    123   shift 3
    124 
    125   run "$@"
    126 
    127   got=$(header_from_output "$header_name" "$TEST_OUTPUT")
    128 
    129   if [ "$got" = "$expected" ]; then
    130     ok "$name"
    131   else
    132     not_ok "$name" \
    133       "expected $header_name: $expected (got: ${got:-none})"
    134   fi
    135 }
    136 
    137 check_redirect() {
    138   name=$1
    139   expected_status=$2
    140   expected_location=$3
    141   shift 3
    142 
    143   run "$@"
    144 
    145   got_status=$(status_from_output "$TEST_OUTPUT")
    146 
    147   if [ "$got_status" != "$expected_status" ]; then
    148     not_ok "$name" \
    149       "expected status: $expected_status (got: ${got_status:-none})"
    150     return
    151   fi
    152 
    153   got_location=$(header_from_output Location "$TEST_OUTPUT")
    154 
    155   if [ "$got_location" != "$expected_location" ]; then
    156     not_ok "$name" \
    157       "expected Location: $expected_location (got: ${got_location:-none})"
    158     return
    159   fi
    160 
    161   ok "$name"
    162 }
    163 
    164 #
    165 # Filesystem assertions
    166 #
    167 
    168 check_file() {
    169   name=$1
    170   file=$2
    171   expected=$3
    172 
    173   if [ ! -f "$file" ]; then
    174     not_ok "$name" "missing file: $file"
    175     return
    176   fi
    177 
    178   size=$(wc -c < "$file" | tr -d ' ')
    179 
    180   #
    181   # POSIX sh does not have ${#string}, so use wc for the expected
    182   # byte count too.
    183   #
    184   expected_size=$(printf '%s' "$expected" | wc -c | tr -d ' ')
    185 
    186   if [ "$size" -ne "$expected_size" ]; then
    187     not_ok "$name" \
    188       "wrong size: expected $expected_size bytes, got $size"
    189     return
    190   fi
    191 
    192   actual=$(cat "$file")
    193 
    194   if [ "$actual" != "$expected" ]; then
    195     not_ok "$name" "unexpected file contents"
    196     return
    197   fi
    198 
    199   ok "$name"
    200 }
    201 
    202 check_file_exists() {
    203   name=$1
    204   file=$2
    205 
    206   if [ -f "$file" ]; then
    207     ok "$name"
    208   else
    209     not_ok "$name" "missing file: $file"
    210   fi
    211 }
    212 
    213 check_file_missing() {
    214   name=$1
    215   file=$2
    216 
    217   if [ ! -e "$file" ]; then
    218     ok "$name"
    219   else
    220     not_ok "$name" "unexpected file: $file"
    221   fi
    222 }
    223 
    224 check_dir_missing() {
    225   name=$1
    226   dir=$2
    227 
    228   if [ ! -d "$dir" ]; then
    229     ok "$name"
    230   else
    231     not_ok "$name" "unexpected directory: $dir"
    232   fi
    233 }
    234 
    235 check_no_temp_uploads() {
    236   name=$1
    237   dir=$2
    238 
    239   if [ ! -d "$dir" ]; then
    240     ok "$name"
    241     return
    242   fi
    243 
    244   if find "$dir" -name '.upload-*' -type f -print |
    245     grep -q .; then
    246     not_ok "$name" "temporary upload remains"
    247   else
    248     ok "$name"
    249   fi
    250 }
    251 
    252 check_file_bytes() {
    253   name=$1
    254   file=$2
    255   expected=$3
    256 
    257   tmp=$(mktemp)
    258 
    259   printf '%b' "$expected" > "$tmp"
    260 
    261   if [ ! -f "$file" ]; then
    262     rm -f "$tmp"
    263     not_ok "$name" "file missing: $file"
    264     return
    265   fi
    266 
    267   if cmp -s "$file" "$tmp"; then
    268     ok "$name"
    269   else
    270     not_ok "$name" "file contents differ: $file"
    271   fi
    272 
    273   rm -f "$tmp"
    274 }
    275 
    276 #
    277 # Test environment helpers
    278 #
    279 
    280 reset_testroot() {
    281   rm -rf "$TESTROOT"
    282   mkdir -p "$TESTROOT/storage/default"
    283   mkdir -p "$TEST_LOCK_DIR"
    284   mkdir -p "$TEST_UPLOAD_DIR"
    285   mkdir -p "$TESTROOT/etc"
    286   chmod go-w "$TEST_UPLOAD_DIR"
    287   printf 'CSRF_ORIGIN=%s\n' "$TEST_CSRF_ORIGIN" > "$TEST_CONFIG"
    288   chmod 644 "$TEST_CONFIG"
    289 }
    290 
    291 make_repo() {
    292   mkdir -p "$TESTROOT/storage/$1"
    293 }
    294 
    295 write_global_config() {
    296   printf '%s\n' "$1" > "$TEST_CONFIG"
    297 }
    298 
    299 write_default_repo_config() {
    300   mkdir -p "$TESTROOT/storage/default"
    301   printf '%s\n' "$1" > "$TESTROOT/storage/default/.config"
    302 }
    303 
    304 #
    305 # Final result
    306 #
    307 
    308 test_result() {
    309   printf '\n%d passed, %d failed\n' "$PASS" "$FAIL"
    310   [ "$FAIL" -eq 0 ]
    311 }