Skip to content

Commit b9138ee

Browse files
committed
introduce testing of DOS internal API Int 2F/AH=12
1 parent d073436 commit b9138ee

16 files changed

Lines changed: 5821 additions & 0 deletions

File tree

‎tests/greatest.h‎

Lines changed: 1266 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/int2f-12/Makefile‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Makefile for INT 2F / AH=12h tests
2+
# Open Watcom 16-bit, real-mode DOS, small memory model
3+
#
4+
# Directory layout assumed:
5+
# tests/
6+
# greatest.h
7+
# testlib.h
8+
# testlib.c
9+
# int2f-12/
10+
# tNNNN.c
11+
# Makefile <- this file
12+
#
13+
# Usage:
14+
# wmake build all .exe files
15+
# wmake clean remove generated files
16+
# wmake ref run all tests in reference mode (writes *.ref)
17+
# wmake test run all tests in test mode (writes *.tst)
18+
19+
CC = wcl
20+
CFLAGS = -zq -q -ms -k4096
21+
INCLUDES= -i=..
22+
TESTLIB = ../testlib.c
23+
DEPS = ../testlib.c ../testlib.h ../greatest.h
24+
25+
# List of test executables (add new ones here as you implement them)
26+
EXES = t121f.com t121f.exe t1203.exe t1204.exe t1211.exe t1212.exe t1213.exe t1214.exe t121a.exe t121c.exe t121d.exe t1225.exe
27+
28+
all: $(EXES)
29+
30+
# Implicit suffix rule: any .c -> .exe in this directory
31+
# wmake uses this when no explicit rule exists for a target
32+
.c.exe: $(DEPS) .AUTODEPEND
33+
$(CC) $(CFLAGS) $(INCLUDES) $[*.c $(TESTLIB)
34+
35+
# MSDOS requires SS=DOSSTACK so we need to build special version, FD kernel does not need SS=DOSSTACK so use .exe version
36+
t121f.com:
37+
$(CC) -zq -q -mt -fpc $(INCLUDES) -dUSEDOSSTACK t121f.c $(TESTLIB)
38+
del testlib.obj
39+
40+
41+
# Reference mode: run on MS-DOS to generate golden .ref files
42+
ref: $(EXES)
43+
for %f in ($(EXES)) do %f ref
44+
45+
# Test mode: compare against .ref files, write .tst
46+
test: $(EXES)
47+
for %f in ($(EXES)) do %f test
48+
49+
clean: .SYMBOLIC
50+
@if exist *.obj del *.obj
51+
@if exist *.map del *.map
52+
@if exist *.err del *.err
53+
54+
clobber: clean .SYMBOLIC
55+
@if exist *.exe del *.exe
56+
@if exist *.ref del *.ref
57+
@if exist *.tst del *.tst
58+
@if exist *.txt del *.txt
59+
@if exist *.out del *.out

‎tests/int2f-12/RUNTEST.BAT‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@ECHO OFF
2+
ECHO Running test %1
3+
%1 ref > %2.txt
4+
REM above create a .REF and .TXT file
5+
%1 test > %2.out
6+
IF [%ERRORLEVEL%]==1 GOTO failed
7+
ECHO Success (all tests passed)
8+
GOTO done
9+
REM above creates a .TST and .OUT file
10+
REM 1st arg is test.exe 2nd arg is function
11+
:failed
12+
ECHO at least one test failed
13+
:done
14+

‎tests/int2f-12/t1203.c‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* t1203.c -- INT 2Fh / AX=1203h GET DOS DATA SEGMENT
3+
*
4+
* Expected: ES = DOS internal data segment
5+
* No register changes other than ES (and possibly AX)
6+
*/
7+
#include "../greatest.h"
8+
#include "../testlib.h"
9+
10+
const char * g_tbasename = "1203";
11+
12+
TEST test_1203(void)
13+
{
14+
PROBE p;
15+
memset(&p, 0, sizeof(p));
16+
p.before.ax = 0x1203;
17+
/* No special input registers needed for this subfunction */
18+
19+
probe_int2f(&p);
20+
21+
/* Record result -- actual assertion is the diff, not a hard value,
22+
but we can sanity-check that ES is nonzero (DOS is loaded) */
23+
print_probe_verbose(&p, "GET_DOS_DATA_SEG", -1);
24+
25+
ASSERT_FALSE(p.after.es == 0); /* ES must point somewhere */
26+
PASS();
27+
}
28+
29+
SUITE(suite)
30+
{
31+
test_1203();
32+
}

‎tests/int2f-12/t1204.c‎

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* t1204.c -- INT 2Fh / AX=1204h NORMALIZE PATH SEPARATOR
3+
*
4+
* RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1204.html):
5+
* AX = 1204h
6+
* STACK: WORD character to normalize
7+
* Return: AL = normalized character ('/' -> '\', others unchanged)
8+
* ZF set if character is a path separator ('\', '/', or SWITCHAR)
9+
* STACK unchanged
10+
*
11+
* NOTE ON CALLING CONVENTION:
12+
* This function is unique among INT 2Fh/12xx subfunctions: the input
13+
* character is passed as a WORD pushed onto the stack BEFORE the INT 2Fh,
14+
* not in any register.
15+
*
16+
* Care registers:
17+
* AL -- normalized character (CARE_AL)
18+
* ZF -- set iff path separator (CARE_ZF)
19+
* All other output registers are don't-cares.
20+
*
21+
* Two modes (see testlib.h):
22+
* ref REFERENCE: run all cases, write 1204.ref, verbose stdout
23+
* default / test TEST: read 1204.ref, run all cases, write 1204.tst
24+
*
25+
* Build:
26+
* wcl -zq -q -ms -i=.. t1204.c ..\testlib.c
27+
*
28+
* Usage:
29+
* T1204 ref (reference mode, writes 1204.ref)
30+
* T1204 test (test mode, reads 1204.ref, writes 1204.tst)
31+
*/
32+
33+
#include "../greatest.h"
34+
#include "../testlib.h"
35+
36+
#include <dos.h>
37+
#include <stdio.h>
38+
#include <string.h>
39+
40+
41+
const char *g_tbasename = "1204"; /* declared by test e.g. "1204" */
42+
43+
44+
/* ----
45+
* We care about AL (normalized char) and ZF (separator flag).
46+
* All other output registers are don't-cares.
47+
* ---- */
48+
#define CARE_1204 (CARE_AL | CARE_FLAGS)
49+
50+
51+
/* ------------------------------------------------------------------ */
52+
/* Helper: fill a PROBE for recording purposes. */
53+
/* after.ax low byte = AL result; after.flags = FLAGS result. */
54+
/* ------------------------------------------------------------------ */
55+
static void setup_1204(PROBE *p, unsigned char ch)
56+
{
57+
memset(p, 0, sizeof(*p));
58+
p->before.ax = 0x1204;
59+
p->before.cx = (unsigned short)ch; /* input char stored in CX for log */
60+
p->value = (unsigned short)ch;
61+
}
62+
63+
/* ------------------------------------------------------------------ */
64+
/* Core test runner for one character. */
65+
/* ------------------------------------------------------------------ */
66+
static int run_char_case(const char *name, unsigned char ch)
67+
{
68+
PROBE p;
69+
70+
setup_1204(&p, ch);
71+
72+
if (g_ref_mode) {
73+
printf("INPUT: ch=0x%02X ('%c')\n",
74+
(unsigned)ch,
75+
(ch >= 0x20 && ch < 0x7F) ? (char)ch : '.'
76+
);
77+
}
78+
79+
return run_case(name, &p, CARE_1204, NULL);
80+
}
81+
82+
/* ------------------------------------------------------------------ */
83+
/* Test suites */
84+
/* ------------------------------------------------------------------ */
85+
86+
/*
87+
* Path separator characters: '/', '\', and the default SWITCHAR '/'.
88+
* All must return AL='\' (5Ch) and ZF=1.
89+
*/
90+
TEST test_separators(void)
91+
{
92+
char name[TC_NAME_MAX];
93+
94+
/* Forward slash -- must be converted to backslash, ZF=1 */
95+
sprintf(name, "1204_fwdslash");
96+
ASSERT(run_char_case(name, '/'));
97+
98+
/* Backslash -- already canonical, ZF=1 */
99+
sprintf(name, "1204_backslash");
100+
ASSERT(run_char_case(name, '\\'));
101+
102+
PASS();
103+
}
104+
105+
/*
106+
* Non-separator printable ASCII characters: AL unchanged, ZF=0.
107+
*/
108+
TEST test_non_separators(void)
109+
{
110+
char name[TC_NAME_MAX];
111+
unsigned int ch;
112+
113+
/* Letters */
114+
sprintf(name, "1204_letter_A");
115+
ASSERT(run_char_case(name, 'A'));
116+
sprintf(name, "1204_letter_a");
117+
ASSERT(run_char_case(name, 'a'));
118+
sprintf(name, "1204_letter_Z");
119+
ASSERT(run_char_case(name, 'Z'));
120+
sprintf(name, "1204_letter_z");
121+
ASSERT(run_char_case(name, 'z'));
122+
123+
/* Digits */
124+
sprintf(name, "1204_digit_0");
125+
ASSERT(run_char_case(name, '0'));
126+
sprintf(name, "1204_digit_9");
127+
ASSERT(run_char_case(name, '9'));
128+
129+
/* Common filename chars */
130+
sprintf(name, "1204_dot");
131+
ASSERT(run_char_case(name, '.'));
132+
sprintf(name, "1204_colon");
133+
ASSERT(run_char_case(name, ':'));
134+
sprintf(name, "1204_space");
135+
ASSERT(run_char_case(name, ' '));
136+
sprintf(name, "1204_underscore");
137+
ASSERT(run_char_case(name, '_'));
138+
sprintf(name, "1204_dash");
139+
ASSERT(run_char_case(name, '-'));
140+
sprintf(name, "1204_tilde");
141+
ASSERT(run_char_case(name, '~'));
142+
sprintf(name, "1204_bang");
143+
ASSERT(run_char_case(name, '!'));
144+
sprintf(name, "1204_hash");
145+
ASSERT(run_char_case(name, '#'));
146+
sprintf(name, "1204_dollar");
147+
ASSERT(run_char_case(name, '$'));
148+
sprintf(name, "1204_percent");
149+
ASSERT(run_char_case(name, '%'));
150+
sprintf(name, "1204_ampersand");
151+
ASSERT(run_char_case(name, '&'));
152+
sprintf(name, "1204_at");
153+
ASSERT(run_char_case(name, '@'));
154+
155+
/* -All- printable ASCII except '/' and '\' */
156+
/* *** we only print some to avoid excessive tests */
157+
for (ch = 0x20; ch <= 0x7E; ch+=3) {
158+
if (ch == '/' || ch == '\\')
159+
continue;
160+
sprintf(name, "1204_ascii_0x%02X", ch);
161+
ASSERT(run_char_case(name, (unsigned char)ch));
162+
}
163+
164+
PASS();
165+
}
166+
167+
/*
168+
* Control characters and NUL: AL unchanged, ZF=0.
169+
*/
170+
TEST test_control_chars(void)
171+
{
172+
char name[TC_NAME_MAX];
173+
174+
sprintf(name, "1204_nul");
175+
ASSERT(run_char_case(name, 0x00));
176+
177+
sprintf(name, "1204_ctrl_01");
178+
ASSERT(run_char_case(name, 0x01));
179+
180+
sprintf(name, "1204_ctrl_1A_EOF"); /* Ctrl-Z / EOF */
181+
ASSERT(run_char_case(name, 0x1A));
182+
183+
sprintf(name, "1204_ctrl_1B_ESC"); /* ESC */
184+
ASSERT(run_char_case(name, 0x1B));
185+
186+
sprintf(name, "1204_ctrl_1F");
187+
ASSERT(run_char_case(name, 0x1F));
188+
189+
sprintf(name, "1204_del_7F");
190+
ASSERT(run_char_case(name, 0x7F));
191+
192+
PASS();
193+
}
194+
195+
/*
196+
* High-byte characters (0x80..0xFF): AL unchanged, ZF=0.
197+
* These are DOS codepage characters; none are path separators.
198+
*/
199+
TEST test_high_bytes(void)
200+
{
201+
char name[TC_NAME_MAX];
202+
unsigned int ch;
203+
204+
/* Spot-check a few */
205+
sprintf(name, "1204_high_80");
206+
ASSERT(run_char_case(name, 0x80));
207+
208+
sprintf(name, "1204_high_FE");
209+
ASSERT(run_char_case(name, 0xFE));
210+
211+
sprintf(name, "1204_high_FF");
212+
ASSERT(run_char_case(name, 0xFF));
213+
214+
/* Sweep 0x80..0xFF */
215+
/* *** we only print some to avoid excess tests */
216+
for (ch = 0x80; ch <= 0xFF; ch+=3) {
217+
sprintf(name, "1204_high_0x%02X", ch);
218+
ASSERT(run_char_case(name, (unsigned char)ch));
219+
}
220+
221+
PASS();
222+
}
223+
224+
/*
225+
* Boundary: characters immediately adjacent to '/' (0x2F) and '\' (0x5C).
226+
*/
227+
TEST test_adjacent_to_separators(void)
228+
{
229+
char name[TC_NAME_MAX];
230+
231+
sprintf(name, "1204_before_fwdslash"); /* 0x2E = '.' */
232+
ASSERT(run_char_case(name, 0x2E));
233+
234+
sprintf(name, "1204_after_fwdslash"); /* 0x30 = '0' */
235+
ASSERT(run_char_case(name, 0x30));
236+
237+
sprintf(name, "1204_before_backslash"); /* 0x5B = '[' */
238+
ASSERT(run_char_case(name, 0x5B));
239+
240+
sprintf(name, "1204_after_backslash"); /* 0x5D = ']' */
241+
ASSERT(run_char_case(name, 0x5D));
242+
243+
PASS();
244+
}
245+
246+
/* ------------------------------------------------------------------ */
247+
/* Suite -- called in main to run tests */
248+
/* ------------------------------------------------------------------ */
249+
250+
SUITE(suite)
251+
{
252+
RUN_TEST(test_separators);
253+
RUN_TEST(test_non_separators);
254+
RUN_TEST(test_control_chars);
255+
RUN_TEST(test_high_bytes);
256+
RUN_TEST(test_adjacent_to_separators);
257+
}

0 commit comments

Comments
 (0)