Repository navigation
Core test suite + FAT12/BASIC/DMK/ROM/CLI correctness fixes - #2
Merged
Merged
Conversation
- Add tests/ (self-contained harness, `ctest`) and CMake options MSXFF_BUILD_GUI / MSXFF_BUILD_TESTS so core+CLI build without SDL2/GL. - DiskImage::loadBytes() loads an image from memory. - Mount: validate the BPB; fall back to the media byte in the FAT for boot sectors without a usable BPB; clamp clusters to FAT capacity. - Writes check free space first: a disk-full write or create no longer leaks clusters, truncates the file or leaves a 0-byte phantom entry. - Validate 8.3 names (too-long names were silently truncated, creating duplicates); rename checks for collisions. - Subdirectories grow past one cluster; new removeDir() and lookup(). - New/modified entries get a date and time (fixed stamp for tests). - fsck and the cluster map no longer recurse forever on directory loops; fsck reports size/chain-length mismatches and bad markers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
Tokenizer fixes (each covered by tests/test_basic.cpp):
- "&B1010" (and any '&' not followed by H/O/octal) hung forever.
- Digits inside variable names (A1, X12$) were crunched to numeric
constants, which MSX-BASIC rejects as a syntax error; they stay ASCII.
- DATA items are stored verbatim up to ':' (they were crunched).
- ELSE is stored as ':' ELSE and ' as ':' REM ''', as on a real MSX;
the detokenizer hides the colon again.
- Names are upper-cased outside strings, REM and DATA.
- '!' / 'E' give single precision (0x1D), '#' / 'D' / reals double
(0x1F); an E/D only starts an exponent when digits follow ("1ELSE").
- RETURN and RESUME take line numbers; LIST/DELETE ranges keep both.
- Lines are sorted; a repeated number replaces, a bare number deletes.
- BCD is built from the decimal digits with half-up rounding instead of
binary floating point, so constants are exact.
The detokenizer formats reals from the BCD digits (".5", "1.5!", "1#",
"1D+20", "2.5E-10"), so detokenize -> tokenize reproduces the bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
- ID and data CRCs (CRC-16/CCITT, MFM 0xA1 preset) are now actually checked; before, idCrcError/dataCrcError were never set although the inspector and README advertise them. - Duplicate sector IDs on a track are flagged (and left unmapped). - Sectors per track come from the BPB, else the most common count of standard sectors. One protected track with an extra sector header used to raise spt for the whole disk and shift every LBA, so the filesystem of such images was unreadable. - Sectors with a data CRC error still map (an FDC returns their bytes). - Writing a logical sector into a DMK recomputes its data CRC, so edited DMKs no longer reload as "protected"; deliberate CRC errors are kept. - dskToDmk() moves into core and emits a proper IBM MFM layout (gaps, syncs, index mark, valid CRCs); tools/dsk2dmk is a thin wrapper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
- A game that only writes 0x6000/0x7000 tallies ASCII8 and ASCII16 equally and was reported as ASCII8; ties now go to ASCII16, and writes to 0x77FF count for ASCII16. - 48K/64K ROMs with no bank writes are plain, not "Unknown". - tsxToCas skips the remaining TZX block types (0x15, 0x18, 0x19, 0x23, 0x26-0x28, 0x2B) and reports a truncated block instead of reading past the end. - Tests: ROM header/mapper detection on synthetic images; .cas parsing; CAS<->WAV (1200/2400 baud) and CAS<->TSX round trips; error paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
- cat/detok/extract/put/del/rename/crc accept DIR/NAME paths; before, only root-directory files could be reached from the CLI. - del removes an empty directory; protect shows duplicate-ID sectors. - diff walks the whole tree and exits 1 when the images differ. - save errors are reported instead of exiting silently. - Usage lists every command. - tests/cli_smoke.cmake drives the binary end to end (format, tok, add, mkdir, ls, cat, extract, rename, del, fsck, diff, dsk2dmk, cas, tsx) as a ctest that runs on every platform. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
- CI runs ctest after every build (the cross-compiled macOS x86_64 binary cannot run on the arm64 runner, so it is skipped there). - README: -DMSXFF_BUILD_GUI=OFF, the test suites, path arguments, and limitations updated (CRC checks and file creation now exist). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
Uses the new Fat12::removeDir(); shown while browsing a subdirectory, goes back up to the parent on success. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
- Entries in a subdirectory's 2nd+ cluster got the offset of the first cluster plus their index, i.e. the wrong place on disk whenever the clusters are not adjacent (normal once a directory grows). put, del, rename and rmdir then wrote into other files' data. Directories are now parsed cluster by cluster with each cluster's own offset. - lookup() no longer resolves "." / ".."; removeDir, renameEntry and deleteFile refuse dot entries (del SUB/. freed SUB under its parent). - A failed writeFile releases the clusters it allocated; mount caps the sector count at the image size (media-byte guesses on short dumps addressed sectors past the end). - chainOf() stops at a cluster it already visited, so writing a file with a looping FAT chain repairs it instead of freeing it. - createFile/makeDir count the extra cluster only when a full subdirectory must grow (makeDir refused with free slots available; a failed create still grew the directory). - DMK sectors whose data runs past the track end stay readable but are not writable (a write clobbered the next track's IDAM table). - cli diff walks each directory once (a self-referencing directory made it run for ever) and no longer drops files below depth 16. Each fix has a regression test that fails without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CtBtjm9PRm6sDhDVJbtciC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the project's first automated tests and fixes the bugs they (and an independent review) turned up. No file-format changes; the GUI gains one button.
Tests & build
tests/: self-contained harness (no external framework), 67 core tests +cli_smoke.cmake, an end-to-end run of themsxforgebinary. Run withctest --test-dir build --output-on-failure.MSXFF_BUILD_GUI/MSXFF_BUILD_TESTS: core + CLI + tests build without SDL2/OpenGL.FAT12
./..cannot be deleted/renamed.removeDir()andlookup(path); new/modified entries get a date/time.MSX-BASIC tokenizer
&B…hung the tokenizer; digits in variable names (A1) were crunched to constants (a syntax error on MSX);DATAis stored verbatim;ELSE/'are stored as:ELSE /:REM'like the ROM does; names are upper-cased;!/Esingle vs#/D/reals double; exponent only when digits follow; RETURN/RESUME line numbers; lines sorted/replaced/deleted.DMK
dskToDmk()in core emits a proper IBM MFM layout with valid CRCs;tools/dsk2dmkwraps it.ROM / tape
tsxToCashandles the remaining TZX block IDs and reports truncation.CLI / GUI
DIR/NAMEpaths (only root files were reachable);delremoves empty dirs;diffwalks the whole tree (loop-safe) and exits 1 on differences; full usage text.Testing
ctestgreen locally (Linux, GCC 13, also under ASan/UBSan); Windows build cross-compiled with MinGW without warnings. GUI builds; the new button was not exercised interactively.Generated by Claude Code