OpenSpec-Review dokumentieren und ISAM-Vertragsabweichungen beheben

This commit is contained in:
2026-09-05 17:55:09 +02:00
parent 19804e0e2d
commit 57d6386a5a
61 changed files with 3087 additions and 86 deletions

View File

@@ -0,0 +1,30 @@
' tb-screen: 80x25
' tb-tempdir
' Alle Zugriffsarten teilen dieselben Nummern, auch nach CLOSE und RESET.
TYPE R
Nr AS INTEGER
END TYPE
ON ERROR GOTO Handler
OPEN "nummern.isam" FOR ISAM R "R" AS #1
PRINT "ISAM="; LTRIM$(STR$(FREEFILE))
OPEN "ausgabe.txt" FOR OUTPUT AS #2
OPEN "random.dat" FOR RANDOM AS #3 LEN = 8
OPEN "binary.dat" FOR BINARY AS #4
OPEN "ausgabe.txt" FOR INPUT AS #5
PRINT "gemischt="; LTRIM$(STR$(FREEFILE))
OPEN "doppelt.txt" FOR OUTPUT AS #1
OPEN "nummern.isam" FOR ISAM R "R" AS #2
CLOSE #3
PRINT "Luecke="; LTRIM$(STR$(FREEFILE))
OPEN "nummern.isam" FOR ISAM R "R" AS #3
PRINT "wiederbelegt="; LTRIM$(STR$(FREEFILE))
CLOSE #1
PRINT "ISAM frei="; LTRIM$(STR$(FREEFILE))
OPEN "binary.dat" FOR BINARY AS #1
PRINT "wiederbelegt="; LTRIM$(STR$(FREEFILE))
RESET
PRINT "RESET="; LTRIM$(STR$(FREEFILE))
END
Handler:
PRINT "ERR="; LTRIM$(STR$(ERR))
RESUME NEXT

View File

@@ -0,0 +1,9 @@
ISAM=2
gemischt=6
ERR=55
ERR=55
Luecke=3
wiederbelegt=6
ISAM frei=1
wiederbelegt=6
RESET=1

View File

@@ -0,0 +1,44 @@
' tb-screen: 80x25
' tb-tempdir
' Verzeichniswechsel und Pfadaliase duerfen Datenbanken nicht verwechseln.
TYPE R
Nr AS INTEGER
END TYPE
DIM r AS R
MKDIR "a"
MKDIR "b"
CHDIR "a"
OPEN "db" FOR ISAM R "R" AS #1
r.Nr = 1
INSERT #1, r
CLOSE
CHDIR "../b"
OPEN "db" FOR ISAM R "R" AS #1
PRINT "B neu="; LTRIM$(STR$(LOF(1)))
r.Nr = 2
INSERT #1, r
CLOSE
CHDIR "../a"
OPEN "db" FOR ISAM R "R" AS #1
PRINT "A="; LTRIM$(STR$(LOF(1)))
BEGINTRANS
r.Nr = 3
INSERT #1, r
OPEN "./db" FOR ISAM R "R" AS #2
PRINT "Alias="; LTRIM$(STR$(LOF(2)))
s% = SAVEPOINT
DELETETABLE "../a/db", "R"
PRINT "frei="; LTRIM$(STR$(FREEFILE))
ROLLBACK s%
OPEN "db" FOR ISAM R "R" AS #1
PRINT "restauriert="; LTRIM$(STR$(LOF(1)))
ROLLBACK ALL
PRINT "A rollback="; LTRIM$(STR$(LOF(1)))
CLOSE
CHDIR "../b"
OPEN "db" FOR ISAM R "R" AS #1
MOVEFIRST #1
RETRIEVE #1, r
PRINT "B Nr="; LTRIM$(STR$(r.Nr))
CLOSE
CHDIR ".."

View File

@@ -0,0 +1,7 @@
B neu=0
A=1
Alias=2
frei=1
restauriert=2
A rollback=1
B Nr=2

27
tests/compat/isamopen.bas Normal file
View File

@@ -0,0 +1,27 @@
' tb-screen: 80x25
' tb-tempdir
' Weitere Bindungen sehen dieselbe Transaktion; CLOSE schreibt nicht fest.
TYPE R
Nr AS INTEGER
END TYPE
DIM r AS R
ON ERROR GOTO Handler
OPEN "open.isam" FOR ISAM R "Alt" AS #1
BEGINTRANS
r.Nr = 1
INSERT #1, r
OPEN "open.isam" FOR ISAM R "Alt" AS #2
PRINT "sichtbar="; LTRIM$(STR$(LOF(2)))
OPEN "open.isam" FOR ISAM R "Neu" AS #3
INSERT #3, r
CLOSE
ROLLBACK ALL
OPEN "open.isam" FOR ISAM R "Alt" AS #1
PRINT "nach Ruecknahme="; LTRIM$(STR$(LOF(1)))
DELETETABLE "open.isam", "Neu"
CLOSE
PRINT "fertig"
END
Handler:
PRINT "ERR="; LTRIM$(STR$(ERR))
RESUME NEXT

