# BST-TIMEOUT: 1200 # 169 cases, 79s measured locally; the nightly's browser run still exceeds 300s . "$BST_LIB" # popt parses command-line options: it walks an argv[] against a table of # struct poptOption rows, stores or dispatches each match, and hands back the # residual arguments. The distro is static-only, so the shipped payload is one # header plus a pkg-config file (-dev) and the archive libpopt.a (-staticdev). # # Unlike every other library this image ships for its own sake, popt already has # a CONSUMER on the target: usleep links it statically and does all of its option # handling through it. So this suite asserts in two registers -- the payload is # real (below), and the library actually RUNS (the second half). The second half # is what no header-and-symbols check can establish, and it is available here # only because that consumer is already installed. inc=/usr/include/popt.h pc=/usr/lib/pkgconfig/popt.pc lib=/usr/lib/libpopt.a check popt/header-present test -f "$inc" check popt/header-nonempty test -s "$inc" check_out popt/header-guard "#define H_POPT" cat "$inc" # popt states its version only in the .pc file -- the header defines no # POPT_VERSION macro -- so the number is asserted there and not here. # Context lifecycle and the option-consuming loop: everything a caller needs to # turn an argv into decisions. poptGetNextOpt is the loop itself; poptGetOptArg # retrieves an option's own value, poptGetArg/poptGetArgs/poptPeekArg the # residual arguments the table did not claim. for f in poptGetContext poptFreeContext poptResetContext poptGetNextOpt \ poptGetOptArg poptGetArg poptGetArgs poptPeekArg; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # Failure reporting. These two are a pair -- poptGetNextOpt returns a negative # code, poptStrerror renders it, poptBadOption names the token that caused it -- # and the runtime half of this suite watches that pair produce its text. for f in poptBadOption poptStrerror; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # Help and usage generation off the same table the parser walks. for f in poptPrintHelp poptPrintUsage poptSetOtherOptionHelp poptGetInvocationName \ poptStrippedArgv; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # argv construction: parsing a command string into an argv, duplicating one, and # pushing extra arguments into a live context. for f in poptParseArgvString poptDupArgv poptStuffArgs; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # Aliases, exec items and the popt config files that define them -- the feature # that separates popt from getopt_long, and the reason poptconfig.o exists. for f in poptAddAlias poptAddItem poptReadConfigFile poptReadConfigFiles \ poptReadDefaultConfig poptConfigFileToString poptSetExecPath; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # The typed store-through helpers a POPT_ARG_* row dispatches to, one per width. for f in poptSaveString poptSaveLongLong poptSaveLong poptSaveInt poptSaveShort; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # The POPT_ARG_BITSET arm: a Bloom-filter set of strings, with its own API. for f in poptBitsAdd poptBitsChk poptBitsClr poptBitsDel poptBitsIntersect \ poptBitsUnion poptBitsArgs poptSaveBits; do check_out "popt/api-${f#popt}" "$f(" cat "$inc" done # The public types a caller declares: the option row, the opaque context handle, # the alias/item records the config layer builds, the callback signature a # POPT_ARG_CALLBACK row names, and the bitset. check_out popt/type-option "struct poptOption {" cat "$inc" check_out popt/type-alias "struct poptAlias {" cat "$inc" check_out popt/type-item "typedef struct poptItem_s {" cat "$inc" check_out popt/type-context "typedef struct poptContext_s * poptContext;" cat "$inc" check_out popt/type-bits "typedef struct poptBits_s {" cat "$inc" check_out popt/type-callback "poptCallbackType" cat "$inc" # The macro assertions below match the whole #define line rather than a literal # "define NAME", because popt.h separates the two with a space on some lines and # a tab on others -- a literal needle silently misses half the table. popt_def() { check "popt/$1" grep -qE "^#define[[:space:]]+$2[[:space:]]" "$inc"; } # The argument-type vocabulary: what a table row's argInfo may say. These are the # API -- a caller cannot write a table without naming them. for c in POPT_ARG_NONE POPT_ARG_STRING POPT_ARG_INT POPT_ARG_LONG POPT_ARG_LONGLONG \ POPT_ARG_SHORT POPT_ARG_FLOAT POPT_ARG_DOUBLE POPT_ARG_VAL POPT_ARG_ARGV \ POPT_ARG_BITSET POPT_ARG_CALLBACK POPT_ARG_INCLUDE_TABLE POPT_ARG_MAINCALL \ POPT_ARG_INTL_DOMAIN POPT_ARG_MASK; do popt_def "arg-$c" "$c" done # Row modifiers: the ones that change how a match is stored (OR/AND/XOR/NOT and # the logical-ops gate), how it is spelled (ONEDASH, OPTIONAL, TOGGLE), and how # it renders in --help (DOC_HIDDEN, SHOW_DEFAULT). for c in POPT_ARGFLAG_ONEDASH POPT_ARGFLAG_DOC_HIDDEN POPT_ARGFLAG_STRIP \ POPT_ARGFLAG_OPTIONAL POPT_ARGFLAG_OR POPT_ARGFLAG_AND POPT_ARGFLAG_XOR \ POPT_ARGFLAG_NOT POPT_ARGFLAG_LOGICALOPS POPT_ARGFLAG_TOGGLE \ POPT_ARGFLAG_SHOW_DEFAULT POPT_ARGFLAG_RANDOM; do popt_def "argflag-${c#POPT_ARGFLAG_}" "$c" done # Callback-row flags and the two bit-store selectors. for c in POPT_CBFLAG_PRE POPT_CBFLAG_POST POPT_CBFLAG_INC_DATA POPT_CBFLAG_SKIPOPTION \ POPT_CBFLAG_CONTINUE POPT_BIT_SET POPT_BIT_CLR; do popt_def "flag-$c" "$c" done # Context-creation flags, and the poptBadOption selector the runtime half below # exercises through usleep. for c in POPT_CONTEXT_NO_EXEC POPT_CONTEXT_KEEP_FIRST POPT_CONTEXT_POSIXMEHARDER \ POPT_CONTEXT_ARG_OPTS POPT_BADOPTION_NOALIAS; do popt_def "ctx-$c" "$c" done # Every error code poptStrerror renders. POPT_ERROR_BADOPT and # POPT_ERROR_UNWANTEDARG are the two the runtime half provokes for real. for c in POPT_ERROR_NOARG POPT_ERROR_BADOPT POPT_ERROR_UNWANTEDARG POPT_ERROR_OPTSTOODEEP \ POPT_ERROR_BADQUOTE POPT_ERROR_ERRNO POPT_ERROR_BADNUMBER POPT_ERROR_OVERFLOW \ POPT_ERROR_BADOPERATION POPT_ERROR_NULLARG POPT_ERROR_MALLOC POPT_ERROR_BADCONFIG; do popt_def "err-${c#POPT_ERROR_}" "$c" done # The nesting limit on POPT_ARG_INCLUDE_TABLE, which is what makes # POPT_ERROR_OPTSTOODEEP reachable at all. popt_def depth POPT_OPTION_DEPTH # The three table macros a caller writes literally into an option table. The # AUTOHELP row carries the "Help options:" heading the runtime --help prints, so # the header and the running library are asserted against the same string. popt_def macro-autohelp POPT_AUTOHELP popt_def macro-autoalias POPT_AUTOALIAS popt_def macro-tableend POPT_TABLEEND check_out popt/macro-helprow "\"Help options:\", NULL }," cat "$inc" # The tables POPT_AUTOHELP and POPT_AUTOALIAS include by reference; they are # extern data, so a caller's table cannot resolve without them. check_out popt/extern-helpoptions "poptHelpOptions[]" cat "$inc" check_out popt/extern-aliasoptions "poptAliasOptions[]" cat "$inc" # pkg-config metadata: shipped so a future recipe can DEPEND on popt, and the one # place the port's version and link line are stated on target. libdir is asserted # substituted rather than left as a literal placeholder. check popt/pc-present test -f "$pc" check_out popt/pc-name "Name: popt" cat "$pc" check_out popt/pc-version "Version: 1.19" cat "$pc" check_out popt/pc-libs "-lpopt" cat "$pc" check_out popt/pc-cflags "-I\${includedir}" cat "$pc" check_out popt/pc-libdir "libdir=/usr/lib" cat "$pc" check popt/lib-present test -f "$lib" check popt/lib-nonempty test -s "$lib" check_out popt/lib-archive "!" head -c 8 "$lib" # Flatten the archive to printable text once: GNU grep suppresses matches inside # binary data, and busybox tr does not handle [:print:] under -c, so the octal # range is the formulation both greps and both trs agree on. flat=${TMPDIR:-/tmp}/bst-popt.$$ tr -c '\40-\176\n' ' ' < "$lib" > "$flat" 2>/dev/null # All five upstream translation units, so a partial compile cannot pass: the # parser core, the argv splitter, the alias/config layer, the help/usage # generator, and the shared internals. for m in popt.o poptparse.o poptconfig.o popthelp.o poptint.o; do check "popt/member-$m" grep -q "$m" "$flat" done # Exported symbols, sampled across all five objects, so the archive's index is # evidence the wasm32 compile really produced each layer. for s in poptGetContext poptFreeContext poptGetNextOpt poptGetArg poptGetOptArg \ poptBadOption poptStrerror poptPrintHelp poptPrintUsage \ poptSetOtherOptionHelp poptParseArgvString poptDupArgv poptStuffArgs \ poptAddAlias poptAddItem poptReadConfigFile poptReadDefaultConfig \ poptSaveInt poptSaveLongLong poptSaveString poptBitsAdd poptBitsChk \ poptGetInvocationName poptStrippedArgv poptSetExecPath; do check "popt/sym-$s" grep -q "$s" "$flat" done # No shared object and no libtool archive: static-only is distro policy, and # popt's autotools build defaults to a shared library, so a stray libpopt.so or # .la here would mean the distro's --disable-shared override was lost. check popt/no-shared sh -c 'set -- /usr/lib/libpopt.so*; [ ! -e "$1" ]' check popt/no-libtool sh -c 'set -- /usr/lib/libpopt.la; [ ! -e "$1" ]' rm -f "$flat" # --- the library running, through its in-image consumer ---------------------- # # usleep does ALL of its option handling through popt (DEPENDS popt; the recipe # links -lpopt), and its table is two POPT_ARG_NONE rows plus POPT_AUTOHELP, with # poptSetOtherOptionHelp("[microseconds]"). So every case below is popt executing # on the target -- the parser, the help generator, and the error path -- read # through the only program on the image that links it. usleep's own behaviour is # 12-usleep.test's subject; what is asserted here is the library's. # # usleep is installed by this image, so its absence would be a real regression, # not a coverage gap -- but `require` keeps this half honest on an image built # without it, where the payload half above still stands on its own. require usleep popt/consumer-present # rc 0 with empty output: for the cases whose whole point is that popt did NOT # act on a token. `check` alone cannot say that -- it would pass on any rc 0. popt_quiet() { _id=$1; shift _out=$("$@" 2>&1); _rc=$? if [ "$_rc" -eq 0 ] && [ -z "$_out" ]; then bst_ok "$_id" else bst_notok "$_id" "rc=$_rc want-silent got:'$(_bst_1line "$_out")'"; fi } # A popt parse failure: poptGetNextOpt returns a negative code, the caller prints # poptBadOption + poptStrerror and exits 2. Both halves are the assertion, so # neither check_out (which demands rc 0) nor check_rc (which drops the text) will # do on its own. popt_err() { _id=$1; _needle=$2; shift 2 _out=$("$@" 2>&1); _rc=$? case "$_out" in *"$_needle"*) _hit=1 ;; *) _hit=0 ;; esac if [ "$_rc" -eq 2 ] && [ "$_hit" -eq 1 ]; then bst_ok "$_id" else bst_notok "$_id" "rc=$_rc want:'$_needle' got:'$(_bst_1line "$_out")'"; fi } # poptPrintHelp renders the table: the poptSetOtherOptionHelp trailer on the # usage line, one row per option with its short name, long name and help text, # and the POPT_AUTOHELP sub-table under its own heading. The heading is the same # literal the header's POPT_AUTOHELP macro carries, asserted above. check_out popt/help-usage-line "Usage: usleep [microseconds]" usleep --help check_out popt/help-row-version "-v, --version" usleep --help check_out popt/help-row-oot "-o, --oot" usleep --help check_out popt/help-row-text "oot says hey!" usleep --help check_out popt/help-heading "Help options:" usleep --help check_out popt/help-autohelp "-?, --help" usleep --help check_out popt/help-autousage "Display brief usage message" usleep --help # poptPrintUsage renders the other form off the same table: a digest of the short # flags, then each option spelled both ways, then the trailer. Its wrap is popt's # own fixed width, not the terminal's, so these needles do not move with COLUMNS. check_out popt/usage-digest "Usage: usleep [-vo?]" usleep --usage check_out popt/usage-longform "[-o|--oot]" usleep --usage check_out popt/usage-autohelp "[-?|--help]" usleep --usage check_out popt/usage-trailer "[microseconds]" usleep --usage # -? is POPT_AUTOHELP's short name for --help, and dispatches the same generator. check_out popt/autohelp-short "Help options:" usleep -? # The error path, twice. An unknown long option is POPT_ERROR_BADOPT; giving an # argument to a POPT_ARG_NONE row is POPT_ERROR_UNWANTEDARG. In both cases the # offending token is echoed by poptBadOption and the text comes from # poptStrerror, so each case pins one specific code's rendering. popt_err popt/err-badopt-text "unknown option" usleep --nosuchopt popt_err popt/err-badopt-token "bad argument --nosuchopt" usleep --nosuchopt popt_err popt/err-badopt-short "bad argument -x" usleep -x popt_err popt/err-unwantedarg "option does not take an argument" usleep --oot=3 popt_err popt/err-unwanted-tok "bad argument --oot=3" usleep --oot=3 # popt matches long names in full: --oo is not accepted as an abbreviation of # --oot the way getopt_long would take it. This is a real difference in the # library's contract, not an implementation detail, so it is pinned. popt_err popt/no-abbrev "unknown option" usleep --oo # Short-option clustering: -ov must dispatch BOTH characters. usleep prints the # version when -v is seen and "oot says hey!" when only -o is, so the version # banner is what proves the cluster's second character reached the table. check_out popt/cluster "usleep version 1.2" usleep -ov # Permutation: popt keeps scanning for options past a non-option argument, so a # flag written after the count is still found. POSIX getopt would stop at "100". check_out popt/permute "oot says hey!" usleep 100 --oot # "--" ends option scanning: everything after it is an argument, however it is # spelled. --oot after -- must NOT fire (silence, not "oot says hey!"), and an # option that does not exist at all must NOT raise POPT_ERROR_BADOPT. popt_quiet popt/dashdash-noflag usleep -- --oot popt_quiet popt/dashdash-nobadopt usleep -- --nosuchopt