. "$BST_LIB" require vim.tiny vim-tiny/present # --- what the binary says it is --------------------------------------------- # These run before the pty leg on purpose: if expect is ever absent, the `require` # further down ends the file, and these have already reported. check_out vim-tiny/version "VIM - Vi IMproved" vim.tiny --version # THE FEATURE SET IS PART OF THE DELIVERABLE, NOT AN IMPLEMENTATION DETAIL. This # image ships vim-tiny, not vim: PACKAGECONFIG[tiny] passes --with-features=tiny, # and the banner names the set it was built with. Asserting it here is what keeps # a future recipe change from quietly shipping the 4 MB full editor -- or, worse, # shipping the tiny binary while the image notes promise the full one. check_out vim-tiny/tiny-build "Tiny version without GUI" vim.tiny --version # ...and the corollary, stated in the negative so it cannot pass by accident: a # tiny build has no expression evaluator, which the banner reports as "-eval". # This is the single most user-visible consequence of the feature set and is why # the test plan tells the reader not to expect scripting on this image. if vim.tiny --version 2>&1 | grep -q -- '-eval'; then bst_ok vim-tiny/no-eval else bst_notok vim-tiny/no-eval "--version does not report -eval; this is not a --with-features=tiny build" fi # --- update-alternatives actually wired the names ---------------------------- # vim-tiny registers vi (/bin/vi) and vim (/usr/bin/vim) at priority 90 against # the busybox applet's 50. Assert the LINKS RESOLVE TO THE SAME BINARY rather # than that a file exists: on an image where the alternative did not win, /bin/vi # is still present and still runs -- it is just busybox vi, and every other case # in this suite would keep passing while the port had not actually taken the name. check_out vim-tiny/alt-vi "VIM - Vi IMproved" /bin/vi --version check_out vim-tiny/alt-vim "VIM - Vi IMproved" /usr/bin/vim --version # --- the Ex leg: a real batch mode, no terminal at all ----------------------- # `-e -s` is silent Ex mode: vim reads ex commands from stdin and writes nothing # to a terminal, so this whole block runs under the piped runner with no pty. # Every case asserts a FILE ON DISK afterwards, which is the strongest statement # available about an editor -- it is the bytes a user would have kept. # -u NONE so no vimrc can change what the commands mean, -n so no swap file is # left behind to prompt at the next session. work=${TMPDIR:-/tmp}/bst-vim.$$ mkdir -p "$work" # S1: substitute across the whole buffer, then write and quit. The exit status is # taken from THIS invocation rather than from a second throwaway one: an Ex script # that fails part way still exits non-zero, so the status and the file content are # two independent readings of the same run and belong together. printf '%s\n' alpha bravo charlie > "$work/sub.txt" printf '%s\n' '%s/alpha/OMEGA/g' 'wq' | vim.tiny -u NONE -n -e -s "$work/sub.txt" ex_rc=$? check_eq vim-tiny/ex-rc 0 "$ex_rc" check_out vim-tiny/ex-subst "OMEGA" sh -c "cat '$work/sub.txt'" check_out vim-tiny/ex-keeps "charlie" sh -c "cat '$work/sub.txt'" if grep -q '^alpha$' "$work/sub.txt" 2>/dev/null; then bst_notok vim-tiny/ex-subst-took "alpha survived %s/alpha/OMEGA/g" else bst_ok vim-tiny/ex-subst-took fi # S2: delete a line by address. Line 2 goes; 1 and 3 stay. printf '%s\n' one two three > "$work/del.txt" printf '%s\n' '2d' 'wq' | vim.tiny -u NONE -n -e -s "$work/del.txt" check_eq vim-tiny/ex-del-lines 2 "$(wc -l < "$work/del.txt" 2>/dev/null | tr -d ' ')" if grep -q '^two$' "$work/del.txt" 2>/dev/null; then bst_notok vim-tiny/ex-del-took "two survived :2d" else bst_ok vim-tiny/ex-del-took fi check_out vim-tiny/ex-del-kept-first "one" sh -c "cat '$work/del.txt'" check_out vim-tiny/ex-del-kept-last "three" sh -c "cat '$work/del.txt'" # S3: ex `append` -- opens input mode inside Ex, terminated by a lone dot. This is # the one Ex case that types TEXT rather than a command, so it covers the input # path the substitute cases do not. printf '%s\n' head > "$work/app.txt" printf '%s\n' '1a' 'appended line' '.' 'wq' | vim.tiny -u NONE -n -e -s "$work/app.txt" check_out vim-tiny/ex-append "appended line" sh -c "cat '$work/app.txt'" check_eq vim-tiny/ex-append-lines 2 "$(wc -l < "$work/app.txt" 2>/dev/null | tr -d ' ')" # S4: write to a DIFFERENT file -- proves the write path is not just an in-place # rewrite of an existing inode, and leaves an artifact whose content is checked. printf '%s\n' copyme > "$work/src.txt" printf '%s\n' "w $work/dst.txt" 'q' | vim.tiny -u NONE -n -e -s "$work/src.txt" check vim-tiny/ex-write-new test -f "$work/dst.txt" check_out vim-tiny/ex-write-body "copyme" sh -c "cat '$work/dst.txt' 2>/dev/null" # --- the pty leg: the terminal half the Ex mode never touches ---------------- # expect supplies the pty; 45-expect.test covers whether that machinery works at # all. The payload types blind and the verdicts below read the disk -- see its # header for why that is both necessary here and the stronger assertion. require expect vim-tiny/expect-present printf '%s\n' alpha bravo charlie > "$work/cut.txt" printf '%s\n' alpha bravo charlie > "$work/arrow.txt" out=$(expect "$BST_DATA/selftest_vim.exp" "$work" 2>&1); rc=$? case "$out" in *ALL-VIM-OK*) all=1 ;; *) all=0 ;; esac if [ "$rc" -eq 0 ] && [ "$all" -eq 1 ]; then bst_ok vim-tiny/all-ok else bst_notok vim-tiny/all-ok "rc=$rc $(_bst_1line "$out")"; fi # Echo the payload's startup measurement into the run output. It is not a verdict # -- there is no threshold worth failing on -- but it is the number the payload's # 60 s timeout was set from, so it has to stay visible on a green run too, which # is exactly when the all-ok detail string that would otherwise carry it is empty. printf '%s\n' "$out" | grep '^V-V1elapsed' || true # vim came up under a real terminal (tgetent + the /etc/terminfo entry for $TERM # + raw mode + first repaint), and each session exited 0 of its own accord. for tag in V1intro V2introexit V3typedexit V4cutexit V5arrowexit; do case "$out" in *"V-$tag OK"*) bst_ok "vim-tiny/$tag" ;; *) bst_notok "vim-tiny/$tag" "not OK in payload output (rc=$rc)" ;; esac done # --- what reached the disk from the pty sessions (the verdicts that count) ---- # S2: text typed in insert mode, saved with :wq, in order and nothing else. check_out vim-tiny/typed-first "hello from vim" sh -c "cat '$work/typed.txt'" check_out vim-tiny/typed-second "second line" sh -c "cat '$work/typed.txt'" check_eq vim-tiny/typed-lines 2 "$(wc -l < "$work/typed.txt" 2>/dev/null | tr -d ' ')" # S3: dd on line 1 removed exactly that line and left the rest intact. check_eq vim-tiny/cut-lines 2 "$(wc -l < "$work/cut.txt" 2>/dev/null | tr -d ' ')" if grep -q '^alpha$' "$work/cut.txt" 2>/dev/null; then bst_notok vim-tiny/cut-removed "alpha still present after dd + :wq" else bst_ok vim-tiny/cut-removed fi check_out vim-tiny/cut-kept "charlie" sh -c "cat '$work/cut.txt'" # S4: THE ESCAPE-SEQUENCE VERDICT. Down arrow (ESC [ B) then dd must take line 2. # alpha kept + charlie kept + bravo gone == the sequence decoded as one key. bravo # present (and alpha gone) would mean the ESC never joined its bracket -- which on # this editor is the interesting failure, because a bare ESC is also vim's own # leave-insert-mode key, so the two readings are a real ambiguity rather than a # stray. A "[B" left in the file would mean it was typed as literal text instead. check_eq vim-tiny/arrow-lines 2 "$(wc -l < "$work/arrow.txt" 2>/dev/null | tr -d ' ')" if grep -q '^bravo$' "$work/arrow.txt" 2>/dev/null; then bst_notok vim-tiny/arrow-decoded "bravo survived: Down (ESC [ B) did not move the cursor to line 2" else bst_ok vim-tiny/arrow-decoded fi check_out vim-tiny/arrow-kept-first "alpha" sh -c "cat '$work/arrow.txt'" check_out vim-tiny/arrow-kept-last "charlie" sh -c "cat '$work/arrow.txt'" if grep -q '\[B' "$work/arrow.txt" 2>/dev/null; then bst_notok vim-tiny/arrow-not-literal "the escape sequence was inserted as literal text" else bst_ok vim-tiny/arrow-not-literal fi rm -rf "$work"