. "$BST_LIB" # BST-TIMEOUT: 900 # ~180 cases. All but one are file reads and string # # compares; the exception is a single 6 MB probe start, # # which bst_probe bounds at 600 s of its own. MEASURED on # # target at 12 s of the 900 s bound (batch-1997 verify, # # 2026-09-02), so the bound is two orders of magnitude of # # headroom and is left where it is. # # lvgl 9.1.0 on wasm32-hwjs glibc -- the Light and Versatile Graphics Library # (meta-openembedded/meta-oe, recipes-graphics/lvgl; one meta-brintos bbappend # and one patch). # # =========================================================================== # WHY THIS LIBRARY CAN BE EXERCISED END TO END WITH NO DISPLAY. # =========================================================================== # # lvgl's rendering target is a buffer the CALLER supplies: the library draws # into memory and hands the dirty rectangles to a flush callback. So the whole # harness data/lvgl-probe needs is a static buffer and a callback that records # what it is given rather than writing it anywhere -- no framebuffer device, no # DRM node, no windowing system, and no input device. That is why this port # closes on its suite and files no follow-on interactive ticket. # # The image is built with all three display backends off (PACKAGECONFIG is # emptied, which also removes the recipe's only target DEPENDS, libdrm) and the # shipped lv_conf.h is asserted below to say so -- the port's coverage rests on # LV_USE_CANVAS and LV_COLOR_DEPTH, not on a backend. # # =========================================================================== # WHAT THIS PORT SHIPS, AND WHY THERE IS NO SHARED LIBRARY. # =========================================================================== # # lvgl-dev + lvgl-staticdev. The meta-oe recipe passes -DBUILD_SHARED_LIBS=ON; # this arm has no shared libraries and conf/distro/brintos.conf's --disable- # shared covers autotools only (BRINTOS-1479), so the bbappend appends OFF and # cmake takes the last -D. The deliverable is four archives -- liblvgl.a and # the thorvg / examples / demos halves -- plus the headers and lvgl.pc. # # The bare `lvgl' package is produced, is EMPTY (lv-conf.inc sets ALLOW_EMPTY), # and IS on the image -- Yocto's packaging generates RRECOMMENDS:lvgl-dev = # "lvgl" and the rootfs installs recommendations, so lvgl-dev drags the empty # placeholder in with it. That is measured, and it is the opposite of what this # suite predicted before the port's first on-target run. The fact worth # asserting was never the package's absence but the absence of a PAYLOAD, so # what is asserted below is that its dpkg file list names no file. # # =========================================================================== # THE FINDING: TWO FILES THAT COMPILE TO NOTHING AND BREAK EVERY CONSUMER. # =========================================================================== # # env_support/cmake/custom.cmake globs src/*.S into the library target # unconditionally. The two files it reaches are lv_blend_neon.S and # lv_blend_helium.S -- ARM NEON and Helium blend backends whose whole body sits # behind `#if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_{NEON,HELIUM}`. This arm's # lv_conf.h carries LV_DRAW_SW_ASM_NONE, so both assemble to EMPTY objects. # # They break the link anyway, and the reason is substrate rather than content: # an assembler input is a NATIVE wasm object whatever the C driver is doing, # while every .c here compiles to LLVM bitcode. The stock recipe's archive was # measured at 286 members, 284 bitcode and exactly those 2 native, and wasmld # refuses the whole of it: # # wasmld: FATAL (HWJS-3 coro arm): archive '.../liblvgl.a' mixes bitcode and # native members -- a half-substrate chimera. # # The package BUILT GREEN in that state and would have shipped, because nothing # in the image links liblvgl.a and no image build ever reaches a consumer. The # port's own probe is the only thing that found it. Both halves are asserted # below: the archive's member list carries no lv_blend_* object, and the probe # -- which is that consumer -- runs. # # =========================================================================== # WHAT THE PROBE COVERS THAT NO FILE CHECK CAN. # =========================================================================== # # data/lvgl-probe is cross-linked against the very liblvgl.a and headers this # package installs. It initialises the library against a memory display and a # recording flush callback, then asserts four things a shell cannot reach: # # * RENDERING, on the buffer lvgl actually wrote. A filled rectangle is exact # -- 16x12 = 192 pixels of the fill colour and not one more -- and so is a # 2 px border (192 - 96 interior = 96). The rounded rectangle and the # gradient are the antialiased cases: the corner leaving and the centre # staying are exact, the arc is asserted to carry a partially blended pixel, # and the gradient is asserted at its endpoints and for monotonicity down # its axis. Every draw is bracketed by a guard region around the canvas # buffer, so a write past the end is a case rather than a corrupted # neighbour. # # * CLIPPING AS THE FAILURE PATH. A rectangle drawn from (30,20) to (90,80) # on a 40x30 canvas must clip: the 10x10 visible corner is drawn, the guard # bytes are untouched, and the pixel just outside is still background. # # * LAYOUT FROM THE OBJECT TREE, not from pixels -- so a layout regression and # a rendering regression are distinguishable. The same three 30x20 children # are laid out under flex row, flex column and the grid engine at fixed # tracks, and their computed coordinates are asserted. # # * THE TIMER, EVENT AND ANIMATION MACHINERY, DRIVEN SYNCHRONOUSLY. The tick # source is the test's own lv_tick_inc, so a 10 ms timer called over 100 ms # of ticks fires exactly ten times, and a linear 0..100 animation over # 100 ms is asserted at its start, its half-way point and its end. # # EVERY EXPECTED VALUE BELOW WAS MEASURED, on x86-64, against THIS EXACT PROBE # built from THIS lvgl 9.1.0 source with THE lv_conf.h THIS RECIPE GENERATES -- # 86 of 86 green, exit 0. The pixel counts (192, 144, 96, 100), the label width # (65 px in Montserrat 14), the button's default 26x16 and the ten timer calls # are all readings, not estimates. # # ON TARGET, they held: the batch-1997 verify of 2026-09-02 ran every one of the # probe's cases green -- the first time this port had run on the machine at all. # The three reds that run did produce were all in THIS FILE and none in the # library: two entry points asserted as archive symbols that are `static inline' # in the headers, and a bare-package assertion that predicted an absence Yocto's # own RRECOMMENDS makes impossible. All three are corrected below, each against # the artifacts of the image that measured them, and each carries the # correction in a comment beside it rather than being quietly rewritten. bst_ok lvgl/suite-canary # first line: absorbs brintos/linux#96, which drops it tmp=${TMPDIR:-/tmp} nl=' ' hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "absent or empty: $2"; fi; } nofile() { _id=$1; shift; if [ ! -e "$1" ]; then bst_ok "$_id"; else bst_notok "$_id" "present: $1"; fi; } has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "not found: $2" ;; esac; } nothas() { case "$3" in *"$2"*) bst_notok "$1" "found and must not be: $2" ;; *) bst_ok "$1" ;; esac; } hasline() { case "$nl$3$nl" in *"$nl$2$nl"*) bst_ok "$1" ;; *) bst_notok "$1" "not present: $2" ;; esac; } inc=/usr/include/lvgl lib=/usr/lib pc=$lib/pkgconfig/lvgl.pc # --- the shipped files --------------------------------------------------------- hasfile lvgl/file-header "$inc/lvgl.h" hasfile lvgl/file-conf "$inc/lv_conf.h" hasfile lvgl/file-private "$inc/src/lvgl_private.h" hasfile lvgl/file-init-header "$inc/src/lv_init.h" hasfile lvgl/file-display-header "$inc/src/display/lv_display.h" hasfile lvgl/file-canvas-header "$inc/src/widgets/canvas/lv_canvas.h" hasfile lvgl/file-demos-header "$inc/demos/lv_demos.h" hasfile lvgl/file-examples-header "$inc/examples/lv_examples.h" hasfile lvgl/file-pc "$pc" for a in liblvgl.a liblvgl_thorvg.a liblvgl_examples.a liblvgl_demos.a; do hasfile "lvgl/file-archive-${a%.a}" "$lib/$a" done # --- what must NOT be here ----------------------------------------------------- # # No shared object of any name: BUILD_SHARED_LIBS=OFF is the port's decision and # the thing a regression would undo first. Upstream's patch 0007 in the meta-oe # recipe exists to produce liblvgl.so.9.1.0 and its two symlinks, so all three # are named. nofile lvgl/no-so-liblvgl "$lib/liblvgl.so" nofile lvgl/no-so-liblvgl-9 "$lib/liblvgl.so.9" nofile lvgl/no-so-liblvgl-9-1-0 "$lib/liblvgl.so.9.1.0" nofile lvgl/no-so-thorvg "$lib/liblvgl_thorvg.so" nofile lvgl/no-so-examples "$lib/liblvgl_examples.so" nofile lvgl/no-so-demos "$lib/liblvgl_demos.so" # The framebuffer demo is a SEPARATE recipe (lvgl-demo-fb) which this port does # not build: it needs a real /dev/fb0 or a DRM card. nofile lvgl/no-demo-binary /usr/bin/lvgl # --- the packaging statement, read from dpkg ----------------------------------- # # The suite asserts where the files land AGAINST WHAT THE PACKAGING SAYS, not # only against the filesystem: a file present but undeclared, or declared and # absent, are different defects and only dpkg's own list tells them apart. DEVLIST=/var/lib/dpkg/info/lvgl-dev.list STLIST=/var/lib/dpkg/info/lvgl-staticdev.list if [ -f "$DEVLIST" ] && [ -f "$STLIST" ]; then bst_ok lvgl/dpkg-lists-present devl=$(cat "$DEVLIST" 2>/dev/null) stl=$(cat "$STLIST" 2>/dev/null) hasline lvgl/dpkg-dev-declares-header "$inc/lvgl.h" "$devl" hasline lvgl/dpkg-dev-declares-conf "$inc/lv_conf.h" "$devl" hasline lvgl/dpkg-dev-declares-pc "$pc" "$devl" for a in liblvgl.a liblvgl_thorvg.a liblvgl_examples.a liblvgl_demos.a; do hasline "lvgl/dpkg-staticdev-declares-${a%.a}" "$lib/$a" "$stl" done # and the split is the right way round: the archives are NOT in -dev. case "$nl$devl$nl" in *"$nl$lib/liblvgl.a$nl"*) bst_notok lvgl/dpkg-split-archives-not-in-dev "liblvgl.a is declared by lvgl-dev" ;; *) bst_ok lvgl/dpkg-split-archives-not-in-dev ;; esac # every file lvgl-staticdev declares exists. The list is read from a TMPFS # COPY: a `while ... done < ' at the top level of a suite makes # dup2(2) return 513 and ash exits, taking every case after it with it # (brintos/linux#73), and a `while' cannot be wrapped in a subshell because it # has to keep the variables it sets. STLOCAL=$(bst_local "$STLIST") missing= while IFS= read -r f; do [ -z "$f" ] && continue [ -e "$f" ] || missing="$missing $f" done < "$STLOCAL" if [ -z "$missing" ]; then bst_ok lvgl/dpkg-staticdev-files-exist else bst_notok lvgl/dpkg-staticdev-files-exist "declared and absent:$missing"; fi else bst_notok lvgl/dpkg-lists-present "one of $DEVLIST / $STLIST is absent" for c in dpkg-dev-declares-header dpkg-dev-declares-conf dpkg-dev-declares-pc \ dpkg-staticdev-declares-liblvgl dpkg-staticdev-declares-liblvgl_thorvg \ dpkg-staticdev-declares-liblvgl_examples dpkg-staticdev-declares-liblvgl_demos \ dpkg-split-archives-not-in-dev dpkg-staticdev-files-exist; do bst_notok "lvgl/$c" "no dpkg list to read" done fi # The bare `lvgl' package: present, and carrying nothing. dpkg records the # package root as `/.' for an empty package, so any other line in the list is a # file this port would be putting on the image at runtime -- which it must not. BARELIST=/var/lib/dpkg/info/lvgl.list hasfile lvgl/bare-package-installed "$BARELIST" barefiles=$(grep -v '^/\.$' "$BARELIST" 2>/dev/null | grep -c .) if [ "${barefiles:-1}" -eq 0 ]; then bst_ok lvgl/bare-package-empty else bst_notok lvgl/bare-package-empty "the bare lvgl package names $barefiles file(s)"; fi # --- lvgl.pc, line for line ---------------------------------------------------- pcbody=$(cat "$pc" 2>/dev/null) hasline lvgl/pc-prefix 'prefix="/usr"' "$pcbody" hasline lvgl/pc-includedir 'includedir="${prefix}/include/lvgl"' "$pcbody" hasline lvgl/pc-libdir 'libdir=${prefix}/lib' "$pcbody" hasline lvgl/pc-name 'Name: lvgl' "$pcbody" hasline lvgl/pc-version 'Version: 9.1.0' "$pcbody" hasline lvgl/pc-libs 'Libs: -L${libdir} -llvgl' "$pcbody" hasline lvgl/pc-cflags 'Cflags: -I${includedir}' "$pcbody" if command -v pkg-config >/dev/null 2>&1; then o=$(pkg-config --modversion lvgl 2>&1); r=$? if [ "$r" -eq 0 ] && [ "$o" = "9.1.0" ]; then bst_ok lvgl/pkg-config-modversion else bst_notok lvgl/pkg-config-modversion "rc=$r out=$o"; fi o=$(pkg-config --libs lvgl 2>&1) case "$o" in *-llvgl*) bst_ok lvgl/pkg-config-libs ;; *) bst_notok lvgl/pkg-config-libs "out=$o" ;; esac o=$(pkg-config --cflags lvgl 2>&1) case "$o" in *-I/usr/include/lvgl*) bst_ok lvgl/pkg-config-cflags ;; *) bst_notok lvgl/pkg-config-cflags "out=$o" ;; esac else bst_skip lvgl/pkg-config-modversion "pkg-config not installed on this image" bst_skip lvgl/pkg-config-libs "pkg-config not installed on this image" bst_skip lvgl/pkg-config-cflags "pkg-config not installed on this image" fi # --- the headers --------------------------------------------------------------- hdr=$(cat "$inc/lvgl.h" 2>&1) has lvgl/hdr-version-major '#define LVGL_VERSION_MAJOR 9' "$hdr" has lvgl/hdr-version-minor '#define LVGL_VERSION_MINOR 1' "$hdr" has lvgl/hdr-version-patch '#define LVGL_VERSION_PATCH 0' "$hdr" has lvgl/hdr-includes-init '#include "src/lv_init.h"' "$hdr" # lv_conf.h is generated by the recipe's do_configure:append from # lv_conf_template.h, so its contents are a statement about THIS build's # configuration and are the thing a PACKAGECONFIG regression would move first. cfg=$(cat "$inc/lv_conf.h" 2>&1) has lvgl/conf-color-depth-32 '#define LV_COLOR_DEPTH 32' "$cfg" has lvgl/conf-canvas-on '#define LV_USE_CANVAS 1' "$cfg" has lvgl/conf-drm-off '#define LV_USE_LINUX_DRM 0' "$cfg" has lvgl/conf-fbdev-off '#define LV_USE_LINUX_FBDEV 0' "$cfg" has lvgl/conf-sdl-off '#define LV_USE_SDL 0' "$cfg" has lvgl/conf-evdev-off '#define LV_USE_EVDEV 0' "$cfg" has lvgl/conf-thorvg-internal-off '#define LV_USE_THORVG_INTERNAL 0' "$cfg" has lvgl/conf-asm-none 'LV_DRAW_SW_ASM_NONE' "$cfg" has lvgl/conf-os-none '#define LV_USE_OS LV_OS_NONE' "$cfg" has lvgl/conf-font-montserrat-14 '#define LV_FONT_MONTSERRAT_14 1' "$cfg" # --- the archive --------------------------------------------------------------- # # liblvgl.a is LLVM IR bitcode, so its string table carries identifiers and # source paths but not C string literals -- the shape 99-libftdi and 99-libusb1 # both record. Symbol names and TU paths are what can be asserted, and they are # the stronger statement anyway. flat=$tmp/lvgl-flat.$$ ( tr -c '\40-\176\n' '\n' < "$lib/liblvgl.a" > "$flat" 2>/dev/null ) hasfile lvgl/archive-flattened "$flat" # THE FINDING, ASSERTED. Neither ARM assembly object may be a member: their # presence is what made the archive a bitcode/native mixture no consumer could # link, and it is invisible in every other signal a build produces. for s in lv_blend_neon lv_blend_helium; do if grep -qF "$s.S.o" "$flat" 2>/dev/null; then bst_notok "lvgl/archive-no-$s" "$s.S.o is a member of liblvgl.a -- the archive is a bitcode/native mixture" else bst_ok "lvgl/archive-no-$s" fi done # The translation units, by the debug path each object records. 284 members, so # a sample of the areas the probe drives is what is named, plus a floor on the # total. tus=$(grep -oE '/usr/src/debug/lvgl/9\.1\.0/src/[A-Za-z0-9_/.-]+\.c' "$flat" 2>/dev/null | sort -u) ntu=$(printf '%s' "$tus" | grep -c .) if [ "$ntu" -ge 200 ]; then bst_ok lvgl/tu-count else bst_notok lvgl/tu-count "distinct translation units=$ntu, want >= 200"; fi for t in core/lv_obj.c display/lv_display.c widgets/canvas/lv_canvas.c \ draw/lv_draw_rect.c layouts/flex/lv_flex.c layouts/grid/lv_grid.c \ misc/lv_anim.c misc/lv_timer.c tick/lv_tick.c \ widgets/label/lv_label.c widgets/slider/lv_slider.c widgets/bar/lv_bar.c; do hasline "lvgl/tu-${t##*/}" "/usr/src/debug/lvgl/9.1.0/src/$t" "$tus" done # COMPLETENESS: every public entry point the probe reaches AND THAT IS A REAL # ARCHIVE SYMBOL must be defined in the archive. -w is load-bearing -- without # it a name that is a strict PREFIX of a real symbol passes vacuously. # # lv_screen_active and lv_slider_set_value are deliberately NOT in this list, # and their absence is the measured correction of a prediction made from the # source before this port had ever run. Both are `static inline' in the 9.1.0 # headers -- src/display/lv_display.h:392 and src/widgets/slider/lv_slider.h:77 # -- so they are inlined at every call site and NO archive can carry them. The # probe reaches both (probe-screen-active, probe-slider-value-roundtrip) and # passes. They are asserted below, against the headers, where they exist. namef=$tmp/lvgl-names.$$ printf '%s\n' \ lv_init lv_deinit lv_is_initialized \ lv_display_create lv_display_set_buffers lv_display_set_flush_cb \ lv_display_flush_ready lv_display_get_default \ lv_display_get_horizontal_resolution lv_display_get_vertical_resolution \ lv_refr_now lv_obj_create lv_obj_delete \ lv_obj_set_size lv_obj_set_pos lv_obj_get_x lv_obj_get_y \ lv_obj_get_width lv_obj_get_height lv_obj_update_layout \ lv_obj_set_layout lv_obj_set_flex_flow lv_obj_set_grid_dsc_array \ lv_obj_set_grid_cell lv_obj_add_event_cb lv_obj_send_event \ lv_canvas_create lv_canvas_set_buffer lv_canvas_fill_bg lv_canvas_get_px \ lv_canvas_init_layer lv_canvas_finish_layer \ lv_draw_rect lv_draw_rect_dsc_init lv_draw_buf_width_to_stride \ lv_label_create lv_label_set_text lv_label_get_text \ lv_button_create lv_slider_create lv_bar_create \ lv_bar_set_value lv_bar_get_value \ lv_timer_create lv_timer_handler lv_timer_delete \ lv_tick_inc lv_tick_get \ lv_anim_init lv_anim_start lv_anim_path_linear lv_anim_count_running \ > "$namef" found=$(grep -owFf "$namef" "$flat" 2>/dev/null | sort -u) ndecl=$(grep -c . "$namef"); nfound=$(printf '%s' "$found" | grep -c .) if [ "$ndecl" -ge 50 ] && [ "$nfound" -eq "$ndecl" ]; then bst_ok lvgl/sym-complete else bst_notok lvgl/sym-complete "named=$ndecl found=$nfound"; fi for s in lv_init lv_display_create lv_draw_rect lv_canvas_get_px \ lv_obj_set_flex_flow lv_obj_set_grid_cell lv_timer_handler \ lv_anim_start lv_label_set_text lv_bar_set_value; do hasline "lvgl/sym-$s" "$s" "$found" done # The two entry points the probe reaches that are header inlines rather than # archive symbols. Asserting them here is what keeps the pair covered, and it # is the stronger statement of the two: it names the definition the compiler # actually uses. has lvgl/hdr-inline-lv_screen_active \ 'static inline lv_obj_t * lv_screen_active(' \ "$(cat "$inc/src/display/lv_display.h" 2>&1)" has lvgl/hdr-inline-lv_slider_set_value \ 'static inline void lv_slider_set_value(' \ "$(cat "$inc/src/widgets/slider/lv_slider.h" 2>&1)" # The default font ships INSIDE the archive rather than as a data file, which is # what makes the label-width case below a statement about this package and not # about a font somewhere else on the image. hasline lvgl/sym-font-montserrat-14 lv_font_montserrat_14 \ "$(grep -owF lv_font_montserrat_14 "$flat" 2>/dev/null | sort -u)" # --- the probe ----------------------------------------------------------------- out=$tmp/lvgl-probe.$$ probe=$tmp/bst-lvgl-probe.$$ hasfile lvgl/probe-shipped "$BST_DATA/lvgl-probe" if cp "$BST_DATA/lvgl-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then bst_ok lvgl/probe-staged bst_probe lvgl/probe-runs "$out" 600 "$probe" prc=$? else bst_notok lvgl/probe-staged "cannot stage $BST_DATA/lvgl-probe" bst_notok lvgl/probe-runs "probe was never staged" prc=127 fi CASES="version-major-9 version-minor-1 version-patch-0 color-depth-32 no-os canvas-enabled uninitialised-before-lv-init initialised-after-lv-init display-created display-hor-res display-ver-res display-is-default screen-active flush-called flush-px-map-non-null flush-area-is-whole-display canvas-created canvas-stride-is-w-times-4 bg-fill-covers-canvas rect-fill-exact-count rect-fill-corner-tl rect-fill-corner-br rect-fill-outside-left rect-fill-outside-right rect-fill-alpha-opaque rect-fill-guard-intact rect-round-corner-cleared rect-round-centre-filled rect-round-fewer-pixels-than-square rect-round-pixel-count-exact rect-round-arc-antialiased rect-round-guard-intact border-edge-drawn border-inner-clear border-outside-clear border-pixel-count-exact border-guard-intact gradient-top-is-first-stop gradient-bottom-is-last-stop gradient-monotone-down-the-axis gradient-is-grey gradient-guard-intact clip-guard-intact clip-visible-part-drawn clip-count-is-visible-part clip-outside-untouched flex-row-child0-x flex-row-child0-y flex-row-child0-size flex-row-child1-x flex-row-child1-y flex-row-child1-size flex-row-child2-x flex-row-child2-y flex-row-child2-size flex-column-child0-y flex-column-child0-x flex-column-child1-y flex-column-child1-x flex-column-child2-y flex-column-child2-x grid-child0-pos grid-child1-pos grid-child2-pos label-text-roundtrip label-height-is-font-line-height label-width-montserrat-14-BRINTOS button-created button-default-size slider-value-roundtrip slider-min slider-max slider-clamps-above-max bar-value-roundtrip bar-clamps-below-min event-delivered-once event-filtered-by-code timer-created timer-ran-per-period timer-stops-after-delete anim-start-value anim-half-way anim-end-value anim-stays-at-end anim-count-is-zero flush-still-non-null" if [ "$prc" -eq 0 ] || [ -s "$out" ]; then pbody=$(cat "$out" 2>/dev/null) for c in $CASES; do case "$nl$pbody$nl" in *"${nl}PROBE-OK $c$nl"*) bst_ok "lvgl/probe-$c" ;; *"${nl}PROBE-FAIL $c "*) bst_notok "lvgl/probe-$c" \ "$(sed -n "s/^PROBE-FAIL $c //p" "$out" | head -n 1)" ;; *) bst_notok "lvgl/probe-$c" "the probe emitted no line for this case" ;; esac done # The measurements the probe reports rather than judges, each asserted against # the value read on x86-64 from this same source. They are integer arithmetic # in every case, so a difference here is a real divergence and not rounding. for kv in "round_red_pixels=144" "border_green_pixels=96" \ "clip_red_pixels=100" "timer_calls=10" "anim_at_50ms=50"; do k=${kv%%=*}; want=${kv#*=} got=$(sed -n "s/^PROBE-INFO $k=//p" "$out" | head -n 1) if [ "$got" = "$want" ]; then bst_ok "lvgl/probe-info-$k" else bst_notok "lvgl/probe-info-$k" "$k=$got, measured $want on x86-64"; fi done g=$(sed -n 's/^PROBE-INFO gradient_top=\([0-9]*\) gradient_bottom=\([0-9]*\)$/\1:\2/p' "$out" | head -n 1) if [ "$g" = "0:255" ]; then bst_ok lvgl/probe-info-gradient-endpoints else bst_notok lvgl/probe-info-gradient-endpoints "top:bottom=$g, measured 0:255"; fi l=$(sed -n 's/^PROBE-INFO label_w=\([0-9]*\) label_h=\([0-9]*\)$/\1:\2/p' "$out" | head -n 1) if [ "$l" = "65:16" ]; then bst_ok lvgl/probe-info-label-metrics else bst_notok lvgl/probe-info-label-metrics "w:h=$l, measured 65:16"; fi f=$(sed -n 's/^PROBE-INFO failures=//p' "$out" | head -n 1) if [ "$f" = "0" ]; then bst_ok lvgl/probe-reports-no-failures else bst_notok lvgl/probe-reports-no-failures "the probe counted $f failure(s)"; fi else for c in $CASES; do bst_notok "lvgl/probe-$c" "the probe produced no transcript (rc=$prc)" done for k in round_red_pixels border_green_pixels clip_red_pixels timer_calls anim_at_50ms; do bst_notok "lvgl/probe-info-$k" "the probe produced no transcript (rc=$prc)" done bst_notok lvgl/probe-info-gradient-endpoints "the probe produced no transcript (rc=$prc)" bst_notok lvgl/probe-info-label-metrics "the probe produced no transcript (rc=$prc)" bst_notok lvgl/probe-reports-no-failures "the probe produced no transcript (rc=$prc)" fi rm -f "$flat" "$namef" "$out" "$out.err" "$probe" "$STLOCAL"