# BST-TIMEOUT: 300 . "$BST_LIB" # pugixml 1.14 -- a light-weight DOM-style XML parser with XPath 1.0, ported as # -dev + -staticdev: two headers, pugixml.pc, the find_package(pugixml) cmake # package and libpugixml.a. There is no CLI and no on-target C++ compiler, so a # shell test alone could only assert that files exist. Almost all of the weight # here is therefore in data/pugixml-probe -- a wasm32 binary cross-linked during # the port against the very libpugixml.a that ships -- which parses # data/pugixml-sample.xml, walks it, runs XPath over it, and drives the error # channel that this port's one configuration decision turns on. # # WHY THIS IMAGE CARRIES TWO tinyxml-CLASS PARSERS. libtinyxml2 (74-libtinyxml2) # has been here since BRINTOS-162 and covers the same DOM ground, but tinyxml2 # has NO XPath at all -- a consumer that wants to select nodes by expression has # to walk the tree by hand. pugixml carries XPath 1.0, and the xpath/* cases # below are the whole of the difference; they are the reason the overlap is a # deliberate answer rather than an unnoticed duplicate. Numbered 74 beside its # sibling for the same reason md4c sits at 76 beside cmark. # # WHAT THE PORT DECIDED, AND WHY IT IS THE THING MOST WORTH TESTING. This arm's # C++ driver compiles with exceptions disabled -- there is no unwinder -- and # pugixml throws in twelve places, so it is built with upstream's own # -DPUGIXML_NO_EXCEPTIONS. That is not merely a build flag: it CHANGES THE # LIBRARY'S ERROR CONTRACT. class xpath_exception ceases to exist, an invalid # XPath expression reports through xpath_query::result() instead of throwing, # and a malformed document is refused only through xml_parse_result::status. # With no exceptions there is no second channel, so a status quietly returning # ok, or every failure collapsing to one code, is indistinguishable from a # working parser to any caller that just asks "did it parse". The probe's # malformed-* group therefore asserts eight refusals with eight DIFFERENT # statuses and the offset of each, and the xpath-error-* group asserts that an # invalid query reports AND yields an empty set -- either half alone would pass # against a library that had lost the other. # # Style follows 81-cjson: files are read once into shell variables and matched # with `case` globs, and the archive symbol table is one batched pass. ~200 # check_out spawns would cost more than the assertions on this runtime. inc=/usr/include/pugixml.hpp incc=/usr/include/pugiconfig.hpp pc=/usr/lib/pkgconfig/pugixml.pc lib=/usr/lib/libpugixml.a cm=/usr/lib/cmake/pugixml nl=' ' hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "absent or empty: $2"; fi; } has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "not found: $2" ;; esac; } lacks() { case "$3" in *"$2"*) bst_notok "$1" "present but should not be: $2" ;; *) bst_ok "$1" ;; esac; } # --------------------------------------------------------------------------- # 1. The shipped payload. hasfile pugixml/header-present "$inc" hasfile pugixml/config-header-present "$incc" hasfile pugixml/pc-present "$pc" hasfile pugixml/archive-present "$lib" hasfile pugixml/cmake-targets-present "$cm/pugixml-targets.cmake" hasfile pugixml/cmake-config-present "$cm/pugixml-config.cmake" hasfile pugixml/cmake-version-present "$cm/pugixml-config-version.cmake" hasfile pugixml/cmake-release-present "$cm/pugixml-targets-release.cmake" # 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 pugixml/no-shared "/usr/lib/libpugixml*.so*" if [ -f /usr/lib/libpugixml.la ]; then bst_notok pugixml/no-la "/usr/lib/libpugixml.la is installed" else bst_ok pugixml/no-la fi hdr=$(cat "$inc" 2>/dev/null) cfg=$(cat "$incc" 2>/dev/null) pcs=$(cat "$pc" 2>/dev/null) tgt=$(cat "$cm/pugixml-targets.cmake" 2>/dev/null) rel=$(cat "$cm/pugixml-targets-release.cmake" 2>/dev/null) has pugixml/header-version-macro "define PUGIXML_VERSION 1140" "$hdr" has pugixml/header-guard "HEADER_PUGIXML_HPP" "$hdr" has pugixml/header-namespace "namespace pugi" "$hdr" has pugixml/config-guard "HEADER_PUGICONFIG_HPP" "$cfg" has pugixml/pc-name "Name: pugixml" "$pcs" has pugixml/pc-version "Version: 1.14" "$pcs" has pugixml/pc-libs "-lpugixml" "$pcs" has pugixml/pc-cflags "Cflags: -I" "$pcs" # --------------------------------------------------------------------------- # 2. HOW THE EXCEPTIONS-OFF MODE REACHES A CONSUMER -- and where it does not. # # PUGIXML_NO_EXCEPTIONS is a PUBLIC compile definition upstream, so the exported # cmake target carries it in INTERFACE_COMPILE_DEFINITIONS and a # find_package(pugixml) consumer inherits it without doing anything. pugixml.pc # carries no definitions at all -- scripts/pugixml.pc.in hardcodes # `Cflags: -I${includedir}` -- so a PKG-CONFIG consumer does NOT inherit it and # will compile against a header that still declares xpath_exception while the # archive defines none of it. That gap is upstream's, and identical on x86-64, # but it only BITES where the mode is not the default, which is exactly here. # Both halves are asserted so a later pugixml release that starts interpolating # definitions into the .pc shows up as a red rather than as silence. has pugixml/cmake-carries-no-exceptions "PUGIXML_NO_EXCEPTIONS" "$tgt" has pugixml/cmake-static-target "pugixml::static STATIC IMPORTED" "$tgt" has pugixml/cmake-imports-archive "libpugixml.a" "$rel" lacks pugixml/pc-silent-on-no-exceptions "PUGIXML_NO_EXCEPTIONS" "$pcs" # --------------------------------------------------------------------------- # 3. The archive, read once. # # The exceptions-off build is visible in the symbol table and nowhere else: the # xpath_exception class is compiled out of existence, and with it every call # into the Itanium exception runtime. Asserting the ABSENCES beside the presence # of the XPath engine is what distinguishes "built with the mode" from "built # with XPath switched off", which would also produce no xpath_exception. check_out pugixml/archive-magic "!" head -c 8 "$lib" # Flattened to printable text rather than read with nm: there is no nm on this # image that understands a wasm32 object, and the octal tr range is the # formulation both greps and both trs agree on -- derived by 69-libb64.test and # reused since. GNU grep otherwise suppresses matches inside data it calls binary. # # THE SUBSHELL IS LOAD-BEARING AND IS NOT STYLE. Written bare, a top-level # `prog < ` makes dup2(2) return 513 -- the kernel's # -ERESTARTNOINTR park sentinel reaching userspace through glibc's errno return # path -- and ash treats a failed top-level redirect as fatal, so THE SUITE'S # SHELL EXITS and every case below here is silently never reached. The runner # then reports the cases it did see as a complete, all-green suite. A subshell # forks before the redirect, which is what makes it safe; a pipeline and `sh -c` # are safe for the same reason, and a tmpfs copy avoids it entirely. See the # packager README, "Do not redirect stdin from the rootfs", and 86-nana.test, # which met the same defect from the other direction. # # 33 suites on this layer still carry the bare form -- 81-cjson.test's last # emitted case is the one immediately before its own flatten, so its six # archive-symbol assertions have not run in any recent build. The sweep, and # making a truncated suite visible to the runner at all, is BRINTOS-1151. # BRINTOS-WORKAROUND: brintos/linux#73 remove -- drop the subshell when the # restart sentinel no longer reaches userspace on a top-level redirect. flat=${TMPDIR:-/tmp}/bst-pugixml-flat.$$ ( tr -c '\40-\176\n' ' ' < "$lib" > "$flat" ) 2>/dev/null if [ -s "$flat" ]; then bst_ok pugixml/archive-readable syms=$(cat "$flat") # pugixml is ONE translation unit, so the member name is the whole manifest -- # there is no partial-compile shape where some members are missing. memb=$(grep -oE '[A-Za-z0-9_.]+\.cpp\.o' "$flat" 2>/dev/null | head -1) check_eq pugixml/archive-member "pugixml.cpp.o" "$memb" # the DOM and the XPath engine are both in there... has pugixml/sym-xpath-query "xpath_query" "$syms" has pugixml/sym-xml-document "xml_document" "$syms" has pugixml/sym-load-file "load_fileEPKc" "$syms" has pugixml/sym-load-string "load_stringEPKc" "$syms" has pugixml/sym-select-nodes "select_nodesEPKc" "$syms" # ...and the exception machinery is not, which is the only place the port's one # configuration decision is visible in the shipped artifact. Asserting these # ABSENCES beside the XPath presences above is what separates "built with # PUGIXML_NO_EXCEPTIONS" from "built with PUGIXML_NO_XPATH", which would also # yield no xpath_exception -- and from a toolchain that quietly dropped the # unwinder calls on its own. lacks pugixml/sym-no-xpath-exception "xpath_exception" "$syms" lacks pugixml/sym-no-cxa-throw "__cxa_throw" "$syms" lacks pugixml/sym-no-cxa-allocate "__cxa_allocate_exception" "$syms" lacks pugixml/sym-no-bad-alloc "bad_alloc" "$syms" else bst_notok pugixml/archive-readable "could not flatten $lib" fi rm -f "$flat" # --------------------------------------------------------------------------- # 4. The probe -- the library actually running. # # Built by the pugixml recipe against the archive that same build produced and # shipped in pugixml-tests, so it cannot drift from the library it tests. It is # installed 0755 in libexecdir and needs no staging: it opens the sample # read-only and writes nothing, so the read-only rootfs at browser runtime is # not in its way. `require' rather than a hard failure -- an image that takes # pugixml-dev without pugixml-tests legitimately has nothing to run here, and # that is a coverage prompt (add the package), not a broken port. PT=/usr/libexec/pugixml-tests require "$PT/pugixml-probe" pugixml/probe-present hasfile pugixml/sample-present "$PT/pugixml-sample.xml" # Run ONCE and keep both the output and the status: on this runtime the wasm # module's start-up dominates the cost of the whole suite. out=$("$PT/pugixml-probe" "$PT" 2>&1); prc=$? bst_ok pugixml/probe-ran # identity, and the two modes that must NOT be on has pugixml/run-version "PX-version OK" "$out" has pugixml/run-xpath-compiled-in "PX-xpath-compiled-in OK" "$out" has pugixml/run-stl-compiled-in "PX-stl-compiled-in OK" "$out" # the bundled document: parsed, encoding detected, walked and counted has pugixml/run-load-file "PX-load-file OK" "$out" has pugixml/run-load-file-status "PX-load-file-status OK" "$out" has pugixml/run-load-file-encoding "PX-load-file-encoding OK" "$out" has pugixml/run-root-name "PX-root-name OK" "$out" has pugixml/run-root-type "PX-root-type OK" "$out" has pugixml/run-element-count "PX-element-count OK" "$out" has pugixml/run-attribute-count "PX-attribute-count OK" "$out" # typed attribute accessors -- the parsing pugixml does that a string DOM does not has pugixml/run-attr-as-int "PX-attr-as-int OK" "$out" has pugixml/run-attr-as-int-count "PX-attr-as-int-count OK" "$out" has pugixml/run-attr-as-string "PX-attr-as-string OK" "$out" has pugixml/run-attr-as-double "PX-attr-as-double OK" "$out" has pugixml/run-attr-as-bool-true "PX-attr-as-bool-true OK" "$out" has pugixml/run-attr-missing-default "PX-attr-missing-default OK" "$out" has pugixml/run-attr-missing-empty "PX-attr-missing-empty OK" "$out" # navigation and text, including a numeric character reference expanded to UTF-8 has pugixml/run-child-by-path "PX-child-by-path OK" "$out" has pugixml/run-child-value "PX-child-value OK" "$out" has pugixml/run-node-text "PX-node-text OK" "$out" has pugixml/run-utf8-entity "PX-utf8-entity OK" "$out" # node kinds, and the parse-mask default that drops two of them has pugixml/run-cdata-type "PX-cdata-type OK" "$out" has pugixml/run-cdata-value "PX-cdata-value OK" "$out" has pugixml/run-default-drops-comment "PX-default-drops-comment OK" "$out" has pugixml/run-default-drops-comment-name "PX-default-drops-comment-name OK" "$out" has pugixml/run-default-drops-declaration "PX-default-drops-declaration OK" "$out" has pugixml/run-opt-in-parse "PX-opt-in-parse OK" "$out" has pugixml/run-declaration-type "PX-declaration-type OK" "$out" has pugixml/run-declaration-name "PX-declaration-name OK" "$out" has pugixml/run-declaration-version "PX-declaration-version OK" "$out" has pugixml/run-comment-type "PX-comment-type OK" "$out" has pugixml/run-comment-value "PX-comment-value OK" "$out" # non-validating: an undeclared entity is text, not an error (libxml2 differs) has pugixml/run-entity-undeclared-accepted "PX-entity-undeclared-accepted OK" "$out" has pugixml/run-entity-undeclared-literal "PX-entity-undeclared-literal OK" "$out" # namespaces are LEXICAL: pugixml does not resolve prefixes has pugixml/run-ns-qualified-name "PX-ns-qualified-name OK" "$out" has pugixml/run-ns-xmlns-is-attribute "PX-ns-xmlns-is-attribute OK" "$out" has pugixml/run-ns-no-resolution "PX-ns-no-resolution OK" "$out" # XPath 1.0 -- the capability this port adds over libtinyxml2 has pugixml/run-xpath-node-set-size "PX-xpath-node-set-size OK" "$out" has pugixml/run-xpath-predicate "PX-xpath-predicate OK" "$out" has pugixml/run-xpath-select-node "PX-xpath-select-node OK" "$out" has pugixml/run-xpath-descendant "PX-xpath-descendant OK" "$out" has pugixml/run-xpath-number "PX-xpath-number OK" "$out" has pugixml/run-xpath-string "PX-xpath-string OK" "$out" has pugixml/run-xpath-boolean "PX-xpath-boolean OK" "$out" has pugixml/run-xpath-empty-set "PX-xpath-empty-set OK" "$out" has pugixml/run-xpath-valid-query-result "PX-xpath-valid-query-result OK" "$out" has pugixml/run-xpath-valid-query-bool "PX-xpath-valid-query-bool OK" "$out" # ...and its error channel, which under NO_EXCEPTIONS is the ONLY one there is. # Both halves matter: a query that reported an error but still returned nodes, # and one that silently returned nothing, are different bugs and each would pass # the other's assertion on its own. has pugixml/run-xpath-error-reported "PX-xpath-error-reported OK" "$out" has pugixml/run-xpath-error-bool-false "PX-xpath-error-bool-false OK" "$out" has pugixml/run-xpath-error-has-description "PX-xpath-error-has-description OK" "$out" has pugixml/run-xpath-error-offset "PX-xpath-error-offset OK" "$out" has pugixml/run-xpath-error-empty-set "PX-xpath-error-empty-set OK" "$out" has pugixml/run-xpath-error-unknown-function "PX-xpath-error-unknown-function OK" "$out" # the parse-error channel: eight refusals, eight distinct statuses, each located for c in mismatch no-root bad-attr bad-pi bad-cdata bad-comment bad-tag bad-end; do has "pugixml/run-malformed-$c-refused" "PX-malformed-$c-refused OK" "$out" has "pugixml/run-malformed-$c-status" "PX-malformed-$c-status OK" "$out" has "pugixml/run-malformed-$c-offset" "PX-malformed-$c-offset OK" "$out" has "pugixml/run-malformed-$c-description" "PX-malformed-$c-description OK" "$out" done # ...with a well-formed control, so the eight above are not passing because the # parser refuses everything, and the file-level error, which is the one a caller # meets first in practice and a different enum value from any syntax status has pugixml/run-malformed-control-ok "PX-malformed-control-ok OK" "$out" has pugixml/run-missing-file-refused "PX-missing-file-refused OK" "$out" has pugixml/run-missing-file-status "PX-missing-file-status OK" "$out" # building, mutating and serializing -- the port writes as well as reads has pugixml/run-build-attr "PX-build-attr OK" "$out" has pugixml/run-build-text "PX-build-text OK" "$out" has pugixml/run-serialize-raw "PX-serialize-raw OK" "$out" has pugixml/run-serialize-escape "PX-serialize-escape OK" "$out" has pugixml/run-roundtrip-parse "PX-roundtrip-parse OK" "$out" has pugixml/run-roundtrip-attr "PX-roundtrip-attr OK" "$out" has pugixml/run-mutate-set-name "PX-mutate-set-name OK" "$out" has pugixml/run-mutate-set-value "PX-mutate-set-value OK" "$out" has pugixml/run-mutate-remove-child "PX-mutate-remove-child OK" "$out" has pugixml/run-mutate-removed "PX-mutate-removed OK" "$out" # The probe's own verdict, which also catches a case this list forgot to name: # it counts its OWN failures, so a case added to the probe and not here still # turns the suite red rather than passing unnoticed. has pugixml/run-all-ok "ALL-PUGIXML-OK" "$out" if [ "$prc" = 0 ]; then bst_ok pugixml/run-exit-status else bst_notok pugixml/run-exit-status "probe exited $prc: $(_bst_1line "$out")" fi # The last line of the suite, and it is a coverage assertion rather than a # formality: a suite that dies mid-file loses its remaining cases SILENTLY -- the # runner counts the lines it saw and reports them as a complete green -- so the # only way a reader can tell a full run from a truncated one is a marker that # only a full run emits. Its absence is what a regression here looks like; see # the pass criterion in docs/brintos-test-plan.md. bst_ok pugixml/suite-complete