# BST-TIMEOUT: 600 # five instantiations of an 8.3 MB probe + one pass over a 1.8 MB archive . "$BST_LIB" # gflags (meta-oe recipes-support/gflags, 2.2.2 at SRCREV e171aa2d, the v2.2.2 # release tag) -- Google's command-line flag library. Flags are DECLARED next # to the code that reads them, in whatever translation unit that is; a static # registrar in each one adds itself to a process-global registry before main; # and one ParseCommandLineFlags call at startup resolves the whole command line # against it and generates --help from it. The third port of the C++ round # (BRINTOS-1094). # # --------------------------------------------------------------------------- # TWO CONSUMERS, BECAUSE THEY PROVE DIFFERENT THINGS # # The PAYLOAD blocks assert what a downstream recipe reaches -- the four # headers and their declared surface, both static archives and their three # translation units, the pkg-config file, the CMake package -- plus the # Itanium-mangled symbols carrying libc++'s `NSt3__1` inline namespace, which # a C compile of the same sources cannot produce and which are therefore the # on-target evidence that the C++ arm of the toolchain genuinely worked. # # gflags HAS NO POLYMORPHIC CLASS, so unlike libtinyxml2 (BRINTOS-162) and # re2 (BRINTOS-1099) there is no _ZTV/_ZTI/_ZTS triple to point at: measured # on the shipped archive, zero vtable, typeinfo and typename records are # emitted. The C++ evidence here is the mangling and the standard-library # types in it, and the suite says so rather than asserting a record that # cannot exist. # # data/gflags-probe is a CONSUMER of that payload: a program compiled against # these headers and linked against this libgflags.a, built by the recipe # itself so it cannot drift from what shipped. It is what fails if the port # ships an archive that PARSES WRONGLY rather than one that is merely absent # -- the whole failure mode a file-presence check cannot see for a parser. # # WHAT IS COMPARED BYTE-FOR-BYTE AND WHAT IS NOT. The probe's scripted run and # its --helpmatch rendering are both compared line for line against # data/gflags-native.txt and data/gflags-help-native.txt -- the identical # source built and run on x86-64 from the gflags-native recipe -- with no # tolerance band. Nothing in either stream is a pointer, a size, a locale or a # clock, and both doubles (0.25, 2.5) are exactly representable, so one # differing line is a defect. # # Plain `--help` is deliberately NOT byte-compared, and the reason is a fact # about gflags rather than about this arm: it prints each flag under a # `Flags from ` header taken from __FILE__ at the point of DEFINE, and # CleanFileName() returns that verbatim (upstream removed the prefix stripping # and left a comment saying so, gflags.cc:564). The library's own fourteen # flags therefore carry the absolute path of the tree that built libgflags.a, # which differs between the two arms by construction -- and because the listing # is sorted BY that filename, the block order differs too. --helpmatch is # restricted to gflags-probe.cc, whose path is `gflags-probe.cc` in both builds # because the recipe compiles the probe from ${WORKDIR} by a bare relative # name. So the help rendering is asserted byte-exactly on the restricted form # and by content on the full one. # # THE ANCHORED CASES EXIST BECAUSE AN ORACLE CAN BE WRONG. A control captured # from an already-broken build would make every compared line agree with it. # So the values gflags' own documentation and this probe's source fix -- the # parsed values, the defaults that survived, is_default, the two refusal # contracts, the type names -- are ALSO asserted against literals here. Those # hold whatever the control says. # --------------------------------------------------------------------------- # A root prefix, empty on the target and set only when this suite is validated # natively before it ships. The runner never sets it. R="${BST_GFLAGS_ROOT:-}" ARCHIVE=$R/usr/lib/libgflags.a NOTHREADS=$R/usr/lib/libgflags_nothreads.a INCDIR=$R/usr/include/gflags PC=$R/usr/lib/pkgconfig/gflags.pc CMDIR=$R/usr/lib/cmake/gflags PROBE=$BST_DATA/gflags-probe NATIVE=$BST_DATA/gflags-native.txt HELPNATIVE=$BST_DATA/gflags-help-native.txt if [ ! -f "$ARCHIVE" ]; then bst_skip gflags/present "gflags not installed on this image" exit 0 fi bst_ok gflags/present nl=' ' tmp=${TMPDIR:-/tmp} # has # A shell `case` rather than a grep: this suite has ~110 content assertions and # an exec apiece is what killed the first draft of the abseil suite on target, # where every process is a fresh instantiation of a multi-megabyte module. has() { case "$2" in *"$nl$3$nl"*) bst_ok "$1" ;; *) bst_notok "$1" "missing: $3" ;; esac } # sub sub() { case "$2" in *"$3"*) bst_ok "$1" ;; *) bst_notok "$1" "missing: $3" ;; esac } # hasnt -- substring, for "must NOT be there" hasnt() { case "$2" in *"$3"*) bst_notok "$1" "present but must not be: $3" ;; *) bst_ok "$1" ;; esac } # --- the package is whole ---------------------------------------------------- check gflags/hdr-gflags test -f "$INCDIR/gflags.h" check gflags/hdr-declare test -f "$INCDIR/gflags_declare.h" check gflags/hdr-completions test -f "$INCDIR/gflags_completions.h" check gflags/hdr-ns test -f "$INCDIR/gflags_gflags.h" check gflags/staticlib test -f "$ARCHIVE" # The nothreads variant is a SECOND library built from the same sources with # NO_THREADS defined. It is shipped because the stock recipe builds it and # because it is the fallback if the registry's rwlock ever stops working on # this arm -- so its absence would be a silent narrowing of the port. check gflags/staticlib-nothreads test -f "$NOTHREADS" # Shape, not absence: this arm converts to shared libraries per recipe # (BRINTOS-1740), so a .so here is a conversion, not a policy breach. bst_lib_shape gflags/no-shared "$R/usr/lib/libgflags*.so*" if [ -n "$(find "$R/usr/lib" -maxdepth 1 -name 'libgflags*.la' 2>/dev/null)" ]; then bst_notok gflags/no-la "a libtool .la is installed" else bst_ok gflags/no-la fi # --- the declared surface, read out of the shipped headers ------------------- # # One `cat` per header and `case` matching over the result: the point is that # the header a downstream recipe would include really declares what it is # supposed to, not merely that a file of that name exists. H=$nl$(cat "$INCDIR/gflags.h" 2>/dev/null)$nl sub gflags/decl-parse "$H" "ParseCommandLineFlags(int" sub gflags/decl-nonhelp "$H" "ParseCommandLineNonHelpFlags(int" sub gflags/decl-info-struct "$H" "struct CommandLineFlagInfo {" sub gflags/decl-getinfo "$H" "GetCommandLineFlagInfo(const char* name" sub gflags/decl-getallflags "$H" "GetAllFlags(std::vector* OUTPUT)" sub gflags/decl-describe "$H" "DescribeOneFlag(const CommandLineFlagInfo& flag)" sub gflags/decl-showusage "$H" "ShowUsageWithFlags(const char *argv0)" sub gflags/decl-showrestrict "$H" "ShowUsageWithFlagsRestrict(const char *argv0" sub gflags/decl-setusage "$H" "SetUsageMessage(const std::string& usage)" sub gflags/decl-setversion "$H" "SetVersionString(const std::string& version)" sub gflags/decl-progshort "$H" "ProgramInvocationShortName()" sub gflags/decl-flagsaver "$H" "class GFLAGS_DLL_DECL FlagSaver" # The seven-overload RegisterFlagValidator set is what makes the probe's # validator case possible at all, and one overload per flag type is how gflags # type-checks the callback at compile time. sub gflags/decl-validator-bool "$H" "RegisterFlagValidator(const bool*" sub gflags/decl-validator-int32 "$H" "RegisterFlagValidator(const int32*" sub gflags/decl-validator-uint32 "$H" "RegisterFlagValidator(const uint32*" sub gflags/decl-validator-int64 "$H" "RegisterFlagValidator(const int64*" sub gflags/decl-validator-uint64 "$H" "RegisterFlagValidator(const uint64*" sub gflags/decl-validator-double "$H" "RegisterFlagValidator(const double*" sub gflags/decl-validator-string "$H" "RegisterFlagValidator(const std::string*" # The DEFINE_ macros are the library's whole user-facing idiom: one per type, # each expanding to a variable plus a static registrar. sub gflags/macro-define-bool "$H" "#define DEFINE_bool" sub gflags/macro-define-int32 "$H" "#define DEFINE_int32" sub gflags/macro-define-uint32 "$H" "#define DEFINE_uint32" sub gflags/macro-define-int64 "$H" "#define DEFINE_int64" sub gflags/macro-define-uint64 "$H" "#define DEFINE_uint64" sub gflags/macro-define-double "$H" "#define DEFINE_double" sub gflags/macro-define-string "$H" "#define DEFINE_string" sub gflags/macro-validator "$H" "#define DEFINE_validator" D=$nl$(cat "$INCDIR/gflags_declare.h" 2>/dev/null)$nl # GFLAGS_NAMESPACE is `google` in this release, not `gflags`: the library's # symbols are _ZN6google..., and gflags_gflags.h below is what makes the # documented `gflags::` spelling work. A consumer that assumed otherwise would # fail to link against the archive we ship. sub gflags/ns-google "$D" "#define GFLAGS_NAMESPACE google" sub gflags/macro-declare-bool "$D" "#define DECLARE_bool" sub gflags/macro-declare-uint32 "$D" "#define DECLARE_uint32" sub gflags/macro-declare-uint64 "$D" "#define DECLARE_uint64" # The per-type storage namespaces the DECLARE/DEFINE macros expand into. They # are why the archive carries _ZN3fLB10FLAGS_helpE and friends, asserted below. sub gflags/ns-fLS "$D" "namespace fLS {" G=$nl$(cat "$INCDIR/gflags_gflags.h" 2>/dev/null)$nl sub gflags/alias-namespace "$G" "namespace gflags {" sub gflags/alias-parse "$G" "using GFLAGS_NAMESPACE::ParseCommandLineFlags;" sub gflags/alias-getinfo "$G" "using GFLAGS_NAMESPACE::GetCommandLineFlagInfo;" sub gflags/alias-setopt "$G" "using GFLAGS_NAMESPACE::SetCommandLineOption;" sub gflags/alias-validator "$G" "using GFLAGS_NAMESPACE::RegisterFlagValidator;" C=$nl$(cat "$INCDIR/gflags_completions.h" 2>/dev/null)$nl sub gflags/decl-completions "$C" "HandleCommandLineCompletions(" # --- pkg-config: how a downstream recipe finds this package at all ----------- check gflags/pkgconfig test -f "$PC" if [ -f "$PC" ]; then PCC=$nl$(cat "$PC")$nl has gflags/pc-name "$PCC" "Name: gflags" has gflags/pc-version "$PCC" "Version: 2.2.2" has gflags/pc-libs "$PCC" "Libs: -L\${libdir} -lgflags" has gflags/pc-cflags "$PCC" "Cflags: -I\${includedir}" has gflags/pc-libdir "$PCC" "libdir=\${prefix}/lib" # -lpthread in Libs.private is not decoration: the registry's Mutex is a # pthread_rwlock_t on this arm (asserted against the archive below), so a # static consumer that dropped it would fail to link. sub gflags/pc-private-pthread "$PCC" "Libs.private: -lpthread" fi # --- the CMake package, which is what gflags' consumers actually use -------- check gflags/cm-config test -f "$CMDIR/gflags-config.cmake" check gflags/cm-version test -f "$CMDIR/gflags-config-version.cmake" check gflags/cm-targets test -f "$CMDIR/gflags-targets.cmake" check gflags/cm-noconfig test -f "$CMDIR/gflags-targets-noconfig.cmake" if [ -f "$CMDIR/gflags-config-version.cmake" ]; then CMV=$nl$(cat "$CMDIR/gflags-config-version.cmake")$nl sub gflags/cm-version-222 "$CMV" "set (PACKAGE_VERSION \"2.2.2\")" fi if [ -f "$CMDIR/gflags-targets-noconfig.cmake" ]; then CMN=$nl$(cat "$CMDIR/gflags-targets-noconfig.cmake")$nl # The import record must name the ARCHIVE, and the target must be the # _static one. A .so here would mean the CMake package describes an artifact # this image does not carry -- which is the failure a consumer meets at # find_package() time, long after the port looked green. sub gflags/cm-target-static "$CMN" "gflags::gflags_static" sub gflags/cm-imports-a "$CMN" "libgflags.a" hasnt gflags/cm-no-so "$CMN" "libgflags.so" fi # --- the archive itself ------------------------------------------------------ case "$(head -c 8 "$ARCHIVE" 2>/dev/null)" in '!'*) bst_ok gflags/ar-magic ;; *) bst_notok gflags/ar-magic "libgflags.a does not start with the ar magic" ;; esac # One pass over the whole archive, mapping every byte that cannot occur inside # a member name or an Itanium-mangled symbol to a newline, and pulling out only # the lines that carry a needle. That is 3 execs for the ~30 assertions below. # # The character class is TIGHTER than the printable-ASCII split re2's suite # uses, and deliberately: gflags ships with its debug string table intact, and # splitting only on non-printables leaves single lines of 325 kB that a busybox # shell then has to hold and rescan for every assertion. Splitting on anything # outside [A-Za-z0-9_.] cuts the same content to ~40 kB of short tokens, which # is what makes `case` matching viable here. nf=$tmp/bst-gflags-needles.$$ hf=$tmp/bst-gflags-hits.$$ cat > "$nf" <<'NEEDLES' gflags.cc.o gflags_completions.cc.o gflags_reporting.cc.o _ZN6google21ParseCommandLineFlagsEPiPPPcb _ZN6google22GetCommandLineFlagInfoEPKcPNS_19CommandLineFlagInfoE _ZN6google20SetCommandLineOptionEPKcS1_ _ZN6google18ShowUsageWithFlagsEPKc _ZN6google26ShowUsageWithFlagsRestrictEPKcS1_ _ZN6google15DescribeOneFlagERKNS_19CommandLineFlagInfoE _ZN6google21RegisterFlagValidatorEPKiPFbPKciE _ZN6google11GetAllFlagsEPNSt3__16vector _ZN6google15SetUsageMessageERKNSt3__112basic_string _ZN3fLB10FLAGS_helpE _ZN3fLB13FLAGS_helpxmlE _ZN3fLS14FLAGS_flagfileE _ZN3fLI28FLAGS_tab_completion_columnsE _ZN22gflags_mutex_namespace5Mutex pthread_rwlock_wrlock NEEDLES cat "$ARCHIVE" 2>/dev/null | tr -c 'A-Za-z0-9_.' '\n' | grep -F -f "$nf" > "$hf" 2>/dev/null HITS=$nl$(cat "$hf" 2>/dev/null)$nl rm -f "$nf" "$hf" # The three translation units this port compiled. Named one by one rather than # counted, so a member silently dropped by a future recipe change points at # itself instead of at a number. sub gflags/member-gflags "$HITS" "gflags.cc.o" sub gflags/member-completions "$HITS" "gflags_completions.cc.o" sub gflags/member-reporting "$HITS" "gflags_reporting.cc.o" # Itanium-mangled entry points, in the `google` namespace this release uses. sub gflags/sym-parse "$HITS" "_ZN6google21ParseCommandLineFlagsEPiPPPcb" sub gflags/sym-getinfo "$HITS" "_ZN6google22GetCommandLineFlagInfoEPKc" sub gflags/sym-setopt "$HITS" "_ZN6google20SetCommandLineOptionEPKcS1_" sub gflags/sym-showusage "$HITS" "_ZN6google18ShowUsageWithFlagsEPKc" sub gflags/sym-showrestrict "$HITS" "_ZN6google26ShowUsageWithFlagsRestrictEPKcS1_" sub gflags/sym-describe "$HITS" "_ZN6google15DescribeOneFlagERKNS_19CommandLineFlagInfoE" sub gflags/sym-validator "$HITS" "_ZN6google21RegisterFlagValidatorEPKiPFbPKciE" # `NSt3__1` inside gflags' OWN symbols is libc++'s inline namespace: these are # C++ symbols mangled against THIS arm's standard library, which is the thing a # C compile of the same sources could not produce. gflags has no polymorphic # class and therefore no vtable record to point at instead (measured: zero # _ZTV/_ZTI/_ZTS defined in the shipped archive), so this is the port's C++ # evidence. sub gflags/sym-libcxx-getallflags "$HITS" "_ZN6google11GetAllFlagsEPNSt3__16vector" sub gflags/sym-libcxx-setusage "$HITS" "_ZN6google15SetUsageMessageERKNSt3__112basic_string" # The per-type flag storage namespaces (fLB bool, fLI int32, fLS string) are # what DEFINE_ expands into, and these four are gflags' OWN flags -- so their # presence is the link-level evidence that --help, --helpxml, --flagfile and # tab completion are compiled in rather than configured out. sub gflags/flagvar-help "$HITS" "_ZN3fLB10FLAGS_helpE" sub gflags/flagvar-helpxml "$HITS" "_ZN3fLB13FLAGS_helpxmlE" sub gflags/flagvar-flagfile "$HITS" "_ZN3fLS14FLAGS_flagfileE" sub gflags/flagvar-tabcolumns "$HITS" "_ZN3fLI28FLAGS_tab_completion_columnsE" # The registry's lock. gflags' cmake found a working pthread here # (find_package(Threads) -> HAVE_PTHREAD=1) and check_type_size resolved # pthread_rwlock_t, so mutex.h took its rwlock arm rather than the plain-mutex # or NO_THREADS one. Asserted because it decides what libgflags.a is undefined # on, and therefore what a static consumer must link. sub gflags/mutex-class "$HITS" "_ZN22gflags_mutex_namespace5Mutex" sub gflags/mutex-rwlock "$HITS" "pthread_rwlock_wrlock" # --- the probe: does the shipped archive PARSE, and parse correctly? -------- if [ ! -f "$PROBE" ]; then bst_notok gflags/probe-present "$PROBE missing -- the library cannot be proven to run" elif [ ! -f "$NATIVE" ]; then bst_notok gflags/native-present "$NATIVE missing -- no x86-64 control for the probe run" elif [ ! -f "$HELPNATIVE" ]; then bst_notok gflags/help-native-present "$HELPNATIVE missing -- no x86-64 control for the help rendering" else bst_ok gflags/probe-present bst_ok gflags/native-present bst_ok gflags/help-native-present # do_install stages data/* at 0644 and the deployed rootfs is read-only at # browser runtime, so the payload cannot be executed where it lies. Stage an # executable copy under TMPDIR, as every probe-driven suite here does. # # Into a PRIVATE DIRECTORY under a FIXED basename, which the other suites do # not need and this one does: gflags prints Basename(argv0) as the first word # of every help and version line, so a `$$`-suffixed filename would put the # PID into output that is compared byte-for-byte against a control. pd=$tmp/bst-gflags.$$ p=$pd/gflags-probe mkdir -p "$pd" 2>/dev/null if cp "$PROBE" "$p" 2>/dev/null && chmod 0755 "$p" 2>/dev/null && [ -x "$p" ]; then bst_ok gflags/probe-exec # === 1. the scripted run ================================================= out=$("$p" 2>/dev/null); rc=$? if [ "$rc" -eq 0 ]; then bst_ok gflags/probe-rc else bst_notok gflags/probe-rc "probe exited $rc"; fi O=$nl$out$nl # The whole-stream gate. Kept separate from the anchored cases below, # because a probe that died before printing anything would leave those with # nothing to disagree with and could look like a shorter clean run. case "$O" in *"${nl}GF-PROBE-OK${nl}") bst_ok gflags/probe-complete ;; *) bst_notok gflags/probe-complete "probe did not reach its final line" ;; esac if [ "$out" = "$(cat "$NATIVE" 2>/dev/null)" ]; then bst_ok gflags/probe-matches-x86-64 else first=$(printf '%s\n' "$out" | diff - "$NATIVE" 2>/dev/null | head -4) bst_notok gflags/probe-matches-x86-64 "$(_bst_1line "${first:-output differs from the control}")" fi # --- anchored cases: literals the library's contract fixes --------------- # A flag SET on the command line, one per type. The int64 case is the one # that carries weight: -9007199254740993 is 2^53+1, which no double can # hold, so a build that routed int64 flags through a floating-point parse # answers -9007199254740992 here and nowhere else. has gflags/set-int32 "$O" "GF-set-int32 42" has gflags/set-string "$O" "GF-set-string loud" has gflags/set-bool "$O" "GF-set-bool 1" has gflags/set-double "$O" "GF-set-double 2.5" has gflags/set-int64 "$O" "GF-set-int64 -9007199254740993" # A flag LEFT AT ITS DEFAULT. Both are unsigned and both are at the top of # their range, so a sign-extension or width defect shows up as a value # rather than as a parse error. has gflags/def-uint32 "$O" "GF-def-uint32 3000000000" has gflags/def-uint64 "$O" "GF-def-uint64 18446744073709551615" # remove_flags=true: the seven-token vector is reduced to argv0 and the one # positional. A parser that left the flags in place, or ate the positional, # fails exactly here. has gflags/argc "$O" "GF-argc 2" has gflags/argv0 "$O" "GF-argv0 gflags-probe" has gflags/argv1 "$O" "GF-argv1 keep-me" # The registry's own record of each flag: type name, default, current # value, and is_default. That last field is the half a value read cannot # show -- FLAGS_gf_uint32 reading 3000000000 proves the default is right, # not that nothing set it. has gflags/info-bool "$O" "GF-info-gf_bool type=bool default=false current=true is_default=0" has gflags/info-int32 "$O" "GF-info-gf_int32 type=int32 default=7 current=42 is_default=0" has gflags/info-uint32 "$O" "GF-info-gf_uint32 type=uint32 default=3000000000 current=3000000000 is_default=1" has gflags/info-int64 "$O" "GF-info-gf_int64 type=int64 default=-5000000000 current=-9007199254740993 is_default=0" has gflags/info-uint64 "$O" "GF-info-gf_uint64 type=uint64 default=18446744073709551615 current=18446744073709551615 is_default=1" has gflags/info-double "$O" "GF-info-gf_double type=double default=0.25 current=2.5 is_default=0" has gflags/info-string "$O" "GF-info-gf_string type=string default=silent current=loud is_default=0" # DescribeOneFlag is the renderer --help uses per flag. Seven flags in, and # the string flag's default quoted -- which is how gflags distinguishes an # empty string default from an unset one. has gflags/describe-count "$O" "GF-describe-count 7" sub gflags/describe-string-quoted "$O" "default: \"silent\" currently: \"loud\"" sub gflags/describe-bool-type "$O" "-gf_bool (bool flag, set on the command line) type: bool default: false" # gflags' own fourteen flags registered too, so the registry is the whole # process's and not just this file's. has gflags/allflags "$O" "GF-allflags-at-least-21 1" # The string-keyed read path, for a consumer that does not have the FLAGS_ # symbol in scope -- and its negative, which must report failure rather # than an empty value. has gflags/getopt-ok "$O" "GF-getopt-ok 1" has gflags/getopt-value "$O" "GF-getopt-value loud" has gflags/getopt-missing "$O" "GF-getopt-missing 0" # THE REFUSALS. gflags declines a bad value in two structurally different # ways and both must be visible rather than silently coerced: the TYPE # cannot hold it, or the type holds it and the PROGRAM's validator refuses. # Both return the empty string and leave the flag at its previous value -- # 42, from the command line, not 7, the default. A port that accepted # either would parse a typo into a number and run on it. has gflags/reject-type-empty "$O" "GF-reject-type-empty 1" has gflags/reject-type-unchanged "$O" "GF-reject-type-unchanged 42" has gflags/validator-registered "$O" "GF-validator-registered 1" has gflags/reject-validator-empty "$O" "GF-reject-validator-empty 1" has gflags/reject-validator-unchanged "$O" "GF-reject-validator-unchanged 42" # And the same call succeeds on a value both accept, so the two above are # refusals rather than a setter that never works. has gflags/accept-nonempty "$O" "GF-accept-nonempty 1" has gflags/accept-message "$O" "GF-accept-message gf_int32 set to 99" has gflags/accept-value "$O" "GF-accept-value 99" has gflags/progname "$O" "GF-progname gflags-probe" has gflags/usage "$O" "GF-usage brintOS gflags port probe" has gflags/version "$O" "GF-version 2.2.2-brintos-probe" # === 2. --helpmatch: the help rendering, byte-for-byte =================== # # Restricted to gflags-probe.cc, whose recorded filename is the same string # in both builds. Exits 1 by design: every help path in gflags ends in # gflags_exitfunc(1). hout=$("$p" --helpmatch=gflags-probe 2>&1); hrc=$? if [ "$hrc" -eq 1 ]; then bst_ok gflags/help-rc else bst_notok gflags/help-rc "--helpmatch exited $hrc, want 1"; fi if [ "$hout" = "$(cat "$HELPNATIVE" 2>/dev/null)" ]; then bst_ok gflags/help-matches-x86-64 else hfirst=$(printf '%s\n' "$hout" | diff - "$HELPNATIVE" 2>/dev/null | head -4) bst_notok gflags/help-matches-x86-64 "$(_bst_1line "${hfirst:-help output differs from the control}")" fi HO=$nl$hout$nl has gflags/help-banner "$HO" "gflags-probe: brintOS gflags port probe" has gflags/help-fromfile "$HO" " Flags from gflags-probe.cc:" # === 3. plain --help: every flag in the process, ours and gflags' own ==== # # Content-asserted rather than byte-compared -- see the header of this file # for why the `Flags from ` lines cannot be. aout=$("$p" --help 2>&1); arc=$? if [ "$arc" -eq 1 ]; then bst_ok gflags/helpall-rc else bst_notok gflags/helpall-rc "--help exited $arc, want 1"; fi AO=$nl$aout$nl # Ours, with their defaults -- which is the listing the port is for. sub gflags/helpall-mine-bool "$AO" "-gf_bool (bool flag, set on the command line) type: bool default: false" sub gflags/helpall-mine-int32 "$AO" "-gf_int32 (int32 flag, set on the command line) type: int32 default: 7" sub gflags/helpall-mine-uint64 "$AO" "default: 18446744073709551615" sub gflags/helpall-mine-string "$AO" "default: \"silent\"" # And gflags' own, which only appear if the library's translation units # registered their flags into the same registry. sub gflags/helpall-flagfile "$AO" "-flagfile (load flags from file) type: string" sub gflags/helpall-fromenv "$AO" "-fromenv (set flags from the environment" sub gflags/helpall-helpxml "$AO" "-helpxml (produce an xml version of help)" sub gflags/helpall-tabcol "$AO" "-tab_completion_columns (Number of columns to use in output for tab" # === 4. the rejected value, on the command line ========================= # # The other half of the refusal contract, and the one a user meets: an # illegal value for a TYPED flag is reported on stderr and the process # DIES. gflags does this without throwing, which is why this arm's # -fno-exceptions costs the library nothing. eout=$("$p" --gf_int32=abc 2>&1); erc=$? if [ "$erc" -ne 0 ]; then bst_ok gflags/reject-cli-rc else bst_notok gflags/reject-cli-rc "an illegal int32 value was accepted (exit 0)"; fi EO=$nl$eout$nl has gflags/reject-cli-message "$EO" "ERROR: illegal value 'abc' specified for int32 flag 'gf_int32'" # It died at the parse, so nothing after ParseCommandLineFlags ran. hasnt gflags/reject-cli-nooutput "$EO" "GF-CLI-OK" # A value the type DOES hold goes through, so the case above is a refusal # rather than a program that cannot take a command line at all. gout=$("$p" --gf_int32=123 --gf_string=fine 2>/dev/null); grc=$? if [ "$grc" -eq 0 ]; then bst_ok gflags/accept-cli-rc else bst_notok gflags/accept-cli-rc "a legal command line exited $grc"; fi GO=$nl$gout$nl has gflags/accept-cli-int32 "$GO" "GF-info-gf_int32 type=int32 default=7 current=123 is_default=0" has gflags/accept-cli-string "$GO" "GF-info-gf_string type=string default=silent current=fine is_default=0" has gflags/accept-cli-done "$GO" "GF-CLI-OK" # === 5. --version, which exits 0 where every help path exits 1 ========== vout=$("$p" --version 2>&1); vrc=$? if [ "$vrc" -eq 0 ]; then bst_ok gflags/version-rc else bst_notok gflags/version-rc "--version exited $vrc, want 0"; fi # Anchored, not byte-compared: ShowVersion() adds a "Debug build" line when # NDEBUG is not defined, and that is a property of the flags each arm's # probe was compiled with rather than of the port. sub gflags/version-line "$nl$vout$nl" "gflags-probe version 2.2.2-brintos-probe" rm -rf "$pd" else rm -rf "$pd" bst_notok gflags/probe-exec "cannot stage an executable copy of $PROBE" fi fi