# BST-TIMEOUT: 1800 # 337 files, 6.8 MB, digested in ONE sha256sum -c pass and # # parsed twice: four DTD-validating libxml2 runs over the # # registries (base.xml alone is 247 KB) and four awk passes # # that re-derive the same counts from the shipped bytes. At # # the 46-68x wall-clock factor this platform carries # # (linux-in-the-browser#117) that is minutes, not seconds. # # The bound is deliberately a LOAD bound: it must fire when # # the guest is starved, not when the package regressed. . "$BST_LIB" # xkeyboard-config is the XKB configuration DATABASE and nothing else -- the # rules, models, layouts, variants and options a keymap compiler resolves a # keyboard description out of. There is no binary to run, so "the port works" is # a statement about the INSTALLED DATA, and the ticket says so: the tree matches # a native build byte for byte, each registry validates against its own DTD, and # every layout, variant and option the registry ADVERTISES is one the symbols # and rules trees actually carry. # # That last one is the case this suite exists for. A registry naming a layout # the tree does not define is not a build error -- it installs, it validates, # and it fails at RUN time, when a keymap lookup finds nothing. It is checked # here against the rootfs, and at do_install against ${D}, by two different # implementations: # # CENSUS gen-xkeyboard-config-census.py, at do_install: the installed set # walked out of ${D} with per-file size and sha256, the four # registries parsed with ElementTree, the resolution of every layout, # variant and option asserted, and the cross-built X11/xkb tree # compared file by file by digest against xkeyboard-config-native's. # # The counts below are re-derived through LIBXML2 and through an awk reader of # the shipped bytes -- neither of which shares code with ElementTree -- so # agreement is a statement about the data rather than about any one parser. XKB=/usr/share/X11/xkb RULES=$XKB/rules MAN=/usr/share/man/man7 V=/usr/share/xkeyboard-config CENSUS=$V/CENSUS PC=/usr/share/pkgconfig/xkeyboard-config.pc REGAWK=$BST_DATA/xkeyboard-config-registry.awk # The first BST result line of a suite is dropped by the guest console # (brintos/linux#96). This case exists to be the one that is lost. bst_ok xkeyboard-config/suite-canary if [ ! -d "$XKB" ]; then bst_skip xkeyboard-config/present "no $XKB on this image" exit 0 fi bst_ok xkeyboard-config/present t=${TMPDIR:-/tmp}/bst-xkbcfg.$$ if ! mkdir -p "$t" 2>/dev/null; then bst_notok xkeyboard-config/tmpdir "cannot create $t" exit 0 fi _num() { case "$1" in ''|*[!0-9]*) echo 0 ;; *) echo "$1" ;; esac; } # --- 1. the recipe's own evidence arrived, intact --------------------------- # # Every later section reads this file. A suite that asserted agreement WITH A # MISSING FILE would agree with nothing and say so as a pass, so the shape of # each read below is "derive from the file, then compare", never "grep the file # for the answer". check xkeyboard-config/census-installed test -s "$CENSUS" check xkeyboard-config/census-green grep -qx "CENSUS-END fails=0" "$CENSUS" check_out xkeyboard-config/census-version "CENSUS-PV 2.41" cat "$CENSUS" check xkeyboard-config/registry-awk-installed test -s "$REGAWK" # --- 2. the declared set, in both directions -------------------------------- # # CENSUS-FILE is the payload ${PN} carries: 292 files. The other 45 files # do_install wrote are the gettext catalogues, which packaging splits into # xkeyboard-config-locale- packages -- CENSUS-LOCALE, checked separately # below against what the image actually installed rather than required present. DECL=$t/declared.list sed -n 's/^CENSUS-FILE \([^ ]*\) .*$/\1/p' "$CENSUS" | LC_ALL=C sort > "$DECL" check_eq xkeyboard-config/declared-count 292 "$(wc -l < "$DECL" | tr -d ' ')" missing=0 while IFS= read -r p; do [ -f "$p" ] || { missing=$((missing+1)); miss1=$p; }; done < "$DECL" check_eq xkeyboard-config/declared-set 0 "$missing" [ "$missing" -eq 0 ] || bst_notok xkeyboard-config/declared-set-first "$miss1 declared but not installed" # The catalogues. The build produces all 45; the image carries exactly the ones # whose locale package it installed, which on this image is none -- so the # assertion is agreement between the two, not a count typed here. A rootfs that # grew IMAGE_LINGUAS stays green; one that dropped a catalogue whose package IS # installed goes red, which is the fault worth catching. LOC=$t/locale.list sed -n 's/^CENSUS-LOCALE \([^ ]*\) .*$/\1/p' "$CENSUS" | LC_ALL=C sort > "$LOC" check_eq xkeyboard-config/locale-declared-count 45 "$(wc -l < "$LOC" | tr -d ' ')" locpresent=0 while IFS= read -r p; do [ -f "$p" ] && locpresent=$((locpresent+1)); done < "$LOC" if [ -r /var/lib/dpkg/status ]; then locpkgs=$(grep -c '^Package: xkeyboard-config-locale-' /var/lib/dpkg/status 2>/dev/null | tr -d ' ') check_eq xkeyboard-config/locale-matches-packages "$(_num "$locpkgs")" "$locpresent" else bst_skip xkeyboard-config/locale-matches-packages "/var/lib/dpkg/status is not readable on this image" fi # $XKB belongs to this package alone, so the count is an EXACT assertion rather # than a floor: a partially unpacked payload fails here and in declared-set, and # nowhere else. check_eq xkeyboard-config/xkb-file-count 290 \ "$(find "$XKB" -type f 2>/dev/null | wc -l | tr -d ' ')" # Both directions: a file under $XKB that the census does NOT declare is as much # a fault as one declared and absent -- it is what a stale tree left behind by a # previous version would look like. extra=0 for p in $(find "$XKB" -type f 2>/dev/null | LC_ALL=C sort); do grep -qxF "$p" "$DECL" || { extra=$((extra+1)); extra1=$p; } done check_eq xkeyboard-config/no-extra-files 0 "$extra" [ "$extra" -eq 0 ] || bst_notok xkeyboard-config/no-extra-files-first "$extra1 installed but not declared" # The five KcGST trees are the shape of the database; losing one takes its # component with it and is the failure a `cp` that lost its recursion makes. # Their per-tree counts come from the census, not from constants here. treebad=0 for d in compat geometry keycodes symbols types; do want=$(sed -n "s/^CENSUS-TREE $d files=\([0-9]*\) .*$/\1/p" "$CENSUS") have=$(find "$XKB/$d" -type f 2>/dev/null | wc -l | tr -d ' ') [ -n "$want" ] && [ "$want" = "$have" ] || { treebad=$((treebad+1)); tree1="$d want=$want have=$have"; } done check_eq xkeyboard-config/kcgst-trees 0 "$treebad" [ "$treebad" -eq 0 ] || bst_notok xkeyboard-config/kcgst-trees-first "${tree1:-?}" # install_subdir excludes Makefile.am; a copy that lost the exclusion would ship # build files as keyboard data. check_eq xkeyboard-config/no-build-files 0 \ "$(find "$XKB" -type f \( -name 'Makefile.am' -o -name 'Makefile.in' -o -name 'meson.build' \) 2>/dev/null | wc -l | tr -d ' ')" # meson defaults xorg-rules-symlinks OFF, so rules/xorg is made by the recipe's # own do_install:append and by nothing else. It is the compatibility name older # X servers ask for; its absence is silent until something looks it up. check xkeyboard-config/rules-xorg-symlink test -L "$RULES/xorg" check_eq xkeyboard-config/rules-xorg-target "base" "$(readlink "$RULES/xorg" 2>/dev/null)" check xkeyboard-config/rules-xorg-resolves test -f "$RULES/xorg" # and the two names the flag did NOT create, asserted as the absences they are # rather than discovered later by something that expected them. check_eq xkeyboard-config/rules-xorg-lst-absent 0 \ "$(ls "$RULES/xorg.lst" "$RULES/xorg.xml" 2>/dev/null | wc -l | tr -d ' ')" # --- 3. the bytes ----------------------------------------------------------- # # ONE sha256sum -c pass over all 292 files rather than 292 invocations: process # creation is the expensive operation on this platform, and a per-file loop here # costs minutes for the same answer. CENSUS-LOCALE is deliberately not in this # set -- sha256sum -c cannot express "absent is allowed", and a missing entry # takes rc non-zero without producing a FAILED line, which is what made the # catalogues show up as a digest fault rather than as the packaging split. awk '/^CENSUS-FILE /{printf "%s %s\n", $4, $2}' "$CENSUS" > "$t/sums" check_eq xkeyboard-config/sumfile-count 292 "$(wc -l < "$t/sums" | tr -d ' ')" sha256sum -c "$t/sums" > "$t/sums.out" 2>&1; sumrc=$? badsums=$(grep -c ': FAILED$' "$t/sums.out" 2>/dev/null); badsums=$(_num "$badsums") check_eq xkeyboard-config/census-sha256 0 "$badsums" if [ "$badsums" -eq 0 ] && [ "$sumrc" -ne 0 ]; then bst_notok xkeyboard-config/census-sha256-rc "sha256sum -c rc=$sumrc: $(_bst_1line "$(head -3 "$t/sums.out")")" else bst_ok xkeyboard-config/census-sha256-rc fi check_eq xkeyboard-config/census-bytes-total "$(sed -n 's/^CENSUS-BYTES total=//p' "$CENSUS")" \ "$(awk '/^CENSUS-FILE /{n+=$3} END{print n+0}' "$CENSUS")" # The digest check above passes on a file whose digest was never computed, so # prove the comparison can go red: the same content plus one byte must not match # the census entry it came from. ref=$RULES/base.xml cp "$ref" "$t/mutated.xml" && printf 'x' >> "$t/mutated.xml" refsum=$(sed -n "s|^CENSUS-FILE $ref [0-9]* ||p" "$CENSUS") mutsum=$(sha256sum "$t/mutated.xml" 2>/dev/null | cut -d' ' -f1) if [ -n "$refsum" ] && [ -n "$mutsum" ] && [ "$refsum" != "$mutsum" ]; then bst_ok xkeyboard-config/control-sha256-detects-change else bst_notok xkeyboard-config/control-sha256-detects-change "census='$refsum' mutated='$mutsum'" fi # --- 4. the null control: the arm contributed nothing ----------------------- # # The payload is architecture-independent keyboard data, so a wasm32 build and # an x86-64 build of the same version must agree byte for byte. The comparison # itself ran at do_install against bitbake's own xkeyboard-config-native; what # is asserted here is its verdict and its scope, because "identical" over an # empty set is also identical. check_out xkeyboard-config/native-identical \ "same=290 differing=0 only-cross=0 only-native=0" cat "$CENSUS" check_eq xkeyboard-config/native-scope 290 \ "$(sed -n 's/^CENSUS-NATIVE cross=\([0-9]*\) .*$/\1/p' "$CENSUS")" check_eq xkeyboard-config/native-no-diff-lines 0 \ "$(grep -c '^CENSUS-NATIVE-DIFF ' "$CENSUS" 2>/dev/null | tr -d ' ')" # --- 5. the registries, through libxml2 ------------------------------------- require xmllint xkeyboard-config/xmllint-present # The DOCTYPE names xkb.dtd by a RELATIVE system id, and xkb.dtd is installed # beside the registries, so --valid resolves it with no catalog and no network. # That is a property of this package's own install layout: shipping the DTD is # what makes the data self-describing on a target with no X.Org anything. check xkeyboard-config/dtd-installed test -s "$RULES/xkb.dtd" nval=0 for f in base evdev base.extras evdev.extras; do xmllint --nonet --noout --valid "$RULES/$f.xml" >/dev/null 2>&1 \ || { nval=$((nval+1)); val1=$f; } done check_eq xkeyboard-config/registries-valid 0 "$nval" [ "$nval" -eq 0 ] || bst_notok xkeyboard-config/registries-valid-first "$val1.xml did not validate against xkb.dtd" # The control for the whole section: xmllint must be able to say no against THIS # DTD, not merely against malformed XML. A where the DTD permits only # is a validity error and nothing else -- the document is well-formed. sed 's||x|' \ "$RULES/base.xml" > "$t/badreg.xml" 2>/dev/null if xmllint --nonet --noout --valid "$t/badreg.xml" >/dev/null 2>&1; then bst_notok xkeyboard-config/control-dtd-detects-invalid "a inside validated" else bst_ok xkeyboard-config/control-dtd-detects-invalid fi # --- 6. the counts, re-derived twice ---------------------------------------- # # libxml2's XPath against the census's ElementTree numbers, and then an awk # reader of the same bytes against both. Three implementations agreeing is what # makes these a measurement of the registry rather than of a parser. for f in base evdev base.extras evdev.extras; do want=$(sed -n "s/^CENSUS-REGISTRY $f //p" "$CENSUS") got=$(xmllint --nonet --xpath 'concat("models=",count(//modelList/model), " layouts=",count(//layoutList/layout), " variants=",count(//layoutList/layout/variantList/variant), " groups=",count(//optionList/group), " options=",count(//optionList/group/option))' "$RULES/$f.xml" 2>/dev/null) check_eq "xkeyboard-config/counts-libxml2-$f" "$want" "$got" awk -f "$REGAWK" "$RULES/$f.xml" > "$t/$f.reg" 2>/dev/null aw=$(awk '{c[$1]++} END{printf "models=%d layouts=%d variants=%d groups=%d options=%d", c["M"], c["L"], c["V"], c["G"], c["O"]}' "$t/$f.reg") check_eq "xkeyboard-config/counts-awk-$f" "$want" "$aw" done # The awk reader has one job libxml2 does for free and it is the one worth # proving: the registry ships COMMENTED-OUT ' ' ' ' ' '' > "$t/comment.xml" check_eq xkeyboard-config/control-awk-skips-comments "G 1 O 1" \ "$(awk -f "$REGAWK" "$t/comment.xml" | awk '{c[$1]++} END{printf "G %d O %d", c["G"], c["O"]}')" # --- 7. what the registry ADVERTISES, resolved against the shipped tree ----- # # THE CASE THIS SUITE EXISTS FOR. Every layout the registry declares must have a # symbols file; every variant must be a section inside it; every option must be # a token some rules file carries. A registry entry with nothing behind it # installs cleanly, validates cleanly, and fails when a keymap is looked up. # # The whole symbols tree is read ONCE into a filesection table, and the # resolution is a join against it -- 195 files and 1664 sections, in one awk # pass rather than 489 greps. SECT=$t/sections awk 'FNR==1 { n=split(FILENAME, a, "/"); f=a[n]; if (a[n-1] != "symbols") f=a[n-1]"/"a[n] } /xkb_symbols[ \t]+"/ { s=$0; sub(/^[^"]*"/, "", s); sub(/".*$/, "", s); print f "\t" s }' \ $(find "$XKB/symbols" -type f 2>/dev/null | LC_ALL=C sort) > "$SECT" 2>/dev/null check_eq xkeyboard-config/symbols-sections \ "$(sed -n 's/^CENSUS-SYMBOLS-FILES n=[0-9]* sections=//p' "$CENSUS")" \ "$(awk '{print $0}' "$SECT" | LC_ALL=C sort -u | wc -l | tr -d ' ')" # base.xml and evdev.xml are byte-identical copies of the same source, so the # resolution is asserted once over the union of base and base.extras -- the two # distinct registries this package actually ships. cat "$t/base.reg" "$t/base.extras.reg" > "$t/all.reg" # `custom` is the one layout declared WITHOUT a symbols file on purpose: it is # the placeholder a user's own ~/.xkb/symbols/custom fills in. Asserted as an # expected absence rather than tolerated by a threshold, so the day upstream # ships it the suite says so. check_eq xkeyboard-config/custom-layout-declared 1 \ "$(awk '$1=="L" && $2=="custom"' "$t/base.reg" | wc -l | tr -d ' ')" check_eq xkeyboard-config/custom-layout-has-no-symbols 0 \ "$(ls "$XKB/symbols/custom" 2>/dev/null | wc -l | tr -d ' ')" lmiss=$(awk -v sect="$SECT" ' BEGIN { while ((getline line < sect) > 0) { split(line, p, "\t"); have[p[1]]=1 } } $1=="L" && $2!="custom" && !($2 in have) { n++ } END { print n+0 }' "$t/all.reg") check_eq xkeyboard-config/layouts-resolve 0 "$lmiss" [ "$lmiss" = "0" ] || bst_notok xkeyboard-config/layouts-resolve-first \ "$(awk -v sect="$SECT" 'BEGIN { while ((getline line < sect) > 0) { split(line, p, "\t"); have[p[1]]=1 } } $1=="L" && $2!="custom" && !($2 in have) { print $2; exit }' "$t/all.reg") has no symbols file" vmiss=$(awk -v sect="$SECT" ' BEGIN { while ((getline line < sect) > 0) { split(line, p, "\t"); sec[p[1] SUBSEP p[2]]=1 } } $1=="V" && !(($2 SUBSEP $3) in sec) { n++ } END { print n+0 }' "$t/all.reg") check_eq xkeyboard-config/variants-resolve 0 "$vmiss" [ "$vmiss" = "0" ] || bst_notok xkeyboard-config/variants-resolve-first \ "$(awk -v sect="$SECT" 'BEGIN { while ((getline line < sect) > 0) { split(line, p, "\t"); sec[p[1] SUBSEP p[2]]=1 } } $1=="V" && !(($2 SUBSEP $3) in sec) { print $2 "(" $3 ")"; exit }' "$t/all.reg") is declared but not defined" # The counts the resolution ran over, so a green above cannot be a green over # nothing. Both come from the census, which derived them from ${D}. check_eq xkeyboard-config/layouts-checked \ "$(( $(sed -n 's/^CENSUS-REGISTRY base .*layouts=\([0-9]*\) .*$/\1/p' "$CENSUS") + \ $(sed -n 's/^CENSUS-REGISTRY base.extras .*layouts=\([0-9]*\) .*$/\1/p' "$CENSUS") ))" \ "$(awk '$1=="L"' "$t/all.reg" | wc -l | tr -d ' ')" check_eq xkeyboard-config/variants-checked \ "$(( $(sed -n 's/^CENSUS-REGISTRY base .*variants=\([0-9]*\) .*$/\1/p' "$CENSUS") + \ $(sed -n 's/^CENSUS-REGISTRY base.extras .*variants=\([0-9]*\) .*$/\1/p' "$CENSUS") ))" \ "$(awk '$1=="V"' "$t/all.reg" | wc -l | tr -d ' ')" # Options resolve through the RULES files rather than through a symbols file # name: `grp:switch` is mapped by rules to +group(switch), and the mapping may # live in an option-only block or in a layout+option one, so the assertion is # that the token appears in a generated rules file at all. TOK=$t/tokens awk '{ sub(/\/\/.*$/, ""); for (i=1; i<=NF; i++) if ($i ~ /^[a-z0-9_]+:[A-Za-z0-9_-]+$/) print $i }' \ "$RULES/base" "$RULES/evdev" 2>/dev/null | LC_ALL=C sort -u > "$TOK" omiss=$(awk -v tok="$TOK" ' BEGIN { while ((getline line < tok) > 0) have[line]=1 } $1=="O" && !($2 in have) { n++ } END { print n+0 }' "$t/all.reg") check_eq xkeyboard-config/options-resolve 0 "$omiss" [ "$omiss" = "0" ] || bst_notok xkeyboard-config/options-resolve-first \ "$(awk -v tok="$TOK" 'BEGIN { while ((getline line < tok) > 0) have[line]=1 } $1=="O" && !($2 in have) { print $2; exit }' "$t/all.reg") is advertised but no rules file resolves it" check_eq xkeyboard-config/options-checked \ "$(( $(sed -n 's/^CENSUS-REGISTRY base .*options=\([0-9]*\)$/\1/p' "$CENSUS") + \ $(sed -n 's/^CENSUS-REGISTRY base.extras .*options=\([0-9]*\)$/\1/p' "$CENSUS") ))" \ "$(awk '$1=="O"' "$t/all.reg" | wc -l | tr -d ' ')" # The control for the whole section: the join must be able to say no. A layout # name that is certainly not in the tree has to come back unresolved. check_eq xkeyboard-config/control-resolution-detects-absent 1 \ "$(printf 'L bst_no_such_layout\n' | awk -v sect="$SECT" ' BEGIN { while ((getline line < sect) > 0) { split(line, p, "\t"); have[p[1]]=1 } } $1=="L" && !($2 in have) { n++ } END { print n+0 }')" # --- 8. the rules files, and the .lst derived from the registry ------------- # # rules/base and rules/evdev are merge.py output over 34 parts; a merge that # produced an empty or headerless file would still install. rbad=0 for r in base evdev; do want=$(sed -n "s/^CENSUS-RULES $r lines=\([0-9]*\) .*$/\1/p" "$CENSUS") have=$(wc -l < "$RULES/$r" | tr -d ' ') [ -n "$want" ] && [ "$want" = "$have" ] || { rbad=$((rbad+1)); rbad1="$r want=$want have=$have"; } done check_eq xkeyboard-config/rules-line-counts 0 "$rbad" [ "$rbad" -eq 0 ] || bst_notok xkeyboard-config/rules-line-counts-first "${rbad1:-?}" blkbad=0 for r in base evdev; do want=$(sed -n "s/^CENSUS-RULES-BLOCKS $r blocks=//p" "$CENSUS") have=$(grep -c '^! ' "$RULES/$r" 2>/dev/null); have=$(_num "$have") [ -n "$want" ] && [ "$want" = "$have" ] || { blkbad=$((blkbad+1)); blk1="$r want=$want have=$have"; } done check_eq xkeyboard-config/rules-blocks 0 "$blkbad" [ "$blkbad" -eq 0 ] || bst_notok xkeyboard-config/rules-blocks-first "${blk1:-?}" # The .lst files are xml2lst.pl's rendering of the SAME registry, in the old # flat format, so their layout and option sets must agree with the XML they were # generated from. This is the one place a PERL script the build ran on the HOST # is checked against the target's own reading of the same bytes. # # THE OPTION SETS DO NOT AGREE EXACTLY, AND THE DIFFERENCE IS UPSTREAM'S, NOT # THIS PORT'S. xml2lst.pl carries its own hand-rolled XML reader and does not # honour , so it renders one option the registry has COMMENTED OUT: # lv5:lsgt_switch_lock_cancel. It is harmless -- rules/base and rules/evdev both # carry `lv5:lsgt_switch_lock_cancel = +level5(lsgt_switch_lock_cancel)`, so the # name the .lst advertises is one a keymap lookup can actually resolve, which is # the property this suite is about. It is pinned by name rather than tolerated # by a count: a SECOND such divergence, or this one ceasing to resolve, is a # real finding and has to surface as a red. lstbad=0 for r in base evdev; do awk '/^! layout/{f=1;next} /^!/{f=0} f && NF{print $1}' "$RULES/$r.lst" \ | LC_ALL=C sort -u > "$t/$r.lst.layouts" awk '$1=="L"{print $2}' "$t/$r.reg" | LC_ALL=C sort -u > "$t/$r.reg.layouts" diff "$t/$r.reg.layouts" "$t/$r.lst.layouts" > "$t/$r.layouts.diff" 2>&1 \ || { lstbad=$((lstbad+1)); lst1="$r layout sets differ"; } done check_eq xkeyboard-config/lst-layouts-match-registry 0 "$lstbad" [ "$lstbad" -eq 0 ] || bst_notok xkeyboard-config/lst-layouts-match-registry-first \ "${lst1:-?}: $(_bst_1line "$(head -4 "$t/base.layouts.diff")")" # Counts, from the census rather than from constants here: the .lst variant and # model sections are flat lists of the registry's own entries. vlstbad=0 for r in base evdev; do nv=$(awk '/^! variant/{f=1;next} /^!/{f=0} f && NF {n++} END{print n+0}' "$RULES/$r.lst") nm=$(awk '/^! model/{f=1;next} /^!/{f=0} f && NF {n++} END{print n+0}' "$RULES/$r.lst") wv=$(sed -n "s/^CENSUS-REGISTRY $r .*variants=\([0-9]*\) .*$/\1/p" "$CENSUS") wm=$(sed -n "s/^CENSUS-REGISTRY $r models=\([0-9]*\) .*$/\1/p" "$CENSUS") [ "$nv" = "$wv" ] && [ "$nm" = "$wm" ] || { vlstbad=$((vlstbad+1)); vlst1="$r variants=$nv/$wv models=$nm/$wm"; } done check_eq xkeyboard-config/lst-variant-model-counts 0 "$vlstbad" [ "$vlstbad" -eq 0 ] || bst_notok xkeyboard-config/lst-variant-model-counts-first "${vlst1:-?}" # The option sets, with the one known divergence stated as an equality rather # than as a tolerance. olstbad=0 for r in base evdev; do awk '/^! option/{f=1;next} /^!/{f=0} f && NF && index($1,":"){print $1}' "$RULES/$r.lst" \ | LC_ALL=C sort -u > "$t/$r.lst.options" awk '$1=="O"{print $2}' "$t/$r.reg" | LC_ALL=C sort -u > "$t/$r.reg.options" extra_o=$(comm -23 "$t/$r.lst.options" "$t/$r.reg.options" | tr '\n' ' ' | sed 's/ *$//') missing_o=$(comm -13 "$t/$r.lst.options" "$t/$r.reg.options" | tr '\n' ' ' | sed 's/ *$//') [ "$extra_o" = "lv5:lsgt_switch_lock_cancel" ] && [ -z "$missing_o" ] \ || { olstbad=$((olstbad+1)); olst1="$r extra='$extra_o' missing='$missing_o'"; } done check_eq xkeyboard-config/lst-options-match-registry 0 "$olstbad" [ "$olstbad" -eq 0 ] || bst_notok xkeyboard-config/lst-options-match-registry-first "${olst1:-?}" # and the commented-out name the .lst advertises IS resolvable, which is what # makes the divergence harmless rather than the very defect this suite hunts. check xkeyboard-config/lst-extra-option-resolves \ grep -q 'lv5:lsgt_switch_lock_cancel' "$RULES/base" check_eq xkeyboard-config/lst-extra-option-is-commented-out 0 \ "$(awk -f "$REGAWK" "$RULES/base.xml" | awk '$1=="O" && $2=="lv5:lsgt_switch_lock_cancel"' | wc -l | tr -d ' ')" # The .lst group names are the registry's optionList groups, and they share the # option section with the options themselves -- which is why the split above is # on the presence of a colon and not on position. glstbad=0 for r in base evdev; do ng=$(awk '/^! option/{f=1;next} /^!/{f=0} f && NF && !index($1,":"){print $1}' "$RULES/$r.lst" | LC_ALL=C sort -u | wc -l | tr -d ' ') wg=$(sed -n "s/^CENSUS-REGISTRY $r .*groups=\([0-9]*\) .*$/\1/p" "$CENSUS") [ "$ng" = "$wg" ] || { glstbad=$((glstbad+1)); glst1="$r groups=$ng/$wg"; } done check_eq xkeyboard-config/lst-group-count 0 "$glstbad" [ "$glstbad" -eq 0 ] || bst_notok xkeyboard-config/lst-group-count-first "${glst1:-?}" # --- 9. the packaging question the ticket asked to check -------------------- # # The recipe inherits python3native and DEPENDS on libxslt-native. Both are # host-class and neither can produce a target RDEPENDS -- but "cannot" is the # reasoning, and this is the measurement: the package's own control stanza, on # the image that installed it. That measurement is now live rather than vacuous: # python3 itself is ported and on this image, so an interpreter dependency would # resolve rather than break do_rootfs. A data package that had quietly dragged # an interpreter would have failed do_rootfs long before this, so a green here # is a statement about what the rootfs actually resolved. DPKG=/var/lib/dpkg/status if [ -r "$DPKG" ]; then DEPS=$(awk '/^Package: xkeyboard-config$/{f=1;next} f && /^Depends:/{sub(/^Depends:[ \t]*/,"");print;exit} f && /^$/{exit}' "$DPKG") check_eq xkeyboard-config/pkg-installed 1 \ "$(grep -c '^Package: xkeyboard-config$' "$DPKG" 2>/dev/null | tr -d ' ')" check_eq xkeyboard-config/no-runtime-depends "" "$DEPS" # The scan can say no: the same reader over a package that DOES declare # dependencies must come back non-empty, or the green above means nothing. anydep=$(awk '/^Depends:/{n++} END{print n+0}' "$DPKG") if [ "$(_num "$anydep")" -gt 0 ]; then bst_ok xkeyboard-config/control-depends-reader-works else bst_notok xkeyboard-config/control-depends-reader-works "no Depends: field anywhere in $DPKG" fi else bst_skip xkeyboard-config/no-runtime-depends "$DPKG is not readable on this image" fi # The other half of the same claim, stated against the installed BYTES rather # than against the control stanza. It used to be stated as "there is no python3 # on this image to have depended on" -- true when this suite was written and # false now: python3 is a member of EMCRAFT_TOOLS and ships on every image, so # that case measured the image's package set and not this port. The absence was # doing the work the measurement should do. What this package must actually be # able to say is that nothing it ships needs an interpreter at run time, and # that is checked here over the whole payload. nshebang=$(grep -rlI '^#!' "$XKB" "$V" 2>/dev/null | wc -l | tr -d ' ') check_eq xkeyboard-config/no-interpreter-scripts 0 "$(_num "$nshebang")" # The scan can say yes: the same reader over a file that DOES carry a shebang # must find it, or the green above is a statement about grep and not about the # payload. printf '#!/bin/sh\n' > "$t/shebang.probe" check_eq xkeyboard-config/control-shebang-scan-works 1 \ "$(_num "$(grep -rlI '^#!' "$t/shebang.probe" 2>/dev/null | wc -l | tr -d ' ')")" # --- 10. the man page and the pkg-config file ------------------------------- # # The man page is the ONE generated file in this package -- xsltproc over # rules/evdev.xml through man/man.xsl -- so it is the one place a cross-build # substitution could have resolved to a build path. Both the presence and the # substitution are checked; a token scan alone would pass on a page whose # __xkb_base__ had resolved to the sysroot. if [ -f "$MAN/xkeyboard-config.7" ]; then bst_ok xkeyboard-config/man-present check_out xkeyboard-config/man-roff ".TH XKEYBOARD-CONFIG 7" cat "$MAN/xkeyboard-config.7" check_out xkeyboard-config/man-version "xkeyboard-config 2.41" cat "$MAN/xkeyboard-config.7" check_out xkeyboard-config/man-xkb-base-substituted "$XKB" cat "$MAN/xkeyboard-config.7" check_eq xkeyboard-config/man-no-unsubstituted-tokens 0 \ "$(grep -cE '__[a-zA-Z][a-zA-Z0-9_]*__' "$MAN/xkeyboard-config.7" 2>/dev/null | tr -d ' ')" # The man page is rendered FROM the registry, so it names layouts -- which is # what makes it evidence that xsltproc read the shipped XML rather than an # empty document. check_out xkeyboard-config/man-lists-layouts "Albanian" cat "$MAN/xkeyboard-config.7" # The control for the token scan: a planted token must be found. printf '.TH T 7\n.\\" __xkb_base__\n' > "$t/planted.7" check xkeyboard-config/control-token-scan-works grep -qE '__[a-zA-Z][a-zA-Z0-9_]*__' "$t/planted.7" else bst_skip xkeyboard-config/man-present "xkeyboard-config-doc is not on this image" fi if [ -f "$PC" ]; then bst_ok xkeyboard-config/pc-present check_out xkeyboard-config/pc-xkb-base "xkb_base=$XKB" cat "$PC" check_out xkeyboard-config/pc-version "Version: 2.41" cat "$PC" # dataonly: true, so the .pc carries no Cflags and no Libs -- there is nothing # to link against. Asserted rather than assumed: a .pc that grew a Libs line # would make every consumer link a library this package does not ship. check_eq xkeyboard-config/pc-no-libs 0 \ "$(grep -c '^Libs:' "$PC" 2>/dev/null | tr -d ' ')" if command -v pkg-config >/dev/null 2>&1; then check_out xkeyboard-config/pkg-config-xkb-base "$XKB" \ pkg-config --variable=xkb_base xkeyboard-config check_out xkeyboard-config/pkg-config-modversion "2.41" \ pkg-config --modversion xkeyboard-config else bst_skip xkeyboard-config/pkg-config-xkb-base "pkg-config not installed on this image" fi else bst_skip xkeyboard-config/pc-present "xkeyboard-config-dev is not on this image" fi # --- 11. the data drives an XSLT engine on this target ---------------------- # # The strongest thing that can be said about a data file is that something reads # it. The stylesheet is written here rather than taken from the package on # purpose: it needs no catalog and no DTD, so a green result is attributable to # the SHIPPED registry and to libxslt on wasm32, and to nothing else. if command -v xsltproc >/dev/null 2>&1; then cat > "$t/probe.xsl" <<'XEOF' LAYOUTS= |VARIANTS= |FIRST= XEOF tout=$(xsltproc --nonet "$t/probe.xsl" "$RULES/base.xml" 2>/dev/null); trc=$? if [ "$trc" -eq 0 ]; then bst_ok xkeyboard-config/transform-rc else bst_notok xkeyboard-config/transform-rc "rc=$trc"; fi check_eq xkeyboard-config/transform-fields \ "LAYOUTS=$(sed -n 's/^CENSUS-REGISTRY base .*layouts=\([0-9]*\) .*$/\1/p' "$CENSUS")|VARIANTS=$(sed -n 's/^CENSUS-REGISTRY base .*variants=\([0-9]*\) .*$/\1/p' "$CENSUS")|FIRST=al" \ "$tout" # The control: the same engine over something that is not XML must fail. printf 'this is not xml\n' > "$t/notxml" if xsltproc --nonet "$t/probe.xsl" "$t/notxml" >/dev/null 2>&1; then bst_notok xkeyboard-config/control-transform-rejects-nonxml "transformed a non-XML input" else bst_ok xkeyboard-config/control-transform-rejects-nonxml fi else bst_skip xkeyboard-config/transform-rc "xsltproc not installed on this image" fi # --- 12. a keymap compiler, if this image ever grows one -------------------- # # Nothing here compiles a keymap: neither xkbcomp nor libxkbcommon is on this # image, and this port does not add one. The check is written anyway, and # reports a SKIP with the reason, so that the day a sibling port lands # xkbcommon the end-to-end case appears by itself rather than being remembered. if command -v xkbcli >/dev/null 2>&1; then check_out xkeyboard-config/keymap-compile "xkb_keymap" \ env XKB_CONFIG_ROOT="$XKB" xkbcli compile-keymap --layout us elif command -v xkbcomp >/dev/null 2>&1; then cat > "$t/km.xkb" <<'KEOF' xkb_keymap { xkb_keycodes { include "evdev" }; xkb_types { include "complete" }; xkb_compat { include "complete" }; xkb_symbols { include "pc+us" }; }; KEOF # -w 0 because the stock database emits "No symbols defined for " style # warnings against the evdev keycodes on every platform; the claim here is that # the five components RESOLVE out of $XKB and compile, not that upstream's data # is warning-free. xkbcomp -w 0 -I"$XKB" -xkb "$t/km.xkb" -o "$t/out.xkb" >/dev/null 2>&1 check xkeyboard-config/keymap-compile test -s "$t/out.xkb" check_out xkeyboard-config/keymap-has-keys "key " cat "$t/out.xkb" else bst_skip xkeyboard-config/keymap-compile \ "no keymap compiler on this image (neither xkbcli/libxkbcommon nor xkbcomp is ported), so the database is verified as data" fi rm -rf "$t" 2>/dev/null