Wildcat: full SDK init (InitWCglobal + LoadMakeWild + BTInitIsam); test across 7 conferences

The TWildcatBase.OpenConference was creating a TMsgDatabase without
populating the SDK globals, causing access violations on MwConfig.
Now calls the full Register sequence: InitWCglobal, LoadMakeWild,
BTInitIsam before opening; BTExitIsam + DisposeWCglobal on close.

test_wildcat reads conferences 0..6 from vendored testdata (copied
to /tmp/ma_wildcat so the source tree stays read-only).
This commit is contained in:
2026-04-15 08:41:02 -07:00
parent c68a225ad9
commit d43f996604
4 changed files with 153 additions and 4 deletions

View File

@@ -2,7 +2,8 @@
## Sample data
Real message bases for testing live at `~/fidonet/msg/`:
Real message bases for testing live at `~/fidonet/msg/` and for
WildCat! at `~/allfix_dev/f_drive/tpfiles/allfix/wc_dev/testdata/`:
- `hudson/` — Hudson MSGINFO/IDX/HDR/TXT/TOIDX.BBS set
- `jam/` — many JAM echo areas (e.g. `10thamd.jhr/jdt/jdx/jlr`)
@@ -11,9 +12,16 @@ Real message bases for testing live at `~/fidonet/msg/`:
- `squish/` — Squish bases (currently empty but layout reserved)
- `local/jam/`, `lowerit/`, `passthru/` — additional collections
- WildCat 4 testdata:
- `CONFDESC.DAT/IX/UX` — conference descriptors (7 conferences)
- `MSG/MSG0..MSG6.DAT + .IX` — per-conference message databases
- `DATA/ALLUSERS.DAT + USERCONF.DAT` — users + per-user conference membership
Tests should open these read-only and verify message counts, first/last
messages, and specific known attributes. Do NOT write to these paths
from tests — copy them into a scratch dir first.
from tests — copy them into a scratch dir first. The Wildcat SDK
mutates the message database during Open (btis locks, modcounters) so
even "read" paths must go through a scratch copy.
## Authoritative specs

View File

