diff --git a/test/programs/raylib-audio.flan b/test/programs/raylib-audio.flan index d77b87f..7e2953a 100644 --- a/test/programs/raylib-audio.flan +++ b/test/programs/raylib-audio.flan @@ -23,12 +23,17 @@ ;; is the strongest shape a headless FFI test has. ;; ;; 2. **The file, as external ground truth.** export-wave writes a RIFF -;; header carrying sample-rate, sample-size and channels, and a payload -;; whose length says frame-count; load-wave reads that header back. Both -;; ends are dr_wav's and agree with each other, not with whatever field -;; order Flan believes in — the same reason the PNG round trip in -;; raylib-image.flan is not the symmetric trap a store-and-return check -;; is. +;; header carrying sample-rate, sample-size and channels; load-wave reads +;; it back. Both ends are dr_wav's and agree with each other, not with +;; whatever field order Flan believes in — the same reason the PNG round +;; trip in raylib-image.flan is not the symmetric trap a store-and-return +;; check is. +;; +;; Its reach is narrower than it looks and the narrowness is worth +;; knowing: exchanging sample-size and channels turns the loaded line +;; into "8 8000 16 16", while exchanging frame-count and sample-rate +;; leaves every line of the round trip untouched. What catches THAT pair +;; is the crop and the reformat, above. Neither claim covers the other. ;; ;; 3. **`data` as a pointer, and the bytes behind it.** load-wave-samples ;; decodes through the buffer. Move `data` up among the integers and @@ -181,6 +186,10 @@ ;; ends are external to Flan and agree with each other, so this is not the ;; round trip that passes for any field order — it is the PNG argument, ;; for audio. It also crosses a path as ptr+len. + ;; + ;; It does not catch everything, and the header note says which: exchange + ;; frame-count and sample-rate and all three lines below stay green. The + ;; crop and the reformat are what go red for that pair. (show-bool "exported" (rl/export-wave src wav-path)) (let [back (rl/load-wave wav-path)] (show-bool "loaded valid" (rl/wave-valid? back)) diff --git a/test/programs/raylib-font.flan b/test/programs/raylib-font.flan index 4b2c719..2f35eb2 100644 --- a/test/programs/raylib-font.flan +++ b/test/programs/raylib-font.flan @@ -40,6 +40,15 @@ ;; texture — and if the texture landed anywhere else in the struct the id ;; would read 0 and every measurement below would collapse to zero. ;; +;; And what is NOT pinned, which matters as much: `glyph-padding` is read by +;; nothing raylib computes on the CPU, `offset-y` only moves a glyph when one +;; is actually drawn, and of each atlas rectangle only `width` is ever looked +;; at — `x`, `y` and `height` come back from get-glyph-atlas-rec exactly as +;; they were stored, which is the symmetric trap and proves nothing. Those +;; four rest on raylib's header and on sand.flan looking right. This is the +;; same limit raylib-ffi.flan records for Texture2D's width, height and +;; mipmaps, and it is written down for the same reason. +;; ;; The numbers are chosen so that no two are equal: base size 10, glyph count ;; 3, padding 2, advances 11 and 13, offsets 1, 2 and 3, atlas widths 5, 7 ;; and 9. Everything prints exactly — no trigonometry, so unlike the rotated @@ -52,7 +61,10 @@ ;; The glyphs themselves. `image` is raylib's own pixels for the glyph and is ;; left zeroed — it is present so the four ints in front of it are at the -;; right offsets and so a GlyphInfo is 40 bytes rather than 16. +;; right offsets and so a GlyphInfo is 40 bytes rather than 16. That claim is +;; checked: moving `image` to the front of the defstruct shifts the four ints +;; by 24 bytes, and the glyph search then finds nothing — every index reads 0 +;; and glyph C answers with A's numbers. (defvar glyphs [3 rl/GlyphInfo]) (defn build-glyphs [] @@ -144,7 +156,8 @@ ;; width plus the offset: 9 + 3 = 12, for 36. This line and the one above ;; disagree by exactly the amount that proves the fallback branch ran, and ;; that branch is the only thing in the file that reads Rectangle.width - ;; out of the recs array. + ;; out of the recs array — exchange x and width in the Rectangle defstruct + ;; and this line reads 39 while the one above stays 24. (show-v "measure ABC" (rl/measure-text-ex f "ABC" 10.0 0.0)) ;; The same string at twice the size and a spacing of 3. Scale is 20/10, diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index 1dc4b9c..0c34439 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -371,9 +371,13 @@ let () = with the frame count it would otherwise equal. export-wave then load-wave is external ground truth, the PNG argument - transposed: dr_wav writes the header from three fields and the payload - length from the fourth, and reads all four back, agreeing with itself - rather than with Flan's field order. + transposed: dr_wav writes the header from three fields and reads them + back, agreeing with itself rather than with Flan's field order. Be + precise about its reach, because it is narrower than it looks — it + catches sample-size against channels (the "loaded" line reads + "8 8000 16 16" when those two are exchanged) and NOT frame-count + against sample-rate, which leaves every line of the round trip green. + The crop and the reformat are what catch that pair. And the decoded samples are the axis discriminator this section needed. load-wave-samples answers a (Ptr f32), which Flan cannot index — [at] @@ -388,9 +392,10 @@ let () = Verified red by permuting the Wave defstruct three ways: frame-count with sample-rate (cropped reads "8 4 16 1" and reformatted - "16000 16000000 8 2"), sample-size with channels (every frame read - turns to "no"), and data moved to the front (the run dies after two - lines). *) + "16000 16000000 8 2", while the file round trip stays green — see + above), sample-size with channels (every frame read turns to "no" and + the loaded line reads "8 8000 16 16"), and data moved to the front + (the run dies after two lines). *) let raylib_audio_out = "valid yes\n\ source 8 8000 16 1\n\ @@ -443,12 +448,24 @@ let () = and not per glyph — without that line, a wrapper that added it per glyph would pass everything else. - Verified red by four permutations: base-size with glyph-count (the - measurements become 80, 120, 163 and 36.6667), offset-x with advance-x - (3, 6, 9, 1), the recs and glyphs pointers (floats in the 1e9 range and - a garbage atlas rectangle), and moving [texture] to the end of the - Font (the run dies after the first line). Two of the four were a crash - rather than a wrong number, which still counts. *) + Verified red by six permutations. In Font: base-size with glyph-count + (the measurements become 80, 120, 163 and 36.6667), the recs and glyphs + pointers (floats in the 1e9 range and a garbage atlas rectangle), and + [texture] moved to the end (the run dies after the first line). In + GlyphInfo: offset-x with advance-x (3, 6, 9, 1), and [image] moved to + the FRONT, which shifts the four ints by 24 bytes — the glyph search + collapses, every index reads 0 and glyph C answers with A's fields. + In Rectangle: x with width, which moves "measure ABC" to 39 and leaves + "measure AB" at 24, since only the advance-0 fallback reads a width out + of the recs array. Two of the six were a crash rather than a wrong + number, which still counts. + + What this case does NOT pin, said here for the same reason the + Texture2D notes above say it: glyph-padding is read by nothing raylib + computes on the CPU, offset-y only moves a glyph when it is drawn, and + of each atlas rectangle only `width` is ever looked at. Those four + fields rest on the header agreeing with raylib's and on sand.flan + looking right, and on nothing else. *) let raylib_font_out = "valid yes\n\ index A 0\nindex B 1\nindex C 2\nindex Z 0\n\