Laufzeit-Eingabe und Zonenzustand korrigieren und Change archivieren
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## Why
|
||||
|
||||
Die Laufzeit verwirft INPUT-Felder, liest INPUT$ mit falscher Zeichenzählung und weicht bei CV-Längen sowie Dateifehlern ab. Zusätzlich fehlt die spezifizierte BASIC-Abfrage des Zeitzonenrückfalls (F14–F17/F19). Siehe [Review vom 05.09.2026](../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
Die Laufzeit verwirft INPUT-Felder, liest INPUT$ mit falscher Zeichenzählung und weicht bei CV-Längen sowie Dateifehlern ab. Zusätzlich fehlt die spezifizierte BASIC-Abfrage des Zeitzonenrückfalls (F14–F17/F19). Siehe [Review vom 05.09.2026](../../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
|
||||
## What Changes
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
//! Unabhängige Reviewproben, 06.09.2026. Als Rust-Testbinary gegen tb-vm/tb-runtime.
|
||||
use std::{path::PathBuf, rc::Rc};
|
||||
use tb_runtime::{
|
||||
builtins::{builtin_table, ids, RtState},
|
||||
datetime::Zeitzone,
|
||||
host::{CaptureHost, Ereignis},
|
||||
value::Value,
|
||||
};
|
||||
use tb_vm::{
|
||||
bytecode::CompiledModule,
|
||||
interp::{RunEvent, Vm},
|
||||
};
|
||||
|
||||
struct Temp(PathBuf);
|
||||
impl Temp {
|
||||
fn new(name: &str) -> Self {
|
||||
let p =
|
||||
std::env::temp_dir().join(format!("tb_runtime_review_{name}_{}", std::process::id()));
|
||||
std::fs::create_dir_all(&p).unwrap();
|
||||
Self(p)
|
||||
}
|
||||
fn file(&self) -> String {
|
||||
self.0.join("data.txt").to_str().unwrap().to_owned()
|
||||
}
|
||||
}
|
||||
impl Drop for Temp {
|
||||
fn drop(&mut self) {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
fn text(vm: &Vm, name: &str) -> String {
|
||||
match vm.inspect(name).unwrap() {
|
||||
Value::Str(s) => s.to_string(),
|
||||
other => panic!("{other:?}"),
|
||||
}
|
||||
}
|
||||
fn expr(s: &str) -> String {
|
||||
let escaped = s
|
||||
.replace('"', "\"\"")
|
||||
.replace('\r', "\" + CHR$(13) + \"")
|
||||
.replace('\n', "\" + CHR$(10) + \"")
|
||||
.replace('\0', "\" + CHR$(0) + \"");
|
||||
format!("\"{escaped}\"")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_input_roundtrip_string_matrix() {
|
||||
let tmp = Temp::new("roundtrip");
|
||||
let p = tmp.file();
|
||||
let parts = ["", "a", " ", "\t", "\"", ",", "\r\n", "ä😀", "\0", "\u{a0}"];
|
||||
for a in parts {
|
||||
for b in parts {
|
||||
let expected = format!("{a}{b}");
|
||||
let src = format!("OPEN \"{p}\" FOR OUTPUT AS #1\nWRITE #1, {}, \"next\"\nCLOSE\nOPEN \"{p}\" FOR INPUT AS #1\nINPUT #1, got$\nINPUT #1, next$\nEND", expr(&expected));
|
||||
let mut vm = Vm::new(tb_vm::compile_source("REVIEW", &src).unwrap());
|
||||
assert_eq!(
|
||||
vm.run(&mut CaptureHost::default()),
|
||||
RunEvent::Ended,
|
||||
"{expected:?}"
|
||||
);
|
||||
assert_eq!(text(&vm, "got"), expected);
|
||||
assert_eq!(text(&vm, "next"), "next");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_nine_file_read_transitions() {
|
||||
let tmp = Temp::new("transitions");
|
||||
let p = tmp.file();
|
||||
for first in 0..3 {
|
||||
for second in 0..3 {
|
||||
std::fs::write(&p, "ä,😀\r\nZ").unwrap();
|
||||
let statement = |mode, variable| match mode {
|
||||
0 => format!("INPUT #1, {variable}$"),
|
||||
1 => format!("{variable}$ = INPUT$(1, #1)"),
|
||||
_ => format!("LINE INPUT #1, {variable}$"),
|
||||
};
|
||||
let src = format!(
|
||||
"OPEN \"{p}\" FOR INPUT AS #1\n{}\n{}\nEND",
|
||||
statement(first, "a"),
|
||||
statement(second, "b")
|
||||
);
|
||||
let mut vm = Vm::new(tb_vm::compile_source("REVIEW", &src).unwrap());
|
||||
assert_eq!(vm.run(&mut CaptureHost::default()), RunEvent::Ended);
|
||||
assert_eq!(text(&vm, "a"), if first == 2 { "ä,😀" } else { "ä" });
|
||||
let expected = match (first, second) {
|
||||
(0, _) => "😀",
|
||||
(1, 0) => "",
|
||||
(1, 1) => ",",
|
||||
(1, 2) => ",😀",
|
||||
_ => "Z",
|
||||
};
|
||||
assert_eq!(text(&vm, "b"), expected, "transition {first}/{second}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_mk_cv_pair_preserves_target_values_and_width() {
|
||||
let mut st = RtState::default();
|
||||
let mut host = CaptureHost::default();
|
||||
let cases = [
|
||||
(0, Value::Int(i16::MIN)),
|
||||
(0, Value::Int(i16::MAX)),
|
||||
(1, Value::Lng(i32::MIN)),
|
||||
(1, Value::Lng(i32::MAX)),
|
||||
(2, Value::Sng(-0.0)),
|
||||
(2, Value::Sng(f32::MAX)),
|
||||
(3, Value::Dbl(-0.0)),
|
||||
(3, Value::Dbl(f64::MIN_POSITIVE)),
|
||||
(4, Value::Cur(i64::MIN)),
|
||||
(4, Value::Cur(i64::MAX)),
|
||||
];
|
||||
for (kind, value) in cases {
|
||||
let encoded = builtin_table()[ids::MK_S as usize](
|
||||
&mut st,
|
||||
&mut host,
|
||||
&mut [value.clone(), Value::Lng(kind)],
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let decoded = builtin_table()[ids::CV_F as usize](
|
||||
&mut st,
|
||||
&mut host,
|
||||
&mut [encoded.clone(), Value::Lng(kind)],
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
match (&value, &decoded) {
|
||||
(Value::Int(a), Value::Int(b)) => assert_eq!(a, b),
|
||||
(Value::Lng(a), Value::Lng(b)) => assert_eq!(a, b),
|
||||
(Value::Cur(a), Value::Cur(b)) => assert_eq!(a, b),
|
||||
(Value::Sng(a), Value::Sng(b)) => assert_eq!(a.to_bits(), b.to_bits()),
|
||||
(Value::Dbl(a), Value::Dbl(b)) => assert_eq!(a.to_bits(), b.to_bits()),
|
||||
_ => panic!("{value:?} -> {decoded:?}"),
|
||||
}
|
||||
let Value::Str(encoded) = encoded else {
|
||||
panic!()
|
||||
};
|
||||
let len = encoded.chars().count();
|
||||
for wrong in [
|
||||
encoded.chars().take(len - 1).collect::<String>(),
|
||||
format!("{encoded}\0"),
|
||||
] {
|
||||
let err = builtin_table()[ids::CV_F as usize](
|
||||
&mut st,
|
||||
&mut host,
|
||||
&mut [Value::Str(Rc::from(wrong)), Value::Lng(kind)],
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(err.0, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timezoneknown_survives_tbc_and_source_failure_recovery() {
|
||||
thread_local! { static ZONE: std::cell::Cell<Option<i32>> = const { std::cell::Cell::new(None) }; }
|
||||
let module = tb_vm::compile_source(
|
||||
"REVIEW",
|
||||
"a% = TIMEZONEKNOWN\nSTOP\nb% = TIMEZONEKNOWN\nSTOP\nc% = TIMEZONEKNOWN\nEND",
|
||||
)
|
||||
.unwrap();
|
||||
let mut vm = Vm::new(CompiledModule::from_tbc(&module.to_tbc()).unwrap());
|
||||
vm.rt.zonen_ermittler = |_| ZONE.get();
|
||||
let mut host = CaptureHost::default();
|
||||
for (name, zone, expected) in [("a", Some(3600), -1), ("b", None, 0), ("c", Some(0), -1)] {
|
||||
ZONE.set(zone);
|
||||
let ev = vm.run(&mut host);
|
||||
assert!(matches!(ev, RunEvent::Stopped { .. } | RunEvent::Ended));
|
||||
assert!(matches!(vm.inspect(name), Some(Value::Int(n)) if n == expected));
|
||||
assert_eq!(vm.rt.zeitzone, Zeitzone::System);
|
||||
assert_eq!(vm.rt.uhr_offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn successive_function_keys_are_split_in_order() {
|
||||
let module = tb_vm::compile_source(
|
||||
"REVIEW",
|
||||
"a$ = INPUT$(3)\nb$ = INPUT$(1)\nc$ = INPUT$(1)\nEND",
|
||||
)
|
||||
.unwrap();
|
||||
let mut vm = Vm::new(module);
|
||||
let mut host = CaptureHost::default();
|
||||
for s in ["\0;", "\0<", "😀"] {
|
||||
host.ereignis(Ereignis::Taste(s.into(), 0));
|
||||
}
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert_eq!(text(&vm, "a"), "\0;\0");
|
||||
assert_eq!(text(&vm, "b"), "<");
|
||||
assert_eq!(text(&vm, "c"), "😀");
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
# Verification Report: laufzeit-eingabe-und-systemstatus
|
||||
|
||||
Erneute Prüfung am 06.09.2026. Grundlage ist der aktuelle, noch uncommittete
|
||||
Arbeitsbaum auf `815825dde76eb8f4b48cb27d83f21732afe707c2`. Die Aussage aus
|
||||
`verification.md` wurde gegen Proposal, Design, Tasks, alle vier Delta-Specs,
|
||||
die tatsächlichen Aufrufpfade und zusätzlich erstellte Reviewproben geprüft.
|
||||
|
||||
## Summary
|
||||
|
||||
| Dimension | Ergebnis |
|
||||
|---|---|
|
||||
| Vollständigkeit | 6/6 Tasks abgeschlossen; 6 Requirements mit 21 Szenarien abgeglichen |
|
||||
| Korrektheit | 463 Workspace-Tests und 5 unabhängige Reviewproben bestanden |
|
||||
| Kohärenz | D1–D4 eingehalten; gemeinsame Dateileseposition, Codepoint-/Byte-Trennung, Pfadfehler und aktuelle Zonenauflösung |
|
||||
| CRITICAL | 0 |
|
||||
| WARNING | 0 |
|
||||
| SUGGESTION | 0 |
|
||||
|
||||
**Keine offenen Befunde im geprüften Change.** Die vorhandene
|
||||
[Szenariozuordnung](verification.md#szenarien-und-ausführbare-nachweise)
|
||||
ist durch die erneute Codeprüfung und den aktuellen Testlauf bestätigt.
|
||||
|
||||
## Zusätzliche unabhängige Proben
|
||||
|
||||
[review-probes.rs](review-probes.rs) wurde separat mit `rustc --test` gegen
|
||||
die aktuell gebauten `tb_vm`- und `tb_runtime`-Bibliotheken aus
|
||||
`target/debug/deps` übersetzt und ausgeführt. Alle fünf Tests bestanden.
|
||||
Die Proben wurden nicht aus den vorhandenen Tests kopiert.
|
||||
|
||||
| Probe | Abdeckung / Ergebnis |
|
||||
|---|---|
|
||||
| `write_input_roundtrip_string_matrix` | 100 Kombinationen aus leeren Strings, ASCII, Leerzeichen, Tab, Anführungszeichen, Komma, CRLF, ä/Emoji, NUL und geschütztem Leerzeichen: WRITE und zwei folgende INPUT-#-Aufrufe erhalten Inhalt und nächstes Feld exakt |
|
||||
| `all_nine_file_read_transitions` | Sämtliche 3×3 Übergänge zwischen INPUT #, INPUT$ und LINE INPUT # auf derselben UTF-8-/CRLF-Datei liefern den erwarteten Cursorfortschritt |
|
||||
| `every_mk_cv_pair_preserves_target_values_and_width` | INTEGER-/LONG-/CURRENCY-Grenzen, negative Null und Fließkomma-Grenzwerte bleiben typ- und bitgetreu; jeweils zu kurze und zu lange Argumente erzeugen Fehler 5 |
|
||||
| `timezoneknown_survives_tbc_and_source_failure_recovery` | Neuer Builtin über Kompilat-Speicherung und -Laden ausführbar; derselbe Resolver wechselt bekannt → ausgefallen → bekannte UTC. BASIC liefert INTEGER -1/0/-1; Zonenquelle und Programmversatz bleiben unverändert |
|
||||
| `successive_function_keys_are_split_in_order` | Zwei aufeinanderfolgende erweiterte Tasten und Emoji werden durch INPUT$(3), INPUT$(1), INPUT$(1) ohne Verlust oder Umordnung gelesen |
|
||||
|
||||
Statisch zusätzlich abgeglichen: gemeinsame Leser-/SEEK-/EOF-Aufrufpfade,
|
||||
Binärzugriff nach Einführung von BufReader, beide INPUT$-Dispatchwege,
|
||||
Trap-Behandlung bereits angenommener Reste, alle fünf CV-Zieltypen,
|
||||
OPEN/KILL/NAME/MKDIR-Fehlerzuordnung sowie Frontend/HIR/Builtin-ID/CLI
|
||||
und alle Zeitfunktionen einschließlich der Zuweisungen an DATE$/TIME$.
|
||||
Die neue Builtin-ID wird angehängt; bestehende IDs werden nicht verschoben.
|
||||
|
||||
## Erneut ausgeführte Abnahme
|
||||
|
||||
- `cargo test --workspace --quiet`: **463 bestanden, 0 fehlgeschlagen,
|
||||
1 ignoriert**; der Golden-Generator blieb ignoriert.
|
||||
- Separate Reviewproben: **5 bestanden, 0 fehlgeschlagen**.
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
|
||||
- `cargo fmt --all -- --check`: bestanden.
|
||||
- `git diff --check`: bestanden vor dem Staging. Die abschließende
|
||||
Prüfung des gestagten Changes mit `git diff --cached --check -- .
|
||||
':(exclude)tests/compat/*.out'` besteht ebenfalls. Die neuen `.out`-Dateien
|
||||
enthalten absichtlich signifikante PRINT-Leerzeichen am Zeilenende.
|
||||
- `openspec validate laufzeit-eingabe-und-systemstatus --strict`: bestanden.
|
||||
- `openspec status` und `openspec instructions apply`: Planung vollständig,
|
||||
6/6 Tasks, `all_done`. Die Häkchen wurden gegen Code und Tests geprüft.
|
||||
- Keine bestehenden Korpus-Sollausgaben verändert; die drei neuen
|
||||
Eingabe-/Zonenprogramme bestehen im regulären Korpuslauf jeweils zweimal.
|
||||
|
||||
Während dieser Verifikation wurden nur dieser Bericht und die zusätzlichen
|
||||
Reviewproben angelegt. Produktcode, bestehende Tests und Sollausgaben blieben
|
||||
unverändert. Headless auf macOS geprüft; kein neuer Windows-/Linux-Lauf oder
|
||||
interaktiver Fremdprogrammvergleich. Die Prüfung betrifft diesen Change und
|
||||
ersetzt nicht den noch offenen übergreifenden Spezifikationsabgleich.
|
||||
|
||||
Alle Prüfungen bestanden. Der Change ist zur Synchronisierung und
|
||||
anschließenden Archivierung bereit.
|
||||
|
||||
## Archivabschluss
|
||||
|
||||
Am 06.09.2026 wurden alle sechs Delta-Requirements mit den vier Hauptspecs
|
||||
synchronisiert und vollständig abgeglichen. Alle 15 Hauptspecs bestehen
|
||||
die strenge Validierung. Der Change wurde anschließend einschließlich
|
||||
der fünf Reviewproben archiviert.
|
||||
@@ -1,14 +1,14 @@
|
||||
## 1. Eingabe und Recordfunktionen
|
||||
|
||||
- [ ] 1.1 Fortlaufenden INPUT-#-Lesefortschritt implementieren; verifizieren mit zwei Einzelreads nach WRITE zweier Felder, mehreren Zeilen, Quotes/Kommas und Fehler 62 bei zu wenigen Feldern.
|
||||
- [ ] 1.2 INPUT$ auf exakt n Codepoints führen und Reste erhalten; verifizieren mit F1 und zwei INPUT$(1)-Aufrufen, UTF-8 ä/Emoji aus Datei, gemischten Lesearten und EOF.
|
||||
- [ ] 1.3 CV-Zielbreiten exakt prüfen; verifizieren mit allen fünf MK/CV-Paaren und jeweils zu kurzen/passenden/zu langen Argumenten.
|
||||
- [ ] 1.4 Datei-/Elternpfadfehler unterscheiden; verifizieren mit fehlender Datei in vorhandenem Verzeichnis, fehlendem Elternpfad und bestehenden erfolgreichen Dateisystemfällen.
|
||||
- [x] 1.1 Fortlaufenden INPUT-#-Lesefortschritt implementieren; verifizieren mit zwei Einzelreads nach WRITE zweier Felder, mehreren Zeilen, Quotes/Kommas und Fehler 62 bei zu wenigen Feldern.
|
||||
- [x] 1.2 INPUT$ auf exakt n Codepoints führen und Reste erhalten; verifizieren mit F1 und zwei INPUT$(1)-Aufrufen, UTF-8 ä/Emoji aus Datei, gemischten Lesearten und EOF.
|
||||
- [x] 1.3 CV-Zielbreiten exakt prüfen; verifizieren mit allen fünf MK/CV-Paaren und jeweils zu kurzen/passenden/zu langen Argumenten.
|
||||
- [x] 1.4 Datei-/Elternpfadfehler unterscheiden; verifizieren mit fehlender Datei in vorhandenem Verzeichnis, fehlendem Elternpfad und bestehenden erfolgreichen Dateisystemfällen.
|
||||
|
||||
## 2. Zonenzustand
|
||||
|
||||
- [ ] 2.1 TIMEZONEKNOWN durch Frontend, HIR, Dispatch und Inventar ergänzen und dynamischen Rückfall sichtbar halten; verifizieren mit ermittelter Zone, UTC-Rückfall, späterem Ausfall/Wiederherstellung und unverändertem DATE$/TIME$/NOW/TIMER-Versatz.
|
||||
- [x] 2.1 TIMEZONEKNOWN durch Frontend, HIR, Dispatch und Inventar ergänzen und dynamischen Rückfall sichtbar halten; verifizieren mit ermittelter Zone, UTC-Rückfall, späterem Ausfall/Wiederherstellung und unverändertem DATE$/TIME$/NOW/TIMER-Versatz.
|
||||
|
||||
## 3. Abnahme
|
||||
|
||||
- [ ] 3.1 Sprach-/Bibliotheksreferenz und Eingabe-/Zonenkorpus ergänzen; verifizieren mit cargo test --workspace, unveränderten vorhandenen Snapshots und openspec validate laufzeit-eingabe-und-systemstatus --strict.
|
||||
- [x] 3.1 Sprach-/Bibliotheksreferenz und Eingabe-/Zonenkorpus ergänzen; verifizieren mit cargo test --workspace, unveränderten vorhandenen Snapshots und openspec validate laufzeit-eingabe-und-systemstatus --strict.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Implementierungs- und Verifikationsnachweis
|
||||
|
||||
Change: `laufzeit-eingabe-und-systemstatus`, Stand 06.09.2026.
|
||||
Grundlage: Arbeitsbaum auf `815825dde76eb8f4b48cb27d83f21732afe707c2`;
|
||||
Proposal, Design, vier Delta-Specs und alle sechs Tasks abgeglichen.
|
||||
|
||||
## Ergebnis
|
||||
|
||||
| Dimension | Ergebnis |
|
||||
|---|---|
|
||||
| Vollständigkeit | 6/6 Tasks, 6/6 Requirements, 21/21 Szenarien abgeglichen |
|
||||
| Korrektheit | Alle zugeordneten Regressionen und Workspace-Tests bestanden |
|
||||
| Kohärenz | D1–D4 umgesetzt; keine zusätzlichen Dependencies |
|
||||
| Offene Befunde | 0 CRITICAL, 0 WARNING, 0 SUGGESTION im Change |
|
||||
|
||||
F14–F17 und F19 sind umgesetzt. Die vier Hauptspecs wurden am 06.09.2026
|
||||
synchronisiert und alle 15 Hauptspecs streng validiert. Der Change ist unter
|
||||
`openspec/changes/archive/2026-09-06-laufzeit-eingabe-und-systemstatus` archiviert.
|
||||
|
||||
## Umsetzung und Design
|
||||
|
||||
- **D1:** `Datei` verwendet einen `BufReader<File>` für den gemeinsamen Cursor.
|
||||
`feld_lesen`, `zeile_lesen`, `zeichen_lesen`, EOF und SEEK erhalten den
|
||||
Lesefortschritt. INPUT # liest einzelne Felder statt vollständiger Zeilen;
|
||||
fehlende Felder erzeugen Fehler 62. Dekodierte Strings werden in der VM
|
||||
nicht erneut von Anführungszeichen oder Rand-Leerraum befreit.
|
||||
- **D2:** INPUT$ zählt UTF-8-Codepoints. Beschädigte oder abgeschnittene
|
||||
UTF-8-Sequenzen führen zu Fehler 57; EOF vor einem geforderten Zeichen
|
||||
zu Fehler 62. Ein bereits angenommener Tastaturrest wird vor weiteren
|
||||
Tasten geliefert und nicht nochmals als Trap-/Forms-Ereignis eingereiht.
|
||||
Direkter Builtin-Dispatch und resumierbare VM-Eingabe verwenden dieselbe
|
||||
Aufteilung. Alle fünf CV-Funktionen prüfen exakte Breite und Bytezeichen.
|
||||
GET/PUT und UTF-32-Recorddarstellung bleiben eigenständige Binärpfade.
|
||||
- **D3:** `fehler_am_pfad` unterscheidet fehlenden Dateieintrag (53) von
|
||||
fehlendem Elternverzeichnis (76) bei OPEN, KILL, NAME und MKDIR.
|
||||
Vorhandene Berechtigungs-/Existenzfehler bleiben erhalten; ein Pfadbestandteil,
|
||||
der kein Verzeichnis ist, wird ebenfalls als Pfadfehler eingeordnet.
|
||||
- **D4:** TIMEZONEKNOWN ist als parameterlose INTEGER-Funktion durch Semantik,
|
||||
HIR, Codegenerator, stabile neue Builtin-ID 156 und Dispatch geführt.
|
||||
`RtState::zeitpunkt` löst Zeit und Status gemeinsam auf. Die Systemquelle
|
||||
bleibt nach Ausfällen aktiv, sodass spätere Erholung sichtbar wird.
|
||||
Tests können die Zonenquelle ersetzen, ohne die Rechnerzone zu verändern.
|
||||
Programmversatz, monotone Ereigniszeit und Betriebssystemuhr werden durch
|
||||
die Statusabfrage nicht verändert. CLI-Startwarnung und Inventar sind angepasst.
|
||||
|
||||
## Szenarien und ausführbare Nachweise
|
||||
|
||||
Testnamen ohne Präfix stehen in `crates/tb-vm/tests/vm.rs`. `runtime` meint
|
||||
`crates/tb-runtime/src/builtins.rs`, `frontend` die Semantik bzw. Inventartests.
|
||||
Die Korpusprogramme liegen in `tests/compat`; der Harness führt jedes zweimal
|
||||
gegen seine festgeschriebene Sollausgabe aus.
|
||||
|
||||
| Requirement / Szenario | Nachweis |
|
||||
|---|---|
|
||||
| Sequenzielle Datenübertragung: WRITE # und INPUT # sind gegenläufig | `input_datei_bewahrt_felder_und_unterscheidet_leer_von_fehlend`; `eingabefortschritt.bas` |
|
||||
| Lesen über das Dateiende | Derselbe Test: leere Datei, fehlendes zweites Feld und EOF; `input_datei_alle_lesearten_teilen_utf8_cursor_und_seek` |
|
||||
| Felder über zwei Aufrufe | `input_datei_bewahrt_felder_und_unterscheidet_leer_von_fehlend`: WRITE a/b, anschließende getrennte Reads |
|
||||
| Zu wenige Felder | Derselbe Test: mit/ohne finales Zeilenende Fehler 62; explizit leere Felder bleiben lesbar |
|
||||
| Record-Konvertierungen: MK und CV sind gegenläufig | `alle_mk_cv_paare_verlangen_exakte_bytezeichenbreite`: alle fünf Paare |
|
||||
| Falsche Argumentlänge | Derselbe Test: jeweils Zielbreite minus ein Zeichen → Fehler 5 |
|
||||
| Zu langes CVI-Argument | Derselbe Test: jeweils Zielbreite plus ein Zeichen → Fehler 5; zusätzlich Nicht-Bytezeichen |
|
||||
| Dateisystem: Rückwärts-Schrägstrich auf Unix | `datei_und_elternpfadfehler_sind_am_sprachzugang_unterscheidbar`: OPEN über Backslash, anschließendes NAME/Lesen/Löschen |
|
||||
| Verzeichnis durchlaufen | Derselbe Test: DIR$ mit Muster und Folgeaufruf; vorhandener Dateikorpus |
|
||||
| Fehlender Pfad | Derselbe Test: MKDIR, NAME-Ziel, CHDIR, RMDIR, DIR$ → 76 |
|
||||
| OPEN mit fehlendem Elternpfad | Derselbe Test: INPUT mit fehlender Datei → 53, fehlendem Elternpfad → 76; zusätzlich OUTPUT/APPEND/BINARY/RANDOM |
|
||||
| Zonenermittlung: Zone nicht ermittelbar | runtime `zonenquelle_ausfall_und_erholung_gelten_fuer_alle_zeitfunktionen`; `timezonefallback.bas` |
|
||||
| Rückfallebene ist erkennbar | `timezoneknown_hat_integer_signatur_und_zeigt_aktuellen_status`; `timezoneknown.bas` und `timezonefallback.bas` |
|
||||
| Rückfall nach Programmstart | Derselbe VM-Test über STOP/Fortsetzung und runtime-Zonenquelle mit Ausfall und Erholung; bekannte UTC liefert -1 |
|
||||
| Signaturen: Element ohne Laufzeitverhalten wird namentlich abgewiesen | Vorhandener frontend-Test `dokumentierte_elemente_werden_namentlich_abgewiesen`; Inventar hat derzeit 0 offene Elemente |
|
||||
| Argumentprüfung ohne Laufzeitverhalten | frontend `builtins_typen`: MKL$() hat benannte Argumentanzahl-Diagnose |
|
||||
| Signatur der Zonenzustandsabfrage | frontend `builtins_typen`: 0 Argumente, INTEGER; TIMEZONEKNOWN(1) benannt abgewiesen; runtime-Test prüft tatsächliches `Value::Int` |
|
||||
| Tastatur: INKEY$ bei leerem Puffer | `inkey_ohne_taste_ist_leer` |
|
||||
| Sondertaste als zwei Zeichen | `inkey_liefert_zeichen_und_sondertaste` |
|
||||
| Sondertastenfolge in zwei Reads | `input_s_teilt_sondertasten_und_bewahrt_rest_fuer_inkey`; `eingabefortschritt.bas`; direkter runtime-Dispatch |
|
||||
| Unicode aus Datei | `input_datei_alle_lesearten_teilen_utf8_cursor_und_seek`: ä/Emoji, INPUT und BINARY |
|
||||
|
||||
Zusätzliche Randfälle: CR/LF/CRLF, Leerzeilen, eingebettete Kommas,
|
||||
verdoppelte Anführungszeichen und Zeilenumbrüche, Null-Länge, negative Länge,
|
||||
ungültiges UTF-8, falscher Dateimodus, SEEK nach EOF und gemischte Lesearten.
|
||||
`unicode_puffergrenzen_und_binaere_records_bleiben_getrennt` prüft UTF-8 an
|
||||
8-KiB-Puffergrenzen sowie GET/PUT zwischen INPUT$-Aufrufen.
|
||||
`sondertastenrest_wird_nicht_erneut_getrappt` prüft F1 unter KEY STOP/ON.
|
||||
Die bestehenden Programmversatz- und Ereignistests bestehen weiterhin.
|
||||
|
||||
## Abnahme
|
||||
|
||||
- `cargo test --workspace --quiet`: **463 bestanden, 0 fehlgeschlagen,
|
||||
1 ignoriert**. Der ignorierte Golden-Generator wurde nicht ausgeführt.
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`: bestanden.
|
||||
- `cargo fmt --all -- --check`: bestanden.
|
||||
- `git diff --check`: bestanden vor dem Staging. Die abschließende
|
||||
Prüfung des gestagten Changes mit `git diff --cached --check -- .
|
||||
':(exclude)tests/compat/*.out'` besteht ebenfalls. Die neuen `.out`-Dateien
|
||||
enthalten absichtlich signifikante PRINT-Leerzeichen am Zeilenende.
|
||||
- `openspec validate laufzeit-eingabe-und-systemstatus --strict`: bestanden.
|
||||
- Bestehende `tests/compat/*.out` unverändert; drei neue Programme mit
|
||||
vorab festgelegten Sollausgaben ergänzt. Die Inventar-Abdeckungszahl
|
||||
berücksichtigt die neue Erweiterung: 795 implementiert, 0 offen,
|
||||
50 Non-Features, insgesamt 845 Einträge.
|
||||
|
||||
Die anfänglichen Testfehler (doppelte Quote-Auswertung, fehlende Korpus-
|
||||
Rückfalldirektive, Test-Namensauflösung, Inventar-Gesamtzahl) sind behoben;
|
||||
der abschließende Workspace-Lauf ist grün. Keine Tests oder vorhandenen
|
||||
Sollausgaben wurden zum Übergehen dieser Fehler abgeschwächt.
|
||||
|
||||
Geprüft wurde headless auf macOS. Es erfolgte kein neuer interaktiver
|
||||
Fremdprogrammvergleich und keine Windows-/Linux-Ausführung. Die ergänzenden
|
||||
Korpusfälle belegen den erklärten TerminalBasic-Vertrag, keine historische
|
||||
Bytekompatibilität. Der verbleibende Change
|
||||
`spezifikationsabgleich-und-regressionsnachweise` bleibt eigenständig.
|
||||
Reference in New Issue
Block a user