@@ -19,7 +19,7 @@ compile() {
local src=$1
echo " compile $(basename "$src")"
"$FPCNATIVE" -Mobjfpc -Sh -Sgic \
-Fusrc -Fusrc/formats -Futests \
-Fusrc -Fusrc/formats -Fusrc/wc_sdk -Futests \
-FUunits/"$TGT" -FEexe/"$TGT" \
"$src" >/tmp/ma_test_build.$$.log 2>&1 || {
cat /tmp/ma_test_build.$$.log
@@ -41,6 +41,7 @@ compile tests/test_read.pas
compile tests/test_roundtrip.pas
compile tests/test_lock.pas
compile tests/test_batch.pas
compile tests/test_wildcat.pas
echo
echo "Running tests..."
@@ -48,6 +49,7 @@ run test_read
run test_roundtrip
run test_lock
run test_batch
run test_wildcat
echo
echo "All tests passed."

View File

@@ -48,7 +48,7 @@ interface
uses
WcType, WcMsgDb, WcUserDb, WcGlobal, WcMisc, WcDb,
Filer, BTISBase;
Filer, BTISBase, BTFileIO;
type
TWildcatBase = class
@@ -150,6 +150,24 @@ end;
{ --- Conference management --- }
function LoadMakeWild(var AMwConfig: TMakewildRec): boolean;
var
F: file of TMakewildRec;
SaveFileMode: word;
begin
Result := False;
Assign(F, 'MAKEWILD.DAT');
SaveFileMode := FileMode;
FileMode := 66; { deny-none share, read-write }
{$I-} Reset(F); {$I+}
FileMode := SaveFileMode;
if IoResult <> 0 then exit;
{$I-} Read(F, AMwConfig); {$I+}
Result := IoResult = 0;
{$I-} Close(F); {$I+}
if IoResult = 0 then {ignore};
end;
function TWildcatBase.OpenConference(Conf: word): boolean;
begin
Result := False;
@@ -158,6 +176,24 @@ begin
SaveAndChangeDir;
{ WC SDK globals must be populated before opening any database.
InitWCglobal allocates the pointers; LoadMakeWild fills MwConfig^
from MAKEWILD.DAT in the current dir; BtInitIsam brings up the
ISAM layer the message/user databases sit on. Done in
CloseConference. }
InitWCglobal;
if not LoadMakeWild(MwConfig^) then begin
DisposeWCglobal;
RestoreDir;
exit;
end;
BtInitIsam(NetSupportType(MwConfig^.Network), MinimizeUseOfNormalHeap, 0);
if not IsamOk then begin
DisposeWCglobal;
RestoreDir;
exit;
end;
New(FMsgDb, Init);
New(FUserDb, Init);
@@ -170,6 +206,8 @@ begin
FUserDb := nil;
if FMsgDb <> nil then Dispose(FMsgDb);
FMsgDb := nil;
BtExitIsam;
DisposeWCglobal;
RestoreDir;
end;
end;
@@ -190,6 +228,8 @@ begin
FUserDb := nil;
end;
BtExitIsam;
DisposeWCglobal;
RestoreDir;
end;

99
tests/test_wildcat.pas Normal file
View File

@@ -0,0 +1,99 @@
{
test_wildcat.pas - WildCat! 4 adapter smoke test.
The WC SDK opens databases for write (btis lock, modcounter
bumps) even when the caller only reads, so we never touch the
source tree directly. This test copies the whole testdata
directory to a scratch location first, runs the adapter there,
then leaves the scratch alone for manual inspection.
Source lives at
~/allfix_dev/f_drive/tpfiles/allfix/wc_dev/testdata/
and is NEVER modified.
}
program test_wildcat;
{$mode objfpc}{$H+}
uses
SysUtils,
testutil,
ma.types, ma.events, ma.api,
ma.fmt.wildcat, ma.fmt.wildcat.uni;
const
SRC = '/home/ken/allfix_dev/f_drive/tpfiles/allfix/wc_dev/testdata';
SCRATCH = '/tmp/ma_wildcat';
function RunShell(const Cmd: string): integer;
begin
Result := ExecuteProcess('/bin/sh', ['-c', Cmd]);
end;
function CopyTree(const Source, Dest: string): boolean;
var
cmd: string;
begin
cmd := SysUtils.Format('cp -r "%s"/. "%s"/ 2>/dev/null', [Source, Dest]);
Result := RunShell(cmd) = 0;
end;
procedure PrepareScratch;
begin
if DirectoryExists(SCRATCH) then
RunShell(SysUtils.Format('rm -rf "%s"', [SCRATCH]));
ForceDirectories(SCRATCH);
if not CopyTree(SRC, SCRATCH) then
raise Exception.Create('cp -r failed');
end;
procedure TestConference(Conf: word);
var
base: TMessageBase;
adapter: TWildcatMessageBase;
msg: TUniMessage;
i, count, ok: longint;
begin
TestBegin(SysUtils.Format('WildCat! conference %d', [Conf]));
base := MessageBaseOpen(mbfWildcat, SCRATCH, momReadWrite);
adapter := base as TWildcatMessageBase;
adapter.Conference := Conf;
try
AssertTrue('Open', base.Open);
count := base.MessageCount;
ok := 0;
for i := 0 to count - 1 do
if base.ReadMessage(i, msg) then begin
Inc(ok);
if i = 0 then
AssertTrue('First msg has sender',
Length(msg.WhoFrom) > 0);
end;
AssertEquals('Read all reported messages', count, ok);
finally
base.Close;
base.Free;
end;
TestOK;
end;
var
conf: word;
begin
WriteLn('message_api: WildCat! 4 read tests');
WriteLn;
if not DirectoryExists(SRC) then begin
WriteLn('SKIP (sample at ', SRC, ' missing)');
Halt(0);
end;
PrepareScratch;
{ testdata has conferences 0..6. Walk each one. }
for conf := 0 to 6 do
TestConference(conf);
Halt(TestsSummary);
end.