test_curses.sh - sfeed_tests - sfeed tests and RSS and Atom files
 (HTM) git clone git://git.codemadness.org/sfeed_tests
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       test_curses.sh (44759B)
       ---
            1 #!/bin/sh
            2 # Dependencies: printf with support for \x, stty, awk, pgrep, pkill, sha256.
            3 #
            4 # Source-code modifications:
            5 # Disable pledge and unveil in util.h
            6 # To test all coverage before _exit add the definition: void __gcov_dump(void); and __gcov_dump() to flush reports.
            7 # Build: make CC=gcc CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"
            8 #
            9 # TODO maybe, for now manual test it:
           10 # ? resources:
           11 #        - fork resource limit ulimit? maybe non-interactive and let many process wait.
           12 #        - memory limit ulimit?
           13 # ? auto test 't' with no items.
           14 # ? page_scrollpage: pages > 0 && if ((p->pos % p->height)).
           15 # ? terminal with size 0x0.
           16 # ? read errors: using /proc/self/mem? (Linux-specific).
           17 # ? write errors: using /dev/full? (Linux-specific).
           18 # ? test reload of feeds while the feed was removed:
           19 #   - lazyload case.
           20 #   - fseek case in feeds_load.
           21 # ? try to find the same feed in the pane but it is not visible anymore.
           22 #   steps: have feed with new items, press 't' and highlight the row: reload
           23 #          feed and make sure it has old items.
           24 # ? memory allocation failures: realloc, calloc, strdup.
           25 # ? open /dev/tty, /dev/null failure.
           26 
           27 #sc="sfeed_curses"
           28 
           29 sc="$(pwd)/sfeed_curses"
           30 markread="$(pwd)/sfeed_markread read"
           31 markunread="$(pwd)/sfeed_markread unread"
           32 
           33 cmd_sha256="$(command -v sha256)" # "sha256" typically on BSD
           34 if test -n "$cmd_sha256"; then
           35 sha() {
           36         sha256 -q # -q only print hash
           37 }
           38 else
           39 sha() {
           40         sha256sum | cut -f 1 -d ' ' # first field is hash
           41 }
           42 fi
           43 
           44 # TODO: portable POSIX wrapper for pgrep.
           45 # maybe: ps -U "$USER" -o pid=,command= | grep "$1" | sed -E 's@^[ ]*|[ ]*$@@g'
           46 #if test -z "$(command -v "pgrep")"; then
           47 #pgrep(programname)
           48 #pgrep() {
           49 #        ps -C "$1"
           50 #}
           51 #fi
           52 
           53 # TODO: portable POSIX wrapper for pkill.
           54 # maybe: pgrep "$1" | cut -f 1 -d ' '
           55 #if test -z "$(command -v "pkill")"; then
           56 # pkill(signal, programname)
           57 #pkill() {
           58 #        ps -C "$2" -o pid= | xargs kill "$1"
           59 #}
           60 #fi
           61 
           62 if test -f "/usr/bin/printf"; then
           63         printf="/usr/bin/printf" # busybox printf on Void Linux is dogshit.
           64 else
           65         printf="$(command -v printf)" # a printf with support for \x.
           66 fi
           67 
           68 test_count=1
           69 test_name=""
           70 test_start() {
           71         test_name="$1"
           72         $printf '[%s] #%d Test starting %s\n' "$(date +'%H:%M:%S')" "$test_count" "$test_name" >&2
           73 }
           74 
           75 test_end() {
           76         #$printf '[%s] #%d Test success: %s %s\n' "$(date +'%H:%M:%S')" "$test_count" "$test_name" "$1" >&2
           77         test_count=$((test_count+1))
           78 }
           79 
           80 fail() {
           81         $printf '[%s] #%d Test failed: %s %s\n' "$(date +'%H:%M:%S')" "$test_count" "$test_name" "$1" >&2
           82         cleanup
           83         exit $?
           84 }
           85 
           86 emptydata() {
           87         $printf ''
           88 }
           89 
           90 fakedata() {
           91         $printf '0\t1. a\thttp://a\n'
           92         $printf '1\t2. b\thttp://b\n'
           93         $printf '2\t3. c\thttp://c\n'
           94 }
           95 
           96 fakedata2() {
           97         $printf '3\t3. d\thttp://d\n'
           98         $printf '4\t4. e\thttp://e\n'
           99         $printf '5\t5. f\thttp://f\n'
          100 }
          101 
          102 fakedata3() {
          103         $printf '6\t6. g\thttp://g\n'
          104         $printf '2124567591\t7. h\thttp://h\n' # 2037-04-28
          105         $printf '\t8. i\thttp://i\tcontent\tplain\tid\tauthor\thttp://enclosure/file.mp3\n'
          106         $printf 'NEIN\t9. j\thttp://j\tcontent\tplain\tid\tauthor\thttp://enclosure2/file.mp3\n'
          107 }
          108 
          109 fakedata4() {
          110         $printf '15\t15. x\thttp://x\n'
          111         $printf '2124567591\t16. y\thttp://y\n' # 2037-04-28
          112         $printf '17\t17. z\thttp://z\n'
          113 }
          114 
          115 sausage="$($printf '\xe3\x82\xbd\xe3\x83\xbc\xe3\x82\xbb\xe3\x83\xbc\xe3\x82\xb8')" # japanese sausage
          116 dollar="$($printf '\xef\xbc\x84\xef\xbc\x84\xef\xbc\x84\xef\xbc\x84\xef\xbc\x84')" # big dollar 2 width
          117 invaliduni="$($printf '\xc3\xc3\xc3\xc3\xc3\xc3')"
          118 ctrl="$($printf 'a\tb\rc\nd')"
          119 wcneg="$($printf '\xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe')"
          120 
          121 fakedataunicode() {
          122         $printf '10\t10. 2 width \xef\xbc\x84\xef\xbc\x84\xef\xbc\x84\xef\xbc\x84\xef\xbc\x84\n' # "big dollar" 2 width
          123         $printf '11\t11. invalid \xc3\xc3\xc3\xc3\xc3\xc3\n' # invalid
          124         $printf '12\t12. replacement char \xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\n' # replacement character
          125         $printf '13\t13. wcwidth -1 \xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe\xef\xbf\xbe\n' # codepoint 0xfffe, wcwidth -1 on some systems.
          126         $printf '14\t14. \xe3\x82\xbd\xe3\x83\xbc\xe3\x82\xbb\xe3\x83\xbc\xe3\x82\xb8\thttp://jp\n' # japanese sausage
          127 }
          128 
          129 muchdata() {
          130         # very wow
          131         echo | awk 'END {
          132                 for (i = 0;i < 500; i++)
          133                         printf("%d\t%d. %d\thttp://%d\n", i, i, i, i);
          134         }'
          135 }
          136 
          137 # setup: create files
          138 # feedfiles
          139 feedfile1=$(mktemp)
          140 feedfile2=$(mktemp)
          141 feedfile3=$(mktemp)
          142 feedfile4=$(mktemp)
          143 emptyfile=$(mktemp)
          144 fakedata > "$feedfile1"
          145 fakedata2 > "$feedfile2"
          146 fakedata3 > "$feedfile3"
          147 fakedata4 > "$feedfile4"
          148 emptydata > "$emptyfile"
          149 # URL file
          150 urlfile=$(mktemp)
          151 touch "$urlfile"
          152 
          153 pipefile="$(mktemp)"
          154 yankfile="$(mktemp)"
          155 
          156 plumbfile="$(mktemp)"
          157 plumbscript="$(mktemp)"
          158 $printf '#!/bin/sh\necho "$1" >"%s"\n' "$plumbfile" > "$plumbscript"
          159 chmod +x "$plumbscript"
          160 
          161 # terminal size.
          162 size=$(stty size)
          163 rows="${size%% *}"
          164 if test "$rows" = "0"; then
          165         rows="24" # serial console
          166 fi
          167 itemrows=$((rows - 1)) # -1 for bottom bar.
          168 
          169 cleanup() {
          170         rm -f \
          171                 "$urlfile" "$yankfile" "$pipefile" "$plumbfile" "$plumbscript" \
          172                 "$feedfile1" "$feedfile2" "$feedfile3" "$feedfile4" "$emptyfile"
          173 }
          174 
          175 # manual tests
          176 manual() {
          177         echo "Manual tests:"
          178         echo "* Press ^L to redraw the terminal."
          179         echo "* Test SIGWINCH by resizing the terminal: resize also to very small sizes in all layouts"
          180         echo "* Test resizing the sidebar in all layouts and resetting it by pressing ="
          181         echo ""
          182         echo "Press RETURN to continue"
          183         read p
          184         test_start "Manual tests"
          185         "$sc" "$feedfile1" "$feedfile2" "$feedfile3" "$emptyfile"
          186         test_end
          187 
          188         sleep 1
          189         echo "Was it OK? [y]/n"
          190         read answer
          191         if test "$answer" = "n"; then
          192                 cleanup
          193                 exit 1
          194         fi
          195 
          196         echo "Unicode data with various widths. Resize the terminal to proper test truncation and decoding."
          197         echo ""
          198         echo "Press RETURN to continue"
          199         read p
          200         test_start "Unicode"
          201         fakedataunicode | "$sc"
          202         test_end
          203 
          204         echo "Was it OK? [y]/n"
          205         read answer
          206         if test "$answer" = "n"; then
          207                 cleanup
          208                 exit 1
          209         fi
          210 
          211         echo "* Test filenames with unicode and multi-column characters"
          212         echo ""
          213         echo "Press RETURN to continue"
          214         read p
          215 
          216         test_start "Test filenames with unicode"
          217         tmpfile1="/tmp/sfeed_$sausage"
          218         tmpfile2="/tmp/sfeed_$invaliduni"
          219         tmpfile3="/tmp/sfeed_$dollar"
          220         tmpfile4="/tmp/sfeed_$ctrl"
          221         tmpfile5="/tmp/sfeed_$wcneg"
          222         cp "$feedfile1" "$tmpfile1"
          223         cp "$feedfile2" "$tmpfile2"
          224         cp "$feedfile3" "$tmpfile3"
          225         cp "$feedfile4" "$tmpfile4"
          226         cp "$feedfile4" "$tmpfile5"
          227         $sc "$tmpfile1" "$tmpfile2" "$tmpfile3" "$tmpfile4" "$tmpfile5"
          228         rm -f "$tmpfile1" "$tmpfile2" "$tmpfile3" "$tmpfile4" "$tmpfile5"
          229         test_end
          230 
          231         echo "Was it OK? [y]/n"
          232         read answer
          233         if test "$answer" = "n"; then
          234                 cleanup
          235                 exit 1
          236         fi
          237 
          238         echo "* Test SIGHUP to reload feed data, after 3 seconds it reloads the feed and the counts"
          239         echo "  should be different. Afterward manually close it by pressing q."
          240         echo ""
          241         echo "Press RETURN to continue"
          242         read p
          243 
          244         test_start "Test SIGHUP to reload feed data"
          245         tmpfile="$(mktemp)"
          246         cat "$feedfile2" > "$tmpfile"
          247         (sleep 3;cp "$feedfile3" "$tmpfile"; pkill -SIGHUP sfeed_curses) &
          248         SFEED_AUTOCMD="" "$sc" "$feedfile1" "$tmpfile"
          249         rm -f "$tmpfile"
          250         test_end
          251 
          252         echo "Was it OK? [y]/n"
          253         read answer
          254         if test "$answer" = "n"; then
          255                 cleanup
          256                 exit 1
          257         fi
          258 
          259         echo "* Test R to reload feed data, after 2 seconds press R to reloads the feed and the counts"
          260         echo "  should be different. Afterward manually close it by pressing q."
          261         echo ""
          262         echo "Press RETURN to continue"
          263         read p
          264 
          265         test_start "Test R to reload feed data"
          266         tmpfile="$(mktemp)"
          267         cat "$feedfile2" > "$tmpfile"
          268         # use muchdata so the counts are changed, should resizing the sidebar.
          269         (sleep 2;muchdata > "$tmpfile") &
          270         SFEED_AUTOCMD="" "$sc" "$feedfile1" "$tmpfile"
          271         rm -f "$tmpfile"
          272         test_end
          273 
          274         echo "Was it OK? [y]/n"
          275         read answer
          276         if test "$answer" = "n"; then
          277                 cleanup
          278                 exit 1
          279         fi
          280 
          281         echo "* Test SIGHUP to reload the URLs list. After 3 seconds it reloads the feed"
          282         echo "  and the first item should be non-bold. Afterward manually close it by pressing q."
          283         echo ""
          284         echo "Press RETURN to continue"
          285         read p
          286 
          287         test_start "Change URL contents externally. Reload URLs with R with stdin input (one-time read)"
          288         rm -f "/tmp/u"
          289         touch "/tmp/u"
          290         (sleep 2; echo "http://a" > "/tmp/u"; pkill -SIGHUP sfeed_curses) &
          291         fakedata | SFEED_URL_FILE="/tmp/u" SFEED_AUTOCMD="G" $sc
          292         status=$?
          293         test $status -eq 0 || fail "Exit code must be 0, was: $status"
          294         rm -f "/tmp/u"
          295         test_end
          296 
          297         echo "Was it OK? [y]/n"
          298         read answer
          299         if test "$answer" = "n"; then
          300                 cleanup
          301                 exit 1
          302         fi
          303 
          304         echo "* Test SIGHUP while the piper program is open. After 3 seconds it sends SIGHUP."
          305         echo "  After closing the piper program after 3 seconds the signal is queued and it"
          306         echo "  should handle the reload event. The counts of the second feed should be"
          307         echo "  new / bold. Afterward manually close it by pressing q."
          308         echo ""
          309         echo "Press RETURN to continue"
          310         read p
          311 
          312         test_start "Test SIGHUP to reload feed data while piper program is open"
          313         tmpfile="$(mktemp)"
          314         cat "$feedfile2" > "$tmpfile"
          315         (sleep 3;cp "$feedfile3" "$tmpfile"; pkill -SIGHUP sfeed_curses) &
          316         SFEED_PIPER_INTERACTIVE="1" SFEED_PIPER="less" SFEED_AUTOCMD="lp" "$sc" "$feedfile1" "$tmpfile"
          317         rm -f "$tmpfile"
          318         test_end
          319 
          320         echo "Was it OK? [y]/n"
          321         read answer
          322         if test "$answer" = "n"; then
          323                 cleanup
          324                 exit 1
          325         fi
          326 
          327         echo "Test exit status of mark read program: if it returns 0 the item"
          328         echo "is marked. Press r to test it. It should mark the items as read."
          329         echo ""
          330         echo "Press RETURN to continue"
          331         read p
          332 
          333         test_start "Test exit status of mark read: exit status zero"
          334         rm -f "$urlfile"
          335         touch "$urlfile"
          336         fakedata | SFEED_URL_FILE="$urlfile" SFEED_MARK_READ="true" $sc
          337         test_end
          338 
          339         echo "Was it OK? [y]/n"
          340         read answer
          341         if test "$answer" = "n"; then
          342                 cleanup
          343                 exit 1
          344         fi
          345 
          346         echo "Test exit status of mark read program: if it returns non-zero the item"
          347         echo "is not marked. Press r to test it, it should NOT mark the items as read."
          348         echo ""
          349         echo "Press RETURN to continue"
          350         read p
          351 
          352         test_start "Test exit status of mark read: exit status non-zero"
          353         rm -f "$urlfile"
          354         touch "$urlfile"
          355         fakedata | SFEED_URL_FILE="$urlfile" SFEED_MARK_READ="false" $sc
          356         test_end
          357 
          358         echo "Was it OK? [y]/n"
          359         read answer
          360         if test "$answer" = "n"; then
          361                 cleanup
          362                 exit 1
          363         fi
          364 }
          365 
          366 # -m runs manual tests only.
          367 if test "$1" = "-m"; then
          368         manual
          369         cleanup
          370         exit
          371 fi
          372 
          373 test_start "Search feed name"
          374 n=$(basename "$feedfile2")
          375 rm -f "$yankfile"
          376 touch "$yankfile"
          377 SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="cat >$yankfile" SFEED_AUTOCMD="$($printf '/%s\r' "$n")olyq" $sc "$feedfile1" "$feedfile2" "$feedfile3" "$feedfile4"
          378 status=$?
          379 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          380 contents="$(cat "$yankfile")"
          381 test "$contents" = "http://d" || fail "Incorrect URL: $contents"
          382 test_end
          383 
          384 test_start "Forward searching and yanking an URL"
          385 rm -f "$yankfile"
          386 touch "$yankfile"
          387 # NOTE: interactive is needed, else it could spawn and close too fast.
          388 fakedata | SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="cat >$yankfile" SFEED_AUTOCMD="$($printf '/\b3\b2\nyq')" $sc
          389 status=$?
          390 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          391 contents="$(cat "$yankfile")"
          392 test "$contents" = "http://b" || fail "Incorrect URL: $contents"
          393 test_end
          394 
          395 test_start "Forward searching (unicode) and yanking an URL"
          396 rm -f "$yankfile"
          397 touch "$yankfile"
          398 # NOTE: interactive is needed, else it could spawn and close too fast.
          399 fakedataunicode | SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="cat >$yankfile" SFEED_AUTOCMD="$($printf '/%s\r' "$sausage")yq" $sc
          400 status=$?
          401 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          402 contents="$(cat "$yankfile")"
          403 test "$contents" = "http://jp" || fail "Incorrect URL: $contents"
          404 test_end
          405 
          406 test_start "Monocle layout: toggle between panes with TAB."
          407 rm -f "$plumbfile"
          408 touch "$plumbfile"
          409 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="l3        jooq" $sc "$feedfile1" "$feedfile2" "$feedfile3"
          410 status=$?
          411 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          412 contents="$(cat "$plumbfile")"
          413 test "$contents" = "http://d" || fail "Incorrect URL: $contents"
          414 test_end
          415 
          416 test_start "Pipe: nonexistant command"
          417 rm -f "$pipefile"
          418 touch "$pipefile"
          419 fakedata | SFEED_PIPER_INTERACTIVE="1" SFEED_PIPER="/nonexist" SFEED_AUTOCMD="pq" $sc
          420 status=$?
          421 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          422 contents="$(cat "$pipefile")"
          423 line1=""
          424 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
          425 test_end
          426 
          427 test_start "Plumb: nonexistant command"
          428 rm -f "$plumbfile"
          429 touch "$plumbfile"
          430 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="/nonexist" SFEED_AUTOCMD="oq" $sc
          431 status=$?
          432 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          433 contents="$(cat "$plumbfile")"
          434 test "$contents" = "" || fail "Incorrect URL: $contents"
          435 test_end
          436 
          437 test_start "Yank: nonexistant command"
          438 rm -f "$yankfile"
          439 touch "$yankfile"
          440 # NOTE: interactive is needed, else it could spawn and close too fast.
          441 fakedata | SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="/nonexist" SFEED_AUTOCMD="$($printf '/\b3\b2\nyq')" $sc
          442 status=$?
          443 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          444 contents="$(cat "$yankfile")"
          445 test "$contents" = "" || fail "Incorrect URL: $contents"
          446 test_end
          447 
          448 test_start "Test \$SFEED_FEED_PATH"
          449 rm -f "$yankfile"
          450 touch "$yankfile"
          451 SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="echo \$SFEED_FEED_PATH >$yankfile" SFEED_AUTOCMD="lyq" $sc "$feedfile1"
          452 status=$?
          453 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          454 contents="$(cat "$yankfile")"
          455 test "$contents" = "$feedfile1" || fail "Incorrect content: $contents"
          456 test_end
          457 
          458 test_start "Test \$SFEED_FEED_PATH for stdin"
          459 rm -f "$yankfile"
          460 touch "$yankfile"
          461 fakedata | SFEED_YANKER_INTERACTIVE="1" SFEED_YANKER="echo a\$SFEED_FEED_PATH >$yankfile" SFEED_AUTOCMD="yq" $sc
          462 status=$?
          463 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          464 contents="$(cat "$yankfile")"
          465 test "$contents" = "a" || fail "Incorrect content: $contents"
          466 test_end
          467 
          468 # Switch to monocle layout: navigation:
          469 # select second feed and open it (opens items pane). Switch to feed pane with left key and
          470 # go one row down and open the next feed. Switch left and right and open the first item.
          471 test_start "Monocle layout: test navigation"
          472 rm -f "$plumbfile"
          473 touch "$plumbfile"
          474 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3johjo$($printf '\x1b[D')loq" $sc "$feedfile1" "$feedfile2" "$feedfile3"
          475 status=$?
          476 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          477 contents="$(cat "$plumbfile")"
          478 test "$contents" = "http://g" || fail "Incorrect URL: $contents"
          479 test_end
          480 
          481 test_start "Navigation keys: up arrow"
          482 expectedurl="http://h"
          483 rm -f "$plumbfile"
          484 touch "$plumbfile"
          485 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="G$($printf '\x1b[A\x1bOA')oq" $sc
          486 status=$?
          487 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          488 contents="$(cat "$plumbfile")"
          489 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          490 test_end
          491 
          492 test_start "Navigation keys: up"
          493 expectedurl="http://h"
          494 rm -f "$plumbfile"
          495 touch "$plumbfile"
          496 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1bOF')kkoq" $sc
          497 status=$?
          498 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          499 contents="$(cat "$plumbfile")"
          500 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          501 test_end
          502 
          503 test_start "Navigation keys: home"
          504 expectedurl="http://g"
          505 rm -f "$plumbfile"
          506 touch "$plumbfile"
          507 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="G$($printf '\x1b[H')oq" $sc
          508 status=$?
          509 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          510 contents="$(cat "$plumbfile")"
          511 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          512 test_end
          513 
          514 test_start "Navigation keys 2: home"
          515 expectedurl="http://g"
          516 rm -f "$plumbfile"
          517 touch "$plumbfile"
          518 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="G$($printf '\x1b[1~')oq" $sc
          519 status=$?
          520 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          521 contents="$(cat "$plumbfile")"
          522 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          523 test_end
          524 
          525 test_start "Navigation keys: home key (urxvt)"
          526 expectedurl="http://g"
          527 rm -f "$plumbfile"
          528 touch "$plumbfile"
          529 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="G$($printf '\x1b[7~')oq" $sc
          530 status=$?
          531 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          532 contents="$(cat "$plumbfile")"
          533 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          534 test_end
          535 
          536 test_start "Navigation keys: end key (urxvt)"
          537 expectedurl="http://j"
          538 rm -f "$plumbfile"
          539 touch "$plumbfile"
          540 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[8~')oq" $sc
          541 status=$?
          542 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          543 contents="$(cat "$plumbfile")"
          544 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          545 test_end
          546 
          547 test_start "Navigation keys: home key (SUN)"
          548 expectedurl="http://g"
          549 rm -f "$plumbfile"
          550 touch "$plumbfile"
          551 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="G$($printf '\x1b[214z')oq" $sc
          552 status=$?
          553 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          554 contents="$(cat "$plumbfile")"
          555 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          556 test_end
          557 
          558 test_start "Navigation keys: end key (SUN)"
          559 expectedurl="http://j"
          560 rm -f "$plumbfile"
          561 touch "$plumbfile"
          562 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[220z')oq" $sc
          563 status=$?
          564 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          565 contents="$(cat "$plumbfile")"
          566 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          567 test_end
          568 
          569 test_start "Navigation keys: unsupported DEC application key INSERT"
          570 fakedata3 | SFEED_AUTOCMD="$($printf '\x1b[2~')q" $sc
          571 status=$?
          572 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          573 test_end
          574 
          575 test_start "Navigation keys: unsupported DEC application key F13"
          576 fakedata3 | SFEED_AUTOCMD="$($printf '\x1b[25~')q" $sc
          577 status=$?
          578 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          579 test_end
          580 
          581 test_start "Navigation keys: unsupported DEC application key, unclosed ~"
          582 fakedata3 | SFEED_AUTOCMD="$($printf '\x1b[2')qq" $sc # NOTE: qq to force-close it since sequence must end with non-digit.
          583 status=$?
          584 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          585 test_end
          586 
          587 test_start "Run it with empty data"
          588 emptydata | SFEED_AUTOCMD="q" $sc
          589 status=$?
          590 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          591 test_end
          592 
          593 test_start "Run with empty data and an URL file"
          594 rm -f "$urlfile"
          595 touch "$urlfile"
          596 emptydata | SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="q" $sc
          597 status=$?
          598 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          599 test_end
          600 
          601 test_start "Run with empty data and an URL file which does not exist"
          602 emptydata | SFEED_URL_FILE="/tmp/notexist" SFEED_AUTOCMD="q" $sc
          603 status=$?
          604 test $status -eq 1 || fail "Exit code must be 1, was: $status"
          605 test_end
          606 
          607 test_start "Mark URL as read. Mark first 2 entries as read"
          608 rm -f "$urlfile"
          609 touch "$urlfile"
          610 fakedata | SFEED_MARK_READ="$markread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="rrq" $sc
          611 status=$?
          612 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          613 expect="997864e8cb6fd5ab981f7d64e9817fd80871dd1172dbd04849db6fefa9dd0208"
          614 result=$(sha < "$urlfile")
          615 test "$result" = "$expect" || fail "Invalid result"
          616 test_end
          617 
          618 test_start "Mark URL as read. Mark first 2 entries as read. Mark already read items as read"
          619 rm -f "$urlfile"
          620 touch "$urlfile"
          621 fakedata | SFEED_MARK_READ="$markread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="rrgjrq" $sc
          622 status=$?
          623 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          624 expect="997864e8cb6fd5ab981f7d64e9817fd80871dd1172dbd04849db6fefa9dd0208"
          625 result=$(sha < "$urlfile")
          626 test "$result" = "$expect" || fail "Invalid result"
          627 test_end
          628 
          629 test_start "Mark URL as read. Select second entry and mark as unread"
          630 fakedata | SFEED_MARK_UNREAD="$markunread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="juq" $sc
          631 status=$?
          632 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          633 result=$(cat "$urlfile")
          634 expect="http://a"
          635 test "$result" = "$expect" || fail "Invalid result"
          636 test_end
          637 
          638 test_start "Mark all URLs of a feed as read"
          639 rm -f "$urlfile"
          640 touch "$urlfile"
          641 fakedata | SFEED_MARK_READ="$markread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="fq" $sc  "$feedfile1" "$feedfile2"
          642 status=$?
          643 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          644 expect="da4a1d3a7c80beb04e451c6c02a7a321a69e87abcee2178e7411f6b5d8e3960d"
          645 result=$(sha < "$urlfile")
          646 test "$result" = "$expect" || fail "Invalid result"
          647 test_end
          648 
          649 test_start "Mark first 2 feeds read, then mark URLs of first feed as unread"
          650 rm -f "$urlfile"
          651 touch "$urlfile"
          652 SFEED_MARK_READ="$markread" SFEED_MARK_UNREAD="$markunread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="fjofgFq" $sc "$feedfile1" "$feedfile2"
          653 status=$?
          654 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          655 expect="da4a1d3a7c80beb04e451c6c02a7a321a69e87abcee2178e7411f6b5d8e3960d"
          656 result=$(sha < "$urlfile")
          657 test "$result" = "$expect" || fail "Invalid result"
          658 test_end
          659 
          660 test_start "Mark all items of the first 2 feeds as read"
          661 rm -f "$urlfile"
          662 touch "$urlfile"
          663 fakedata | SFEED_MARK_READ="$markread" SFEED_URL_FILE="$urlfile" SFEED_AUTOCMD="fjofq" $sc "$feedfile1" "$feedfile2"
          664 status=$?
          665 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          666 expect="9228e2265258aa0c4afe33a129b4484f9b1d01e10ad30333a2139beb6bb0881d"
          667 result=$(sha < "$urlfile")
          668 test "$result" = "$expect" || fail "Invalid result"
          669 test_end
          670 
          671 test_start "Backward search and plumb script"
          672 rm -f "$plumbfile"
          673 touch "$plumbfile"
          674 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="llG$($printf '?2\noq')" $sc "$feedfile1" "$feedfile2"
          675 status=$?
          676 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          677 contents="$(cat "$plumbfile")"
          678 test "$contents" = "http://b" || fail "Incorrect URL: $contents"
          679 test_end
          680 
          681 test_start "Pipe contents of item to a pipe script"
          682 rm -f "$pipefile"
          683 touch "$pipefile"
          684 fakedata | SFEED_PIPER_INTERACTIVE="1" SFEED_PIPER="cat >$pipefile" SFEED_AUTOCMD="pq" $sc
          685 status=$?
          686 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          687 contents="$(cat "$pipefile")"
          688 line1="$($printf '0\t1. a\thttp://a\t\t\t\t\t\t\n')"
          689 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
          690 test_end
          691 
          692 test_start "Plumb script"
          693 rm -f "$plumbfile"
          694 touch "$plumbfile"
          695 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="oq" $sc
          696 status=$?
          697 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          698 contents="$(cat "$plumbfile")"
          699 test "$contents" = "http://a" || fail "Incorrect URL: $contents"
          700 test_end
          701 
          702 test_start "Plumb script and lazyload"
          703 rm -f "$plumbfile"
          704 touch "$plumbfile"
          705 SFEED_LAZYLOAD="1" SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="loq" $sc "$feedfile1" "$feedfile2"
          706 status=$?
          707 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          708 contents="$(cat "$plumbfile")"
          709 test "$contents" = "http://a" || fail "Incorrect URL: $contents"
          710 test_end
          711 
          712 test_start "Toggle new feeds in sidebar, but there are none"
          713 rm -f "$plumbfile"
          714 touch "$plumbfile"
          715 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="toloq" $sc "$emptyfile"
          716 status=$?
          717 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          718 contents="$(cat "$plumbfile")"
          719 test "$contents" = "" || fail "Incorrect URL: $contents"
          720 test_end
          721 
          722 test_start "Toggle new feeds in sidebar (horizontal mode), but there are none"
          723 rm -f "$plumbfile"
          724 touch "$plumbfile"
          725 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="2toloq" $sc "$emptyfile"
          726 status=$?
          727 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          728 contents="$(cat "$plumbfile")"
          729 test "$contents" = "" || fail "Incorrect URL: $contents"
          730 test_end
          731 
          732 test_start "Select a new feed in the sidebar, toggle new feeds: make sure it selects the same item"
          733 rm -f "$plumbfile"
          734 touch "$plumbfile"
          735 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="Gktoloq" $sc "$feedfile1" "$feedfile3" "$feedfile4" "$feedfile2"
          736 status=$?
          737 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          738 contents="$(cat "$plumbfile")"
          739 test "$contents" = "http://x" || fail "Incorrect URL: $contents"
          740 test_end
          741 
          742 test_start "Jump to next bold item"
          743 rm -f "$plumbfile"
          744 touch "$plumbfile"
          745 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="JolJoq" $sc "$feedfile1" "$feedfile2" "$feedfile3" "$feedfile4"
          746 status=$?
          747 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          748 expect="http://h"
          749 contents="$(cat "$plumbfile")"
          750 test "$contents" = "$expect" || fail "Incorrect URL: $contents"
          751 test_end
          752 
          753 test_start "Jump to previous bold item"
          754 rm -f "$plumbfile"
          755 touch "$plumbfile"
          756 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="GKolGKoq" $sc "$feedfile1" "$feedfile2" "$feedfile3" "$feedfile4"
          757 status=$?
          758 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          759 expect="http://h"
          760 contents="$(cat "$plumbfile")"
          761 test "$contents" = "$expect" || fail "Incorrect URL: $contents"
          762 test_end
          763 
          764 test_start "Jump to next or previous bold item but there are none"
          765 rm -f "$plumbfile"
          766 touch "$plumbfile"
          767 emptydata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="JJKKoq" $sc
          768 status=$?
          769 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          770 expect=""
          771 contents="$(cat "$plumbfile")"
          772 test "$contents" = "$expect" || fail "Incorrect URL: $contents"
          773 test_end
          774 
          775 test_start "Plumb script (enclosure)"
          776 rm -f "$plumbfile"
          777 touch "$plumbfile"
          778 fakedata3 | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="jjeq" $sc
          779 status=$?
          780 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          781 contents="$(cat "$plumbfile")"
          782 test "$contents" = "http://enclosure/file.mp3" || fail "Incorrect URL: $contents"
          783 test_end
          784 
          785 # monocle layout: open second feed (switches pane to item in monocle mode),
          786 # open second item.
          787 test_start "Monocle layout: open second feed (switches pane to item in monocle mode)"
          788 rm -f "$plumbfile"
          789 touch "$plumbfile"
          790 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3jojoq" $sc "$feedfile1" "$feedfile2"
          791 status=$?
          792 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          793 contents="$(cat "$plumbfile")"
          794 test "$contents" = "http://e" || fail "Incorrect URL: $contents"
          795 test_end
          796 
          797 test_start "Load first and second feed, switch to item and open it"
          798 rm -f "$plumbfile"
          799 touch "$plumbfile"
          800 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="]]l$($printf '\x1b[C')joq" $sc "$feedfile1" "$feedfile2"
          801 status=$?
          802 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          803 contents="$(cat "$plumbfile")"
          804 test "$contents" = "http://e" || fail "Incorrect URL: $contents"
          805 test_end
          806 
          807 # arrow key navigation.
          808 # monocle layout: arrow down, open second feed (switches pane to item in monocle mode),
          809 # page down, open item.
          810 test_start "Monocle layout: arrow keys: open second feed (switches pane to item in monocle mode)"
          811 rm -f "$plumbfile"
          812 touch "$plumbfile"
          813 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3hh$($printf '\x1b[B')o$($printf '\x1b[6~')oq" $sc "$feedfile1" "$feedfile2"
          814 status=$?
          815 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          816 contents="$(cat "$plumbfile")"
          817 test "$contents" = "http://f" || fail "Incorrect URL: $contents"
          818 test_end
          819 
          820 # arrow key navigation.
          821 # monocle layout: arrow down, open second feed (switches pane to item in monocle mode),
          822 # page down, open item.
          823 test_start "Monocle layout: arrow keys 2: open second feed (switches pane to item in monocle mode)"
          824 rm -f "$plumbfile"
          825 touch "$plumbfile"
          826 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3$($printf '\x1bOB')o$($printf '\x1b[6~')oq" $sc "$feedfile1" "$feedfile2"
          827 status=$?
          828 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          829 contents="$(cat "$plumbfile")"
          830 test "$contents" = "http://f" || fail "Incorrect URL: $contents"
          831 test_end
          832 
          833 test_start "Scroll 3 pages down and one up (selecting the last item of that page)"
          834 expectedurl="http://$((itemrows * 3 - 1))"
          835 rm -f "$plumbfile"
          836 touch "$plumbfile"
          837 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="   $($printf '\x1b[5~')oq" $sc
          838 status=$?
          839 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          840 contents="$(cat "$plumbfile")"
          841 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          842 test_end
          843 
          844 test_start "SUN keys: scroll 3 pages down and one up (selecting the last item of that page)"
          845 expectedurl="http://$((itemrows * 3 - 1))"
          846 rm -f "$plumbfile"
          847 touch "$plumbfile"
          848 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[222z\x1b[222z\x1b[222z\x1b[216z')oq" $sc
          849 status=$?
          850 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          851 contents="$(cat "$plumbfile")"
          852 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          853 test_end
          854 
          855 test_start "SCO keys: scroll 3 pages down and one up (selecting the last item of that page)"
          856 expectedurl="http://$((itemrows * 3 - 1))"
          857 rm -f "$plumbfile"
          858 touch "$plumbfile"
          859 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[G\x1b[G\x1b[G\x1b[I')oq" $sc
          860 status=$?
          861 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          862 contents="$(cat "$plumbfile")"
          863 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          864 test_end
          865 
          866 test_start "End key: go to last item"
          867 expectedurl="http://499"
          868 rm -f "$plumbfile"
          869 touch "$plumbfile"
          870 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[4~')oq" $sc
          871 status=$?
          872 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          873 contents="$(cat "$plumbfile")"
          874 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          875 test_end
          876 
          877 # toggle to monocle
          878 # monocle layout: open second feed (switches pane to item in monocle mode),
          879 # open second item.
          880 test_start "Toggle to monocle layout: open second feed (switches pane to item in monocle mode)"
          881 rm -f "$plumbfile"
          882 touch "$plumbfile"
          883 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="sjojoq" $sc "$feedfile1" "$feedfile2"
          884 status=$?
          885 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          886 contents="$(cat "$plumbfile")"
          887 test "$contents" = "http://e" || fail "Incorrect URL: $contents"
          888 test_end
          889 
          890 # Test mouse, reference:
          891 #
          892 # mouse button encoding:
          893 # 0 is left button
          894 # 1 is middle button
          895 # 2 is right button
          896 # 64 scroll up
          897 # 65 scroll down
          898 # 128 side button, button 7 backward
          899 # 129 side button, button 8 forward
          900 #
          901 # SGR:
          902 # m is press, M is release
          903 #
          904 # SGR mouse:
          905 
          906 test_start "Mouse SGR: left button, press column (x, y) = (1, 2) which is the second row, double-click"
          907 rm -f "$plumbfile"
          908 touch "$plumbfile"
          909 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[<0;1;2M\x1b[<0;1;2m\x1b[<0;1;2M\x1b[<0;1;2m')q" "$sc"
          910 status=$?
          911 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          912 contents="$(cat "$plumbfile")"
          913 test "$contents" = "http://b" || fail "Incorrect content: $contents"
          914 test_end
          915 
          916 test_start "Mouse SGR: left button, press column (x, y) = (1, 2) which loads the second feed"
          917 rm -f "$plumbfile"
          918 touch "$plumbfile"
          919 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[<0;1;2M\x1b[<0;1;2m')loq" "$sc" "$feedfile1" "$feedfile2"
          920 status=$?
          921 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          922 contents="$(cat "$plumbfile")"
          923 test "$contents" = "http://d" || fail "Incorrect content: $contents"
          924 test_end
          925 
          926 test_start "Mouse SGR: right button, pipe contents of item to a pipe script"
          927 rm -f "$pipefile"
          928 touch "$pipefile"
          929 fakedata | SFEED_PIPER_INTERACTIVE="1" SFEED_PIPER="cat >$pipefile" SFEED_AUTOCMD="$($printf '\x1b[<2;1;2M\x1b[<2;1;2m')q" $sc
          930 status=$?
          931 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          932 contents="$(cat "$pipefile")"
          933 line1="$($printf '1\t2. b\thttp://b\t\t\t\t\t\t\n')"
          934 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
          935 test_end
          936 
          937 test_start "Mouse SGR: side button 7"
          938 rm -f "$plumbfile"
          939 touch "$plumbfile"
          940 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3o$($printf '\x1b[<128;1;2M\x1b[<128;1;2m\x1b[<128;1;2M\x1b[<128;1;2m')jooq" "$sc" "$feedfile1" "$feedfile2"
          941 status=$?
          942 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          943 contents="$(cat "$plumbfile")"
          944 test "$contents" = "http://d" || fail "Incorrect content: $contents"
          945 test_end
          946 
          947 test_start "Mouse SGR: side button 8"
          948 rm -f "$plumbfile"
          949 touch "$plumbfile"
          950 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3joh$($printf '\x1b[<129;1;2M\x1b[<129;1;2m\x1b[<129;1;2M\x1b[<129;1;2m')oq" "$sc" "$feedfile1" "$feedfile2"
          951 status=$?
          952 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          953 contents="$(cat "$plumbfile")"
          954 test "$contents" = "http://d" || fail "Incorrect content: $contents"
          955 test_end
          956 
          957 test_start "Mouse SGR: scroll 3 pages down and one up (selecting the last item of that page)"
          958 expectedurl="http://$((itemrows * 3 - 1))"
          959 rm -f "$plumbfile"
          960 touch "$plumbfile"
          961 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[<65;1;1M\x1b[<65;1;1M\x1b[<65;1;1M\x1b[<64;1;1M')oq" $sc
          962 status=$?
          963 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          964 contents="$(cat "$plumbfile")"
          965 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          966 test_end
          967 
          968 test_start "Mouse X10: left button, press column (x, y) = (1, 2) which is the second row, double-click"
          969 rm -f "$plumbfile"
          970 touch "$plumbfile"
          971 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[M !"\x1b[M#!"\x1b[M !"\x1b[M#!"')q" "$sc"
          972 status=$?
          973 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          974 contents="$(cat "$plumbfile")"
          975 test "$contents" = "http://b" || fail "Incorrect URL: $contents"
          976 test_end
          977 
          978 test_start "Mouse X10: right button, pipe contents of item to a pipe script"
          979 rm -f "$pipefile"
          980 touch "$pipefile"
          981 fakedata | SFEED_PIPER_INTERACTIVE="1" SFEED_PIPER="cat >$pipefile" SFEED_AUTOCMD="$($printf '\x1b[M"!"\x1b[M#!"')q" $sc
          982 status=$?
          983 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          984 contents="$(cat "$pipefile")"
          985 line1="$($printf '1\t2. b\thttp://b\t\t\t\t\t\t\n')"
          986 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
          987 test_end
          988 
          989 test_start "Mouse X10: scroll 3 pages down and one up (selecting the last item of that page)"
          990 expectedurl="http://$((itemrows * 3 - 1))"
          991 rm -f "$plumbfile"
          992 touch "$plumbfile"
          993 muchdata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="$($printf '\x1b[Ma!!\x1b[Ma!!\x1b[Ma!!\x1b[M`!!')oq" $sc
          994 status=$?
          995 test $status -eq 0 || fail "Exit code must be 0, was: $status"
          996 contents="$(cat "$plumbfile")"
          997 test "$contents" = "$expectedurl" || fail "Incorrect URL: $contents"
          998 test_end
          999 
         1000 test_start "Mouse X10: side button 7"
         1001 rm -f "$plumbfile"
         1002 touch "$plumbfile"
         1003 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3o$($printf '\x1b[M\xa0!!\x1b[M#!!')jooq" "$sc" "$feedfile1" "$feedfile2"
         1004 status=$?
         1005 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1006 contents="$(cat "$plumbfile")"
         1007 test "$contents" = "http://d" || fail "Incorrect content: $contents"
         1008 test_end
         1009 
         1010 test_start "Mouse X10: side button 8"
         1011 rm -f "$plumbfile"
         1012 touch "$plumbfile"
         1013 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3joh$($printf '\x1b[M\xa1!!\x1b[M#!!')oq" "$sc" "$feedfile1" "$feedfile2"
         1014 status=$?
         1015 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1016 contents="$(cat "$plumbfile")"
         1017 test "$contents" = "http://d" || fail "Incorrect content: $contents"
         1018 test_end
         1019 
         1020 # monocle layout: arrow down, open second feed (switches pane to item in monocle mode),
         1021 # scroll down, open item.
         1022 test_start "Monocle layout: mouse scroll down, open second feed (switches pane to item in monocle mode)"
         1023 rm -f "$plumbfile"
         1024 touch "$plumbfile"
         1025 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="3$($printf '\x1b[B')o$($printf '\x1b[<65;1;2M\x1b[<65;1;2m')oq" $sc "$feedfile1" "$feedfile2"
         1026 status=$?
         1027 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1028 contents="$(cat "$plumbfile")"
         1029 test "$contents" = "http://f" || fail "Incorrect URL: $contents"
         1030 test_end
         1031 
         1032 # Select pane items with keybind, then mouse side button 7 backward, go one item down,
         1033 # open it, switch to items pane with TAB, open item.
         1034 test_start "Mouse: side button 7, switches to feeds pane. Then open the item"
         1035 rm -f "$plumbfile"
         1036 touch "$plumbfile"
         1037 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="l$($printf '\x1b[<128;1;2M\x1b[<128;1;2m')jo        joq" "$sc" "$feedfile1" "$feedfile2"
         1038 status=$?
         1039 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1040 contents="$(cat "$plumbfile")"
         1041 test "$contents" = "http://e" || fail "Incorrect URL: $contents"
         1042 test_end
         1043 
         1044 # mouse disabled (toggle off), left button, press column (x, y) = (1, 2)
         1045 # which is the second row, double-click. So this should not do anything.
         1046 test_start "Mouse disabled (toggle off), left button, press column (x, y) = (1, 2)"
         1047 rm -f "$plumbfile"
         1048 touch "$plumbfile"
         1049 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="m$($printf '\x1b[<0;1;2M\x1b[<0;1;2m\x1b[<0;1;2M\x1b[<0;1;2m')q" "$sc"
         1050 status=$?
         1051 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1052 contents="$(cat "$plumbfile")"
         1053 test "$contents" = "" || fail "Incorrect URL: $contents"
         1054 test_end
         1055 
         1056 # Horizontal layout, resize 4 down, 2 up, doubleclick cell (1, 8). (3 feeds + line separator + items).
         1057 test_start "Resize sidebar"
         1058 rm -f "$plumbfile"
         1059 touch "$plumbfile"
         1060 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="2>>>><<$($printf '\x1b[<0;1;8M\x1b[<0;1;8m\x1b[<0;1;8M\x1b[<0;1;8m')q" "$sc" "$feedfile1" "$feedfile2" "$feedfile3"
         1061 status=$?
         1062 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1063 contents="$(cat "$plumbfile")"
         1064 test "$contents" = "http://b" || fail "Incorrect content: $contents"
         1065 test_end
         1066 
         1067 # file does not exist.
         1068 test_start "Test opening a file via argv that does not exist"
         1069 SFEED_AUTOCMD="q" "$sc" "$feedfile1" "$feedfile2" "/tmp/noexist"
         1070 status=$?
         1071 test $status -eq 1 || fail "Exit code must be 1, was: $status"
         1072 test_end
         1073 
         1074 # file access denied.
         1075 test_start "Test opening a file via argv with no permission to it"
         1076 SFEED_AUTOCMD="q" "$sc" "$feedfile1" "$feedfile2" "/root/denied"
         1077 status=$?
         1078 test $status -eq 1 || fail "Exit code must be 1, was: $status"
         1079 test_end
         1080 
         1081 # setupterm: terminfo database or entry for $TERM not found
         1082 # NOTE: if using minicurses this does not error.
         1083 test_start 'Test bogus $TERM'
         1084 emptydata | TERM=noexist "$sc"
         1085 status=$?
         1086 test $status -eq 1 || fail "Exit code must be 1, was: $status"
         1087 test_end
         1088 
         1089 # $TERM: test tparm() returning NULL. Assuming TERM=dumb exists and returns NULL.
         1090 test_start 'Test tparm() returning NULL for a capability'
         1091 fakedata | TERM=dumb SFEED_AUTOCMD="jjkkq" "$sc"
         1092 status=$?
         1093 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1094 test_end
         1095 
         1096 test_start "Mark read: nonexistant command: child in popen returns status non-zero"
         1097 rm -f "$urlfile"
         1098 echo -n "test" > "$urlfile"
         1099 (sleep 1; pkill -SIGTERM sfeed_curses) &
         1100 fakedata | SFEED_URL_FILE="$urlfile" SFEED_MARK_READ="/tmp/nonexist" SFEED_AUTOCMD="r" $sc
         1101 status=$?
         1102 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1103 expect="test"
         1104 result=$(cat "$urlfile")
         1105 test "$result" = "$expect" || fail "Invalid result"
         1106 test_end
         1107 
         1108 test_start "Check if sfeed_curses is killed by SIGTERM while an interactive child program is running"
         1109 rm -f /tmp/sfeed_curses_sigterm # state file.
         1110 plumbscript2="$(mktemp)"
         1111 $printf '#!/bin/sh\ncat\n' > "$plumbscript2"
         1112 chmod +x "$plumbscript2"
         1113 
         1114 (sleep 1; pkill -SIGTERM sfeed_curses;
         1115 sleep 1; pgrep sfeed_curses >/dev/null && touch /tmp/sfeed_curses_sigterm) &
         1116 
         1117 (sleep 3; pkill -SIGKILL sfeed_curses) & # watchdog: make sure it is killed eventually.
         1118 
         1119 fakedata | SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript2" SFEED_AUTOCMD="o" $sc
         1120 status=$?
         1121 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1122 wait
         1123 
         1124 rm -f "$plumbscript2"
         1125 if test -f /tmp/sfeed_curses_sigterm; then
         1126         rm -f /tmp/sfeed_curses_sigterm
         1127         fail "sfeed_curses was not killed by SIGTERM while the program was running"
         1128 fi
         1129 rm -f /tmp/sfeed_curses_sigterm
         1130 test_end
         1131 
         1132 test_start "Test non-interactive mode for yanking a link"
         1133 rm -f "$pipefile"
         1134 touch "$pipefile"
         1135 (sleep 1;pkill -SIGTERM sfeed_curses) &
         1136 SFEED_YANKER_INTERACTIVE="0" SFEED_YANKER="cat >$pipefile" SFEED_AUTOCMD="ly" $sc "$feedfile1" "$feedfile2" "$feedfile3"
         1137 status=$?
         1138 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1139 contents="$(cat "$pipefile")"
         1140 line1="$($printf 'http://a')"
         1141 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
         1142 test_end
         1143 
         1144 test_start "Test non-interactive mode for piping content"
         1145 rm -f "$pipefile"
         1146 touch "$pipefile"
         1147 (sleep 1;pkill -SIGTERM sfeed_curses) &
         1148 SFEED_PIPER_INTERACTIVE="0" SFEED_PIPER="cat >$pipefile" SFEED_AUTOCMD="lp" $sc "$feedfile1" "$feedfile2" "$feedfile3"
         1149 status=$?
         1150 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1151 contents="$(cat "$pipefile")"
         1152 line1="$($printf '0\t1. a\thttp://a\t\t\t\t\t\t\n')"
         1153 test "$contents" = "$line1" || fail "Incorrect content: $contents, expected: $line1"
         1154 test_end
         1155 
         1156 test_start "Test non-interactive mode for plumbing a link"
         1157 rm -f "$plumbfile"
         1158 touch "$plumbfile"
         1159 (sleep 1;pkill -SIGTERM sfeed_curses) &
         1160 SFEED_PLUMBER_INTERACTIVE="0" SFEED_PLUMBER="$plumbscript" SFEED_AUTOCMD="lo" $sc "$feedfile1" "$feedfile2" "$feedfile3"
         1161 status=$?
         1162 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1163 contents="$(cat "$plumbfile")"
         1164 test "$contents" = "http://a" || fail "Incorrect URL: $contents"
         1165 test_end
         1166 
         1167 # SIGTERM while search is open.
         1168 test_start "test SIGTERM while search is open: should exit"
         1169 (sleep 1;pkill -SIGTERM sfeed_curses) &
         1170 SFEED_AUTOCMD="/abc" "$sc" "$feedfile1" "$feedfile2"
         1171 status=$?
         1172 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1173 test_end
         1174 
         1175 test_start "test SIGINT and exit status"
         1176 (sleep 1;pkill -SIGINT sfeed_curses) &
         1177 SFEED_AUTOCMD="jo" "$sc" "$feedfile1" "$feedfile2"
         1178 status=$?
         1179 test $status -eq 130 || fail "Exit code must be 130, was: $status"
         1180 test_end
         1181 
         1182 test_start "test SIGINT, interrupting the search prompt"
         1183 rm -f /tmp/sfeed_tests.tmp
         1184 (sleep 1
         1185 pkill -SIGINT sfeed_curses
         1186 sleep 1
         1187 c=$(pgrep sfeed_curses | wc -l)
         1188 echo "$c" > /tmp/sfeed_tests.tmp
         1189 pkill -SIGTERM sfeed_curses # make sure it stops.
         1190 ) &
         1191 SFEED_AUTOCMD="$($printf '/abc')" "$sc" "$feedfile1" "$feedfile2"
         1192 status=$?
         1193 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1194 c="$(cat /tmp/sfeed_tests.tmp)"
         1195 c=$((c+0)) # convert int
         1196 test $c -gt 0 || fail "The process was interrupted instead of the prompt"
         1197 rm -f /tmp/sfeed_tests.tmp
         1198 test_end
         1199 
         1200 test_start "Check reaping zombies (SIGCHLD)"
         1201 rm -f /tmp/sfeed_zombies
         1202 touch /tmp/sfeed_zombies
         1203 (sleep 3
         1204 # check for any zombies
         1205 ps -o 'state=' | grep Z > "/tmp/sfeed_zombies"
         1206 pkill -SIGTERM sfeed_curses
         1207 ) &
         1208 fakedata | \
         1209 SFEED_YANKER_INTERACTIVE="0" SFEED_YANKER="sleep 1" \
         1210 SFEED_AUTOCMD="yjy" \
         1211 $sc
         1212 status=$?
         1213 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1214 count=$(wc -l < "/tmp/sfeed_zombies")
         1215 count=$((count + 0))
         1216 rm -f /tmp/sfeed_zombies
         1217 test $count -eq 0 || fail "Failed to handle SIGCHLD and reap zombies"
         1218 test_end
         1219 
         1220 test_start "Check reaping zombies (SIGCHLD) while line editor is open"
         1221 rm -f /tmp/sfeed_zombies
         1222 touch /tmp/sfeed_zombies
         1223 (sleep 3
         1224 # check for any zombies
         1225 ps -o 'state=' | grep Z > "/tmp/sfeed_zombies"
         1226 pkill -SIGTERM sfeed_curses
         1227 ) &
         1228 fakedata | \
         1229 SFEED_YANKER_INTERACTIVE="0" SFEED_YANKER="sleep 1" \
         1230 SFEED_AUTOCMD="yjy/abc" \
         1231 $sc
         1232 status=$?
         1233 test $status -eq 143 || fail "Exit code must be 143, was: $status"
         1234 count=$(wc -l < "/tmp/sfeed_zombies")
         1235 count=$((count + 0))
         1236 rm -f /tmp/sfeed_zombies
         1237 test $count -eq 0 || fail "Failed to handle SIGCHLD and reap zombies"
         1238 test_end
         1239 
         1240 test_start "Check if \$SFEED_FEED_PATH variable is properly set for plumbing"
         1241 rm -f /tmp/sfeed_curses_path # value of $SFEED_FEED_PATH
         1242 plumbscript2="$(mktemp)"
         1243 $printf '#!/bin/sh\necho "$SFEED_FEED_PATH" > /tmp/sfeed_curses_path\n' > "$plumbscript2"
         1244 chmod +x "$plumbscript2"
         1245 SFEED_PLUMBER_INTERACTIVE="1" SFEED_PLUMBER="$plumbscript2" SFEED_AUTOCMD="loq" $sc "$feedfile1"
         1246 status=$?
         1247 test $status -eq 0 || fail "Exit code must be 0, was: $status"
         1248 rm -f "$plumbscript2"
         1249 content=$(cat '/tmp/sfeed_curses_path')
         1250 if ! test "$content" = "$feedfile1"; then
         1251         rm -f /tmp/sfeed_curses_path
         1252         fail 'Value of $SFEED_FEED_PATH is incorrect'
         1253 fi
         1254 rm -f /tmp/sfeed_curses_path
         1255 test_end
         1256 
         1257 # -a runs automated tests only.
         1258 test "$1" = "-a" || manual
         1259 
         1260 cleanup
         1261 echo "OK, all tests (${test_count}) passed \o/"