Forms-Zustand und Darstellung korrigieren und Change archivieren
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## Why
|
||||
|
||||
Listen und Timer erfüllen einfache gültige Zustandsübergänge nicht: ListIndex=-1 liefert Fehler 5; ein spät aktivierter Timer holt Zeit seit Programmstart nach. F12/F13 betreffen das Zustandsmodell unabhängig von dessen späterem Ereignisdispatch. Siehe [Review vom 05.09.2026](../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
Listen und Timer erfüllen einfache gültige Zustandsübergänge nicht: ListIndex=-1 liefert Fehler 5; ein spät aktivierter Timer holt Zeit seit Programmstart nach. F12/F13 betreffen das Zustandsmodell unabhängig von dessen späterem Ereignisdispatch. Siehe [Review vom 05.09.2026](../../../../docs/reviews/2026-09-05-openspec-code-review.md).
|
||||
|
||||
## What Changes
|
||||
|
||||
@@ -21,4 +21,10 @@ Keine neuen Capability-Pfade.
|
||||
|
||||
crates/tb-ui/src/forms.rs, Forms-Unit-/VM-Tests, Formular-Korpus und docs/forms-referenz.md. Baut auf der geordneten Ereigniszustellung auf.
|
||||
|
||||
Die Behebung der Darstellungsbefunde betrifft zusätzlich
|
||||
crates/tb-runtime/src/screen.rs: Forms-Zeilen verwenden den vorhandenen
|
||||
Zellenschreibpfad ohne Umbruch oder Scrollen am Bildschirmrand. `tb-ui`
|
||||
nutzt die bereits vorhandene Workspace-Abhängigkeit `unicode-width` für
|
||||
dieselbe Breitenberechnung wie die Runtime.
|
||||
|
||||
Nach ereigniszustellung-und-hostgrenzen. Ändert nur die Requirements zu Listen und Timer, nicht Fokus/Menü desselben Capability-Pfads.
|
||||
@@ -0,0 +1,154 @@
|
||||
//! Unabhängige Review-Proben: zwei behobene Vertragslücken, Timer und Mindestmaße.
|
||||
//! Ausführung über den temporären Cargo-Treiber aus review.md.
|
||||
use tb_frontend::forms::{self, FormCatalog, ObjectClass};
|
||||
use tb_runtime::{
|
||||
host::{CaptureHost, Host},
|
||||
screen::TextScreen,
|
||||
};
|
||||
use tb_ui::forms::{FormsModel, PropertyValue as V};
|
||||
use tb_vm::interp::{RunEvent, Vm};
|
||||
|
||||
fn model(class: ObjectClass) -> FormsModel {
|
||||
let mut c = FormCatalog::default();
|
||||
c.add("Form1", ObjectClass::Form, None, false);
|
||||
c.add("List1", class, Some("Form1"), false);
|
||||
let mut m = FormsModel::new(c.objects, 80, 25);
|
||||
m.set_initial(0, prop(ObjectClass::Form, "WIDTH"), V::Integer(40))
|
||||
.unwrap();
|
||||
m.set_initial(0, prop(ObjectClass::Form, "HEIGHT"), V::Integer(12))
|
||||
.unwrap();
|
||||
m
|
||||
}
|
||||
fn prop(class: ObjectClass, name: &str) -> u16 {
|
||||
forms::property(class, name).unwrap().0
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sorted_nach_befuellen_ordnet_liste_und_erhaelt_auswahl() {
|
||||
let mut results = vec![];
|
||||
for class in [ObjectClass::ListBox, ObjectClass::ComboBox] {
|
||||
let mut m = model(class);
|
||||
m.add_item((1, None), "b".into(), None).unwrap();
|
||||
m.add_item((1, None), "a".into(), None).unwrap();
|
||||
m.set(1, prop(class, "LISTINDEX"), V::Integer(0)).unwrap();
|
||||
m.set(1, prop(class, "SORTED"), V::Boolean(true)).unwrap();
|
||||
m.add_item((1, None), "c".into(), None).unwrap();
|
||||
let list: Vec<_> = (0..3)
|
||||
.map(|i| m.get_indexed(1, prop(class, "LIST"), i).unwrap())
|
||||
.collect();
|
||||
println!(
|
||||
"{class:?}: {list:?}; Auswahl={:?}",
|
||||
m.get(1, prop(class, "LISTINDEX")).unwrap()
|
||||
);
|
||||
results.push((list, m.get(1, prop(class, "LISTINDEX")).unwrap()));
|
||||
}
|
||||
for (list, index) in results {
|
||||
assert_eq!(
|
||||
list,
|
||||
vec![
|
||||
V::String("a".into()),
|
||||
V::String("b".into()),
|
||||
V::String("c".into())
|
||||
]
|
||||
);
|
||||
assert_eq!(index, V::Integer(1));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combo_simple_zeigt_seine_listeneintraege() {
|
||||
let class = ObjectClass::ComboBox;
|
||||
let mut m = model(class);
|
||||
for (name, value) in [
|
||||
("STYLE", V::Integer(1)),
|
||||
("WIDTH", V::Integer(15)),
|
||||
("HEIGHT", V::Integer(5)),
|
||||
("LEFT", V::Integer(2)),
|
||||
("TOP", V::Integer(2)),
|
||||
("TEXT", V::String("frei".into())),
|
||||
] {
|
||||
m.set_initial(1, prop(class, name), value).unwrap();
|
||||
}
|
||||
m.add_item((1, None), "apfel".into(), None).unwrap();
|
||||
m.add_item((1, None), "birne".into(), None).unwrap();
|
||||
m.show(0, false).unwrap();
|
||||
let mut screen = TextScreen::new();
|
||||
m.render(&mut screen);
|
||||
let text = tb_runtime::snapshot::text(&screen);
|
||||
println!("{text}");
|
||||
assert!(
|
||||
text.contains("frei"),
|
||||
"Kontrolle: das Control muss sichtbar sein"
|
||||
);
|
||||
assert!(text.contains("apfel") && text.contains("birne"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_array_wird_beim_laden_an_aktueller_hostzeit_aktiviert() {
|
||||
let mut c = FormCatalog::default();
|
||||
c.add("Form1", ObjectClass::Form, None, false);
|
||||
c.add("Timer1", ObjectClass::Timer, Some("Form1"), true);
|
||||
let src="DIM SHARED s$\nForm1.Show\nTimer1(0).Interval=100\nSTOP\nLOAD Timer1(1)\nTimer1(0).Interval=0\nSTOP\nDOEVENTS\nEND\nSUB Timer1_Timer(Index AS INTEGER)\nSHARED s$\ns$=s$+LTRIM$(STR$(Index))\nEND SUB";
|
||||
let mut vm = Vm::new(tb_vm::compile_source_with_forms("FORM1", src, &c).unwrap());
|
||||
let mut h = CaptureHost::default();
|
||||
assert!(matches!(vm.run(&mut h), RunEvent::Stopped { .. }));
|
||||
h.uhr_setzen(1000);
|
||||
assert!(matches!(vm.run(&mut h), RunEvent::Stopped { .. }));
|
||||
assert_eq!(vm.forms.next_deadline(), Some(1100));
|
||||
h.uhr_setzen(1100);
|
||||
assert_eq!(vm.run(&mut h), RunEvent::Ended);
|
||||
assert_eq!(h.jetzt_ms(), 1100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn listen_bleiben_auch_bei_minimalmassen_im_controlrechteck() {
|
||||
let mut failures = vec![];
|
||||
for (class, width, height) in [
|
||||
(ObjectClass::ComboBox, 15, 5),
|
||||
(ObjectClass::ListBox, 6, 4),
|
||||
(ObjectClass::ComboBox, 1, 5),
|
||||
(ObjectClass::ListBox, 1, 4),
|
||||
(ObjectClass::ListBox, 6, 1),
|
||||
] {
|
||||
let mut m = model(class);
|
||||
for (name, value) in [
|
||||
("WIDTH", width),
|
||||
("HEIGHT", height),
|
||||
("LEFT", 2),
|
||||
("TOP", 2),
|
||||
] {
|
||||
m.set_initial(1, prop(class, name), V::Integer(value))
|
||||
.unwrap();
|
||||
}
|
||||
if class == ObjectClass::ComboBox {
|
||||
m.set_initial(1, prop(class, "STYLE"), V::Integer(1))
|
||||
.unwrap();
|
||||
}
|
||||
m.add_item((1, None), "apfel".into(), None).unwrap();
|
||||
m.set(1, prop(class, "VISIBLE"), V::Boolean(false)).unwrap();
|
||||
m.show(0, false).unwrap();
|
||||
let mut screen = TextScreen::new();
|
||||
m.render(&mut screen);
|
||||
let before = tb_runtime::snapshot::text(&screen);
|
||||
m.set(1, prop(class, "VISIBLE"), V::Boolean(true)).unwrap();
|
||||
m.render(&mut screen);
|
||||
let after = tb_runtime::snapshot::text(&screen);
|
||||
let mut outside = vec![];
|
||||
for (row, (a, b)) in before.lines().zip(after.lines()).enumerate() {
|
||||
for (col, (a, b)) in a.chars().zip(b.chars()).enumerate() {
|
||||
if a != b
|
||||
&& !(row >= 2
|
||||
&& row < 2 + height as usize
|
||||
&& col >= 2
|
||||
&& col < 2 + width as usize)
|
||||
{
|
||||
outside.push((row + 1, col + 1, a, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
if !outside.is_empty() {
|
||||
failures.push(format!("{class:?} {width}x{height}: {outside:?}"));
|
||||
}
|
||||
}
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
# Verifikation: forms-zustand-und-bedienung
|
||||
|
||||
Abnahme vom 05.09.2026, umgesetzt auf Basis von `644a862`.
|
||||
Nach erfolgreicher Verifikation am selben Tag synchronisiert und archiviert. **V1, V2 und V3 sind behoben. Keine
|
||||
offenen Befunde im Change.** Beide Delta-Requirements, alle acht Szenarien,
|
||||
die ergänzten Abnahmetasks und D1–D3 wurden erneut gegen Code und Tests geprüft.
|
||||
|
||||
| Dimension | Ergebnis |
|
||||
| --- | --- |
|
||||
| Vollständigkeit | 7/7 Tasks vollständig umgesetzt; beide Delta-Requirements mit allen acht Szenarien abgedeckt. Task 4.2 einschließlich Mindestmaßen und verwandten Zeichenpfaden erfüllt. |
|
||||
| Korrektheit | 428 Workspace-Tests und alle vier Review-Proben bestanden. Keine kritischen Befunde, Warnungen oder offenen Verbesserungsvorschläge. |
|
||||
| Kohärenz | D1–D3 umgesetzt. Die stabile Sortierung erhält die Auswahl; Simple-ComboBox und ListBox verwenden denselben Listenrenderer. |
|
||||
|
||||
## V3 — behoben; historischer Befund vor der Korrektur
|
||||
|
||||
Die folgenden Beobachtungen gelten für den vorherigen Stand. Die Korrektur
|
||||
und ihre erweiterten Nachweise stehen im nächsten Abschnitt.
|
||||
|
||||
### V3 (ursprünglich mittel): Listenrenderer überschreitet zulässige Mindestmaße
|
||||
|
||||
**Reproduktion:** Sichtbare Simple-ComboBox mit Width = 1, Height = 5,
|
||||
Left = 2, Top = 2 in einem ausreichend großen Formular. Gegenüber dem
|
||||
Bildschirm mit ausgeblendetem Control werden auch die Zellen in Spalte 4,
|
||||
Zeilen 4–7 überschrieben; die einzige erlaubte Controlspalte ist Spalte 3.
|
||||
Eine ListBox mit Width = 1 hat denselben horizontalen Überlauf. Bei einer
|
||||
ListBox mit Width = 6, Height = 1 wird zusätzlich die vollständige Zeile
|
||||
unterhalb des Controls gezeichnet. Benachbarte Inhalte können dadurch
|
||||
überschrieben werden.
|
||||
|
||||
**Ursache:** [list_lines](../../../../crates/tb-ui/src/forms.rs#L2047) verwendet
|
||||
`box_lines`, das Breite und Höhe auf mindestens 2 erhöht. Für Width < 3
|
||||
kehrt der Listenrenderer ohne Begrenzung zurück; im ListBox-Pfad fehlt
|
||||
auch eine abschließende Höhenbegrenzung. `write_at` begrenzt ausschließlich
|
||||
auf den Bildschirm. [Width und Height](../../../../crates/tb-frontend/src/forms.rs#L202)
|
||||
lassen ausdrücklich den Wert 1 zu.
|
||||
|
||||
**Vertrag:** Task 4.2 verlangt die Prüfung von Kürzung und Größenbegrenzung
|
||||
für die Simple-ComboBox. Der neue gemeinsame Renderer übernimmt die bereits
|
||||
vorhandene Mindestmaß-Lücke auch für die nun dargestellte Simple-Liste.
|
||||
Die bestehenden Regressionen prüfen Breite 6 und kleine Combo-Höhen,
|
||||
aber weder Breite 1 noch die ListBox-Höhe 1.
|
||||
|
||||
**Behebung:** Die gemeinsame Listenausgabe auf die tatsächlich angeforderte
|
||||
Breite und Höhe begrenzen. Mindestbreite 1 für beide Klassen und Mindesthöhe 1
|
||||
für ListBox durch Bildschirmprüfungen absichern; normale Maße beibehalten.
|
||||
|
||||
**Nachweis:** `listen_bleiben_auch_bei_minimalmassen_im_controlrechteck` in
|
||||
[review-probes.rs](review-probes.rs) prüft den tatsächlichen Bildschirm vor
|
||||
und nach Einblenden des Controls. Die Kontrollfälle ComboBox 15×5 und
|
||||
ListBox 6×4 bleiben innerhalb ihrer Grenzen; die drei Mindestmaßfälle
|
||||
schlugen vor der Behebung fehl und bestehen jetzt mit unveränderten Erwartungen.
|
||||
|
||||
## Behebung und Regressionen
|
||||
|
||||
- **V1:** Gemeinsame Sortierung für Laufzeit- und initiale Property-Zugriffe.
|
||||
Sortierung ohne Beachtung der Groß-/Kleinschreibung; ursprüngliche Indizes
|
||||
erhalten die Auswahl auch zwischen gleichen Texten. Regressionen prüfen
|
||||
beide Klassen, alle ComboBox-Stile, Basis-/Arrayindex 0 und dynamische
|
||||
Arrayelemente, wiederholtes Sortieren sowie anschließendes Einfügen/Entfernen.
|
||||
Der Formular-Korpus prüft jetzt das Einschalten von Sorted nach dem Befüllen
|
||||
mit unveränderter Sollausgabe.
|
||||
- **V2:** Simple verwendet den bestehenden Listenrenderer samt Rahmen und
|
||||
Auswahlmarkierung. Der Bildschirmtest prüft tatsächliche Einträge, Auswahl,
|
||||
Entfernen und erhaltenen Eingabetext. V3 ergänzt die Mindestmaßabnahme.
|
||||
- **V3:** `list_lines` begrenzt sämtliche Rahmenzeilen auf die angeforderte
|
||||
Breite und Höhe, auch vor dem frühen Rücksprung für schmale Controls.
|
||||
Alle Aufrufer (ListBox, Simple-ComboBox, DirListBox und FileListBox)
|
||||
verwenden diese Korrektur. Die gemeinsame Textkürzung zählt dieselben
|
||||
Zellenbreiten wie TextScreen und behandelt Steuerzeichen als Leerzeichen.
|
||||
`TextScreen::print_line` verwendet den vorhandenen Zellenschreibpfad ohne
|
||||
Umbruch oder Scrollen; `write_at` nutzt ihn für Forms-Ausgaben.
|
||||
Das normale BASIC-PRINT behält Umbruch und Scrollen.
|
||||
|
||||
Die zusätzliche Regression
|
||||
`listenrenderer_haelt_zellgrenzen_auch_an_bildschirmraendern_ein` vergleicht
|
||||
alle Bildschirmzellen außerhalb des jeweiligen Controlrechtecks einschließlich
|
||||
Farben und Unicode-Fortsetzungsmarkierung. **3.360 Kombinationen bestehen:**
|
||||
ListBox, Combo-Stile 0/1/2, DirListBox, FileListBox und DriveListBox;
|
||||
Basis- und dynamische Arrayelemente; Breiten 1/2/3/6/15/254 und Höhen
|
||||
1/2/3/5/254; vier Positionen einschließlich rechtem/unterem Bildschirmrand
|
||||
und vollständig außerhalb; leere und gefüllte Listen mit langen Texten,
|
||||
breiten Unicode-Zeichen und CR/LF. Vor der Korrektur schlug dieser Test
|
||||
bereits bei einer ListBox 1×1 fehl.
|
||||
|
||||
`ui_zeile_bleibt_am_rand_ohne_umbruch_oder_scrollen` prüft zusätzlich
|
||||
vollständig passende und nicht passende breite Zeichen, Farben, CR/LF
|
||||
sowie den rechten/unteren Rand und einen eigenen VIEW-PRINT-Bereich.
|
||||
Bestehende Zeichenbild-, Auswahl-, Timer-, VM- und Korpustests bestehen
|
||||
unverändert in ihren Erwartungen.
|
||||
|
||||
## Ursprüngliche Befunde — historischer Stand vor der Behebung
|
||||
|
||||
Die folgenden Ist-Beobachtungen dokumentieren den fehlgeschlagenen Review.
|
||||
Beide Befunde sind durch die Nachweise oben geschlossen.
|
||||
|
||||
### V1: Nachträgliches Sorted lässt den Listeninhalt unsortiert
|
||||
|
||||
**Reproduktion:** In ListBox oder ComboBox zuerst `b`, dann `a` hinzufügen,
|
||||
Eintrag 0 (`b`) auswählen, anschließend `Sorted = -1` setzen und `c`
|
||||
hinzufügen. **Ist:** `List = [b, a, c]`, ListIndex = 0.
|
||||
**Soll:** sortierte Liste `[a, b, c]` mit weiterhin ausgewähltem `b`, Index 1.
|
||||
|
||||
Der [Property-Setter](../../../../crates/tb-ui/src/forms.rs#L430) speichert
|
||||
SORTED ohne Sortierung des vorhandenen Inhalts. [ADDITEM](../../../../crates/tb-ui/src/forms.rs#L1025)
|
||||
verwendet anschließend `partition_point`, das bereits sortierte Daten
|
||||
voraussetzt. Der Fehler tritt bei beiden Klassen auf.
|
||||
|
||||
**Vertrag:** Delta „Steuerelemente mit Listeninhalt“, Sortierung bei
|
||||
Sorted = −1 und Konsistenz von List/ListIndex/Text; Task 1.1.
|
||||
Die Tests setzen Sorted ausschließlich vor dem Befüllen und decken den
|
||||
zulässigen Wechsel an einer gefüllten Liste nicht ab.
|
||||
|
||||
**Behebung:** Beim Einschalten der Sortierung vorhandene Einträge sortieren
|
||||
und die Auswahl ihrem bisherigen Eintrag zuordnen; anschließend Einfügen
|
||||
und Entfernen weiterhin konsistent halten. Regression für beide Klassen,
|
||||
einschließlich der Auswahl, ergänzen.
|
||||
|
||||
### V2: ComboBox.Style 1 zeichnet keine Listeneinträge
|
||||
|
||||
**Reproduktion:** Sichtbare ComboBox mit Style = 1, Width = 15, Height = 5,
|
||||
Text = `frei`; ADDITEM `apfel` und `birne`. **Ist:** Der Bildschirm zeigt
|
||||
`frei` und einen leeren eingerahmten Listenbereich. **Soll:** Die beiden
|
||||
Einträge erscheinen in diesem ausreichend großen Bereich.
|
||||
|
||||
Der [Renderer](../../../../crates/tb-ui/src/forms.rs#L2184) hängt für Style 1
|
||||
nur `box_lines` mit leerem Inhalt an. Er liest die vorhandenen Listeneinträge
|
||||
für diesen Bereich nicht. Die Probe prüft zuerst, dass das Control über den
|
||||
Text `frei` tatsächlich sichtbar ist, und danach die beiden Listeneinträge.
|
||||
|
||||
**Vertrag:** Delta „Steuerelemente mit Listeninhalt“ verlangt die Darstellung
|
||||
aller drei ComboBox-Stile; die [Forms-Referenz](../../../../docs/forms-referenz.md#L180)
|
||||
zeigt für Simple einen sichtbaren Listeneintrag. Task 1.1 verlangt die Prüfung
|
||||
aller Stile. Der bestehende Stiltest prüft nur Zeilenzahl und Präfix;
|
||||
die neuen Auswahltests prüfen nur die oberste Zeile.
|
||||
|
||||
**Behebung:** Den vorhandenen Listeninhalt samt Auswahl im Simple-Bereich
|
||||
darstellen und dessen Inhalt mit einem Bildschirmtest absichern. Die bereits
|
||||
festgelegten Zeichenformen beibehalten.
|
||||
|
||||
Beide Lücken bestanden bereits vor diesem Change. Es handelt sich um
|
||||
verbleibende Abweichungen im übernommenen Listen-Requirement, nicht um neu
|
||||
eingeführte Regressionen. Die Korrekturen wurden nach diesem Review umgesetzt.
|
||||
|
||||
## Szenarioabdeckung und positive Nachweise
|
||||
|
||||
| Delta-Szenario | Nachweis |
|
||||
| --- | --- |
|
||||
| Element hinzufügen | Bestehender Sorted-Listentest und neue Auswahlmatrix: a/b, ListCount und List(i). Nachträgliches Einschalten einschließlich stabiler Auswahl durch V1-Regressionen abgesichert. |
|
||||
| Keine Auswahl | ListIndex −1 bei leerer Liste und nach Entfernen der Auswahl. |
|
||||
| Auswahl ausdrücklich aufheben | Modellmatrix für ListBox und ComboBox-Stile 0/1/2; Formular-Korpus. |
|
||||
| Eintrag vor Auswahl einfügen | Sortierte/unsortierte Modellmatrix prüft Indexverschiebung und erhaltenen Text. |
|
||||
| Timer feuert im Abstand | Zwei Ereignisse nach 250 ms aktiver Zeit, mehrere Timer und Arrayelemente, identische Wiederholung. |
|
||||
| Interval 0 schaltet ab | Modelltest, Arrayindex-0-Reset und Änderung im VM-Handler. |
|
||||
| Späte Aktivierung | VM: direkte Property, Control-Parameter und Enabled; Aktivierung bei 1000, still bei 1099, einmal bei 1100 ms. Zusätzliche erfolgreiche Probe für spät geladenes Timer-Arrayelement. |
|
||||
| Abschalten verwirft anstehende Ereignisse | Interval/Enabled-Reset, Array-Entladen und Handlerwechsel mit altem Rückstau. |
|
||||
|
||||
Erneut ausgeführt:
|
||||
|
||||
- `cargo test --workspace`: **428 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
|
||||
Ignoriert bleibt der Generator für Sollausgaben; keine Golden Files geändert.
|
||||
- `openspec validate forms-zustand-und-bedienung --strict`: gültig.
|
||||
- `git diff --check`: erfolgreich.
|
||||
- [Zusätzliche Review-Proben](review-probes.rs): **4 bestanden, 0 fehlgeschlagen**.
|
||||
|
||||
`cargo clippy -p tb-ui -p tb-vm -p tb-runtime --all-targets --all-features -- -D warnings`
|
||||
und `cargo fmt --all -- --check` wurden nach der Behebung erfolgreich ausgeführt. Kein interaktiver Terminal-/VBDOS-Vergleich und
|
||||
keine Windows-/Linux-Matrix. Die Darstellungsprobe prüft den echten Zellenpuffer
|
||||
ohne Terminal; Timerprüfungen verwenden ausschließlich virtuelle Hostzeit.
|
||||
|
||||
## Review-Proben reproduzieren
|
||||
|
||||
Im Repository-Wurzelverzeichnis ausführen; erzeugt einen separaten temporären
|
||||
Cargo-Treiber. Auf dem korrigierten Stand bestehen alle vier Proben.
|
||||
|
||||
```sh
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import json, subprocess, tempfile
|
||||
root = Path.cwd()
|
||||
p = Path(tempfile.mkdtemp(prefix='tb-forms-review-'))
|
||||
manifest = '[package]\nname="tb-forms-review"\nversion="0.0.0"\nedition="2021"\n[workspace]\n'
|
||||
manifest += '[[test]]\nname="probes"\npath=' + json.dumps(str(root / 'openspec/changes/archive/2026-09-05-forms-zustand-und-bedienung/review-probes.rs')) + '\n[dependencies]\n'
|
||||
for name in ['tb-ui', 'tb-vm', 'tb-runtime', 'tb-frontend']:
|
||||
manifest += name + ' = { path = ' + json.dumps(str(root / 'crates' / name)) + ' }\n'
|
||||
(p / 'Cargo.toml').write_text(manifest)
|
||||
subprocess.run(['cargo', 'test', '--manifest-path', str(p / 'Cargo.toml'), '--offline', '--test', 'probes', '--', '--nocapture'], check=True, timeout=120)
|
||||
PY
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
## 1. Listen
|
||||
|
||||
- [x] 1.1 ListIndex=-1 korrekt zulassen und Text/List/Count bei ADDITEM/REMOVEITEM konsistent halten; verifizieren mit leeren/sortierten Listen, Einfügen vor Auswahl, Entfernen der Auswahl und allen ComboBox-Stilen.
|
||||
|
||||
## 2. Timer
|
||||
|
||||
- [x] 2.1 Aktivierungs-/Änderungszeit über den Host erfassen und deaktivierte Queueeinträge entfernen; verifizieren mit Aktivierung bei 1000 ms, erster Fälligkeit bei 1100 ms, Änderung im Handler und Interval=0.
|
||||
- [x] 2.2 Fortlaufende Timer und gleichzeitige Fälligkeit erhalten; verifizieren mit exakt zwei Ereignissen bei 250 ms sowie mehreren Timer-/Arraynamen und Wiederholbarkeit.
|
||||
|
||||
## 3. Abnahme
|
||||
|
||||
- [x] 3.1 Formular-Korpus um Listenauswahl und späte Timeraktivierung ergänzen und Referenz dokumentieren; verifizieren mit cargo test -p tb-ui, cargo test -p tb-vm und cargo test -p tb-cli --test compat.
|
||||
- [x] 3.2 Delta-Specs und Diffs prüfen; verifizieren mit openspec validate forms-zustand-und-bedienung --strict und git diff --check.
|
||||
|
||||
Abnahmenachweise: [verification.md](verification.md).
|
||||
|
||||
## 4. Verifikationsbefunde
|
||||
|
||||
- [x] 4.1 V1: Gefüllte Listen beim Einschalten von Sorted stabil sortieren und die Auswahl einschließlich gleicher Texte erhalten; beide Klassen und Arrayzugriffe prüfen.
|
||||
- [x] 4.2 V2/V3: Simple-ComboBox mit dem bestehenden Listenrenderer darstellen; Einträge, Auswahl, Kürzung und Größenbegrenzung einschließlich Mindestmaßen, breiten Zeichen und Bildschirmrändern am Bildschirm prüfen. Alle Aufrufer des Listenrenderers berücksichtigen.
|
||||
@@ -0,0 +1,90 @@
|
||||
# Implementierungsnachweis — 05.09.2026
|
||||
|
||||
Change: `forms-zustand-und-bedienung`, Ausgangscommit `644a862`.
|
||||
Alle sieben Tasks sind abgeschlossen; V1, V2 und V3 sind behoben. Die erneute
|
||||
[Verifikation](review.md) bestätigt beide Requirements und alle acht Szenarien
|
||||
ohne offene Befunde. Beide Delta-Requirements wurden am 05.09.2026 mit
|
||||
der Hauptspec synchronisiert und vollständig abgeglichen; anschließend
|
||||
wurde der Change unter `2026-09-05-forms-zustand-und-bedienung` archiviert.
|
||||
|
||||
## Umsetzung und Nachweise
|
||||
|
||||
| Task / Befund | Umsetzung | Ausführbarer Nachweis |
|
||||
| --- | --- | --- |
|
||||
| 1.1 / F12 | −1 ist bei leerer und gefüllter Liste zulässig. Einfügen/Entfernen verschiebt die Auswahl mit ihrem Eintrag; Entfernen der Auswahl hebt sie auf. Textabfrage und Combo-Anzeige verwenden denselben Auswahlzustand, editierbarer Text bleibt erhalten. | `listenauswahl_bleibt_beim_einfuegen_und_entfernen_konsistent`: ListBox und alle drei ComboBox-Stile, jeweils sortiert/unsortiert, Grenzen, Auswahl, List/Text/Count und Darstellung. Korpus `listenauswahl.frm`. |
|
||||
| 2.1 / F13 | Aktivierungszeit wird über die Hostuhr erfasst. Interval-Zuweisung setzt die aktive Phase zurück; unverändertes Enabled lässt sie weiterlaufen. Reset/Deaktivierung entfernt wartende Ereignisse einschließlich Arrayindex 0. Verstecken/Entladen beendet die Phase. | `timer_neustart_verwirft_alte_fristen_und_ereignisse`; VM-Test `spaete_timeraktivierung_nutzt_hostzeit_auch_ueber_control_parameter` für direkte/dynamische Property-Zuweisung und Enabled; bei 1000 ms aktiviert, bei 1099 ms still, bei 1100 ms einmal zugestellt. |
|
||||
| 2.1 | Intervalländerung im eigenen Handler verwirft bereits fällige Altintervalle. | `intervallaenderung_im_handler_verwirft_bereits_faellige_altintervalle`: erster Handler bei 100 ms, Änderung bei 450 ms, neue erste Frist bei 650 ms, dann Interval = 0. |
|
||||
| 2.2 | Durchgehend aktive Timer behalten die Nachholregel. Gleichzeitige Timer werden nach Name, Arrayelemente nach numerischem Index geordnet. | `timerarrays_holen_nur_aktive_zeit_nach_und_sortieren_nach_name_und_index`: zwei Ereignisse pro Timer nach 250 ms aktiver Zeit, identische Wiederholung, gezielte Deaktivierung/Entladung und Neustart nach HIDE/SHOW. Bestehende Menüsperr-/Timer-Reihenfolgetests. |
|
||||
| 3.1 | Zwei Formular-Korpusfälle mit ausdrücklich festgelegten Sollausgaben und ergänzte [Forms-Referenz](../../../../docs/forms-referenz.md). | `listenauswahl.frm`: −1, verschobene Auswahl und erhaltener Combo-Text. `timer-aktivierung.frm`: Aktivierung bei 1000 ms, Ereignis beendet SLEEP bei 1100 ms. Beide im normalen Korpus zweimal ausgeführt. |
|
||||
| 3.2 | Beide vollständigen Delta-Requirements mit acht Szenarien wurden nach erfolgreicher Abnahme in die Hauptspec übernommen. | OpenSpec-Validierung und Diff-Prüfung erfolgreich. |
|
||||
|
||||
Das Terminalbeispiel `tb-ui/examples/spike.rs` benötigt jetzt ausdrücklich
|
||||
das Feature `terminal`. Damit funktioniert auch der vorgeschriebene
|
||||
Einzelaufruf `cargo test -p tb-ui` ohne die Feature-Vereinigung des
|
||||
Workspace. `tb-ui` nutzt für die Zellenbreite jetzt dieselbe bereits im
|
||||
Workspace vorhandene Bibliothek `unicode-width` wie `tb-runtime`; kein
|
||||
zusätzliches Bibliothekspaket wurde eingeführt.
|
||||
|
||||
## Behebung der Verifikationsbefunde
|
||||
|
||||
V1, V2 und V3 sind geschlossen. Die gemeinsame stabile Sortierung erhält die
|
||||
Auswahl über ursprüngliche Eintragsindizes, auch bei Duplikaten. Laufzeit-
|
||||
und initiale Property-Zugriffe verwenden denselben Pfad. Die Simple-ComboBox
|
||||
nutzt den Listenrenderer der ListBox einschließlich Auswahlmarkierung und
|
||||
Begrenzung auf den verfügbaren Raum, einschließlich Mindestbreite und
|
||||
Mindesthöhe 1. Der gemeinsame Listenrenderer begrenzt Rahmen vor dem frühen
|
||||
Rücksprung für schmale Controls. `fit` berücksichtigt die Zellenbreite und
|
||||
ersetzt Steuerzeichen; `TextScreen::print_line` verhindert Umbruch und
|
||||
Scrollen bei Forms-Ausgaben am Bildschirmrand. BASIC-PRINT behält seinen
|
||||
bisherigen Zeichenpfad mit Umbruch und Scrollen.
|
||||
|
||||
Die neuen Modell-/Bildschirmtests heißen
|
||||
`sorted_wechsel_erhaelt_auch_die_auswahl_zwischen_duplikaten` und
|
||||
`simple_combo_zeichnet_listeninhalt_auswahl_und_begrenzung`. Die drei
|
||||
ursprünglichen Review-Proben bestehen unverändert in ihren Erwartungen.
|
||||
Der Korpus prüft nachträgliches Sorted bei unveränderter Sollausgabe.
|
||||
|
||||
`listenrenderer_haelt_zellgrenzen_auch_an_bildschirmraendern_ein` prüft
|
||||
3.360 Kombinationen: ListBox, alle drei Combo-Stile, DirListBox, FileListBox,
|
||||
DriveListBox; Basis- und dynamische Arrayelemente; Breiten 1/2/3/6/15/254,
|
||||
Höhen 1/2/3/5/254; normale, randnahe und außerhalb liegende Positionen;
|
||||
leere und gefüllte Listen mit breiten Zeichen und CR/LF. Alle Zellen
|
||||
außerhalb des Controlrechtecks werden einschließlich Farben und
|
||||
Fortsetzungsmarkierung mit dem Ausgangsbild verglichen.
|
||||
Der Test schlug vor der Korrektur fehl und besteht danach.
|
||||
`ui_zeile_bleibt_am_rand_ohne_umbruch_oder_scrollen` sichert zusätzlich
|
||||
den rechten/unteren Bildschirmrand und einen eigenen VIEW-PRINT-Bereich ab.
|
||||
|
||||
## Ausgeführte Prüfungen
|
||||
|
||||
Nach Behebung erneut ausgeführt:
|
||||
|
||||
- `cargo test --workspace`: **428 bestanden, 0 fehlgeschlagen, 1 ignoriert**.
|
||||
- Separater Treiber für `review-probes.rs`: **4 bestanden, 0 fehlgeschlagen**;
|
||||
die Erwartungen der ursprünglichen Mindestmaßprobe wurden nicht abgeschwächt.
|
||||
- `cargo clippy -p tb-ui -p tb-vm -p tb-runtime --all-targets --all-features -- -D warnings`: erfolgreich.
|
||||
- Format-, OpenSpec- und Diff-Prüfung: erfolgreich.
|
||||
|
||||
Die vorherige Implementierungsabnahme umfasste zusätzlich folgende Einzelaufrufe:
|
||||
|
||||
- `cargo test -p tb-ui`: 42 bestanden.
|
||||
- `cargo test -p tb-vm`: 149 bestanden, darunter 27 Ereignisregressionen.
|
||||
- Abschließend beide Pakete zusammen: `cargo test -p tb-ui -p tb-vm`,
|
||||
191 bestanden, 0 fehlgeschlagen.
|
||||
- `cargo test -p tb-cli --test compat`: 16 bestanden, 1 bewusst ignoriert
|
||||
(`erzeuge_sollausgaben`). Keine bestehenden Golden Files verändert oder
|
||||
neu aufgezeichnet.
|
||||
- `cargo clippy -p tb-ui -p tb-vm --all-targets --all-features -- -D warnings`:
|
||||
erfolgreich, ohne Warnungen.
|
||||
- `cargo fmt --all -- --check`: erfolgreich.
|
||||
- `openspec validate forms-zustand-und-bedienung --strict`: erfolgreich.
|
||||
- `git diff --check`: erfolgreich.
|
||||
|
||||
## Grenzen
|
||||
|
||||
Die neuen Nachweise prüfen den vereinbarten Vertrag mit virtueller Hostzeit.
|
||||
Kein neuer interaktiver VBDOS-/Terminalvergleich und keine Windows-/Linux-
|
||||
Ausführung. Bestehende Zeichenbilder bleiben unverändert; ihr Combo-Test
|
||||
wählt den darzustellenden Eintrag nun ausdrücklich aus. Einbetter mit
|
||||
direktem Forms-Modellzugriff müssen neue Timerphasen durch `sync_timers`
|
||||
mit ihrer Hostzeit beginnen lassen; die VM übernimmt das selbst.
|
||||
@@ -1,13 +0,0 @@
|
||||
## 1. Listen
|
||||
|
||||
- [ ] 1.1 ListIndex=-1 korrekt zulassen und Text/List/Count bei ADDITEM/REMOVEITEM konsistent halten; verifizieren mit leeren/sortierten Listen, Einfügen vor Auswahl, Entfernen der Auswahl und allen ComboBox-Stilen.
|
||||
|
||||
## 2. Timer
|
||||
|
||||
- [ ] 2.1 Aktivierungs-/Änderungszeit über den Host erfassen und deaktivierte Queueeinträge entfernen; verifizieren mit Aktivierung bei 1000 ms, erster Fälligkeit bei 1100 ms, Änderung im Handler und Interval=0.
|
||||
- [ ] 2.2 Fortlaufende Timer und gleichzeitige Fälligkeit erhalten; verifizieren mit exakt zwei Ereignissen bei 250 ms sowie mehreren Timer-/Arraynamen und Wiederholbarkeit.
|
||||
|
||||
## 3. Abnahme
|
||||
|
||||
- [ ] 3.1 Formular-Korpus um Listenauswahl und späte Timeraktivierung ergänzen und Referenz dokumentieren; verifizieren mit cargo test -p tb-ui, cargo test -p tb-vm und cargo test -p tb-cli --test compat.
|
||||
- [ ] 3.2 Delta-Specs und Diffs prüfen; verifizieren mit openspec validate forms-zustand-und-bedienung --strict und git diff --check.
|
||||
Reference in New Issue
Block a user