# BST-TIMEOUT: 300 # 45 cases, no compiled probe: this suite drives fc-cache
# # once and then fc-list/fc-query/fc-match over FOUR faces
# # totalling 486,852 bytes. 99-liberation-fonts declares the
# # same 300 for a comparable fontconfig-only workload over
# # fourteen larger files.
# #
# # MEASURED, 2026-08-29, first on-target run after
# # BRINTOS-1762 cleared: ==BST-SUITE elapsed=39s bound=300s
# # cases=45==, on hz1 under brintos_local_verify. The bound
# # is kept at 300 rather than tightened to the measurement:
# # 39s is one run on an idle host, fc-cache -f is the whole
# # of it, and that call scales with every font package the
# # image gains, not with this one.
# #
# # 45 = 26 emitted here + 19 emitted by the verify awk. The
# # three `require' calls are NOT among them: require emits a
# # case only when the tool is ABSENT, in which case it skips
# # and ends the suite. Counting them would put the test-plan
# # floor three above what a clean run can produce.
#
# ttf-liberation-sans-narrow 1.07.4 -- the four Liberation Sans Narrow faces,
# packaged apart from the rest of the family because they come from a different
# upstream release. meta-openembedded
# meta-oe/recipes-graphics/ttf-fonts/ttf-liberation-sans-narrow_1.07.4.bb.
#
# ============================================================================
# THE PAYLOAD IS UNDER /usr/share/fonts/TTF, NOT truetype/. THAT IS MEASURED,
# AND IT IS NOT WHAT THE TICKET PREDICTED.
# ============================================================================
#
# BRINTOS-1722 describes the files as landing under ${datadir}/fonts/truetype/
# and the recipe as "pruning everything but the narrow faces out of the tarball".
# Both halves are wrong about the mechanism, and the first is wrong about the
# result. What the recipe actually does, read off ttf.inc plus the .bb:
#
# ttf.inc do_install install every *.tt[cf] -> ${datadir}/fonts/truetype/
# (all SIXTEEN faces: Mono, Sans, SansNarrow, Serif)
# do_install:append install LiberationSansNarrow*.ttf -> ${datadir}/fonts/TTF/
# install the fontconfig fragment, install License.txt
# rm -rf ${D}${datadir}/fonts/truetype
#
# So the last line removes the truetype directory WHOLESALE. There is no
# face-by-face prune, and nothing this package installs ends up under truetype/.
# Every case below is scoped to TTF/; a suite written to the ticket's wording
# would have asserted an empty set and passed.
#
# The ticket's underlying worry is still the right one and is asserted here in
# the form the code actually takes: prune-nonnarrow-absent checks the twelve
# non-narrow basenames are not under TTF/, and prune-truetype-unowned checks --
# from the dpkg database, not the filesystem, because truetype/ has four other
# tenants -- that this package claims no path there at all. Those two are what
# stand between this port and a third Liberation release colliding with
# ttf-liberation 0.2 and poky's liberation-fonts 2.1.5, which share all twelve
# basenames with this tarball at three different sizes.
#
# ============================================================================
# THIS PORT IS THE SOLE TENANT OF /usr/share/fonts/TTF AND OF /etc/conf.avail,
# SO NO NEIGHBOURING SUITE IS AMENDED. THAT WAS SWEPT, NOT ASSUMED.
# ============================================================================
#
# Read off the last COMPLETE image (BRINTOS-1714, 2026-08-27), /usr/share/fonts
# carried exactly four subdirectories -- cantarell(2), terminus(19),
# truetype(27), ttf(23) -- and no TTF. /etc/conf.avail did not exist. So unlike
# the sibling ttf-liberation port, which landed twelve files into the shared
# truetype/ and had to amend three cases in two suites, this one adds a
# directory nothing else reads.
#
# The neighbours were swept anyway, by what they COUNT rather than by name: no
# suite counts /usr/share/fonts whole-tree and none pipes a bare fc-list into
# wc. The one whole-directory enumeration in the font suites --
# 99-liberation-fonts:99 -- names /usr/share/fonts/truetype explicitly, which
# this port does not write to. 57-fontconfig's conf-avail cases count
# /usr/share/fontconfig/conf.avail, fontconfig's own bundled set, and are
# bounded from below; /etc/conf.avail is a different directory and does not
# reach them. 57-fontconfig's etc-confd is an existence check on
# /etc/fonts/conf.d, which this package creates empty and does not populate.
#
# ============================================================================
# THE RECIPE'S OWN FONTCONFIG FRAGMENT IS NEVER READ -- AND IT WOULD CHANGE
# NOTHING IF IT WERE. BOTH HALVES MEASURED.
# ============================================================================
#
# The recipe creates ${sysconfdir}/fonts/conf.d/ and then installs its fragment
# to ${sysconfdir}/conf.avail/30-${PN}-sans.conf -- /etc/conf.avail, with no
# fonts/ component. The image's /etc/fonts/fonts.conf carries exactly one
# include, `conf.d`, resolved relative
# to /etc/fonts. There is no conf.avail include anywhere. So the shipped
# fragment is inert: conf-not-in-confd pins that, and it is stated as a fact
# about this recipe rather than as a defect this port introduced.
#
# It costs nothing, and that is the second measurement rather than an inference.
# The fragment aliases Arial Narrow <-> Liberation Sans Narrow in both
# directions. fontconfig 2.15.0's own 30-metric-aliases.conf -- which IS active,
# symlinked into /etc/fonts/conf.d from /usr/share/fontconfig/conf.avail --
# already carries both:
#
# line 603 Arial Narrow
# Liberation Sans Narrow
# line 344 Liberation Sans Narrow
# Arial Narrow
#
# The recipe's fragment is a verbatim duplicate of stock fontconfig. Installing
# it at the correct path would add nothing; leaving it at the wrong one removes
# nothing. NO BBAPPEND, therefore, and no workaround marker is owed: nothing was
# worked around. conf-aliases-are-stock asserts the stock file still carries the
# alias, so the day fontconfig drops it this suite says so rather than silently
# depending on a fragment that is not being read.
#
# This is also why fc-match-arial-narrow is a POSITIVE case here. "Arial Narrow"
# is a family this package does not provide, and it nevertheless resolves into
# this package -- correctly, through stock metric aliasing. The ticket asks for
# an unprovided family that must NOT resolve here; Arial Narrow is not it, and
# neither is Helvetica Narrow, which stock fontconfig aliases to Arial Narrow.
# fc-match-liberation-sans-elsewhere is the real negative: "Liberation Sans" is
# one word from ours, is provided by poky's liberation-fonts on this image, and
# must resolve to ITS file. That is the mis-scoping guard, and it is the same
# guard as prune-truetype-unowned seen from the consumer side.
#
# ============================================================================
# NO NEW MAXIMUM FOR THE mmap REFUSAL BAND.
# ============================================================================
#
# File-backed mmap is refused on this arm above a mapping-length threshold and
# the consumer parks rather than falling back (linux-in-the-browser#165,
# bracketed by BRINTOS-1450 between ~66 kB and 577,708 bytes). The four faces
# here are 110,560 / 113,304 / 129,448 / 133,540 bytes. The largest is smaller
# than the SMALLEST of the twelve poky Liberation faces this image already scans
# on every fc-cache (281,536, range to 415,816), so this port adds no new
# maximum and nothing to the band #165 is about. No hold-out, no marker.
#
# ============================================================================
. "$BST_LIB"
S=ttf-liberation-sans-narrow
bst_ok $S/suite-canary
D=$BST_DATA
REF=$D/ttf-liberation-sans-narrow-manifest.txt
FACES=$D/ttf-liberation-sans-narrow-fcfaces.txt
NONNARROW=$D/ttf-liberation-sans-narrow-nonnarrow.txt
VERIFY=$D/ttf-liberation-sans-narrow-verify.awk
TTFDIR=/usr/share/fonts/TTF
TRUETYPE=/usr/share/fonts/truetype
CONFAVAIL=/etc/conf.avail
CONF=$CONFAVAIL/30-ttf-liberation-sans-narrow-sans.conf
CONFD=/etc/fonts/conf.d
METRIC=/usr/share/fontconfig/conf.avail/30-metric-aliases.conf
LICDIR=/usr/share/licenses/ttf-liberation-sans-narrow
PKGLIST=/var/lib/dpkg/info/ttf-liberation-sans-narrow.list
PI=/var/lib/dpkg/info/ttf-liberation-sans-narrow.postinst
FCCACHE=/var/cache/fontconfig
tmp=${TMPDIR:-/tmp}
W=$tmp/bst-ttflsn.$$
require gawk $S/gawk-present
require sha256sum $S/sha256sum-present
require find $S/find-present
for t in fc-cache fc-list fc-match fc-query; do
if [ -x "/usr/bin/$t" ]; then bst_ok $S/$t-present
else bst_notok $S/$t-present "fontconfig-utils is a Depends of ttf-liberation-sans-narrow but /usr/bin/$t is absent"; fi
done
if [ ! -f "$REF" ] || [ ! -f "$FACES" ] || [ ! -f "$NONNARROW" ] || [ ! -f "$VERIFY" ]; then
bst_notok $S/ref-present "the reference data did not ship: $REF / $FACES / $NONNARROW / $VERIFY"
exit 0
fi
bst_ok $S/ref-present
if [ -d "$TTFDIR" ]; then bst_ok $S/ttfdir-is-dir
else bst_notok $S/ttfdir-is-dir "$TTFDIR is not a directory -- the payload did not reach the image"; fi
# ---- collect the file layer -------------------------------------------------
find "$TTFDIR" "$TRUETYPE" "$CONFAVAIL" "$LICDIR" \
-maxdepth 1 -printf '%p %y %s %m\n' 2>/dev/null | LC_ALL=C sort > "$W.inv"
: > "$W.sums"
for p in "$TTFDIR"/LiberationSansNarrow-Bold.ttf \
"$TTFDIR"/LiberationSansNarrow-BoldItalic.ttf \
"$TTFDIR"/LiberationSansNarrow-Italic.ttf \
"$TTFDIR"/LiberationSansNarrow-Regular.ttf \
"$CONF" \
"$LICDIR"/LICENSE ; do
sha256sum "$p" >> "$W.sums" 2>/dev/null
done
cat "$PKGLIST" > "$W.pkgf" 2>/dev/null || : > "$W.pkgf"
# The dpkg list names every parent directory the package owns, not just its
# payload, so only its file rows can be compared against the manifest. Record
# which rows are directories rather than naming them one at a time: the package
# co-owns the standard parents (/., /etc, /etc/fonts/conf.d, /usr/share/...)
# with fontconfig and the other font packages, and that set is not this port's
# to pin. PKGPATH itself stays whole -- prune-truetype-unowned has to be able to
# see an owned DIRECTORY under truetype/, which is one shape the collision this
# port guards against would take.
: > "$W.pkgd"
while IFS= read -r _p; do
[ -d "$_p" ] && printf '%s\n' "$_p"
done < "$W.pkgf" >> "$W.pkgd" 2>/dev/null
# ---- the fontcache postinst ran, and left a cache ---------------------------
if [ -f "$PI" ]; then bst_ok $S/postinst-present
else bst_notok $S/postinst-present "$PI is absent -- the fontcache postinst did not reach the image"; fi
check_out $S/postinst-runs-fc-cache "fc-cache" cat "$PI"
fc-cache -f >/dev/null 2>&1
_ncache=$(find "$FCCACHE" -type f 2>/dev/null | wc -l)
if [ "${_ncache:-0}" -gt 0 ]; then bst_ok $S/fc-cache-usable
else bst_notok $S/fc-cache-usable "$FCCACHE holds no cache files after fc-cache -f"; fi
# ---- fc-query the four faces, in the committed field order ------------------
: > "$W.qry"
for f in "$TTFDIR"/LiberationSansNarrow-*.ttf; do
[ -f "$f" ] || continue
LC_ALL=C fc-query --format '%{file|basename}|%{family}|%{style}|%{slant}|%{weight}|%{width}\n' \
"$f" >> "$W.qry" 2>/dev/null
done
LC_ALL=C sort -o "$W.qry" "$W.qry"
LC_ALL=C gawk -v REF="$REF" -v SUMS="$W.sums" -v INV="$W.inv" -v PKGF="$W.pkgf" \
-v PKGD="$W.pkgd" \
-v FACES="$FACES" -v QRY="$W.qry" -v NONNARROW="$NONNARROW" \
-f "$VERIFY" "$REF" "$W.sums" "$W.inv" "$W.pkgf" "$W.pkgd" "$FACES" "$W.qry" "$NONNARROW"
# ---- the package database ---------------------------------------------------
sed -n '/^Package: ttf-liberation-sans-narrow$/,/^$/p' /var/lib/dpkg/status > "$W.st" 2>/dev/null
_known=0; _arch=0; _dep=0
while IFS= read -r l; do
case "$l" in
"Package: ttf-liberation-sans-narrow") _known=1 ;;
"Architecture: all") _arch=1 ;;
"Depends: "*) case "$l" in *fontconfig-utils*) _dep=1 ;; esac ;;
esac
done < "$W.st"
if [ "$_known" -eq 1 ]; then bst_ok $S/pkg-known
else bst_notok $S/pkg-known "dpkg does not know the package ttf-liberation-sans-narrow"; fi
if [ "$_arch" -eq 1 ]; then bst_ok $S/pkg-arch-all
else bst_notok $S/pkg-arch-all "ttf-liberation-sans-narrow is not Architecture: all -- inherit allarch did not take"; fi
if [ "$_dep" -eq 1 ]; then bst_ok $S/pkg-depends-fontconfig
else bst_notok $S/pkg-depends-fontconfig "ttf-liberation-sans-narrow does not Depend on fontconfig-utils -- the fontcache class did not wire it"; fi
# PACKAGES is an assignment naming only ${PN}, so there is no -doc, -dev or -dbg.
for sfx in doc dev dbg staticdev; do
if grep -q "^Package: ttf-liberation-sans-narrow-$sfx\$" /var/lib/dpkg/status 2>/dev/null; then
bst_notok $S/pkg-no-$sfx "ttf-liberation-sans-narrow-$sfx is installed -- PACKAGES no longer names only \${PN}"
else
bst_ok $S/pkg-no-$sfx
fi
done
# ---- the fragment, and why it does not matter -------------------------------
if [ -f "$CONF" ]; then bst_ok $S/conf-avail-shipped
else bst_notok $S/conf-avail-shipped "$CONF is absent -- the recipe's fragment did not reach the image"; fi
if [ -e "$CONFD/30-ttf-liberation-sans-narrow-sans.conf" ]; then
bst_notok $S/conf-not-in-confd "the fragment is now under $CONFD -- it is being READ, which this suite's header says it is not; re-measure the aliases before trusting any fc-match case here"
else
bst_ok $S/conf-not-in-confd
fi
if grep -q 'Liberation Sans Narrow' "$METRIC" 2>/dev/null; then bst_ok $S/conf-aliases-are-stock
else bst_notok $S/conf-aliases-are-stock "$METRIC no longer names Liberation Sans Narrow -- the alias this port relies on came from stock fontconfig, and it is gone"; fi
# ---- the consumer reads -----------------------------------------------------
# fc-list enumerates the family, and every file it returns is ours.
LC_ALL=C fc-list "Liberation Sans Narrow" file 2>/dev/null | sed 's/: *$//' | LC_ALL=C sort > "$W.list"
_nlist=$(wc -l < "$W.list")
_foreign=$(grep -cv "^$TTFDIR/" "$W.list" 2>/dev/null)
if [ "${_nlist:-0}" -eq 4 ] && [ "${_foreign:-1}" -eq 0 ]; then
bst_ok $S/fc-list-family
else
bst_notok $S/fc-list-family "fc-list 'Liberation Sans Narrow' returned ${_nlist:-0} files (want 4), ${_foreign:-?} of them outside $TTFDIR"
fi
# fc-match for the family resolves to a file from THIS package. This is the case
# that proves the font is usable rather than merely present on disk.
_m=$(LC_ALL=C fc-match --format '%{file}\n' "Liberation Sans Narrow" 2>/dev/null)
case "$_m" in
"$TTFDIR"/LiberationSansNarrow-*.ttf) bst_ok $S/fc-match-family ;;
*) bst_notok $S/fc-match-family "fc-match 'Liberation Sans Narrow' => '${_m:-}', want a face under $TTFDIR" ;;
esac
# Arial Narrow lands here too -- through stock 30-metric-aliases, not through the
# recipe's inert fragment. Positive on purpose; see the header.
_a=$(LC_ALL=C fc-match --format '%{file}\n' "Arial Narrow" 2>/dev/null)
case "$_a" in
"$TTFDIR"/LiberationSansNarrow-*.ttf) bst_ok $S/fc-match-arial-narrow ;;
*) bst_notok $S/fc-match-arial-narrow "fc-match 'Arial Narrow' => '${_a:-}', want a face under $TTFDIR -- stock 30-metric-aliases accepts Liberation Sans Narrow for it" ;;
esac
# THE MIS-SCOPING GUARD. Liberation Sans is one word from this package's family,
# is provided by poky's liberation-fonts on this image, and must resolve THERE.
for fam in "Liberation Sans" "Liberation Serif" "Liberation Mono"; do
_id=$(echo "$fam" | tr 'A-Z ' 'a-z-')
_o=$(LC_ALL=C fc-match --format '%{file}\n' "$fam" 2>/dev/null)
case "$_o" in
"$TTFDIR"/*) bst_notok $S/fc-match-$_id-elsewhere "fc-match '$fam' => '$_o' -- a family this package does not provide resolved INTO it; the port is mis-scoped" ;;
"") bst_notok $S/fc-match-$_id-elsewhere "fc-match '$fam' returned nothing" ;;
*) bst_ok $S/fc-match-$_id-elsewhere ;;
esac
done
rm -f "$W.inv" "$W.sums" "$W.pkgf" "$W.pkgd" "$W.qry" "$W.st" "$W.list" 2>/dev/null