. "$BST_LIB" # BRINTOS-WORKAROUND: brintos/linux-in-the-browser#138 revisit -- the FIRST line a # suite writes after the runner's ==BST-BEGIN== can be swallowed when a kernel # printk lands on the console in between, which cost 79-libevdev a scored case # that vanished from the transcript while the runner's cases= count still # included it. The failure direction is the dangerous one: a harness counting # result lines reads N of N green and is wrong about COVERAGE. This absorbs the # loss with a line nobody scores. Drop it once #138 lands. printf '#diag: libserialport suite start (this line is a console-loss absorber, not a case)\n' # libserialport 0.1.1 -- the sigrok project's cross-platform serial-port # abstraction (meta-oe recipes-extended/libserialport), what turns termios, the # Windows SetupAPI and IOKit into one typed API. What ships here is # /usr/lib/libserialport.a, /usr/lib/pkgconfig/libserialport.pc, the generated # /usr/include/libserialport.h, and the probe this suite scores. The package # installs NO program at all -- lib_LTLIBRARIES and no bin_PROGRAMS -- which is # why the probe exists. # # --------------------------------------------------------------------------- # WHAT NEEDS A SERIAL DEVICE HERE, AND WHAT DOES NOT. # # * THE CONFIG OBJECT (group D) needs NOTHING. sp_set_config_ and # sp_get_config_ are generated by CREATE_ACCESSORS in serialport.c and # operate on a plain struct sp_port_config -- no port, no fd, no ioctl. The # set-then-read-back contract the ticket asks for is therefore fully # measurable on a machine with no serial hardware, and group D is where that # assertion actually lives. # * THE REFUSALS (group C) need nothing either -- they are the SP_ERR_ARG # paths, reached with a NULL or a name no machine has. # * ENUMERATION (group B) needs only /sys/class/tty. # * A REAL PORT (group E) needs a device, and this guest has none. # # WHY GROUP E IS EXPECTED TO REPORT `none`, AND WHY THAT IS NOT A HOLE. # list_ports() in linux.c skips every tty whose /sys/class/tty/ link resolves # through "virtual" (`if (strstr(target, "virtual")) continue;`). Every tty a # brintOS guest has IS virtual -- the HWJS virtio console hvc0 and the pty # multiplexer -- so enumeration correctly returns zero ports. That is upstream # behaving properly on this machine, not a defect in the port and not a platform # gap, so nothing is filed for it. The group asserts WHICHEVER branch the machine # presents: `none` with every downstream value NODEV is green here, and a guest # that does carry a UART is held to the full open + set + read-back instead. No # edit is owed when that day comes. # # --------------------------------------------------------------------------- # THE ORACLE IS A NATIVE x86-64 RUN OF THE SAME PROBE AT THE SAME VERSION. # # Every value pinned in groups A, C and D below is what a native x86-64 build of # libserialport_probe.c against libserialport 0.1.1 produced (2026-08-17). Those # three groups are architecture-independent by construction -- version strings # compiled in by configure, SP_ERR_ARG constants from the public enum, and a # struct round trip that touches no syscall -- so the wasm32 build must agree # exactly, and a mismatch is a real defect rather than a platform difference. # # The enum values were checked against libserialport.h rather than merely copied # out of the native run: SP_OK=0, SP_ERR_ARG=-1, SP_ERR_FAIL=-2; SP_PARITY_NONE=0, # ODD=1, EVEN=2, MARK=3, SPACE=4; SP_RTS_FLOW_CONTROL=2, SP_CTS_FLOW_CONTROL=1, # SP_DTR_FLOW_CONTROL=2, SP_DSR_FLOW_CONTROL=1, SP_XONXOFF_INOUT=3; and the # `unspecified` sentinel every field of a fresh sp_port_config carries is -1. PROBE=${BST_LIBSERIALPORT_PROBE:-/usr/libexec/libserialport-tests/libserialport-probe} ARCHIVE=/usr/lib/libserialport.a PCFILE=/usr/lib/pkgconfig/libserialport.pc HDR=/usr/include/libserialport.h # The version the recipe pins. Asserted rather than read back, so a recipe bumped # without updating this suite is a red here instead of a silent change of subject # -- the values pinned above are the oracle for THIS version only. WANT_VERSION=0.1.1 if [ ! -f "$ARCHIVE" ]; then bst_skip libserialport/present "libserialport not installed on this image" exit 0 fi bst_ok libserialport/present # --- the package is whole ----------------------------------------------------- # The header is asserted at the TOP of includedir, not under a versioned subdir: # Makefile.am declares it nodist_include_HEADERS and the .pc says # Cflags: -I${includedir}, so a consumer's resolves there and # nowhere else. It is also generated by configure rather than shipped, which is # the reason it can go missing while every other file is present. check libserialport/staticlib test -s "$ARCHIVE" check libserialport/pkgconfig test -s "$PCFILE" check libserialport/header test -s "$HDR" # 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 libserialport/no-shared "/usr/lib/libserialport.so" "/usr/lib/libserialport.so.0" # The generated header must actually carry the API, not just exist: it is # produced from libserialport.h.in by AC_CONFIG_HEADERS, so a configure that # half-ran leaves a file that is present and useless. check_out libserialport/hdr-api "sp_get_port_by_name" cat "$HDR" check_out libserialport/hdr-enum "SP_ERR_ARG" cat "$HDR" pcver=$(sed -n 's/^Version: *//p' "$PCFILE" 2>/dev/null | head -1) check_eq libserialport/pkgconfig-version "$WANT_VERSION" "$pcver" check_out libserialport/pkgconfig-libs "-lserialport" cat "$PCFILE" # The archive carries the API. grep rather than nm: the image ships no binutils # nm, and the names are present as plain bytes. -a where the grep supports it -- # on this arm the archive members are LLVM IR bitcode (ThinLTO), so a grep that # suppresses matches in a file containing NULs reports nothing; GNU grep needs # -a, busybox grep as shipped does not. if echo x | grep -aq x 2>/dev/null; then _grepq="grep -aq"; else _grepq="grep -q"; fi for sym in sp_get_port_by_name sp_free_port sp_list_ports sp_copy_port \ sp_free_port_list sp_open sp_close sp_get_port_name \ sp_get_port_description sp_get_port_transport \ sp_new_config sp_free_config sp_get_config sp_set_config \ sp_set_baudrate sp_get_config_baudrate sp_set_config_baudrate \ sp_set_bits sp_get_config_bits sp_set_config_bits \ sp_set_parity sp_get_config_parity sp_set_config_parity \ sp_set_stopbits sp_get_config_stopbits sp_set_config_stopbits \ sp_set_flowcontrol sp_get_config_xon_xoff \ sp_blocking_read sp_blocking_write sp_nonblocking_read \ sp_input_waiting sp_output_waiting sp_flush sp_drain \ sp_get_signals sp_start_break sp_end_break \ sp_new_event_set sp_add_port_events sp_wait sp_free_event_set \ sp_last_error_code sp_last_error_message \ sp_get_package_version_string sp_get_lib_version_string; do if $_grepq "$sym" "$ARCHIVE" 2>/dev/null; then bst_ok "libserialport/sym-$sym" else bst_notok "libserialport/sym-$sym" "$sym absent from $ARCHIVE" fi done # --- the probe ---------------------------------------------------------------- if [ ! -x "$PROBE" ]; then bst_skip libserialport/probe-runs "$PROBE absent from the image" exit 0 fi pout=${TMPDIR:-/tmp}/bst-libserialport-out.$$ "$PROBE" > "$pout" 2>&1 prc=$? if [ "$prc" -eq 0 ]; then bst_ok libserialport/probe-runs elif bst_execfail "$(head -c 200 "$pout" 2>/dev/null)"; then bst_unrun libserialport/probe-runs "$(head -c 200 "$pout" 2>/dev/null)" else bst_notok libserialport/probe-runs "rc=$prc $(head -c 200 "$pout" 2>/dev/null)" fi if grep -q '^PROBE-END$' "$pout" 2>/dev/null; then bst_ok libserialport/probe-complete else bst_notok libserialport/probe-complete "probe output has no PROBE-END terminator (last line: $(tail -1 "$pout" 2>/dev/null))" fi # val -- the probe's value for one case, empty when the probe stopped # first. Matched on the ID in field 1 rather than taken by position, since the # probe's output is captured with 2>&1 and the library may write to stderr. val() { awk -v k="$1" '$1==k { $1=""; sub(/^ /,""); print; exit }' "$pout"; } # want -- score one probe value against a pinned answer. # A missing value is reported as the probe having stopped early rather than as a # mismatch against '', which is a different fault and localises to a different # line. The probe prints EMPTY for a legitimately empty string, so nothing it # actually emitted can arrive here as ''. want() { _got=$(val "$1") if [ -z "$_got" ]; then bst_notok "libserialport/$2" "no value on target (probe stopped before $1); want='$3'" elif [ "$_got" = "$3" ]; then bst_ok "libserialport/$2" else bst_notok "libserialport/$2" "want:'$3' got:'$_got'" fi } # --- A: the version the library reports ------------------------------------- # Both version pairs are compiled in by configure from configure.ac's m4 defines, # so these also confirm the build used the source the recipe thinks it did. want A01 version-package-string "$WANT_VERSION" want A02 version-major "0" want A03 version-minor "1" want A04 version-micro "1" want A05 version-lib-string "1:0:1" want A06 version-lib-current "1" want A07 version-lib-revision "0" want A08 version-lib-age "1" # --- B: enumeration ----------------------------------------------------------- # sp_list_ports must SUCCEED; how many ports it finds is a property of the guest, # not of the port, so the count is reported rather than pinned. What is pinned is # the invariant that survives either answer: the list is non-NULL, every name it # yields is under /dev/, and an empty list is reported as EMPTY rather than as a # phantom entry. want B01 enumerate-rc "0" want B02 enumerate-nonnull "yes" want B05 enumerate-dev-prefixed "yes" bcount=$(val B03) bnames=$(val B04) printf '#diag: libserialport enumerated %s port(s): %s\n' "${bcount:-?}" "${bnames:-?}" # The count and the name list have to agree with each other. This is the case # that would catch a list whose NULL terminator was lost -- the count would run # past the names, or the names past the count. if [ -z "$bcount" ]; then bst_notok libserialport/enumerate-consistent "probe stopped before B03" elif [ "$bcount" = "0" ] && [ "$bnames" = "EMPTY" ]; then bst_ok libserialport/enumerate-consistent elif [ "$bcount" != "0" ] && [ "$bnames" != "EMPTY" ] && [ -n "$bnames" ]; then bst_ok libserialport/enumerate-consistent else bst_notok libserialport/enumerate-consistent "count='$bcount' disagrees with names='$bnames'" fi # --- C: the documented refusals ---------------------------------------------- # Every one of these is SP_ERR_ARG (-1). C04 is the case the ticket names: a # /dev/ name no machine has, which passes get_port_details()'s /dev/ prefix check # and then fails its lstat of /sys/class/tty/ -- "Device not found". C03 is # the other SP_ERR_ARG in the same function, a name not under /dev/ at all # ("Device name not recognized"); the two are separate lines because they are # separate branches and a change to either localises here. want C01 refuse-null-name "-1" want C02 refuse-null-result "-1" want C03 refuse-bad-prefix "-1" want C04 refuse-absent-device "-1" want C05 refuse-leaves-null "null" want C06 refuse-newconfig-null "-1" want C07 refuse-getcfg-null-cfg "-1" want C08 refuse-getcfg-null-out "-1" want C09 refuse-setcfg-null-cfg "-1" want C10 refuse-open-null "-1" want C11 refuse-close-null "-1" want C12 refuse-getconfig-null "-1" want C13 refuse-setconfig-null "-1" # --- D: the config round trip, with no device involved ------------------------ # This is the ticket's set-then-read-back assertion, made where it can actually # run. A fresh config carries -1 ("unspecified") in every field, which is the # value sp_set_config reads as "leave this one alone" -- a default that came back # as anything else would silently reconfigure a real port. want D01 config-new-rc "0" want D02 config-default-baud "-1" want D03 config-default-bits "-1" want D04 config-default-parity "-1" want D05 config-default-stop "-1" want D06 config-default-rts "-1" want D07 config-default-cts "-1" want D08 config-default-dtr "-1" want D09 config-default-dsr "-1" # The four fields the ticket names, set together and read back together. want D10 roundtrip-baud "115200" want D11 roundtrip-bits "8" want D12 roundtrip-parity "0" want D13 roundtrip-stop "1" want D14 roundtrip-all "match" # Each field swept across its documented range. A setter that clamped, truncated # or ignored its argument passes the single case above and fails here. want D20 baud-1200 "1200" want D21 baud-2400 "2400" want D22 baud-4800 "4800" want D23 baud-9600 "9600" want D24 baud-19200 "19200" want D25 baud-38400 "38400" want D26 baud-57600 "57600" want D27 baud-115200 "115200" want D28 baud-230400 "230400" want D30 bits-5 "5" want D31 bits-6 "6" want D32 bits-7 "7" want D33 bits-8 "8" want D40 parity-none "0" want D41 parity-odd "1" want D42 parity-even "2" want D43 parity-mark "3" want D44 parity-space "4" want D50 stopbits-1 "1" want D51 stopbits-2 "2" want D60 flow-rts-flowcontrol "2" want D61 flow-cts-flowcontrol "1" want D62 flow-dtr-flowcontrol "2" want D63 flow-dsr-flowcontrol "1" want D64 flow-xonxoff-inout "3" # All nine fields distinct, read back in one pass: a setter writing the wrong # struct member passes every single-field case above and only shows up here. want D90 config-fields-independent "57600,7,2,2,1,0,0,0,1" want D99 config-freed "freed" # --- E: a real port, where the machine has one -------------------------------- # Scored by branch. On a guest whose only ttys are virtual, `none` is the correct # answer and every downstream value must be NODEV; on a guest that carries a UART # the full open + set + read-back is held to the same standard as group D. Either # way this needs no edit -- see the header. edev=$(val E01) if [ -z "$edev" ]; then bst_notok libserialport/device-branch "probe stopped before E01" elif [ "$edev" = "none" ]; then bst_ok libserialport/device-branch printf '#diag: libserialport found no openable serial device -- expected on this guest (list_ports skips virtual ttys)\n' want E03 device-nodev-name "NODEV" want E07 device-nodev-fields "NODEV" want E08 device-nodev-match "NODEV" elif [ "$edev" = "yes" ]; then bst_ok libserialport/device-branch printf '#diag: libserialport found a serial device: %s\n' "$(val E03)" want E04 device-open-rc "0" want E05 device-setconfig-rc "0" want E06 device-getconfig-rc "0" want E07 device-fields "9600,8,0,1" want E08 device-match "match" else bst_notok libserialport/device-branch "E01 is neither 'yes' nor 'none': '$edev'" fi # The console is never a candidate: enumeration filters virtual ttys, and the # probe additionally refuses any port matching ttyname() on its own descriptors. # E02 reports whether that second guard ever had to fire -- a `yes` here on a # guest whose console is the only tty would mean the first filter stopped working. want E02 device-own-tty-skipped "no" rm -f "$pout"