Artifact db6aff9d9ec7ee27c860f1d9cf9aa9863143885712941ef79bdf384528fdaa0d:
- File
conformance/requirements/delta.tsv
— part of check-in
[0629de2beb]
at
2026-10-11 01:07:38
on branch trunk
— test(conformance): delta-format conformance suite (#262) (#280)
* test(conformance): delta-format conformance suite (#262)
Check internal/delta against draft-fossil-delta-format-00, requirement by requirement: 39 requirements, 88 cases. Decoder cases (Apply and OutputSize) are byte vectors, each also given to fossil(1) through its SQL delta functions; fossil's verdict must match unless the case records why it follows the draft instead (fossil masks the high bit, does not verify the checksum, and returns the size as a signed int). Each rejection breaks one rule and keeps the trailer valid, so check order cannot hide the rule under test. Producer cases check Create against a strict oracle and against fossil's delta_apply, and fossil's delta_create against Apply.
FuzzDeltaApply compares Apply with an independent model decoder; FuzzDeltaRoundTrip checks Apply(Create(s, t)) == t. DF-3.1-6 (Create has no 2^32 bound) has no case: it needs a 4 GiB input.
* test(conformance): delta suite names the reason each rejection must give
A rejection case could pass because some other rule rejected the input. Every rejection case now names a substring of go-libfossil's error (or ErrChecksum), and the harness fails the case when the message differs.
Vectors that were rejected for the wrong reason are fixed or reattributed: copy-truncated (DF-4-2), reject-10-nul (non-empty count, so the NUL is the opcode), copy-overflow-64 (DF-4-11), and high-bit-count, which now tells a masking decoder from a conforming one (fossil accepts it). The phantom-base case uses a literal-only delta; the content-discard case checks ErrChecksum and the store-side header refusals move to DF-4.1-3. The allocation bound gets its own row (DF-6-5) and takes the least of five runs. DF-3.1-6 notes issue #279. Drops a duplicate size-query case, the sizeCase helper and the decorative fuzz guard bytes. (user: [email protected], size: 5144) [annotate] [blame] [check-ins using]
# Requirements of draft-fossil-delta-format-00, one normative requirement per row, # written from the draft text. There are no delta errata. # draft draft-fossil-delta-format-00.txt 6a28ee7e2e146f806350161875068e496af0b9ff3d2f92c1c729242f1b1a781b DF-3-1 3 A delta is a header, zero or more segments and a trailer, concatenated with nothing between them (delta = header *segment trailer); a decoder accepts every such delta whose bounds hold. DF-3-2 3 Applying a delta a producer emitted for a source and target to that source yields the target exactly. Section 5 states this informatively; every producer requirement presupposes it, so the cases check it as the producer's baseline. DF-3.1-1 3.1 A producer writes every integer in canonical form: base 64, most significant digit first, no leading zeros, and zero as the single digit 0. DF-3.1-2 3.1 Digits 0-9 have values 0-9, A-Z 10-35, _ 36, a-z 37-62 and ~ 63, and a multi-digit integer is read most significant digit first. DF-3.1-3 3.1 Reading an integer stops at the first byte that is not a digit; that byte is the opcode or separator that follows the integer. DF-3.1-4 3.1 A decoder that accepts an integer field with no digits treats it as zero; it may reject such a delta instead. DF-3.1-5 3.1 A decoder that accepts an integer field with leading zeros uses its decoded value; it may reject such a delta instead. DF-3.1-6 3.1 A producer emits only integer values below 2^32. Create has no 2^32 bound (#279); targets and sources of 4 GiB or more are not exercised: they need 4 GiB allocations. DF-3.2-1 3.2 A decoder rejects a delta whose header integer is not immediately followed by 0x0a. DF-3.3.1-1 3.3.1 A copy segment (count @ offset ,) appends count bytes of the source starting at zero-based byte position offset. DF-3.3.1-2 3.3.1 A decoder rejects a copy segment whose offset is not followed by a comma (0x2c). DF-3.3.1-3 3.3.1 A copy segment with count zero copies zero bytes, not the rest of the source (Appendix A). DF-3.3.1-4 3.3.1 A producer never emits a copy segment with count zero. DF-3.3.2-1 3.3.2 A literal segment (count : payload) appends the count bytes that follow the colon. DF-3.3.2-2 3.3.2 A reader consumes exactly count payload bytes without scanning them for a separator; any byte in a payload, 0x0a included, is data. DF-3.4-1 3.4 A producer always ends a delta with a trailer (checksum ;) carrying the checksum of the target, including when the target is empty. DF-3.4-2 3.4 The checksum is the sum modulo 2^32 of the target's big-endian 32-bit words, plus any 1 to 3 trailing bytes added as z[0]<<24, z[1]<<16 and z[2]<<8. DF-3.4-3 3.4 A decoder that verifies the checksum rejects a delta whose trailer does not match the reconstructed target. go-libfossil always verifies; the non-verifying branch of the draft is not exercised. DF-3.4-4 3.4 A decoder treats the delta as complete at the trailer opcode; bytes after it are not read as segments. DF-4-1 4 A decoder rejects a zero-length delta before attempting any read (also section 6). DF-4-2 4 A decoder rejects a delta that ends inside an integer field. DF-4-3 4 A decoder rejects a copy segment that would take the output past the declared target length. DF-4-4 4 A decoder rejects a copy segment whose offset plus count exceeds the source length. DF-4-5 4 The offset-plus-count check is made with arithmetic that cannot overflow, so large offsets or counts cannot wrap past it. DF-4-6 4 A decoder rejects a literal segment that would take the output past the declared target length. DF-4-7 4 A decoder rejects a literal segment whose count exceeds the bytes remaining in the delta. DF-4-8 4 A decoder rejects a delta whose output length at the trailer differs from the declared target length. DF-4-9 4 A decoder rejects a segment whose opcode byte is not @, : or ;. DF-4-10 4 A decoder rejects a delta that ends without a ; trailer. DF-4-11 4 A decoder that accepts an empty, leading-zero or 2^32-or-larger integer still applies every structural and bounds check to the value it uses. DF-4-12 4 A decoder does not require, or reject a delta for, a particular segmentation or copy strategy. DF-4.1-1 4.1 A target-size query returns the header integer after reading only it and the following 0x0a; it needs no later bytes and does not validate them. DF-4.1-2 4.1 A target-size query fails on an empty buffer. DF-4.1-3 4.1 A target-size query fails when the header integer is not immediately followed by 0x0a. DF-4.2-1 4.2 The caller supplies the complete source before invoking the decoder; a delta whose source is not held is not applied. DF-6-1 6 A parser never reads past the end of the delta buffer it was given; integer accumulation stops at that boundary. DF-6-2 6 A failed delta application is never reported as success. DF-6-3 6 A caller discards the output buffer when application fails. DF-6-4 6 Bytes 0x80 through 0xFF in integer position terminate the integer; they are never decoded as digits (no high-bit masking). DF-6-5 6 A decoder treats the header's declared target length as untrusted: it does not allocate in proportion to it before the delta supplies that much output (SHOULD).