. "$BST_LIB" require lzop lzop/present # lzop is the COMMAND LINE that 57-lzo.test says is missing: that file states, in # its own header, that LZO "ships NO CLI -- the lzop(1) command line is a SEPARATE # poky recipe that is not ported here", and exercises the library through # mtd-utils instead. This suite closes that gap, so liblzo2 is now driven through # its own front end rather than only through a consumer that happens to link it. # # THE ORACLE. lzop's compressed output is not merely "valid" -- for a given input # and level it is a FIXED byte string, because LZO1X is a deterministic function # of the input bytes with no tuning, no timing and no entropy. So this suite does # not settle for a round-trip (which passes just as happily if BOTH directions are # wrong in the same way). It compares the target's own compressed bytes against # archives produced by a native x86_64 build of the identical lzop 1.04 + lzo 2.10 # sources, and requires them to be IDENTICAL. # # WHAT IS COMPARED, AND WHY IT IS NOT THE WHOLE FILE. An lzop header carries the # input's mtime and mode, so two runs of the same command a second apart differ in # bytes 25-28 -- measured, not assumed. Everything from byte 39 on is the # compressed payload and is invariant: identical across runs, and identical # whether stdin is a pipe or a redirected file (both measured). Every archive # here is therefore written FROM A PIPE, which stores no filename and pins the # header at exactly 38 bytes on both machines, and the comparison is # `tail -c +39`. The header is not skipped as an inconvenience -- its fixed fields # are asserted separately below, including the two version words that prove which # liblzo2 this binary is actually linked against. # # BOTH DIRECTIONS ARE ORACLED. The target must reproduce the native machine's # bytes (encode) and must decode the native machine's archives (decode). Encode # alone would miss a decoder that is broken in a compensating way; decode alone # would miss an encoder that emits a valid but different stream. tmp=${TMPDIR:-/tmp}/bst-lzop.$$ D=$BST_DATA corpus=$D/lzop-corpus.txt runs=$D/lzop-runs.bin # ---- identity --------------------------------------------------------------- # --version names both the tool and the library it linked, so one case pins the # port and its dependency at once. check_out lzop/version-tool "lzop 1.04" sh -c "lzop --version 2>&1" check_out lzop/version-lzo "LZO library 2.10" sh -c "lzop --version 2>&1" check lzop/in-usr-bin test -x /usr/bin/lzop # ---- the shipped control payload ------------------------------------------- # Every oracle case below reads one of these, so a failure here explains the rest. check lzop/data-corpus test -s "$corpus" check lzop/data-runs test -s "$runs" check lzop/data-corpus-l1 test -s "$D/lzop-corpus-1.lzo" check lzop/data-corpus-l7 test -s "$D/lzop-corpus-7.lzo" check lzop/data-corpus-l9 test -s "$D/lzop-corpus-9.lzo" check lzop/data-corpus-f test -s "$D/lzop-corpus-F.lzo" check lzop/data-runs-l1 test -s "$D/lzop-runs-1.lzo" check lzop/data-runs-l9 test -s "$D/lzop-runs-9.lzo" # ---- DECODE oracle: the target reads what x86_64 wrote ---------------------- # A wasm32 build that could not read a native archive would be a format break -- # the single most consequential way this port could be wrong, because an lzop # archive is an interchange artifact and is expected to cross machines. check lzop/decode-native-l1 sh -c "lzop -dc '$D/lzop-corpus-1.lzo' | cmp -s - '$corpus'" check lzop/decode-native-l7 sh -c "lzop -dc '$D/lzop-corpus-7.lzo' | cmp -s - '$corpus'" check lzop/decode-native-l9 sh -c "lzop -dc '$D/lzop-corpus-9.lzo' | cmp -s - '$corpus'" check lzop/decode-native-f sh -c "lzop -dc '$D/lzop-corpus-F.lzo' | cmp -s - '$corpus'" check lzop/decode-runs-l1 sh -c "lzop -dc '$D/lzop-runs-1.lzo' | cmp -s - '$runs'" check lzop/decode-runs-l9 sh -c "lzop -dc '$D/lzop-runs-9.lzo' | cmp -s - '$runs'" # -t must also accept them, which is the integrity path rather than the data path. check lzop/test-native-l1 lzop -t "$D/lzop-corpus-1.lzo" check lzop/test-native-l9 lzop -t "$D/lzop-corpus-9.lzo" check lzop/test-native-f lzop -t "$D/lzop-corpus-F.lzo" # ---- ENCODE oracle: the target writes what x86_64 wrote --------------------- # The strict half. Not "compresses to something that decompresses" but "emits the # same bytes LZO1X is defined to emit". A regression in the match finder, the # hash table, or any pointer-width assumption inside it shows up here and # essentially nowhere else. tail -c +39 "$D/lzop-corpus-1.lzo" > "$tmp.c1.ctl" 2>/dev/null tail -c +39 "$D/lzop-corpus-7.lzo" > "$tmp.c7.ctl" 2>/dev/null tail -c +39 "$D/lzop-corpus-9.lzo" > "$tmp.c9.ctl" 2>/dev/null tail -c +39 "$D/lzop-runs-1.lzo" > "$tmp.r1.ctl" 2>/dev/null tail -c +39 "$D/lzop-runs-9.lzo" > "$tmp.r9.ctl" 2>/dev/null cat "$corpus" | lzop -1 -c 2>/dev/null | tail -c +39 > "$tmp.c1.own" cat "$corpus" | lzop -7 -c 2>/dev/null | tail -c +39 > "$tmp.c7.own" cat "$corpus" | lzop -9 -c 2>/dev/null | tail -c +39 > "$tmp.c9.own" cat "$runs" | lzop -1 -c 2>/dev/null | tail -c +39 > "$tmp.r1.own" cat "$runs" | lzop -9 -c 2>/dev/null | tail -c +39 > "$tmp.r9.own" check lzop/encode-l1-identical cmp -s "$tmp.c1.own" "$tmp.c1.ctl" check lzop/encode-l7-identical cmp -s "$tmp.c7.own" "$tmp.c7.ctl" check lzop/encode-l9-identical cmp -s "$tmp.c9.own" "$tmp.c9.ctl" check lzop/encode-runs-l1-identical cmp -s "$tmp.r1.own" "$tmp.r1.ctl" check lzop/encode-runs-l9-identical cmp -s "$tmp.r9.own" "$tmp.r9.ctl" # Exact payload sizes, stated as literals. cmp above already implies these, but a # size mismatch reports as one legible number rather than "files differ", which is # what a reader of a failing run actually needs. check_eq lzop/encode-l1-size 1090 "$(wc -c < "$tmp.c1.own" | tr -d ' ')" check_eq lzop/encode-l7-size 1050 "$(wc -c < "$tmp.c7.own" | tr -d ' ')" check_eq lzop/encode-l9-size 1043 "$(wc -c < "$tmp.c9.own" | tr -d ' ')" check_eq lzop/encode-runs-l1-size 48 "$(wc -c < "$tmp.r1.own" | tr -d ' ')" check_eq lzop/encode-runs-l9-size 28 "$(wc -c < "$tmp.r9.own" | tr -d ' ')" # The levels must actually DIFFER, or the five cases above would pass on a build # that ignored -1/-9 entirely and emitted one algorithm for everything. check lzop/level-9-beats-1 sh -c "[ $(wc -c < "$tmp.r9.own" | tr -d ' ') -lt $(wc -c < "$tmp.r1.own" | tr -d ' ') ]" # ---- the header, field by field --------------------------------------------- # Written from a pipe, so: 9-byte magic, 0x1040 lzop version, 0x20a0 LZO library # version, 0x0940 version-needed-to-extract, then method/level. The library word # is the one that matters most -- it is written from LZO_VERSION at runtime, so it # is evidence about the liblzo2 actually linked in, not about a header lzop saw. cat "$corpus" | lzop -1 -c 2>/dev/null > "$tmp.hdr.lzo" check_out lzop/magic "89 4c 5a 4f 00 0d 0a 1a 0a" sh -c "od -An -tx1 -N9 '$tmp.hdr.lzo'" check_out lzop/hdr-version "10 40" sh -c "od -An -tx1 -j9 -N2 '$tmp.hdr.lzo'" check_out lzop/hdr-libversion "20 a0" sh -c "od -An -tx1 -j11 -N2 '$tmp.hdr.lzo'" check_out lzop/hdr-needed "09 40" sh -c "od -An -tx1 -j13 -N2 '$tmp.hdr.lzo'" # Method 2 == LZO1X-1(15), which is what -1 selects. check_out lzop/hdr-method-l1 "02" sh -c "od -An -tx1 -j15 -N1 '$tmp.hdr.lzo'" check_out lzop/hdr-level-l1 "01" sh -c "od -An -tx1 -j16 -N1 '$tmp.hdr.lzo'" # No filename stored when the source is a pipe -- this is what pins the header at # 38 bytes and makes `tail -c +39` the right cut on both machines. check_out lzop/hdr-no-name "00" sh -c "od -An -tx1 -j33 -N1 '$tmp.hdr.lzo'" # ---- -l / --info: the method names, which are the algorithm's public label --- # Measured against the native build, level by level. -1..-6 are LZO1X-1 and # -7..-9 are LZO1X-999 at the matching effort; -1 alone reports the (15) variant. check_out lzop/list-header "uncompressed_name" sh -c "lzop -l '$D/lzop-corpus-1.lzo' 2>&1" check_eq lzop/method-l1 "LZO1X-1(15)" "$(lzop -l "$D/lzop-corpus-1.lzo" 2>/dev/null | awk 'NR==2{print $1}')" check_eq lzop/method-l7 "LZO1X-999/7" "$(lzop -l "$D/lzop-corpus-7.lzo" 2>/dev/null | awk 'NR==2{print $1}')" check_eq lzop/method-l9 "LZO1X-999/9" "$(lzop -l "$D/lzop-corpus-9.lzo" 2>/dev/null | awk 'NR==2{print $1}')" # -F selects CRC32 and leaves the level at the default 3, so LZO1X-1 with no (15). check_eq lzop/method-f "LZO1X-1" "$(lzop -l "$D/lzop-corpus-F.lzo" 2>/dev/null | awk 'NR==2{print $1}')" # The listed uncompressed size is read out of the archive, so it proves the header # survived the round trip rather than being regenerated. check_eq lzop/list-uncompressed-size 11690 "$(lzop -l "$D/lzop-corpus-1.lzo" 2>/dev/null | awk 'NR==2{print $3}')" # ---- own round-trip, stream form -------------------------------------------- # Stream form (-c) for the data path, exactly as 54-gzip.test and 54-pigz.test # explain: the named-file path also restores owner/perms/mtime, which is a # different subsystem and is exercised deliberately further down. check lzop/roundtrip-corpus sh -c "cat '$corpus' | lzop -c | lzop -dc | cmp -s - '$corpus'" check lzop/roundtrip-runs sh -c "cat '$runs' | lzop -c | lzop -dc | cmp -s - '$runs'" check_out lzop/pipe-text "the quick brown fox" sh -c "printf 'the quick brown fox\n' | lzop -c | lzop -dc" # Implicit stdin/stdout with no -c at all: lzop reads stdin when given no file. check_out lzop/implicit-stdio "quick brown" sh -c "printf 'the quick brown fox\n' | lzop | lzop -d" check lzop/test-own sh -c "cat '$corpus' | lzop -c > '$tmp.own.lzo' && lzop -t '$tmp.own.lzo'" # ---- incompressible input --------------------------------------------------- # LZO stores an incompressible block verbatim and the archive grows a little. A # port that silently corrupted the stored-block path would still round-trip # compressible text, so this is its own case. dd if=/dev/urandom of="$tmp.rnd" bs=1024 count=32 2>/dev/null check lzop/incompressible-roundtrip sh -c "cat '$tmp.rnd' | lzop -c | lzop -dc | cmp -s - '$tmp.rnd'" check lzop/incompressible-grows sh -c "[ $(cat "$tmp.rnd" | lzop -c 2>/dev/null | wc -c | tr -d ' ') -gt 32768 ]" # ---- degenerate sizes ------------------------------------------------------- check_eq lzop/empty-roundtrip 0 "$(printf '' | lzop -c 2>/dev/null | lzop -dc 2>/dev/null | wc -c | tr -d ' ')" check_eq lzop/one-byte-roundtrip 1 "$(printf 'x' | lzop -c 2>/dev/null | lzop -dc 2>/dev/null | wc -c | tr -d ' ')" check_eq lzop/three-byte-roundtrip 3 "$(printf 'xyz' | lzop -c 2>/dev/null | lzop -dc 2>/dev/null | wc -c | tr -d ' ')" # An empty input still produces a full, testable archive rather than nothing. check lzop/empty-is-valid sh -c "printf '' | lzop -c > '$tmp.empty.lzo' && lzop -t '$tmp.empty.lzo'" # ---- checksums -------------------------------------------------------------- # -F swaps the adler32 payload checksum for CRC32; --no-checksum drops it. Both # must still round-trip, and -F must still be verifiable by -t. check lzop/crc32-roundtrip sh -c "cat '$corpus' | lzop -F -c | lzop -dc | cmp -s - '$corpus'" check lzop/crc32-testable sh -c "cat '$corpus' | lzop -F -c > '$tmp.f.lzo' && lzop -t '$tmp.f.lzo'" check lzop/nochecksum-roundtrip sh -c "cat '$corpus' | lzop --no-checksum -c | lzop -dc | cmp -s - '$corpus'" # ---- integrity is enforced, not merely advertised --------------------------- # Corrupt one byte well inside the compressed payload; -t must REJECT it. A # checksum that is computed and then ignored looks identical in every case above. cp "$tmp.own.lzo" "$tmp.bad.lzo" 2>/dev/null printf 'X' | dd of="$tmp.bad.lzo" bs=1 seek=80 conv=notrunc 2>/dev/null check_rc lzop/corrupt-rejected 1 lzop -t "$tmp.bad.lzo" check lzop/corrupt-message sh -c "lzop -t '$tmp.bad.lzo' 2>&1 | grep -q 'Checksum error'" # Decompressing it must fail too, not emit partial data as success. check_rc lzop/corrupt-decode-fails 1 sh -c "lzop -dc '$tmp.bad.lzo' > /dev/null 2>&1" # ---- error paths ------------------------------------------------------------ check_rc lzop/missing-file-rc 1 sh -c "lzop -t /nonexistent-lzop-input.lzo >/dev/null 2>&1" check lzop/missing-file-msg sh -c "lzop -t /nonexistent-lzop-input.lzo 2>&1 | grep -q 'No such file or directory'" printf 'this is definitely not an lzop archive' > "$tmp.junk" check_rc lzop/not-lzop-rc 1 sh -c "lzop -t '$tmp.junk' >/dev/null 2>&1" check lzop/not-lzop-msg sh -c "lzop -t '$tmp.junk' 2>&1 | grep -q 'not a lzop file'" # ---- named-file mode: the attribute path ------------------------------------ # lzop FILE writes FILE.lzo and stamps owner/perms/mtime onto it, then lzop -d # reverses it. That is chmod/chown/utimes territory -- the syscalls that were # ENOSYS on this runtime until brintos/linux#8 -- so it is checked as real # behaviour rather than assumed to work because the stream path does. cp "$corpus" "$tmp.nf" 2>/dev/null check lzop/named-compress lzop "$tmp.nf" check lzop/named-archive test -s "$tmp.nf.lzo" check lzop/named-decompress sh -c "lzop -dc '$tmp.nf.lzo' | cmp -s - '$corpus'" # The stored filename comes back in the listing -- proof the name field is # written and read, which the pipe-sourced archives above deliberately do not use. check lzop/named-stores-name sh -c "lzop -l '$tmp.nf.lzo' 2>/dev/null | awk 'NR==2{print \$5}' | grep -q ." # lzop KEEPS its input by default -- the opposite of gzip, and measured rather # than carried over from the gzip suites. check lzop/default-keeps-input test -f "$tmp.nf" # -U is the opt-in that removes it. cp "$corpus" "$tmp.u" 2>/dev/null check lzop/unlink-flag sh -c "lzop -U '$tmp.u' && [ ! -e '$tmp.u' ] && [ -s '$tmp.u.lzo' ]" # Round-trip back to a real file on disk, not just to stdout. rm -f "$tmp.d.txt" cp "$corpus" "$tmp.d.txt" 2>/dev/null check lzop/named-file-roundtrip sh -c "lzop -f '$tmp.d.txt' && rm -f '$tmp.d.txt' && lzop -d '$tmp.d.txt.lzo' && cmp -s '$tmp.d.txt' '$corpus'" # ---- the lzo library is really the one in the image ------------------------- # lzop links liblzo2 statically, so the archive it produces carries the library # version it was built against (asserted at lzop/hdr-libversion above) and the # image's own liblzo2.a is the thing that was linked. 57-lzo.test owns the # library's surface; this case only pins that the dependency is present, so that # a red here reads as "the dependency vanished" rather than as an lzop defect. check lzop/lzo-archive-present test -f /usr/lib/liblzo2.a rm -f "$tmp".* "$tmp"