View File

@@ -0,0 +1,4 @@
sichtbar=1
nach Ruecknahme=0
ERR=82
fertig

View File

@@ -0,0 +1,54 @@
' tb-screen: 80x25
' tb-tempdir
' Verschachtelte Sicherungspunkte nehmen Inhalt, Indizes und Tabellen zurueck.
TYPE R
Nr AS INTEGER
END TYPE
DIM r AS R
ON ERROR GOTO Handler
OPEN "struktur.isam" FOR ISAM R "R" AS #1
CREATEINDEX #1, "Nr", 1, "Nr"
r.Nr = 1
INSERT #1, r
BEGINTRANS
a% = SAVEPOINT
CREATEINDEX #1, "Neu", 0, "Nr"
b% = SAVEPOINT
DELETEINDEX #1, "Nr"
INSERT #1, r
CLOSE #1
ROLLBACK b%
OPEN "struktur.isam" FOR ISAM R "R" AS #1
PRINT "Saetze="; LTRIM$(STR$(LOF(1)))
SETINDEX #1, "Neu"
PRINT "Index="; GETINDEX$(1)
INSERT #1, r
CLOSE
DELETETABLE "struktur.isam", "R"
OPEN "struktur.isam" FOR ISAM R "R" AS #1
r.Nr = 9
INSERT #1, r
CLOSE
ROLLBACK a%
OPEN "struktur.isam" FOR ISAM R "R" AS #1
SETINDEX #1, "Neu"
SETINDEX #1, "Nr"
RETRIEVE #1, r
PRINT "wiederhergestellt="; LTRIM$(STR$(r.Nr))
c% = SAVEPOINT
r.Nr = 2
UPDATE #1, r
DELETE #1
INSERT #1, r
CLOSE
ROLLBACK c%
COMMITTRANS
OPEN "struktur.isam" FOR ISAM R "R" AS #1
SETINDEX #1, "Nr"
RETRIEVE #1, r
PRINT "nach COMMIT="; LTRIM$(STR$(r.Nr))
CLOSE
END
Handler:
PRINT "ERR="; LTRIM$(STR$(ERR))
RESUME NEXT

View File

@@ -0,0 +1,6 @@
Saetze=1
Index=Neu
ERR=86
ERR=83
wiederhergestellt=1
nach COMMIT=1

View File

@@ -0,0 +1,65 @@
//! Harte Frist auch für blockierende Bibliotheksaufrufe im Testprozess.
use std::sync::mpsc::{self, Sender};
use std::time::Duration;
pub struct Prozessfrist(Sender<()>);
impl Prozessfrist {
pub fn neu(name: &str, dauer: Duration) -> Self {
let (tx, rx) = mpsc::channel();
let name = name.to_string();
std::thread::spawn(move || {
if matches!(rx.recv_timeout(dauer), Err(mpsc::RecvTimeoutError::Timeout)) {
eprintln!("Prozessfrist überschritten: {name}");
// Auch ein in redb blockierter Test lässt sich so sicher beenden.
std::process::exit(124);
}
});
Self(tx)
}
}
impl Drop for Prozessfrist {
fn drop(&mut self) {
let _ = self.0.send(());
}
}
#[test]
fn frist_beendet_blockierten_testprozess() {
use std::process::{Command, Stdio};
use std::time::Instant;
const MARKER: &str = "TB_TEST_FRIST_KIND";
if std::env::var_os(MARKER).is_some() {
let _frist = Prozessfrist::neu("absichtlich blockiert", Duration::from_millis(100));
loop {
std::thread::park();
}
}
let mut child = Command::new(std::env::current_exe().unwrap())
.arg("frist_beendet_blockierten_testprozess")
.arg("--nocapture")
.current_dir(std::env::temp_dir())
.env(MARKER, "1")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let start = Instant::now();
loop {
if child.try_wait().unwrap().is_some() {
break;
}
if start.elapsed() > Duration::from_secs(5) {
let _ = child.kill();
let _ = child.wait();
panic!("Prozessfrist hat den blockierten Test nicht beendet");
}
std::thread::sleep(Duration::from_millis(10));
}
let out = child.wait_with_output().unwrap();
assert_eq!(out.status.code(), Some(124), "{out:?}");
assert!(String::from_utf8_lossy(&out.stderr).contains("absichtlich blockiert"));
}