web-a2e 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clangd +5 -0
- package/.mcp.json +12 -0
- package/CLAUDE.md +362 -0
- package/CMakeLists.txt +774 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/build-wasm/generated/roms.cpp +2447 -0
- package/docker-compose.staging.yml +9 -0
- package/docs/basic-rom-disassembly.md +6663 -0
- package/docs/softswitch-comparison.md +273 -0
- package/docs/thunderclock-debug.md +89 -0
- package/examples/cube.bas +72 -0
- package/examples/hello.s +55 -0
- package/examples/scroll.s +140 -0
- package/package.json +18 -0
- package/public/assets/apple-logo-old.png +0 -0
- package/public/assets/apple-logo.png +0 -0
- package/public/assets/drive-closed-light-on.png +0 -0
- package/public/assets/drive-closed.png +0 -0
- package/public/assets/drive-open-light-on.png +0 -0
- package/public/assets/drive-open.png +0 -0
- package/public/audio-worklet.js +82 -0
- package/public/disks/Apple DOS 3.3 January 1983.dsk +0 -0
- package/public/disks/ProDOS 2.4.3.po +0 -0
- package/public/disks/h32mb.2mg +0 -0
- package/public/disks/library.json +26 -0
- package/public/docs/llms/llm-assembler.txt +90 -0
- package/public/docs/llms/llm-basic-program.txt +256 -0
- package/public/docs/llms/llm-disk-drives.txt +72 -0
- package/public/docs/llms/llm-file-explorer.txt +50 -0
- package/public/docs/llms/llm-hard-drives.txt +80 -0
- package/public/docs/llms/llm-main.txt +51 -0
- package/public/docs/llms/llm-slot-configuration.txt +66 -0
- package/public/icons/icon-192.svg +4 -0
- package/public/icons/icon-512.svg +4 -0
- package/public/index.html +661 -0
- package/public/llms.txt +49 -0
- package/public/manifest.json +29 -0
- package/public/shaders/burnin.glsl +22 -0
- package/public/shaders/crt.glsl +706 -0
- package/public/shaders/edge.glsl +109 -0
- package/public/shaders/vertex.glsl +8 -0
- package/public/sw.js +186 -0
- package/roms/341-0027.bin +0 -0
- package/roms/341-0160-A-US-UK.bin +0 -0
- package/roms/341-0160-A.bin +0 -0
- package/roms/342-0273-A-US-UK.bin +0 -0
- package/roms/342-0349-B-C0-FF.bin +0 -0
- package/roms/Apple Mouse Interface Card ROM - 342-0270-C.bin +0 -0
- package/roms/Thunderclock Plus ROM.bin +0 -0
- package/scripts/generate_roms.sh +69 -0
- package/src/bindings/wasm_interface.cpp +1940 -0
- package/src/core/assembler/assembler.cpp +1239 -0
- package/src/core/assembler/assembler.hpp +115 -0
- package/src/core/audio/audio.cpp +160 -0
- package/src/core/audio/audio.hpp +81 -0
- package/src/core/basic/basic_detokenizer.cpp +436 -0
- package/src/core/basic/basic_detokenizer.hpp +41 -0
- package/src/core/basic/basic_tokenizer.cpp +286 -0
- package/src/core/basic/basic_tokenizer.hpp +26 -0
- package/src/core/basic/basic_tokens.hpp +295 -0
- package/src/core/cards/disk2_card.cpp +568 -0
- package/src/core/cards/disk2_card.hpp +316 -0
- package/src/core/cards/expansion_card.hpp +185 -0
- package/src/core/cards/mockingboard/ay8910.cpp +616 -0
- package/src/core/cards/mockingboard/ay8910.hpp +159 -0
- package/src/core/cards/mockingboard/via6522.cpp +530 -0
- package/src/core/cards/mockingboard/via6522.hpp +163 -0
- package/src/core/cards/mockingboard_card.cpp +312 -0
- package/src/core/cards/mockingboard_card.hpp +159 -0
- package/src/core/cards/mouse_card.cpp +654 -0
- package/src/core/cards/mouse_card.hpp +190 -0
- package/src/core/cards/smartport/block_device.cpp +202 -0
- package/src/core/cards/smartport/block_device.hpp +60 -0
- package/src/core/cards/smartport/smartport_card.cpp +603 -0
- package/src/core/cards/smartport/smartport_card.hpp +120 -0
- package/src/core/cards/thunderclock_card.cpp +237 -0
- package/src/core/cards/thunderclock_card.hpp +122 -0
- package/src/core/cpu/cpu6502.cpp +1609 -0
- package/src/core/cpu/cpu6502.hpp +203 -0
- package/src/core/debug/condition_evaluator.cpp +470 -0
- package/src/core/debug/condition_evaluator.hpp +87 -0
- package/src/core/disassembler/disassembler.cpp +552 -0
- package/src/core/disassembler/disassembler.hpp +171 -0
- package/src/core/disk-image/disk_image.hpp +267 -0
- package/src/core/disk-image/dsk_disk_image.cpp +827 -0
- package/src/core/disk-image/dsk_disk_image.hpp +204 -0
- package/src/core/disk-image/gcr_encoding.cpp +147 -0
- package/src/core/disk-image/gcr_encoding.hpp +78 -0
- package/src/core/disk-image/woz_disk_image.cpp +1049 -0
- package/src/core/disk-image/woz_disk_image.hpp +343 -0
- package/src/core/emulator.cpp +2126 -0
- package/src/core/emulator.hpp +434 -0
- package/src/core/filesystem/dos33.cpp +178 -0
- package/src/core/filesystem/dos33.hpp +66 -0
- package/src/core/filesystem/pascal.cpp +262 -0
- package/src/core/filesystem/pascal.hpp +87 -0
- package/src/core/filesystem/prodos.cpp +369 -0
- package/src/core/filesystem/prodos.hpp +119 -0
- package/src/core/input/keyboard.cpp +227 -0
- package/src/core/input/keyboard.hpp +111 -0
- package/src/core/mmu/mmu.cpp +1387 -0
- package/src/core/mmu/mmu.hpp +236 -0
- package/src/core/types.hpp +196 -0
- package/src/core/video/video.cpp +680 -0
- package/src/core/video/video.hpp +156 -0
- package/src/css/assembler-editor.css +1617 -0
- package/src/css/base.css +470 -0
- package/src/css/basic-debugger.css +791 -0
- package/src/css/basic-editor.css +792 -0
- package/src/css/controls.css +783 -0
- package/src/css/cpu-debugger.css +1413 -0
- package/src/css/debug-base.css +160 -0
- package/src/css/debug-windows.css +6455 -0
- package/src/css/disk-drives.css +406 -0
- package/src/css/documentation.css +392 -0
- package/src/css/file-explorer.css +867 -0
- package/src/css/hard-drive.css +180 -0
- package/src/css/layout.css +217 -0
- package/src/css/memory-windows.css +798 -0
- package/src/css/modals.css +510 -0
- package/src/css/monitor.css +425 -0
- package/src/css/release-notes.css +101 -0
- package/src/css/responsive.css +400 -0
- package/src/css/rule-builder.css +340 -0
- package/src/css/save-states.css +201 -0
- package/src/css/settings-windows.css +1231 -0
- package/src/css/window-switcher.css +150 -0
- package/src/js/agent/agent-manager.js +643 -0
- package/src/js/agent/agent-tools.js +293 -0
- package/src/js/agent/agent-version-tools.js +131 -0
- package/src/js/agent/assembler-tools.js +357 -0
- package/src/js/agent/basic-program-tools.js +894 -0
- package/src/js/agent/disk-tools.js +417 -0
- package/src/js/agent/file-explorer-tools.js +269 -0
- package/src/js/agent/index.js +13 -0
- package/src/js/agent/main-tools.js +222 -0
- package/src/js/agent/slot-tools.js +303 -0
- package/src/js/agent/smartport-tools.js +257 -0
- package/src/js/agent/window-tools.js +80 -0
- package/src/js/audio/audio-driver.js +417 -0
- package/src/js/audio/audio-worklet.js +85 -0
- package/src/js/audio/index.js +8 -0
- package/src/js/config/default-layout.js +34 -0
- package/src/js/config/version.js +8 -0
- package/src/js/data/apple2-rom-routines.js +577 -0
- package/src/js/debug/assembler-editor-window.js +2993 -0
- package/src/js/debug/basic-breakpoint-manager.js +529 -0
- package/src/js/debug/basic-program-parser.js +436 -0
- package/src/js/debug/basic-program-window.js +2594 -0
- package/src/js/debug/basic-variable-inspector.js +447 -0
- package/src/js/debug/breakpoint-manager.js +472 -0
- package/src/js/debug/cpu-debugger-window.js +2396 -0
- package/src/js/debug/index.js +22 -0
- package/src/js/debug/label-manager.js +238 -0
- package/src/js/debug/memory-browser-window.js +416 -0
- package/src/js/debug/memory-heat-map-window.js +481 -0
- package/src/js/debug/memory-map-window.js +206 -0
- package/src/js/debug/mockingboard-window.js +882 -0
- package/src/js/debug/mouse-card-window.js +355 -0
- package/src/js/debug/rule-builder-window.js +648 -0
- package/src/js/debug/soft-switch-window.js +458 -0
- package/src/js/debug/stack-viewer-window.js +221 -0
- package/src/js/debug/symbols.js +416 -0
- package/src/js/debug/trace-panel.js +291 -0
- package/src/js/debug/zero-page-watch-window.js +297 -0
- package/src/js/disk-manager/disk-drives-window.js +212 -0
- package/src/js/disk-manager/disk-operations.js +284 -0
- package/src/js/disk-manager/disk-persistence.js +301 -0
- package/src/js/disk-manager/disk-surface-renderer.js +388 -0
- package/src/js/disk-manager/drive-sounds.js +139 -0
- package/src/js/disk-manager/hard-drive-manager.js +481 -0
- package/src/js/disk-manager/hard-drive-persistence.js +187 -0
- package/src/js/disk-manager/hard-drive-window.js +57 -0
- package/src/js/disk-manager/index.js +890 -0
- package/src/js/display/display-settings-window.js +383 -0
- package/src/js/display/index.js +10 -0
- package/src/js/display/screen-window.js +342 -0
- package/src/js/display/webgl-renderer.js +705 -0
- package/src/js/file-explorer/disassembler.js +574 -0
- package/src/js/file-explorer/dos33.js +266 -0
- package/src/js/file-explorer/file-viewer.js +359 -0
- package/src/js/file-explorer/index.js +1261 -0
- package/src/js/file-explorer/prodos.js +549 -0
- package/src/js/file-explorer/utils.js +67 -0
- package/src/js/help/documentation-window.js +1096 -0
- package/src/js/help/index.js +10 -0
- package/src/js/help/release-notes-window.js +85 -0
- package/src/js/help/release-notes.js +612 -0
- package/src/js/input/gamepad-handler.js +176 -0
- package/src/js/input/index.js +12 -0
- package/src/js/input/input-handler.js +396 -0
- package/src/js/input/joystick-window.js +404 -0
- package/src/js/input/mouse-handler.js +99 -0
- package/src/js/input/text-selection.js +462 -0
- package/src/js/main.js +653 -0
- package/src/js/state/index.js +15 -0
- package/src/js/state/save-states-window.js +393 -0
- package/src/js/state/state-manager.js +409 -0
- package/src/js/state/state-persistence.js +218 -0
- package/src/js/ui/confirm.js +43 -0
- package/src/js/ui/disk-drive-positioner.js +347 -0
- package/src/js/ui/reminder-controller.js +129 -0
- package/src/js/ui/slot-configuration-window.js +560 -0
- package/src/js/ui/theme-manager.js +61 -0
- package/src/js/ui/toast.js +44 -0
- package/src/js/ui/ui-controller.js +897 -0
- package/src/js/ui/window-switcher.js +275 -0
- package/src/js/utils/basic-autocomplete.js +832 -0
- package/src/js/utils/basic-highlighting.js +473 -0
- package/src/js/utils/basic-tokenizer.js +153 -0
- package/src/js/utils/basic-tokens.js +117 -0
- package/src/js/utils/constants.js +28 -0
- package/src/js/utils/indexeddb-helper.js +225 -0
- package/src/js/utils/merlin-editor-support.js +905 -0
- package/src/js/utils/merlin-highlighting.js +551 -0
- package/src/js/utils/storage.js +125 -0
- package/src/js/utils/string-utils.js +19 -0
- package/src/js/utils/wasm-memory.js +54 -0
- package/src/js/windows/base-window.js +690 -0
- package/src/js/windows/index.js +9 -0
- package/src/js/windows/window-manager.js +375 -0
- package/tests/catch2/catch.hpp +17976 -0
- package/tests/common/basic_program_builder.cpp +119 -0
- package/tests/common/basic_program_builder.hpp +209 -0
- package/tests/common/disk_image_builder.cpp +444 -0
- package/tests/common/disk_image_builder.hpp +141 -0
- package/tests/common/test_helpers.hpp +118 -0
- package/tests/gcr/gcr-test.cpp +142 -0
- package/tests/integration/check-rom.js +70 -0
- package/tests/integration/compare-boot.js +239 -0
- package/tests/integration/crash-trace.js +102 -0
- package/tests/integration/disk-boot-test.js +264 -0
- package/tests/integration/memory-crash.js +108 -0
- package/tests/integration/nibble-read-test.js +249 -0
- package/tests/integration/phase-test.js +159 -0
- package/tests/integration/test_emulator.cpp +291 -0
- package/tests/integration/test_emulator_basic.cpp +91 -0
- package/tests/integration/test_emulator_debug.cpp +344 -0
- package/tests/integration/test_emulator_disk.cpp +153 -0
- package/tests/integration/test_emulator_state.cpp +163 -0
- package/tests/klaus/6502_functional_test.bin +0 -0
- package/tests/klaus/65C02_extended_opcodes_test.bin +0 -0
- package/tests/klaus/klaus_6502_test.cpp +184 -0
- package/tests/klaus/klaus_65c02_test.cpp +197 -0
- package/tests/thunderclock/thunderclock_mmu_test.cpp +304 -0
- package/tests/thunderclock/thunderclock_test.cpp +550 -0
- package/tests/unit/test_assembler.cpp +521 -0
- package/tests/unit/test_audio.cpp +196 -0
- package/tests/unit/test_ay8910.cpp +311 -0
- package/tests/unit/test_basic_detokenizer.cpp +265 -0
- package/tests/unit/test_basic_tokenizer.cpp +382 -0
- package/tests/unit/test_block_device.cpp +259 -0
- package/tests/unit/test_condition_evaluator.cpp +219 -0
- package/tests/unit/test_cpu6502.cpp +1301 -0
- package/tests/unit/test_cpu_addressing.cpp +361 -0
- package/tests/unit/test_cpu_cycle_counts.cpp +409 -0
- package/tests/unit/test_cpu_decimal.cpp +166 -0
- package/tests/unit/test_cpu_interrupts.cpp +285 -0
- package/tests/unit/test_disassembler.cpp +323 -0
- package/tests/unit/test_disk2_card.cpp +330 -0
- package/tests/unit/test_dos33.cpp +273 -0
- package/tests/unit/test_dsk_disk_image.cpp +315 -0
- package/tests/unit/test_expansion_card.cpp +178 -0
- package/tests/unit/test_gcr_encoding.cpp +232 -0
- package/tests/unit/test_keyboard.cpp +262 -0
- package/tests/unit/test_mmu.cpp +555 -0
- package/tests/unit/test_mmu_slots.cpp +323 -0
- package/tests/unit/test_mockingboard.cpp +352 -0
- package/tests/unit/test_mouse_card.cpp +386 -0
- package/tests/unit/test_pascal.cpp +248 -0
- package/tests/unit/test_prodos.cpp +259 -0
- package/tests/unit/test_smartport_card.cpp +321 -0
- package/tests/unit/test_thunderclock.cpp +354 -0
- package/tests/unit/test_via6522.cpp +323 -0
- package/tests/unit/test_video.cpp +319 -0
- package/tests/unit/test_woz_disk_image.cpp +257 -0
- package/vite.config.js +96 -0
- package/wiki/AI-Agent.md +372 -0
- package/wiki/Architecture-Overview.md +303 -0
- package/wiki/Audio-System.md +449 -0
- package/wiki/CPU-Emulation.md +477 -0
- package/wiki/Debugger.md +516 -0
- package/wiki/Disk-Drives.md +161 -0
- package/wiki/Disk-System-Internals.md +547 -0
- package/wiki/Display-Settings.md +88 -0
- package/wiki/Expansion-Slots.md +187 -0
- package/wiki/File-Explorer.md +259 -0
- package/wiki/Getting-Started.md +156 -0
- package/wiki/Home.md +69 -0
- package/wiki/Input-Devices.md +183 -0
- package/wiki/Keyboard-Shortcuts.md +158 -0
- package/wiki/Memory-System.md +364 -0
- package/wiki/Save-States.md +172 -0
- package/wiki/Video-Rendering.md +658 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* test_mouse_card.cpp - Unit tests for MouseCard
|
|
3
|
+
*
|
|
4
|
+
* Tests the Apple Mouse Interface card implementation including:
|
|
5
|
+
* - Construction
|
|
6
|
+
* - Card metadata (name, preferred slot)
|
|
7
|
+
* - ROM presence
|
|
8
|
+
* - ROM data reading
|
|
9
|
+
* - Mouse delta input and position tracking
|
|
10
|
+
* - Button state tracking
|
|
11
|
+
* - Position clamping
|
|
12
|
+
* - PIA register access
|
|
13
|
+
* - Reset behavior
|
|
14
|
+
* - Serialization round-trip
|
|
15
|
+
* - Slot number configuration
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#define CATCH_CONFIG_MAIN
|
|
19
|
+
#include "catch.hpp"
|
|
20
|
+
|
|
21
|
+
#include "mouse_card.hpp"
|
|
22
|
+
#include "roms.cpp"
|
|
23
|
+
|
|
24
|
+
#include <cstring>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
using namespace a2e;
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Construction
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
TEST_CASE("MouseCard constructor creates valid instance", "[mouse]") {
|
|
34
|
+
MouseCard card;
|
|
35
|
+
REQUIRE(card.getName() != nullptr);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Card metadata
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
TEST_CASE("MouseCard getName returns Mouse", "[mouse]") {
|
|
43
|
+
MouseCard card;
|
|
44
|
+
REQUIRE(std::string(card.getName()) == "Mouse");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
TEST_CASE("MouseCard getPreferredSlot returns 4", "[mouse]") {
|
|
48
|
+
MouseCard card;
|
|
49
|
+
REQUIRE(card.getPreferredSlot() == 4);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// ROM presence
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
TEST_CASE("MouseCard hasROM returns true", "[mouse]") {
|
|
57
|
+
MouseCard card;
|
|
58
|
+
REQUIRE(card.hasROM());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
TEST_CASE("MouseCard hasExpansionROM returns false", "[mouse]") {
|
|
62
|
+
MouseCard card;
|
|
63
|
+
REQUIRE_FALSE(card.hasExpansionROM());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// ROM data reading
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
TEST_CASE("MouseCard readROM returns ROM data from embedded mouse ROM", "[mouse]") {
|
|
71
|
+
MouseCard card;
|
|
72
|
+
|
|
73
|
+
// The mouse ROM should not be all zeros
|
|
74
|
+
bool allZero = true;
|
|
75
|
+
for (int i = 0; i < 256; ++i) {
|
|
76
|
+
if (card.readROM(static_cast<uint8_t>(i)) != 0x00) {
|
|
77
|
+
allZero = false;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
REQUIRE_FALSE(allZero);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
TEST_CASE("MouseCard readROM returns ROM data not all 0xFF", "[mouse]") {
|
|
85
|
+
MouseCard card;
|
|
86
|
+
|
|
87
|
+
bool allFF = true;
|
|
88
|
+
for (int i = 0; i < 256; ++i) {
|
|
89
|
+
if (card.readROM(static_cast<uint8_t>(i)) != 0xFF) {
|
|
90
|
+
allFF = false;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
REQUIRE_FALSE(allFF);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Mouse delta input: addDelta
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
TEST_CASE("MouseCard initial position is 0,0", "[mouse]") {
|
|
102
|
+
MouseCard card;
|
|
103
|
+
REQUIRE(card.getMouseX() == 0);
|
|
104
|
+
REQUIRE(card.getMouseY() == 0);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
TEST_CASE("MouseCard addDelta changes position", "[mouse]") {
|
|
108
|
+
MouseCard card;
|
|
109
|
+
|
|
110
|
+
card.addDelta(10, 20);
|
|
111
|
+
REQUIRE(card.getMouseX() == 10);
|
|
112
|
+
REQUIRE(card.getMouseY() == 20);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
TEST_CASE("MouseCard addDelta sets moved flag", "[mouse]") {
|
|
116
|
+
MouseCard card;
|
|
117
|
+
|
|
118
|
+
REQUIRE_FALSE(card.getMoved());
|
|
119
|
+
card.addDelta(5, 5);
|
|
120
|
+
REQUIRE(card.getMoved());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
TEST_CASE("MouseCard addDelta accumulates", "[mouse]") {
|
|
124
|
+
MouseCard card;
|
|
125
|
+
|
|
126
|
+
card.addDelta(10, 10);
|
|
127
|
+
card.addDelta(5, -3);
|
|
128
|
+
REQUIRE(card.getMouseX() == 15);
|
|
129
|
+
REQUIRE(card.getMouseY() == 7);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
TEST_CASE("MouseCard addDelta with zero does not change position", "[mouse]") {
|
|
133
|
+
MouseCard card;
|
|
134
|
+
|
|
135
|
+
card.addDelta(0, 0);
|
|
136
|
+
REQUIRE(card.getMouseX() == 0);
|
|
137
|
+
REQUIRE(card.getMouseY() == 0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// Button state
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
TEST_CASE("MouseCard button starts unpressed", "[mouse]") {
|
|
145
|
+
MouseCard card;
|
|
146
|
+
REQUIRE_FALSE(card.getMouseButton());
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
TEST_CASE("MouseCard setMouseButton true sets button pressed", "[mouse]") {
|
|
150
|
+
MouseCard card;
|
|
151
|
+
|
|
152
|
+
card.setMouseButton(true);
|
|
153
|
+
REQUIRE(card.getMouseButton());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
TEST_CASE("MouseCard setMouseButton sets buttonChanged flag", "[mouse]") {
|
|
157
|
+
MouseCard card;
|
|
158
|
+
|
|
159
|
+
REQUIRE_FALSE(card.getButtonChanged());
|
|
160
|
+
card.setMouseButton(true);
|
|
161
|
+
REQUIRE(card.getButtonChanged());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
TEST_CASE("MouseCard setMouseButton false after true clears button", "[mouse]") {
|
|
165
|
+
MouseCard card;
|
|
166
|
+
|
|
167
|
+
card.setMouseButton(true);
|
|
168
|
+
REQUIRE(card.getMouseButton());
|
|
169
|
+
|
|
170
|
+
card.setMouseButton(false);
|
|
171
|
+
REQUIRE_FALSE(card.getMouseButton());
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// Position clamping
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
TEST_CASE("MouseCard default clamp range is 0-1023", "[mouse]") {
|
|
179
|
+
MouseCard card;
|
|
180
|
+
REQUIRE(card.getClampMinX() == 0);
|
|
181
|
+
REQUIRE(card.getClampMaxX() == 1023);
|
|
182
|
+
REQUIRE(card.getClampMinY() == 0);
|
|
183
|
+
REQUIRE(card.getClampMaxY() == 1023);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
TEST_CASE("MouseCard position clamps to max bounds", "[mouse]") {
|
|
187
|
+
MouseCard card;
|
|
188
|
+
|
|
189
|
+
// Move far beyond the default max clamp of 1023
|
|
190
|
+
card.addDelta(2000, 2000);
|
|
191
|
+
|
|
192
|
+
REQUIRE(card.getMouseX() <= card.getClampMaxX());
|
|
193
|
+
REQUIRE(card.getMouseY() <= card.getClampMaxY());
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
TEST_CASE("MouseCard position clamps to min bounds", "[mouse]") {
|
|
197
|
+
MouseCard card;
|
|
198
|
+
|
|
199
|
+
// Move far negative beyond the default min clamp of 0
|
|
200
|
+
card.addDelta(-1000, -1000);
|
|
201
|
+
|
|
202
|
+
REQUIRE(card.getMouseX() >= card.getClampMinX());
|
|
203
|
+
REQUIRE(card.getMouseY() >= card.getClampMinY());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// PIA register access
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
TEST_CASE("MouseCard readIO for PIA registers does not crash", "[mouse]") {
|
|
211
|
+
MouseCard card;
|
|
212
|
+
|
|
213
|
+
// PIA has 4 registers at offsets 0-3
|
|
214
|
+
for (uint8_t offset = 0; offset < 4; ++offset) {
|
|
215
|
+
uint8_t val = card.readIO(offset);
|
|
216
|
+
(void)val;
|
|
217
|
+
}
|
|
218
|
+
REQUIRE(true);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
TEST_CASE("MouseCard writeIO for PIA registers does not crash", "[mouse]") {
|
|
222
|
+
MouseCard card;
|
|
223
|
+
|
|
224
|
+
for (uint8_t offset = 0; offset < 4; ++offset) {
|
|
225
|
+
card.writeIO(offset, 0x00);
|
|
226
|
+
card.writeIO(offset, 0xFF);
|
|
227
|
+
}
|
|
228
|
+
REQUIRE(true);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
TEST_CASE("MouseCard peekIO does not crash", "[mouse]") {
|
|
232
|
+
MouseCard card;
|
|
233
|
+
|
|
234
|
+
for (uint8_t offset = 0; offset < 4; ++offset) {
|
|
235
|
+
uint8_t val = card.peekIO(offset);
|
|
236
|
+
(void)val;
|
|
237
|
+
}
|
|
238
|
+
REQUIRE(true);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
TEST_CASE("MouseCard PIA debug accessors return initial values", "[mouse]") {
|
|
242
|
+
MouseCard card;
|
|
243
|
+
|
|
244
|
+
// After construction, PIA registers should be 0
|
|
245
|
+
REQUIRE(card.getDDRA() == 0);
|
|
246
|
+
REQUIRE(card.getDDRB() == 0);
|
|
247
|
+
REQUIRE(card.getORA() == 0);
|
|
248
|
+
REQUIRE(card.getORB() == 0);
|
|
249
|
+
REQUIRE(card.getCRA() == 0);
|
|
250
|
+
REQUIRE(card.getCRB() == 0);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// Reset
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
TEST_CASE("MouseCard reset clears state", "[mouse]") {
|
|
258
|
+
MouseCard card;
|
|
259
|
+
|
|
260
|
+
// Set up some state
|
|
261
|
+
card.addDelta(100, 200);
|
|
262
|
+
card.setMouseButton(true);
|
|
263
|
+
|
|
264
|
+
card.reset();
|
|
265
|
+
|
|
266
|
+
// After reset, position and button should be cleared
|
|
267
|
+
REQUIRE(card.getMouseX() == 0);
|
|
268
|
+
REQUIRE(card.getMouseY() == 0);
|
|
269
|
+
REQUIRE_FALSE(card.getMouseButton());
|
|
270
|
+
REQUIRE_FALSE(card.getMoved());
|
|
271
|
+
REQUIRE_FALSE(card.getButtonChanged());
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
TEST_CASE("MouseCard reset clears PIA registers", "[mouse]") {
|
|
275
|
+
MouseCard card;
|
|
276
|
+
|
|
277
|
+
// Write to PIA registers to set state
|
|
278
|
+
card.writeIO(0, 0xFF);
|
|
279
|
+
card.writeIO(1, 0xFF);
|
|
280
|
+
|
|
281
|
+
card.reset();
|
|
282
|
+
|
|
283
|
+
REQUIRE(card.getDDRA() == 0);
|
|
284
|
+
REQUIRE(card.getDDRB() == 0);
|
|
285
|
+
REQUIRE(card.getORA() == 0);
|
|
286
|
+
REQUIRE(card.getORB() == 0);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
// Serialization round-trip
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
|
|
293
|
+
TEST_CASE("MouseCard getStateSize is correct", "[mouse]") {
|
|
294
|
+
MouseCard card;
|
|
295
|
+
REQUIRE(card.getStateSize() == MouseCard::STATE_SIZE);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
TEST_CASE("MouseCard serialize/deserialize round-trip", "[mouse]") {
|
|
299
|
+
MouseCard card1;
|
|
300
|
+
|
|
301
|
+
// Set up some state
|
|
302
|
+
card1.addDelta(50, 75);
|
|
303
|
+
card1.setMouseButton(true);
|
|
304
|
+
|
|
305
|
+
int16_t xBefore = card1.getMouseX();
|
|
306
|
+
int16_t yBefore = card1.getMouseY();
|
|
307
|
+
bool btnBefore = card1.getMouseButton();
|
|
308
|
+
|
|
309
|
+
// Serialize
|
|
310
|
+
std::vector<uint8_t> buffer(card1.getStateSize());
|
|
311
|
+
size_t written = card1.serialize(buffer.data(), buffer.size());
|
|
312
|
+
REQUIRE(written > 0);
|
|
313
|
+
REQUIRE(written <= buffer.size());
|
|
314
|
+
|
|
315
|
+
// Deserialize
|
|
316
|
+
MouseCard card2;
|
|
317
|
+
size_t consumed = card2.deserialize(buffer.data(), written);
|
|
318
|
+
REQUIRE(consumed > 0);
|
|
319
|
+
|
|
320
|
+
// Verify state preserved
|
|
321
|
+
REQUIRE(card2.getMouseX() == xBefore);
|
|
322
|
+
REQUIRE(card2.getMouseY() == yBefore);
|
|
323
|
+
REQUIRE(card2.getMouseButton() == btnBefore);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ---------------------------------------------------------------------------
|
|
327
|
+
// Slot number
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
TEST_CASE("MouseCard default slot is 4", "[mouse]") {
|
|
331
|
+
MouseCard card;
|
|
332
|
+
REQUIRE(card.getSlotNumber() == 4);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
TEST_CASE("MouseCard setSlotNumber changes slot", "[mouse]") {
|
|
336
|
+
MouseCard card;
|
|
337
|
+
|
|
338
|
+
card.setSlotNumber(2);
|
|
339
|
+
REQUIRE(card.getSlotNumber() == 2);
|
|
340
|
+
|
|
341
|
+
card.setSlotNumber(7);
|
|
342
|
+
REQUIRE(card.getSlotNumber() == 7);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
// IRQ state
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
|
|
349
|
+
TEST_CASE("MouseCard isIRQActive is false initially", "[mouse]") {
|
|
350
|
+
MouseCard card;
|
|
351
|
+
REQUIRE_FALSE(card.isIRQActive());
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
// Update
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
|
|
358
|
+
TEST_CASE("MouseCard update does not crash", "[mouse]") {
|
|
359
|
+
MouseCard card;
|
|
360
|
+
card.update(100);
|
|
361
|
+
card.update(1000);
|
|
362
|
+
REQUIRE(true);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
// Mode
|
|
367
|
+
// ---------------------------------------------------------------------------
|
|
368
|
+
|
|
369
|
+
TEST_CASE("MouseCard initial mode is 0", "[mouse]") {
|
|
370
|
+
MouseCard card;
|
|
371
|
+
REQUIRE(card.getMode() == 0);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Debug accessors
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
|
|
378
|
+
TEST_CASE("MouseCard getLastCommand returns 0 initially", "[mouse]") {
|
|
379
|
+
MouseCard card;
|
|
380
|
+
REQUIRE(card.getLastCommand() == 0);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
TEST_CASE("MouseCard getResponseState returns 0 initially", "[mouse]") {
|
|
384
|
+
MouseCard card;
|
|
385
|
+
REQUIRE(card.getResponseState() == 0);
|
|
386
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* test_pascal.cpp - Unit tests for Apple Pascal filesystem parser
|
|
3
|
+
*
|
|
4
|
+
* Tests the Pascal filesystem reader including:
|
|
5
|
+
* - Format detection (isPascal)
|
|
6
|
+
* - Volume information parsing
|
|
7
|
+
* - Catalog reading
|
|
8
|
+
* - File data retrieval
|
|
9
|
+
* - File type mapping for viewer
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#define CATCH_CONFIG_MAIN
|
|
13
|
+
#include "catch.hpp"
|
|
14
|
+
|
|
15
|
+
#include "pascal.hpp"
|
|
16
|
+
#include "disk_image_builder.hpp"
|
|
17
|
+
|
|
18
|
+
#include <array>
|
|
19
|
+
#include <cstring>
|
|
20
|
+
#include <vector>
|
|
21
|
+
|
|
22
|
+
using namespace a2e;
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// isPascal - Format detection
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
TEST_CASE("isPascal returns true for valid Pascal image", "[pascal][detection]") {
|
|
29
|
+
test::PascalDiskBuilder builder("PASCAL");
|
|
30
|
+
REQUIRE(Pascal::isPascal(builder.data(), builder.size()));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
TEST_CASE("isPascal returns false for zeroed data", "[pascal][detection]") {
|
|
34
|
+
std::vector<uint8_t> zeroed(143360, 0x00);
|
|
35
|
+
REQUIRE_FALSE(Pascal::isPascal(zeroed.data(), zeroed.size()));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
TEST_CASE("isPascal returns false for too-small data", "[pascal][detection]") {
|
|
39
|
+
std::vector<uint8_t> small(512, 0x00);
|
|
40
|
+
REQUIRE_FALSE(Pascal::isPascal(small.data(), small.size()));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
TEST_CASE("isPascal returns false for null pointer", "[pascal][detection]") {
|
|
44
|
+
REQUIRE_FALSE(Pascal::isPascal(nullptr, 0));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// parseVolumeInfo - Volume information
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
TEST_CASE("parseVolumeInfo returns correct volume name", "[pascal][volume]") {
|
|
52
|
+
test::PascalDiskBuilder builder("MYDISC");
|
|
53
|
+
|
|
54
|
+
PascalVolumeInfo info;
|
|
55
|
+
bool result = Pascal::parseVolumeInfo(builder.data(), builder.size(), &info);
|
|
56
|
+
REQUIRE(result);
|
|
57
|
+
CHECK(std::string(info.volumeName) == "MYDISC");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
TEST_CASE("parseVolumeInfo returns correct total blocks", "[pascal][volume]") {
|
|
61
|
+
test::PascalDiskBuilder builder("TEST");
|
|
62
|
+
|
|
63
|
+
PascalVolumeInfo info;
|
|
64
|
+
bool result = Pascal::parseVolumeInfo(builder.data(), builder.size(), &info);
|
|
65
|
+
REQUIRE(result);
|
|
66
|
+
CHECK(info.totalBlocks == 280);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
TEST_CASE("parseVolumeInfo file count reflects added files", "[pascal][volume]") {
|
|
70
|
+
test::PascalDiskBuilder builder("TEST");
|
|
71
|
+
|
|
72
|
+
const uint8_t data1[] = "FIRST";
|
|
73
|
+
const uint8_t data2[] = "SECOND";
|
|
74
|
+
builder.addFile("FILE1", 2, data1, sizeof(data1)); // 2 = Code file
|
|
75
|
+
builder.addFile("FILE2", 3, data2, sizeof(data2)); // 3 = Text file
|
|
76
|
+
|
|
77
|
+
PascalVolumeInfo info;
|
|
78
|
+
bool result = Pascal::parseVolumeInfo(builder.data(), builder.size(), &info);
|
|
79
|
+
REQUIRE(result);
|
|
80
|
+
CHECK(info.fileCount == 2);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
TEST_CASE("parseVolumeInfo returns false for zeroed data", "[pascal][volume]") {
|
|
84
|
+
std::vector<uint8_t> zeroed(143360, 0x00);
|
|
85
|
+
PascalVolumeInfo info;
|
|
86
|
+
REQUIRE_FALSE(Pascal::parseVolumeInfo(zeroed.data(), zeroed.size(), &info));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// readCatalog - Catalog reading
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
TEST_CASE("readCatalog returns correct file count", "[pascal][catalog]") {
|
|
94
|
+
test::PascalDiskBuilder builder("TEST");
|
|
95
|
+
|
|
96
|
+
const uint8_t data[] = "HELLO PASCAL";
|
|
97
|
+
builder.addFile("GREETING", 3, data, sizeof(data)); // 3 = Text
|
|
98
|
+
|
|
99
|
+
PascalCatalogEntry entries[32];
|
|
100
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
101
|
+
REQUIRE(count == 1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
TEST_CASE("Catalog entry has correct filename", "[pascal][catalog]") {
|
|
105
|
+
test::PascalDiskBuilder builder("TEST");
|
|
106
|
+
|
|
107
|
+
const uint8_t data[] = "DATA";
|
|
108
|
+
builder.addFile("MYCODE", 2, data, sizeof(data)); // 2 = Code
|
|
109
|
+
|
|
110
|
+
PascalCatalogEntry entries[32];
|
|
111
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
112
|
+
REQUIRE(count == 1);
|
|
113
|
+
CHECK(std::string(entries[0].filename) == "MYCODE");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
TEST_CASE("Catalog entry has correct file type name", "[pascal][catalog]") {
|
|
117
|
+
test::PascalDiskBuilder builder("TEST");
|
|
118
|
+
|
|
119
|
+
const uint8_t data[] = "CONTENT";
|
|
120
|
+
builder.addFile("SOURCE", 3, data, sizeof(data)); // 3 = Text
|
|
121
|
+
|
|
122
|
+
PascalCatalogEntry entries[32];
|
|
123
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
124
|
+
REQUIRE(count == 1);
|
|
125
|
+
CHECK(entries[0].fileType == 3);
|
|
126
|
+
CHECK(std::string(entries[0].fileTypeName) == "TEXT");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
TEST_CASE("readCatalog with empty disk returns zero", "[pascal][catalog]") {
|
|
130
|
+
test::PascalDiskBuilder builder("EMPTY");
|
|
131
|
+
|
|
132
|
+
PascalCatalogEntry entries[32];
|
|
133
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
134
|
+
REQUIRE(count == 0);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
TEST_CASE("Multiple files in Pascal catalog", "[pascal][catalog]") {
|
|
138
|
+
test::PascalDiskBuilder builder("MULTI");
|
|
139
|
+
|
|
140
|
+
const uint8_t d1[] = "AAA";
|
|
141
|
+
const uint8_t d2[] = "BBB";
|
|
142
|
+
const uint8_t d3[] = "CCC";
|
|
143
|
+
builder.addFile("ALPHA", 3, d1, sizeof(d1)); // Text
|
|
144
|
+
builder.addFile("BETA", 2, d2, sizeof(d2)); // Code
|
|
145
|
+
builder.addFile("GAMMA", 5, d3, sizeof(d3)); // Data
|
|
146
|
+
|
|
147
|
+
PascalCatalogEntry entries[32];
|
|
148
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
149
|
+
REQUIRE(count == 3);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
TEST_CASE("Catalog entry has valid block range", "[pascal][catalog]") {
|
|
153
|
+
test::PascalDiskBuilder builder("TEST");
|
|
154
|
+
|
|
155
|
+
const uint8_t data[] = "BLOCK DATA";
|
|
156
|
+
builder.addFile("BLKFILE", 2, data, sizeof(data)); // Code
|
|
157
|
+
|
|
158
|
+
PascalCatalogEntry entries[32];
|
|
159
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
160
|
+
REQUIRE(count == 1);
|
|
161
|
+
CHECK(entries[0].startBlock >= 6); // First data block is after directory
|
|
162
|
+
CHECK(entries[0].nextBlock > entries[0].startBlock);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
TEST_CASE("Catalog entry fileSize is computed correctly", "[pascal][catalog]") {
|
|
166
|
+
test::PascalDiskBuilder builder("TEST");
|
|
167
|
+
|
|
168
|
+
// Create a file smaller than one block
|
|
169
|
+
std::vector<uint8_t> data(100, 0x42);
|
|
170
|
+
builder.addFile("SMALL", 5, data.data(), static_cast<int>(data.size()));
|
|
171
|
+
|
|
172
|
+
PascalCatalogEntry entries[32];
|
|
173
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
174
|
+
REQUIRE(count == 1);
|
|
175
|
+
CHECK(entries[0].fileSize == 100);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// readFile - File data retrieval
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
TEST_CASE("readFile retrieves correct data", "[pascal][readFile]") {
|
|
183
|
+
test::PascalDiskBuilder builder("TEST");
|
|
184
|
+
|
|
185
|
+
std::vector<uint8_t> fileData(64);
|
|
186
|
+
for (int i = 0; i < 64; i++) {
|
|
187
|
+
fileData[i] = static_cast<uint8_t>(i);
|
|
188
|
+
}
|
|
189
|
+
builder.addFile("SEQDATA", 5, fileData.data(), static_cast<int>(fileData.size()));
|
|
190
|
+
|
|
191
|
+
PascalCatalogEntry entries[32];
|
|
192
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
193
|
+
REQUIRE(count == 1);
|
|
194
|
+
|
|
195
|
+
std::vector<uint8_t> outBuf(1024, 0);
|
|
196
|
+
int bytesRead = Pascal::readFile(builder.data(), builder.size(),
|
|
197
|
+
&entries[0], outBuf.data(),
|
|
198
|
+
static_cast<int>(outBuf.size()));
|
|
199
|
+
REQUIRE(bytesRead > 0);
|
|
200
|
+
|
|
201
|
+
// Verify the data bytes match
|
|
202
|
+
for (int i = 0; i < 64; i++) {
|
|
203
|
+
INFO("Byte at offset " << i);
|
|
204
|
+
CHECK(outBuf[i] == static_cast<uint8_t>(i));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
TEST_CASE("readFile with code file type", "[pascal][readFile]") {
|
|
209
|
+
test::PascalDiskBuilder builder("TEST");
|
|
210
|
+
|
|
211
|
+
std::vector<uint8_t> codeData = {0xEA, 0xEA, 0x60, 0x00}; // NOP NOP RTS BRK
|
|
212
|
+
builder.addFile("PROG", 2, codeData.data(), static_cast<int>(codeData.size())); // 2 = Code
|
|
213
|
+
|
|
214
|
+
PascalCatalogEntry entries[32];
|
|
215
|
+
int count = Pascal::readCatalog(builder.data(), builder.size(), entries, 32);
|
|
216
|
+
REQUIRE(count == 1);
|
|
217
|
+
|
|
218
|
+
std::vector<uint8_t> outBuf(1024, 0);
|
|
219
|
+
int bytesRead = Pascal::readFile(builder.data(), builder.size(),
|
|
220
|
+
&entries[0], outBuf.data(),
|
|
221
|
+
static_cast<int>(outBuf.size()));
|
|
222
|
+
REQUIRE(bytesRead >= 4);
|
|
223
|
+
CHECK(outBuf[0] == 0xEA);
|
|
224
|
+
CHECK(outBuf[1] == 0xEA);
|
|
225
|
+
CHECK(outBuf[2] == 0x60);
|
|
226
|
+
CHECK(outBuf[3] == 0x00);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// mapFileTypeForViewer - File type mapping
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
TEST_CASE("mapFileTypeForViewer maps Text type", "[pascal][fileType]") {
|
|
234
|
+
// Pascal file type 3 = TEXT -> text viewer (0x00)
|
|
235
|
+
int viewerType = Pascal::mapFileTypeForViewer(3);
|
|
236
|
+
CHECK(viewerType == 0x00); // Text viewer
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
TEST_CASE("mapFileTypeForViewer maps Code type to hex dump", "[pascal][fileType]") {
|
|
240
|
+
// Pascal file type 2 = CODE -> not mapped (-1, hex dump)
|
|
241
|
+
int viewerType = Pascal::mapFileTypeForViewer(2);
|
|
242
|
+
CHECK(viewerType == -1);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
TEST_CASE("mapFileTypeForViewer returns -1 for unknown type", "[pascal][fileType]") {
|
|
246
|
+
int viewerType = Pascal::mapFileTypeForViewer(99);
|
|
247
|
+
CHECK(viewerType == -1);
|
|
248
|
+
}
|