. "$BST_LIB" # BST-TIMEOUT: 420 # ~110 cases, each one exec of a multi-MB wasm image; that # exec is the whole cost here -- every case is bounded and # none of them waits on anything. Replace with a measured # elapsed once this suite has run on target a few times. # 57-xrefresh.test -- xrefresh 1.1.0 (meta-oe recipes-graphics/xorg-app): the # screen-refresh utility. It maps an override-redirect window of a chosen # background over all or part of the screen, flushes, waits out -delay, and # unmaps it by exiting, forcing every client underneath to repaint. See # recipes-graphics/xorg-app/xrefresh_%.bbappend for what the port changes -- a # static-link closure, and nothing else. # # THIS IS ROUND 14's CONTROL CASE, which is the whole reason BRINTOS-2503 exists # and the reason this suite is worth its cases beside sixteen that look like it. # xrefresh's DEPENDS is `util-macros-native virtual/libx11' and nothing more: # configure.ac:43 asks pkg-config for `x11 xproto' alone, and xrefresh.c includes # Xlib.h, Xutil.h and Xos.h and no extension header at all. Every other member of # the round carries an extension library ON TOP OF the connection path this one # carries alone. So if xrefresh produces the documented refusal and a member # around it does not, the difference is in that member's extension library and # not in the connection path they share -- and this suite is what makes that # comparison possible, by measuring the shared path with nothing else in it. # # THERE IS NO SCREEN HERE. Everything xrefresh does -- XCreateWindow, XMapWindow, # XFlush -- lives on a server, and there is no server on this image. So what is # reachable is its OPTION PARSER and its REFUSAL, and the whole of this suite is # about those two and the boundary between them. # # THE BOUNDARY IS THE OPPOSITE WAY ROUND FROM xprop'S, and the same way round as # xsetroot's. xprop (BRINTOS-2462) calls Setup_Display_And_Screen() BEFORE its # own option loop, so even `xprop -version' dies at the connection and its port # needed a patch. xrefresh is built the other way: main()'s whole argv loop # (xrefresh.c:207-253) runs to completion, THEN XOpenDisplay is called at :255. # That single ordering fact decides every case below, so the suite asserts it in # BOTH directions: # # PRE-CONNECT, answering as themselves -- `-version' (:241, stdout, exit 0), # `-help' (:245, stdout, exit 0), a missing option argument (missing_arg at # :95), an unrecognised argument (unknown_arg at :101). None of these needs a # server and none of them is patched in; they work as shipped. # # POST-CONNECT, replaced by the refusal -- everything that INTERPRETS an # option's argument rather than storing it. XParseGeometry for `-geometry' # (:308), XParseColor/XAllocColor for `-solid' (:358), XGetDefault for the # resource defaults (:264), and nanosleep for `-delay' (:399). # # SO THE PARSING LOSES THE RACE WITH THE CONNECTING, and that REFUTES a criterion # BRINTOS-2503 was written with. The ticket asked for `-geometry' with a # malformed specification to produce "the documented diagnostic and a non-zero # exit". The exit is non-zero, but the diagnostic is the CONNECTION's, not a # geometry one: # # xrefresh -geometry notageometry -> exit 1, "unable to open display ''" # # and it is byte-identical to what a WELL-FORMED geometry produces. There is no # geometry diagnostic upstream to reach in any case: XParseGeometry returns a # bitmask and a spec it cannot read simply yields NoValue, so xrefresh never # learns that its argument was malformed and never could report it. The same # holds for `-solid' with a colour name that is not one. Section 8 asserts that # refutation directly, as a measurement rather than as prose, and those are the # cases that would go red the day this image grows a server -- which is the right # time to be told. # # THE REFUSAL ITSELF IS THE PORT'S OWN CASE. A wasm32 socket-address or # struct-packing mistake lands in connection setup, and it lands there as a # crash, a hang, or a diagnostic that is not this one. Every refusal case is # therefore the same four-part shape: the documented text on STDERR, nothing on # STDOUT, status 1, and inside a bound. A red names which of the four the target # got wrong. # # EXIT 1, NOT 2. xrefresh.c:258 is `exit (1)' -- unlike xsetroot.c:233, which # exits 2 from a diagnostic that reads the same. Writing 2 here would make every # refusal case red against a correct binary. # # EVERY EXPECTATION BELOW IS AN x86-64 MEASUREMENT, NOT A READING OF THE SOURCE. # The authoring host ships xrefresh 1.0.7, which is NOT the version the recipe # pins and whose Syntax()/missing_arg()/unknown_arg() shape is the older one -- so # the distro binary was NOT used. Instead the recipe's own tarball (sha256 # 29ed592d… , the value in xrefresh_1.1.0.bb) was built on the host against the # host's libX11 on 2026-09-12 and every case below run against THAT binary with # DISPLAY removed: the refusal text and its two spaces, exit 1, the stream each # answer uses, the argument-error wording, the eleven usage lines, and the # geometry/colour orderings. That is what a phase-A suite can honestly assert # without a target: it removes typo-shaped reds from the first on-target run, so # a red that DOES arrive is about wasm32 rather than about the expectation. # # WHAT THE CONTROL CANNOT SAY, and the target run is what settles it: whether # wasm32's connect path reaches this refusal at all rather than crashing or # hanging (sections 5 and 6 bound it for exactly that), and the packaging cases # in section 1, which are about this image's .deb and have no x86-64 analogue. S=xrefresh require xrefresh $S/present W=${TMPDIR:-/tmp}/bst-xrefresh.$$ mkdir -p "$W" 2>/dev/null check $S/tmp-writable sh -c "printf x > $W/.w && rm -f $W/.w" nl=' ' # The exact refusal, built from the display name the run should report. # # TWO SPACES after the colon: xrefresh.c:256 is # `fprintf(stderr, "%s: unable to open display '%s'\n", ...)'. Every OTHER # diagnostic in this program uses ONE -- missing_arg at :97 and unknown_arg at # :104 -- so the asymmetry is upstream's and both spellings are asserted. # # The `%s' is ProgramName, and :205 is `ProgramName = argv[0]' with no # basename() -- so this is `xrefresh' only because every invocation here goes # through PATH. A case that ran /usr/bin/xrefresh by path would expect the path. refusal() { printf "xrefresh: unable to open display '%s'" "$1"; } # first : its first line, with shell builtins only (no fork). first() { case "$1" in *"$nl"*) printf '%s' "${1%%$nl*}" ;; *) printf '%s' "$1" ;; esac; } # split : run xrefresh with DISPLAY REMOVED, bounded, keeping # the two streams APART; sets $sout, $serr and $rc. # # `env -u DISPLAY' rather than `DISPLAY= ': XDisplayName() treats an EMPTY # DISPLAY and an ABSENT one alike, so both reach the same diagnostic -- but only # the absent one is the state this image actually boots in, and asserting the # state we ship is the point. # # Keeping the streams apart is more of what this suite asserts than it was for # xsetroot, because xrefresh 1.1.0 CHOOSES its stream from its exit status # (Syntax at :75 is `FILE *out = (exitval == EXIT_SUCCESS) ? stdout : stderr'): # the identical usage block lands on stdout for `-help' and on stderr for an # argument error. A folded capture could not tell those two apart at all. # Both files are under $TMPDIR, never the rootfs. split() { _t=$1; shift bst_bound "$_t" env -u DISPLAY xrefresh "$@" >"$W/o" 2>"$W/e" rc=$? sout=$(cat "$W/o" 2>/dev/null); serr=$(cat "$W/e" 2>/dev/null) } # withdisp : as split, but with DISPLAY SET. withdisp() { _t=$1; _dpy=$2; shift 2 bst_bound "$_t" env DISPLAY="$_dpy" xrefresh "$@" >"$W/o" 2>"$W/e" rc=$? sout=$(cat "$W/o" 2>/dev/null); serr=$(cat "$W/e" 2>/dev/null) } # refuses : the whole four-part refusal shape, as three # cases. Used by the option sweep, where the assertion is identical every time # and only the argv changes. refuses() { _rid=$1; _rt=$2; shift 2 split "$_rt" "$@" check_eq "$S/$_rid-rc" "1" "$rc" check_eq "$S/$_rid-stderr" "$(refusal '')" "$serr" check_eq "$S/$_rid-stdout" "" "$sout" } # rejects : the pre-connect # diagnostic shape -- status 1, the tool's own message as the FIRST stderr line, # the usage block behind it ON STDERR, and nothing on stdout. # # The first line only, not the whole blob: Syntax() prints an eleven-line option # list and pinning it per case would assert the help text a dozen times over. # That text is asserted ONCE, in the -help cases below. rejects() { _jid=$1; _jt=$2; _jwant=$3; shift 3 split "$_jt" "$@" check_eq "$S/$_jid-rc" "1" "$rc" check_eq "$S/$_jid-stderr" "$_jwant" "$(first "$serr")" check_eq "$S/$_jid-stdout" "" "$sout" case "$serr" in *"usage: xrefresh [-options] [geometry] [display]"*) bst_ok "$S/$_jid-usage" ;; *) bst_notok "$S/$_jid-usage" "no usage block behind the diagnostic: $(_bst_1line "$serr")" ;; esac } # --- 1. the packaging -------------------------------------------------------- # Asserted against dpkg's own file list as well as by stat: a binary that # reached the image by some other route satisfies the stat and does not satisfy # the claim. check $S/install-path test -x /usr/bin/xrefresh check_eq $S/which "/usr/bin/xrefresh" "$(command -v xrefresh)" check $S/man-installed test -s /usr/share/man/man1/xrefresh.1 pkglist=$(cat /var/lib/dpkg/info/xrefresh.list 2>/dev/null) if [ -n "$pkglist" ]; then bst_ok $S/pkg-list hasline() { case "$nl$3$nl" in *"$nl$2$nl"*) bst_ok "$1" ;; *) bst_notok "$1" "not listed: $2" ;; esac; } hasline $S/pkg-binary /usr/bin/xrefresh "$pkglist" # xorg-app-common.inc's FILES:${PN} would also take ${libdir}/X11/xrefresh # and the app-defaults directory if the package had grown either; xrefresh # ships neither, so the one binary IS the package's runtime content. check_eq $S/pkg-one-binary 1 \ "$(printf '%s\n' "$pkglist" | LC_ALL=C grep -c '^/usr/bin/')" else bst_notok $S/pkg-list "no /var/lib/dpkg/info/xrefresh.list -- the packaging cases cannot run" fi # The man page is a SEPARATE package, and naming it in the roster is a decision # a split could silently undo. doclist=$(cat /var/lib/dpkg/info/xrefresh-doc.list 2>/dev/null) if [ -n "$doclist" ]; then bst_ok $S/pkg-doc-list hasline $S/pkg-doc-man /usr/share/man/man1/xrefresh.1 "$doclist" else bst_notok $S/pkg-doc-list "no /var/lib/dpkg/info/xrefresh-doc.list" fi # dpkg's own view of the install, which is what "the .deb installs on target" # means as an assertion rather than as a claim. sed -n '/^Package: xrefresh$/,/^$/p' /var/lib/dpkg/status > "$W/st" 2>/dev/null check $S/pkg-known test -s "$W/st" check_out $S/pkg-installed "Status: install ok installed" cat "$W/st" check_out $S/pkg-arch "Architecture: wasm32" cat "$W/st" # --- 2. the binary ran at all ------------------------------------------------ # THE FIRST THING TO ESTABLISH, and it is the static-link closure's case. # # A main whose recorded needed entries cannot be bound is refused by the loader # before its first instruction, and that refusal arrives as exit 127 (or 126 on # the needed-entry leg) with no output of the program's own -- see # lib/bst-census.sh for why those two statuses and not others. xrefresh failing # to open a display is a status the PROGRAM chose, so a status of 1 carrying # xrefresh's own diagnostic is proof that the image bound libX11, libxcb, libXau # and libXdmcp and entered main(). If the .bbappend's XREFRESH_LIBS closure were # missing, wasmld would have refused the image long before this -- but if such a # binary ever did ship, this is the case that would name it. split 30 -none check_eq $S/linked-and-ran "1" "$rc" # --- 3. -version: the one thing that answers on stdout with no argument ------ # xrefresh.c:241-243 is inside the argv loop, so it answers BEFORE any connect # and needs no patch. PACKAGE_STRING is autoconf's ` ' from # AC_INIT, which is what pins the shipped version to the recipe's PV. split 30 -version check_eq $S/version-rc "0" "$rc" check_eq $S/version-stdout "xrefresh 1.1.0" "$sout" check_eq $S/version-stderr "" "$serr" # -version WINS OVER A LATER OPTION, because the loop exits at it. Without this # the suite would not have measured that the answer is an exit rather than a # flag consulted afterwards. split 30 -version -solid red check_eq $S/version-first-rc "0" "$rc" check_eq $S/version-first-stdout "xrefresh 1.1.0" "$sout" # ...and it does NOT win over an earlier hard error, for the same reason: the # loop reaches the unrecognized argument first and never gets to -version. split 30 -nosuchopt -version check_eq $S/version-after-error-rc "1" "$rc" # --- 4. -help: the usage text, and the stream it picks ----------------------- # THIS IS WHERE xrefresh 1.1.0 DIFFERS FROM ITS NEIGHBOURS AND FROM ITS OWN # 1.0.x. xsetroot's usage() prints to STDERR and exits 1 for `-help'. xrefresh # 1.1.0 introduced `Syntax(int exitval)' (xrefresh.c:72-92), which picks the # stream FROM the status -- stdout for EXIT_SUCCESS, stderr for EXIT_FAILURE -- # so `-help' is a SUCCESS that prints on STDOUT, and the identical block behind # an argument error is a FAILURE that prints on stderr. A port that quietly # restored the older behaviour would satisfy neither half. split 30 -help check_eq $S/help-rc "0" "$rc" check_eq $S/help-stderr "" "$serr" check_eq $S/help-first "usage: xrefresh [-options] [geometry] [display]" "$(first "$sout")" # The option list itself, in one pass. Every name here is an option the sweep # below drives, so a help text that stopped documenting one of them would be # caught beside the option still working. for _o in -display -geometry -black -white -solid -root -none -delay -version; do case "$sout" in *" $_o"*) bst_ok "$S/help-documents$_o" ;; *) bst_notok "$S/help-documents$_o" "not in the usage text" ;; esac done # The two short forms are documented on their own options' lines rather than as # entries of their own, so they are matched as text rather than as list items. case "$sout" in *"or -d"*) bst_ok $S/help-documents-d ;; *) bst_notok $S/help-documents-d "the -d short form is not documented" ;; esac case "$sout" in *"or -g spec"*) bst_ok $S/help-documents-g ;; *) bst_notok $S/help-documents-g "the -g short form is not documented" ;; esac # The trailer, which states the defaults the program applies when nothing is # asked of it -- and which is the last line of the block, so asserting it says # the whole block arrived rather than a truncated head of it. case "$sout" in *"The default is: xrefresh -none -delay 0"*) bst_ok $S/help-defaults-line ;; *) bst_notok $S/help-defaults-line "the defaults trailer is missing" ;; esac # `-h' is an abbreviation of -help, not an option in its own right: :245 is # `isabbreviation("-help", arg, 1)'. It must produce the identical block. split 30 -h _helpout=$sout split 30 -help check_eq $S/help-abbrev-same "$_helpout" "$sout" check_eq $S/help-abbrev-rc "0" "$rc" # THE SAME BLOCK ON THE OTHER STREAM, asserted directly. This is the single case # that says Syntax() picks its stream from its status rather than always using # one: the usage text after an argument error must be byte-identical to -help's # and must arrive on stderr with nothing on stdout. split 30 -nosuchopt check_eq $S/help-block-on-stderr "$_helpout" "${serr#*"$nl$nl"}" check_eq $S/help-block-stdout-empty "" "$sout" # --- 5. the documented refusal, with no DISPLAY ------------------------------ split 30 -none check_eq $S/nodisplay-rc "1" "$rc" check_eq $S/nodisplay-stderr "$(refusal '')" "$serr" check_eq $S/nodisplay-stdout "" "$sout" # A bare `xrefresh' -- no arguments at all -- takes the same path, and it is the # documented DEFAULT invocation (`-none -delay 0'), so it is the one a user # actually types. It is worth its own case because with action left at doDefault # the program is a different one after the connect: :264 consults XGetDefault # for a `Solid' resource and then walks pair_table. All of that is post-connect, # so the observable answer is identical, and asserting so is what says the # argument-less path was not overlooked. split 30 check_eq $S/bare-rc "1" "$rc" check_eq $S/bare-stderr "$(refusal '')" "$serr" check_eq $S/bare-stdout "" "$sout" # TWICE, IDENTICALLY. A connection setup that scribbles -- an uninitialised # sockaddr, a struct whose wasm32 packing differs from the host's -- can produce # the right answer once and a different one next time. Two runs agreeing is # cheap and is the only case here that could catch that. split 30 -none _firstrun=$serr split 30 -none check_eq $S/nodisplay-repeatable "$_firstrun" "$serr" # --- 6. the refusal with a DISPLAY nothing is listening on ------------------- # TWO TRANSPORTS, and they are different code in libX11's xtrans: a TCP display # goes through a connect(2) to a port, a `:N' display through a unix socket in # /tmp/.X11-unix. Either could HANG rather than refuse on a target whose socket # layer is new, and a hang is the failure this bound exists to name. # # 15 seconds is far more than a refusal needs and far less than a stalled # connect would take; a 124 here IS the finding, and it is reported as one # rather than as a wrong string. withdisp 15 127.0.0.1:9 -none check_eq $S/tcp-rc "1" "$rc" check_eq $S/tcp-stderr "$(refusal '127.0.0.1:9')" "$serr" check_eq $S/tcp-stdout "" "$sout" withdisp 15 :99 -none check_eq $S/unix-rc "1" "$rc" check_eq $S/unix-stderr "$(refusal ':99')" "$serr" check_eq $S/unix-stdout "" "$sout" # `-display ' on the COMMAND LINE, which is a different variable from the # environment one (displayname at :213 rather than XDisplayName's getenv), and # it must win. The refusal naming the argument is what proves the option was # consumed rather than ignored. split 15 -display 127.0.0.1:9 -none check_eq $S/opt-display-rc "1" "$rc" check_eq $S/opt-display-stderr "$(refusal '127.0.0.1:9')" "$serr" # -d is the documented short form, and -di an undocumented abbreviation of the # same option: :211 is `isabbreviation("-display", arg, 2)', so ANY prefix of # -display two characters or longer is accepted. Both are asserted because the # short form is an interface and the abbreviation is a consequence of it. split 15 -d 127.0.0.1:9 -none check_eq $S/opt-d-rc "1" "$rc" check_eq $S/opt-d-stderr "$(refusal '127.0.0.1:9')" "$serr" split 15 -di 127.0.0.1:9 -none check_eq $S/opt-di-stderr "$(refusal '127.0.0.1:9')" "$serr" # The command line beats the environment, in that order. withdisp 15 :99 -display 127.0.0.1:9 -none check_eq $S/opt-display-wins "$(refusal '127.0.0.1:9')" "$serr" # --- 7. the option sweep ----------------------------------------------------- # Every option the parser accepts, each asserted to be CONSUMED (no usage, no # `unrecognized argument') and to reach the same refusal. This is what keeps an # option-parsing failure distinguishable from a connection failure -- the # ticket's own criterion, and the one this suite meets rather than refutes. refuses opt-white 30 -white refuses opt-black 30 -black refuses opt-solid 30 -solid red refuses opt-root 30 -root refuses opt-none 30 -none refuses opt-delay 30 -delay 0 refuses opt-geometry 30 -geometry 100x100+0+0 # The two-character abbreviations, which are what :211-240's minslen of 2 buys. # Each is asserted because a parser that lost them would still pass every case # above: the long forms would keep working and the short ones would land in # unknown_arg. refuses abbrev-w 30 -w refuses abbrev-b 30 -b refuses abbrev-s 30 -s red refuses abbrev-r 30 -r refuses abbrev-n 30 -n refuses abbrev-de 30 -de 0 refuses abbrev-g 30 -g 100x100+0+0 # -d IS -display AND NOT -delay, which is a real ambiguity the ordering of the # if-chain settles: :211 tests -display before :236 tests -delay, so the shorter # shared prefix goes to whichever is written first. The case above proved -d # consumed an address; this one proves it did NOT consume it as a delay, by # asserting the refusal names it. split 15 -d 127.0.0.1:9 check_eq $S/abbrev-d-is-display "$(refusal '127.0.0.1:9')" "$serr" # The OBSOLETE positional geometry, `=WxH+X+Y' (:249-250). It is undocumented in # the usage text and still accepted, so it is asserted here rather than left to # be discovered by the unknown-argument cases in section 10. refuses obsolete-eq 30 =100x100+0+0 # Options COMBINE, and the last background option wins rather than colliding: # there is no exclusive-option check in this program at all, unlike xsetroot's # {solid,gray,bitmap,mod}. `-black -white' is therefore accepted and reaches the # connect, and asserting so is what says the absence of that check was measured # rather than assumed. refuses two-actions 30 -black -white refuses action-plus-geom 30 -root -geometry 10x10+0+0 refuses action-plus-delay 30 -solid blue -delay 100 # --- 8. THE ORDERING, which is what REFUTES the ticket's criterion ----------- # Each of these poses an input a REACHABLE parser would reject, and asserts that # the connect refusal arrives instead. They are the cases that answer "which of # the argument-interpreting and the connecting happens first". # A malformed geometry. XParseGeometry (:308) is post-connect and never runs. split 30 -geometry notageometry check_eq $S/order-geom-malformed-rc "1" "$rc" check_eq $S/order-geom-malformed-stderr "$(refusal '')" "$serr" case "$serr" in *geometr*|*Geometr*) bst_notok $S/order-geom-malformed-not-parsed \ "a geometry diagnostic arrived -- XParseGeometry ran BEFORE XOpenDisplay, or a diagnostic was added" ;; *) bst_ok $S/order-geom-malformed-not-parsed ;; esac # THE MALFORMED AND THE WELL-FORMED ARE THE SAME ANSWER, asserted directly # rather than left to a reader comparing two cases. This is the single case that # says a malformed geometry is NOT reportable on this image -- the ticket asked # for a documented diagnostic here and there is none to reach, upstream or # otherwise, because XParseGeometry returns a bitmask and reports nothing. split 30 -geometry notageometry _badgeom=$serr split 30 -geometry 100x100+0+0 check_eq $S/order-geom-indistinguishable "$_badgeom" "$serr" # An empty geometry, which is the degenerate form of the same input. split 30 -geometry "" check_eq $S/order-geom-empty-same "$_badgeom" "$serr" # An unparseable colour. XParseColor (:358) is post-connect too, and its failure # would not even have been fatal: :363 warns `unable to allocate color' and # falls back to no background rather than exiting. split 30 -solid nosuchcolourname check_eq $S/order-solid-rc "1" "$rc" check_eq $S/order-solid-stderr "$(refusal '')" "$serr" case "$serr" in *"unable to allocate color"*) bst_notok $S/order-solid-not-parsed \ "XParseColor ran BEFORE XOpenDisplay -- the ordering this port documented has changed" ;; *) bst_ok $S/order-solid-not-parsed ;; esac # ...and it is the same answer a REAL colour name produces. Two inputs, one # answer, for the same reason the two geometries gave one. split 30 -solid nosuchcolourname _badcolour=$serr split 30 -solid red check_eq $S/order-solid-indistinguishable "$_badcolour" "$serr" # A malformed DISPLAY specification, which the ticket also asked about. This one # is different from the two above and the difference is worth its own case: the # spec IS consumed and IS reported, because the refusal interpolates # XDisplayName's answer -- but what arrives is still the connection diagnostic # and not a parse one, and the status is the same 1. split 15 -display 'not a display' -none check_eq $S/order-display-malformed-rc "1" "$rc" check_eq $S/order-display-malformed-stderr "$(refusal 'not a display')" "$serr" # --- 9. -delay's atol, which is NOT an argument error ------------------------ # THE ONE OPTION WHOSE BAD INPUT IS SILENTLY ACCEPTED. :238 is # `delay = ((unsigned long)atol(argv[i])) * 1000000L' -- atol returns 0 for a # non-numeric string and there is no errno check, so `-delay foo' becomes a zero # delay and proceeds to the connect. It is NOT diagnosed, and a reader expecting # the ticket's error-path list to cover it would have it backwards; only a # MISSING argument is an error (section 10). refuses delay-nonnumeric 30 -delay foo refuses delay-zero 30 -delay 0 refuses delay-negative 30 -delay -5 # `-delay -5' is the case that shows the argument is taken by POSITION and not # screened for a leading `-': a parser treating -5 as an option would have said # `unrecognized argument', and the refusal above says it did not. The cast to # unsigned long then makes it an enormous nanosleep -- which nothing here can # observe, because :399 is post-connect. That unreachability is why a negative # delay cannot hang this suite, and is why the case is safe to run at all. # --- 10. the pre-connect argument errors ------------------------------------- # Status 1, the tool's own first line, the usage block behind it ON STDERR, # nothing on stdout. Every one of these is diagnosed BEFORE any connect is # attempted, so they are the half of the boundary that answers as itself. # # NOTE THE SINGLE SPACE after `xrefresh:' in every one of them, against the # refusal's two. Both spellings are upstream's and neither is this port's to # normalise. rejects unknown-opt 30 "xrefresh: unrecognized argument -nosuchopt" -nosuchopt # A bare non-option word is the same path -- the only positional forms are the # obsolete `=geom' and nothing else. rejects stray-word 30 "xrefresh: unrecognized argument stray" stray # ...including one that looks like a long option. `--help' is NOT -help: the # argument starts `-' and `--help' is not a prefix of any option name. rejects gnu-style 30 "xrefresh: unrecognized argument --help" --help rejects gnu-version 30 "xrefresh: unrecognized argument --version" --version rejects doubledash 30 "xrefresh: unrecognized argument --" -- # UPSTREAM ECHOES THE ARGUMENT AS TYPED, NOT THE CANONICAL OPTION NAME, in both # helpers: unknown_arg above prints the unrecognised string bare (no quotes, # unlike xsetroot's), and missing_arg at :95 is called as `missing_arg(arg)' with # argv[i] rather than with the option it matched. So the four abbreviated forms # below name themselves in the diagnostic, and a port that "tidied" that into the # long name would be changing an interface. rejects miss-display 30 "xrefresh: -display requires an argument" -display rejects miss-d 30 "xrefresh: -d requires an argument" -d rejects miss-geometry 30 "xrefresh: -geometry requires an argument" -geometry rejects miss-g 30 "xrefresh: -g requires an argument" -g rejects miss-solid 30 "xrefresh: -solid requires an argument" -solid rejects miss-s 30 "xrefresh: -s requires an argument" -s rejects miss-delay 30 "xrefresh: -delay requires an argument" -delay rejects miss-de 30 "xrefresh: -de requires an argument" -de # A missing argument is diagnosed EVEN WHEN A LATER ARGUMENT EXISTS TO EAT, # because the check is `if (++i >= argc)' and nothing else -- so `-solid -white' # consumes -white AS THE COLOUR rather than diagnosing either. That is the # opposite of what the wording suggests, and it is measured here as a refusal # (the colour is never parsed, section 8) rather than as an argument error. refuses solid-eats-next-option 30 -solid -white # THE BARE DASH, which is the one surprise in this parser and is upstream's own. # :241 is `isabbreviation("-version", arg, 1)' -- minslen ONE -- and a lone `-' # is a one-character prefix of "-version", so it passes every earlier test # (whose minslen is 2) and lands on -version. `xrefresh -' therefore PRINTS THE # VERSION and exits 0. It is asserted because it is the sharpest possible probe # of the abbreviation rule: a parser that got minslen wrong anywhere would most # likely answer this one differently. split 30 - check_eq $S/bare-dash-rc "0" "$rc" check_eq $S/bare-dash-stdout "xrefresh 1.1.0" "$sout" # An EMPTY argument is not a dash and not an `=', so it is unrecognised -- and # the diagnostic names nothing, which is what echoing the argument as typed # means at the limit. The trailing space is upstream's format string, not a typo. rejects empty-arg 30 "xrefresh: unrecognized argument " "" rm -rf "$W" 2>/dev/null