# BST-TIMEOUT: 300 . "$BST_LIB" # jsoncpp 1.9.5 -- the long-established C++ JSON library, a Json::Value DOM with # reader and writer builders, ported as -dev + -staticdev: ten headers, # jsoncpp.pc, five find_package(jsoncpp) cmake files and libjsoncpp.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 # /usr/libexec/jsoncpp-tests/jsoncpp-probe -- a wasm32 binary the jsoncpp recipe # cross-linked against the very libjsoncpp.a that ships -- which parses # jsoncpp-sample.json, reads it back typed, re-serializes it byte-exactly with # three different writers, round-trips it, and drives the error channel that this # port's one configuration decision leaves as the only one there is. # # WHY THIS IMAGE CARRIES A FOURTH JSON PARSER. cJSON, json-c and libfastjson are # all C, and nlohmann-json (82) is header-only -- it ships no library at all, so # a C++ consumer that wants a compiled DOM has had nothing here until now. That # is the whole of the overlap and the whole of the reason it is deliberate: # jsoncpp is the default JSON dependency of a large body of existing C++ code, # which links -ljsoncpp and includes and cannot be pointed at a # header-only alternative without being rewritten. Numbered 81 beside its C # siblings 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 # json_value.cpp throws in two places, so it is built with upstream's own # -DJSON_USE_EXCEPTION=0. That is not merely a build flag: it CHANGES THE # LIBRARY'S ERROR CONTRACT. Json::Exception, RuntimeError and LogicError cease to # exist, and Json::throwRuntimeError / throwLogicError -- the funnel every # JSON_ASSERT and JSON_FAIL_MESSAGE in the library reaches -- now print to stderr # and abort() instead of throwing. So a Json::Value TYPE ERROR is fatal to the # process rather than catchable, and the reader's `errs` string is the entire # remaining error channel. The malformed-* group therefore asserts eight refusals # with their specific messages AND locations, and the lax-* group asserts what the # reader accepts that is not JSON at all. # # AND THE PORT FIXED SOMETHING, which is unusual for a package port and is # asserted here rather than trusted. jsoncpp gives that mode NO channel to a # consumer: it is not a cmake option, so the exported cmake package carries no # INTERFACE_COMPILE_DEFINITIONS for it, and pkg-config/jsoncpp.pc.in interpolates # no definitions either. config.h's own default is the OPPOSITE of what the # archive was built with. Left alone, every consumer on this image would compile # against a header declaring an exception hierarchy the archive does not define. # The recipe rewrites the default in the installed copy, preserving the #ifndef so # an explicit -D still wins; the three cases below pin the rewrite AND the two # channels that remain silent, because a later release that starts carrying the # definition properly should show up as a red rather than as nothing. # # Style follows 81-cjson and 74-pugixml: files are read once into shell variables # and matched with `case` globs, and the archive symbol table is one batched pass. # ~230 check_out spawns would cost more than the assertions on this runtime. incdir=/usr/include/json pc=/usr/lib/pkgconfig/jsoncpp.pc lib=/usr/lib/libjsoncpp.a cm=/usr/lib/cmake/jsoncpp 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; } # A case this platform is KNOWN to fail, with the issue that owns it. Still a red # -- the suite does not paper over a gap -- but one that carries its attribution # in its own detail line, so a reader of the report does not have to find the # comment that explains it. It flips to green with no edit here the day the # issue lands, which is the point of keeping the case rather than deleting it. knownred() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "expected red on wasm32 -- $4" ;; esac; } # --------------------------------------------------------------------------- # 1. The shipped payload. # # All ten public headers, because jsoncpp's is a facade that # includes the rest -- a missing one is a compile error for a consumer and # invisible to any check that only opens the facade. for h in allocator assertions config forwards json json_features reader value version writer; do hasfile "jsoncpp/header-$h" "$incdir/$h.h" done hasfile jsoncpp/pc-present "$pc" hasfile jsoncpp/archive-present "$lib" hasfile jsoncpp/cmake-config-present "$cm/jsoncppConfig.cmake" hasfile jsoncpp/cmake-version-present "$cm/jsoncppConfigVersion.cmake" hasfile jsoncpp/cmake-targets-present "$cm/jsoncpp-targets.cmake" hasfile jsoncpp/cmake-release-present "$cm/jsoncpp-targets-release.cmake" hasfile jsoncpp/cmake-namespaced-present "$cm/jsoncpp-namespaced-targets.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 jsoncpp/no-shared "/usr/lib/libjsoncpp*.so*" if [ -f /usr/lib/libjsoncpp.la ]; then bst_notok jsoncpp/no-la "/usr/lib/libjsoncpp.la is installed" else bst_ok jsoncpp/no-la fi # The archive is named libjsoncpp.a and not libjsoncpp_static.a: src/lib_json's # STATIC_SUFFIX is only non-empty when both arms are built, so the name is # evidence that exactly one arm was. if [ -f /usr/lib/libjsoncpp_static.a ]; then bst_notok jsoncpp/no-static-suffix "libjsoncpp_static.a is installed, so both library arms were built" else bst_ok jsoncpp/no-static-suffix fi cfg=$(cat "$incdir/config.h" 2>/dev/null) ver=$(cat "$incdir/version.h" 2>/dev/null) val=$(cat "$incdir/value.h" 2>/dev/null) pcs=$(cat "$pc" 2>/dev/null) tgt=$(cat "$cm/jsoncpp-targets.cmake" 2>/dev/null) rel=$(cat "$cm/jsoncpp-targets-release.cmake" 2>/dev/null) nsp=$(cat "$cm/jsoncpp-namespaced-targets.cmake" 2>/dev/null) cfgv=$(cat "$cm/jsoncppConfigVersion.cmake" 2>/dev/null) has jsoncpp/header-version-string "JSONCPP_VERSION_STRING \"1.9.5\"" "$ver" has jsoncpp/header-version-major "JSONCPP_VERSION_MAJOR 1" "$ver" has jsoncpp/header-guard "JSON_CONFIG_H_INCLUDED" "$cfg" has jsoncpp/header-namespace "namespace Json" "$val" has jsoncpp/pc-name "Name: jsoncpp" "$pcs" has jsoncpp/pc-version "Version: 1.9.5" "$pcs" has jsoncpp/pc-libs "-ljsoncpp" "$pcs" has jsoncpp/pc-cflags "Cflags: -I" "$pcs" has jsoncpp/cmake-static-target "add_library(jsoncpp_static STATIC IMPORTED)" "$tgt" has jsoncpp/cmake-imports-archive "/lib/libjsoncpp.a" "$rel" has jsoncpp/cmake-version "PACKAGE_VERSION \"1.9.5\"" "$cfgv" # The namespaced alias resolves to the STATIC target, because that is the only # one built. A shared arm sneaking back in would flip this to jsoncpp_lib. has jsoncpp/cmake-namespaced-static "INTERFACE_LINK_LIBRARIES \"jsoncpp_static\"" "$nsp" # --------------------------------------------------------------------------- # 2. THE EXCEPTIONS-OFF MODE, AND THE THREE PLACES IT COULD HAVE BEEN RECORDED. # # jsoncpp has no cmake option for JSON_USE_EXCEPTION and no .pc hook for it, so # two of the three are structurally silent and stay that way. The third is # config.h's own #ifndef default, which the recipe rewrites from 1 to 0 so the # shipped header describes the shipped archive. Without that rewrite a consumer # compiles against a declared Json::Exception hierarchy the archive does not # define -- an undefined reference if it catches one, and a silent abort() where # it expected a throw. # # The #ifndef is asserted alongside the value: rewriting the guard away would # take an explicit consumer -DJSON_USE_EXCEPTION with it, which is a different # and worse change than the one intended. has jsoncpp/config-exceptions-off "#define JSON_USE_EXCEPTION 0" "$cfg" lacks jsoncpp/config-exceptions-not-on "#define JSON_USE_EXCEPTION 1" "$cfg" has jsoncpp/config-ifndef-preserved "#ifndef JSON_USE_EXCEPTION" "$cfg" lacks jsoncpp/pc-silent-on-exceptions "JSON_USE_EXCEPTION" "$pcs" lacks jsoncpp/cmake-silent-on-exceptions "JSON_USE_EXCEPTION" "$tgt" # --------------------------------------------------------------------------- # 3. The archive, read once. # # The exceptions-off build is visible in the symbol table and nowhere else. What # distinguishes it from a build that merely lost its error handling is the PAIR: # the Json::Exception hierarchy and the Itanium unwinder calls are gone, while # throwRuntimeError and throwLogicError are still there -- they are the funnels # every JSON_ASSERT reaches, and under this mode they abort instead of throwing. # Asserting only the absences would also pass against a library built with its # error path deleted. check_out jsoncpp/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. # 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-jsoncpp-flat.$$ ( tr -c '\40-\176\n' ' ' < "$lib" > "$flat" ) 2>/dev/null if [ -s "$flat" ]; then bst_ok jsoncpp/archive-readable syms=$(cat "$flat") # Three translation units, and all three have to be in there: a partial compile # that dropped the writer would still give a consumer a working parser. for u in json_value json_reader json_writer; do has "jsoncpp/archive-member-$u" "$u.cpp.o" "$syms" done # the DOM, both readers and both writer families are present... has jsoncpp/sym-value "Json5Value" "$syms" has jsoncpp/sym-charreaderbuilder "CharReaderBuilder" "$syms" has jsoncpp/sym-legacy-reader "Json6Reader" "$syms" has jsoncpp/sym-streamwriter "StreamWriterBuilder" "$syms" has jsoncpp/sym-fastwriter "FastWriter" "$syms" has jsoncpp/sym-styledwriter "StyledWriter" "$syms" # ...the error funnels are still there, aborting rather than throwing... has jsoncpp/sym-throw-runtime-error "throwRuntimeError" "$syms" has jsoncpp/sym-throw-logic-error "throwLogicError" "$syms" # ...and the exception machinery is not, which is the only place the port's one # configuration decision is visible in the shipped binary. The mangled class # names are matched rather than the plain words, since "Exception" appears in # unrelated string data. lacks jsoncpp/sym-no-exception-class "9ExceptionE" "$syms" lacks jsoncpp/sym-no-runtime-error-class "12RuntimeErrorE" "$syms" lacks jsoncpp/sym-no-logic-error-class "10LogicErrorE" "$syms" lacks jsoncpp/sym-no-cxa-throw "__cxa_throw" "$syms" lacks jsoncpp/sym-no-cxa-allocate "__cxa_allocate_exception" "$syms" else bst_notok jsoncpp/archive-readable "could not flatten $lib" fi rm -f "$flat" # --------------------------------------------------------------------------- # 4. The probe -- the library actually running. # # Built by the jsoncpp recipe against the archive that same build produced and # shipped in jsoncpp-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 jsoncpp-dev # without jsoncpp-tests legitimately has nothing to run here, and that is a # coverage prompt (add the package), not a broken port. JT=/usr/libexec/jsoncpp-tests require "$JT/jsoncpp-probe" jsoncpp/probe-present hasfile jsoncpp/sample-present "$JT/jsoncpp-sample.json" # 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=$("$JT/jsoncpp-probe" "$JT" 2>&1); prc=$? bst_ok jsoncpp/probe-ran # identity, and the mode this port is built in # JSONCPP_VERSION_* is read from the shipped version.h, so a version bump that moved # the archive without moving the header shows up here first. has jsoncpp/run-version-string "JC-version-string OK" "$out" has jsoncpp/run-version-major "JC-version-major OK" "$out" has jsoncpp/run-version-minor "JC-version-minor OK" "$out" has jsoncpp/run-version-patch "JC-version-patch OK" "$out" has jsoncpp/run-version-hexa "JC-version-hexa OK" "$out" has jsoncpp/run-exceptions-off "JC-exceptions-off OK" "$out" has jsoncpp/run-int64-supported "JC-int64-supported OK" "$out" # the bundled document, read three ways # parse-legacy-tree-differs is an ASSERTION THAT THE TWO READERS DISAGREE, and it is # deliberate. Reader::decodeNumber stores a positive integer as LargestUInt above # Value::maxInt (2^31-1) while OurReader::decodeNumber uses maxLargestInt (2^63-1) # for the same test, so every positive integer over 2147483647 comes back intValue # from the modern reader and uintValue from the legacy one. The serialized text is # byte-identical either way -- only Value::operator== sees it, and it compares the # type first. Upstream's behaviour, identical on x86-64; asserted so a release that # reconciles the two readers surfaces as a red rather than in silence, and so the next # reader does not re-derive it from a mysterious inequality. has jsoncpp/run-sample-open "JC-sample-open OK" "$out" has jsoncpp/run-sample-nonempty "JC-sample-nonempty OK" "$out" has jsoncpp/run-parse-stream "JC-parse-stream OK" "$out" has jsoncpp/run-parse-stream-no-errs "JC-parse-stream-no-errs OK" "$out" has jsoncpp/run-parse-charreader "JC-parse-charreader OK" "$out" has jsoncpp/run-parse-charreader-no-errs "JC-parse-charreader-no-errs OK" "$out" has jsoncpp/run-parse-charreader-agrees "JC-parse-charreader-agrees OK" "$out" has jsoncpp/run-parse-legacy-reader "JC-parse-legacy-reader OK" "$out" has jsoncpp/run-parse-legacy-same-text "JC-parse-legacy-same-text OK" "$out" has jsoncpp/run-parse-legacy-tree-differs "JC-parse-legacy-tree-differs OK" "$out" has jsoncpp/run-parse-legacy-large-type "JC-parse-legacy-large-type OK" "$out" has jsoncpp/run-parse-modern-large-type "JC-parse-modern-large-type OK" "$out" has jsoncpp/run-parse-legacy-large-value-agrees "JC-parse-legacy-large-value-agrees OK" "$out" has jsoncpp/run-parse-legacy-small-agrees "JC-parse-legacy-small-agrees OK" "$out" # the tree: type, size and member order # Json::Value's object is an ordered map, so getMemberNames() comes back SORTED rather # than in document order -- the sample is written unsorted on purpose. has jsoncpp/run-root-type "JC-root-type OK" "$out" has jsoncpp/run-root-is-object "JC-root-is-object OK" "$out" has jsoncpp/run-root-size "JC-root-size OK" "$out" has jsoncpp/run-member-count "JC-member-count OK" "$out" has jsoncpp/run-member-first "JC-member-first OK" "$out" has jsoncpp/run-member-last "JC-member-last OK" "$out" has jsoncpp/run-member-names-sorted "JC-member-names-sorted OK" "$out" has jsoncpp/run-is-member-present "JC-is-member-present OK" "$out" has jsoncpp/run-is-member-absent "JC-is-member-absent OK" "$out" # typed accessors -- the parsing jsoncpp does that a string DOM does not # Three of these are traps rather than routine reads. large-* is 2^53+1: an Int64 that # is NOT an int, so asInt() on it would ABORT under this port's exceptions-off mode. # isdouble-true-for-int pins that isDouble() is a CONVERTIBILITY predicate covering # intValue and uintValue rather than a storage one -- and isNumeric() is literally an # alias for it. measurement-value is DBL_MAX, compared bit-exactly. has jsoncpp/run-counts-is-object "JC-counts-is-object OK" "$out" has jsoncpp/run-counts-size "JC-counts-size OK" "$out" has jsoncpp/run-small-is-int "JC-small-is-int OK" "$out" has jsoncpp/run-small-value "JC-small-value OK" "$out" has jsoncpp/run-zero-is-int "JC-zero-is-int OK" "$out" has jsoncpp/run-zero-value "JC-zero-value OK" "$out" has jsoncpp/run-large-is-int64 "JC-large-is-int64 OK" "$out" has jsoncpp/run-large-not-int "JC-large-not-int OK" "$out" has jsoncpp/run-large-is-integral "JC-large-is-integral OK" "$out" has jsoncpp/run-large-value "JC-large-value OK" "$out" has jsoncpp/run-large-type "JC-large-type OK" "$out" has jsoncpp/run-large-not-real "JC-large-not-real OK" "$out" has jsoncpp/run-isdouble-true-for-int "JC-isdouble-true-for-int OK" "$out" has jsoncpp/run-isdouble-false-for-string "JC-isdouble-false-for-string OK" "$out" has jsoncpp/run-isnumeric-aliases-isdouble "JC-isnumeric-aliases-isdouble OK" "$out" has jsoncpp/run-isintegral-false-for-real "JC-isintegral-false-for-real OK" "$out" has jsoncpp/run-unsigned-is-uint64 "JC-unsigned-is-uint64 OK" "$out" has jsoncpp/run-unsigned-not-int64 "JC-unsigned-not-int64 OK" "$out" has jsoncpp/run-unsigned-value "JC-unsigned-value OK" "$out" has jsoncpp/run-ratio-is-double "JC-ratio-is-double OK" "$out" has jsoncpp/run-ratio-value "JC-ratio-value OK" "$out" has jsoncpp/run-measurement-value "JC-measurement-value OK" "$out" has jsoncpp/run-title-is-string "JC-title-is-string OK" "$out" has jsoncpp/run-title-value "JC-title-value OK" "$out" has jsoncpp/run-title-length "JC-title-length OK" "$out" has jsoncpp/run-unicode-value "JC-unicode-value OK" "$out" has jsoncpp/run-unicode-length "JC-unicode-length OK" "$out" has jsoncpp/run-solidus-value "JC-solidus-value OK" "$out" has jsoncpp/run-enabled-is-bool "JC-enabled-is-bool OK" "$out" has jsoncpp/run-enabled-value "JC-enabled-value OK" "$out" has jsoncpp/run-disabled-value "JC-disabled-value OK" "$out" has jsoncpp/run-absent-is-null "JC-absent-is-null OK" "$out" has jsoncpp/run-absent-type "JC-absent-type OK" "$out" has jsoncpp/run-mixed-is-array "JC-mixed-is-array OK" "$out" has jsoncpp/run-mixed-size "JC-mixed-size OK" "$out" has jsoncpp/run-mixed-0-int "JC-mixed-0-int OK" "$out" has jsoncpp/run-mixed-1-double "JC-mixed-1-double OK" "$out" has jsoncpp/run-mixed-2-string "JC-mixed-2-string OK" "$out" has jsoncpp/run-mixed-3-bool "JC-mixed-3-bool OK" "$out" has jsoncpp/run-mixed-4-null "JC-mixed-4-null OK" "$out" has jsoncpp/run-mixed-5-object "JC-mixed-5-object OK" "$out" has jsoncpp/run-mixed-5-member "JC-mixed-5-member OK" "$out" has jsoncpp/run-mixed-6-array "JC-mixed-6-array OK" "$out" has jsoncpp/run-mixed-6-empty "JC-mixed-6-empty OK" "$out" has jsoncpp/run-mixed-out-of-range "JC-mixed-out-of-range OK" "$out" has jsoncpp/run-empty-array-is-array "JC-empty-array-is-array OK" "$out" has jsoncpp/run-empty-array-size "JC-empty-array-size OK" "$out" has jsoncpp/run-empty-object-is-object "JC-empty-object-is-object OK" "$out" has jsoncpp/run-empty-object-size "JC-empty-object-size OK" "$out" has jsoncpp/run-nested-level "JC-nested-level OK" "$out" has jsoncpp/run-nested-inner-level "JC-nested-inner-level OK" "$out" has jsoncpp/run-nested-inner-leaf "JC-nested-inner-leaf OK" "$out" has jsoncpp/run-get-present "JC-get-present OK" "$out" has jsoncpp/run-get-missing "JC-get-missing OK" "$out" has jsoncpp/run-subscript-missing-is-null "JC-subscript-missing-is-null OK" "$out" # the writers, byte-exact against the x86-64 reference # The whole point of the group: a wasm32 double-to-string path that rounds differently, # or an object map that orders differently, is invisible to any assertion weaker than a # byte compare. Three writer shapes are pinned separately because they agree on nothing # but the data -- FastWriter ends in a newline, the StreamWriterBuilder compact form # does not, and the default form indents with a tab and breaks before a nested # container's brace. has jsoncpp/run-fast-writer-bytes "JC-fast-writer-bytes OK" "$out" has jsoncpp/run-fast-writer-length "JC-fast-writer-length OK" "$out" has jsoncpp/run-fast-writer-newline "JC-fast-writer-newline OK" "$out" has jsoncpp/run-styled-writer-bytes "JC-styled-writer-bytes OK" "$out" has jsoncpp/run-styled-writer-length "JC-styled-writer-length OK" "$out" has jsoncpp/run-streamwriter-default-length "JC-streamwriter-default-length OK" "$out" has jsoncpp/run-streamwriter-default-tabs "JC-streamwriter-default-tabs OK" "$out" has jsoncpp/run-streamwriter-default-brace-own-line "JC-streamwriter-default-brace-own-line OK" "$out" has jsoncpp/run-streamwriter-compact-bytes "JC-streamwriter-compact-bytes OK" "$out" has jsoncpp/run-streamwriter-compact-length "JC-streamwriter-compact-length OK" "$out" has jsoncpp/run-compact-is-fast-less-newline "JC-compact-is-fast-less-newline OK" "$out" has jsoncpp/run-streamwriter-utf8-length "JC-streamwriter-utf8-length OK" "$out" has jsoncpp/run-streamwriter-utf8-raw "JC-streamwriter-utf8-raw OK" "$out" has jsoncpp/run-streamwriter-default-escapes "JC-streamwriter-default-escapes OK" "$out" # round-trip: parse -> write -> parse reaches the same tree and the same bytes has jsoncpp/run-roundtrip-parse "JC-roundtrip-parse OK" "$out" has jsoncpp/run-roundtrip-equal "JC-roundtrip-equal OK" "$out" has jsoncpp/run-roundtrip-fast-idempotent "JC-roundtrip-fast-idempotent OK" "$out" has jsoncpp/run-roundtrip-styled-idempotent "JC-roundtrip-styled-idempotent OK" "$out" has jsoncpp/run-roundtrip-styled-parse "JC-roundtrip-styled-parse OK" "$out" has jsoncpp/run-roundtrip-styled-equal "JC-roundtrip-styled-equal OK" "$out" # the reader's error channel, which under JSON_USE_EXCEPTION=0 is the only one there is # Each malformed case asserts four things and all four are needed: REFUSED, REPORTED (a # non-empty errs), the specific MESSAGE, and the LOCATION. A reader that refused # everything with one generic string would pass the first two; the control case is what # stops exactly that. has jsoncpp/run-malformed-no-value-refused "JC-malformed-no-value-refused OK" "$out" has jsoncpp/run-malformed-no-value-reported "JC-malformed-no-value-reported OK" "$out" has jsoncpp/run-malformed-no-value-message "JC-malformed-no-value-message OK" "$out" has jsoncpp/run-malformed-no-value-located "JC-malformed-no-value-located OK" "$out" has jsoncpp/run-malformed-unterm-str-refused "JC-malformed-unterm-str-refused OK" "$out" has jsoncpp/run-malformed-unterm-str-reported "JC-malformed-unterm-str-reported OK" "$out" has jsoncpp/run-malformed-unterm-str-message "JC-malformed-unterm-str-message OK" "$out" has jsoncpp/run-malformed-unterm-str-located "JC-malformed-unterm-str-located OK" "$out" has jsoncpp/run-malformed-no-colon-refused "JC-malformed-no-colon-refused OK" "$out" has jsoncpp/run-malformed-no-colon-reported "JC-malformed-no-colon-reported OK" "$out" has jsoncpp/run-malformed-no-colon-message "JC-malformed-no-colon-message OK" "$out" has jsoncpp/run-malformed-no-colon-located "JC-malformed-no-colon-located OK" "$out" has jsoncpp/run-malformed-bad-literal-refused "JC-malformed-bad-literal-refused OK" "$out" has jsoncpp/run-malformed-bad-literal-reported "JC-malformed-bad-literal-reported OK" "$out" has jsoncpp/run-malformed-bad-literal-message "JC-malformed-bad-literal-message OK" "$out" has jsoncpp/run-malformed-bad-literal-located "JC-malformed-bad-literal-located OK" "$out" has jsoncpp/run-malformed-unclosed-refused "JC-malformed-unclosed-refused OK" "$out" has jsoncpp/run-malformed-unclosed-reported "JC-malformed-unclosed-reported OK" "$out" has jsoncpp/run-malformed-unclosed-message "JC-malformed-unclosed-message OK" "$out" has jsoncpp/run-malformed-unclosed-located "JC-malformed-unclosed-located OK" "$out" has jsoncpp/run-malformed-empty-refused "JC-malformed-empty-refused OK" "$out" has jsoncpp/run-malformed-empty-reported "JC-malformed-empty-reported OK" "$out" has jsoncpp/run-malformed-empty-message "JC-malformed-empty-message OK" "$out" has jsoncpp/run-malformed-empty-located "JC-malformed-empty-located OK" "$out" has jsoncpp/run-malformed-bad-escape-refused "JC-malformed-bad-escape-refused OK" "$out" has jsoncpp/run-malformed-bad-escape-reported "JC-malformed-bad-escape-reported OK" "$out" has jsoncpp/run-malformed-bad-escape-message "JC-malformed-bad-escape-message OK" "$out" has jsoncpp/run-malformed-bad-escape-located "JC-malformed-bad-escape-located OK" "$out" has jsoncpp/run-malformed-nan-refused "JC-malformed-nan-refused OK" "$out" has jsoncpp/run-malformed-nan-reported "JC-malformed-nan-reported OK" "$out" has jsoncpp/run-malformed-nan-message "JC-malformed-nan-message OK" "$out" has jsoncpp/run-malformed-nan-located "JC-malformed-nan-located OK" "$out" has jsoncpp/run-malformed-bad-escape-detail "JC-malformed-bad-escape-detail OK" "$out" has jsoncpp/run-malformed-control-accepted "JC-malformed-control-accepted OK" "$out" has jsoncpp/run-malformed-control-no-errs "JC-malformed-control-no-errs OK" "$out" has jsoncpp/run-malformed-control-escape "JC-malformed-control-escape OK" "$out" has jsoncpp/run-legacy-error-refused "JC-legacy-error-refused OK" "$out" has jsoncpp/run-legacy-error-message "JC-legacy-error-message OK" "$out" has jsoncpp/run-legacy-error-located "JC-legacy-error-located OK" "$out" # WHAT THE DEFAULT READER ACCEPTS, AND IT IS NOT JSON # The most consequential behaviour of this port for a caller, and invisible to any test # that only feeds it good input: in its DEFAULT settings jsoncpp accepts trailing # garbage after the document, a trailing comma in an array, a duplicate object key # (last one wins) and a bare scalar root. strictMode() refuses each with a specific # message. Both halves are asserted, so a release that tightens the default or loosens # strict mode changes a red here. has jsoncpp/run-lax-trailing-garbage-default-accepts "JC-lax-trailing-garbage-default-accepts OK" "$out" has jsoncpp/run-lax-trailing-garbage-strict-refuses "JC-lax-trailing-garbage-strict-refuses OK" "$out" has jsoncpp/run-lax-trailing-garbage-strict-message "JC-lax-trailing-garbage-strict-message OK" "$out" has jsoncpp/run-lax-trailing-comma-default-accepts "JC-lax-trailing-comma-default-accepts OK" "$out" has jsoncpp/run-lax-trailing-comma-strict-refuses "JC-lax-trailing-comma-strict-refuses OK" "$out" has jsoncpp/run-lax-trailing-comma-strict-message "JC-lax-trailing-comma-strict-message OK" "$out" has jsoncpp/run-lax-duplicate-key-default-accepts "JC-lax-duplicate-key-default-accepts OK" "$out" has jsoncpp/run-lax-duplicate-key-strict-refuses "JC-lax-duplicate-key-strict-refuses OK" "$out" has jsoncpp/run-lax-duplicate-key-strict-message "JC-lax-duplicate-key-strict-message OK" "$out" has jsoncpp/run-lax-scalar-root-default-accepts "JC-lax-scalar-root-default-accepts OK" "$out" has jsoncpp/run-lax-scalar-root-strict-refuses "JC-lax-scalar-root-strict-refuses OK" "$out" has jsoncpp/run-lax-scalar-root-strict-message "JC-lax-scalar-root-strict-message OK" "$out" has jsoncpp/run-lax-duplicate-key-last-wins "JC-lax-duplicate-key-last-wins OK" "$out" has jsoncpp/run-lax-duplicate-key-size "JC-lax-duplicate-key-size OK" "$out" has jsoncpp/run-lax-comment-accepted "JC-lax-comment-accepted OK" "$out" has jsoncpp/run-lax-comment-value "JC-lax-comment-value OK" "$out" # building, mutating and serializing -- the port writes as well as reads has jsoncpp/run-build-is-object "JC-build-is-object OK" "$out" has jsoncpp/run-build-size "JC-build-size OK" "$out" has jsoncpp/run-build-list-size "JC-build-list-size OK" "$out" has jsoncpp/run-build-deep "JC-build-deep OK" "$out" has jsoncpp/run-build-serialized "JC-build-serialized OK" "$out" has jsoncpp/run-mutate-copy-equal "JC-mutate-copy-equal OK" "$out" has jsoncpp/run-mutate-set "JC-mutate-set OK" "$out" has jsoncpp/run-mutate-source-unchanged "JC-mutate-source-unchanged OK" "$out" has jsoncpp/run-mutate-copy-differs "JC-mutate-copy-differs OK" "$out" has jsoncpp/run-mutate-remove-member "JC-mutate-remove-member OK" "$out" has jsoncpp/run-mutate-removed-value "JC-mutate-removed-value OK" "$out" has jsoncpp/run-mutate-removed-gone "JC-mutate-removed-gone OK" "$out" has jsoncpp/run-mutate-size-after-remove "JC-mutate-size-after-remove OK" "$out" has jsoncpp/run-mutate-remove-absent "JC-mutate-remove-absent OK" "$out" has jsoncpp/run-mutate-remove-index "JC-mutate-remove-index OK" "$out" has jsoncpp/run-mutate-removed-index-value "JC-mutate-removed-index-value OK" "$out" has jsoncpp/run-mutate-list-size-after "JC-mutate-list-size-after OK" "$out" has jsoncpp/run-mutate-list-compacted "JC-mutate-list-compacted OK" "$out" has jsoncpp/run-mutate-resize "JC-mutate-resize OK" "$out" has jsoncpp/run-mutate-resize-nulls "JC-mutate-resize-nulls OK" "$out" has jsoncpp/run-mutate-swap-a "JC-mutate-swap-a OK" "$out" has jsoncpp/run-mutate-swap-b "JC-mutate-swap-b OK" "$out" has jsoncpp/run-mutate-clear "JC-mutate-clear OK" "$out" # DOUBLE PARSING AT THE EDGES -- and the one place this arm differs from x86-64 # EXPECT double-subnormal-* AND stdlib-subnormal-* TO BE RED ON THIS TARGET, and read # the rest of the group as the evidence that nothing else is: # brintos.io/brintos/linux-in-the-browser/issues/174. # # jsoncpp decodes a number through `IStringStream >> double`, so what it can parse is # whatever this C++ runtime's num_get can. Under static libc++ on wasm32 a SUBNORMAL # literal (5e-324, 1e-320) sets failbit, and jsoncpp turns that into "is not a number" # and refuses the whole document at that token. Every normal double in the group -- # DBL_MAX, DBL_MIN, 1e300, 1e-300 -- is accepted, which is what makes this an # underflow-reporting difference between two standard libraries rather than a broken # float path. # # Each literal is parsed in its OWN document on purpose. They were once members of the # shared sample, and the one refusal took the whole document with it: 38 assertions # about unrelated members went red at once and the suite reported a platform gap as a # port failure. Isolated, the gap costs exactly the cases it owns. # # stdlib-subnormal-* asks the runtime the same question with jsoncpp out of the way, # which is what says whose defect it is -- so a fix landing in libc++ turns these green # without anything here changing. has jsoncpp/run-double-half-parsed "JC-double-half-parsed OK" "$out" has jsoncpp/run-double-half-value "JC-double-half-value OK" "$out" has jsoncpp/run-double-negative-parsed "JC-double-negative-parsed OK" "$out" has jsoncpp/run-double-negative-value "JC-double-negative-value OK" "$out" has jsoncpp/run-double-exp-plus-parsed "JC-double-exp-plus-parsed OK" "$out" has jsoncpp/run-double-exp-plus-value "JC-double-exp-plus-value OK" "$out" has jsoncpp/run-double-exp-minus-parsed "JC-double-exp-minus-parsed OK" "$out" has jsoncpp/run-double-exp-minus-value "JC-double-exp-minus-value OK" "$out" has jsoncpp/run-double-dbl-max-parsed "JC-double-dbl-max-parsed OK" "$out" has jsoncpp/run-double-dbl-max-value "JC-double-dbl-max-value OK" "$out" has jsoncpp/run-double-dbl-min-parsed "JC-double-dbl-min-parsed OK" "$out" has jsoncpp/run-double-dbl-min-value "JC-double-dbl-min-value OK" "$out" knownred jsoncpp/run-double-subnormal-parsed "JC-double-subnormal-parsed OK" "$out" "brintos.io/brintos/linux-in-the-browser/issues/174 (iostreams set failbit on a subnormal double)" knownred jsoncpp/run-double-subnormal-value "JC-double-subnormal-value OK" "$out" "brintos.io/brintos/linux-in-the-browser/issues/174 (iostreams set failbit on a subnormal double)" knownred jsoncpp/run-double-subnormal-2-parsed "JC-double-subnormal-2-parsed OK" "$out" "brintos.io/brintos/linux-in-the-browser/issues/174 (iostreams set failbit on a subnormal double)" knownred jsoncpp/run-double-subnormal-2-value "JC-double-subnormal-2-value OK" "$out" "brintos.io/brintos/linux-in-the-browser/issues/174 (iostreams set failbit on a subnormal double)" has jsoncpp/run-double-zero-parsed "JC-double-zero-parsed OK" "$out" has jsoncpp/run-double-zero-value "JC-double-zero-value OK" "$out" has jsoncpp/run-double-neg-zero-parsed "JC-double-neg-zero-parsed OK" "$out" has jsoncpp/run-double-neg-zero-value "JC-double-neg-zero-value OK" "$out" knownred jsoncpp/run-stdlib-subnormal-extracted "JC-stdlib-subnormal-extracted OK" "$out" "brintos.io/brintos/linux-in-the-browser/issues/174 (iostreams set failbit on a subnormal double)" has jsoncpp/run-stdlib-subnormal-value "JC-stdlib-subnormal-value OK" "$out" has jsoncpp/run-stdlib-normal-extracted "JC-stdlib-normal-extracted OK" "$out" # the reader type-split, measured at its boundary # 2147483647 is the last value the two readers agree on and 2147483648 the first they do # not; negatives are unaffected. Asserted at the edge rather than only where the sample # happens to land. has jsoncpp/run-reader-split-below-same-text "JC-reader-split-below-same-text OK" "$out" has jsoncpp/run-reader-split-below-agree "JC-reader-split-below-agree OK" "$out" has jsoncpp/run-reader-split-at-same-text "JC-reader-split-at-same-text OK" "$out" has jsoncpp/run-reader-split-at-differ "JC-reader-split-at-differ OK" "$out" has jsoncpp/run-reader-split-above-same-text "JC-reader-split-above-same-text OK" "$out" has jsoncpp/run-reader-split-above-differ "JC-reader-split-above-differ OK" "$out" has jsoncpp/run-reader-split-negative-same-text "JC-reader-split-negative-same-text OK" "$out" has jsoncpp/run-reader-split-negative-agree "JC-reader-split-negative-agree OK" "$out" # comparison and ordering, which a consumer uses to diff two documents has jsoncpp/run-compare-equal "JC-compare-equal OK" "$out" has jsoncpp/run-compare-unequal "JC-compare-unequal OK" "$out" has jsoncpp/run-compare-less "JC-compare-less OK" "$out" has jsoncpp/run-compare-null-first "JC-compare-null-first 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. # Both of these are ROLL-UPS of the probe's own failure count, so on this target # they are red for exactly one reason -- the five subnormal cases above -- and # they are the guard that a case added to the probe and not named in this file # still turns the suite red rather than passing unnoticed. Their detail names the # issue so a reader does not read them as a sixth and seventh independent fault. knownred jsoncpp/run-all-ok "ALL-JSONCPP-OK" "$out" \ "roll-up of the 5 subnormal cases -- brintos.io/brintos/linux-in-the-browser/issues/174; a HIGHER failure count than 5 is a real regression" if [ "$prc" = 0 ]; then bst_ok jsoncpp/run-exit-status else bst_notok jsoncpp/run-exit-status \ "expected red on wasm32 -- probe exited $prc with the 5 subnormal cases of brintos.io/brintos/linux-in-the-browser/issues/174: $(_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 jsoncpp/suite-complete