Spezifikationsabgleich und Regressionsnachweise abschließen
This commit is contained in:
@@ -626,3 +626,284 @@ fn intervallaenderung_im_handler_verwirft_bereits_faellige_altintervalle() {
|
||||
assert_eq!(integer(&vm, "n"), 2);
|
||||
assert_eq!(vm.forms.next_deadline(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formular_tastatur_fallback_fuehrt_alle_drei_basic_handler_aus() {
|
||||
let mut catalog = FormCatalog::default();
|
||||
catalog.add("Form1", ObjectClass::Form, None, false);
|
||||
for (input, expected) in [("a", "DPU"), ("\0;", "DU")] {
|
||||
let src = "DIM SHARED s$\nForm1.Show\nSTOP\nDOEVENTS\nEND\nSUB Form_KeyDown(KeyCode AS INTEGER, Shift AS INTEGER)\nSHARED s$\ns$ = s$ + \"D\"\nEND SUB\nSUB Form_KeyPress(KeyAscii AS INTEGER)\nSHARED s$\ns$ = s$ + \"P\"\nEND SUB\nSUB Form_KeyUp(KeyCode AS INTEGER, Shift AS INTEGER)\nSHARED s$\ns$ = s$ + \"U\"\nEND SUB";
|
||||
let mut vm = Vm::new(tb_vm::compile_source_with_forms("FORM1", src, &catalog).unwrap());
|
||||
let mut host = CaptureHost::default();
|
||||
stop(&mut vm, &mut host);
|
||||
host.ereignis(key(input));
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
assert_eq!(
|
||||
string(&vm, "s"),
|
||||
expected,
|
||||
"FORM_KEYDOWN/KEYPRESS/KEYUP: Status implementiert, Hosttaste {input:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registrierte_form_ereignisse_erreichen_basic_aus_realen_quellen() {
|
||||
use tb_frontend::forms::{self, EventParamType};
|
||||
for name in forms::events(ObjectClass::Form) {
|
||||
let mut catalog = FormCatalog::default();
|
||||
catalog.add("Form1", ObjectClass::Form, None, false);
|
||||
catalog.add("Source", ObjectClass::TextBox, Some("Form1"), false);
|
||||
let args = forms::event_params(name)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(n, t)| {
|
||||
format!(
|
||||
"{n} AS {}",
|
||||
match t {
|
||||
EventParamType::Integer => "INTEGER",
|
||||
EventParamType::Single => "SINGLE",
|
||||
EventParamType::Control => "CONTROL",
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let operation = match *name {
|
||||
"LOAD" | "GOTFOCUS" => "Form1.Show",
|
||||
"LOSTFOCUS" => "Form1.Hide",
|
||||
"UNLOAD" => "Form1.Unload",
|
||||
"PAINT" => "Form1.Refresh",
|
||||
"RESIZE" => "Form1.Width = 70",
|
||||
"DRAGOVER" | "DRAGDROP" => "Source.Drag 1",
|
||||
"KEYDOWN" | "KEYPRESS" | "KEYUP" | "MOUSEDOWN" | "MOUSEMOVE" | "MOUSEUP" | "CLICK"
|
||||
| "DBLCLICK" => "",
|
||||
other => panic!("FORM_{other}: Status implementiert, Auslöser fehlt"),
|
||||
};
|
||||
let setup = if matches!(*name, "LOAD" | "GOTFOCUS") {
|
||||
""
|
||||
} else {
|
||||
"Form1.Show"
|
||||
};
|
||||
let src = format!("DIM SHARED n%\nSource.Left=2\nSource.Top=2\n{setup}\nn%=0\nSTOP\n{operation}\nDOEVENTS\nEND\nSUB Form_{name}({args})\nSHARED n%\nn%=n%+1\nEND SUB");
|
||||
let mut vm = Vm::new(
|
||||
tb_vm::compile_source_with_forms("FORM1", &src, &catalog)
|
||||
.unwrap_or_else(|d| panic!("{name}: {d:?}")),
|
||||
);
|
||||
let mut host = CaptureHost::default();
|
||||
stop(&mut vm, &mut host);
|
||||
if name.starts_with("KEY") {
|
||||
host.ereignis(key("a"));
|
||||
}
|
||||
let events: &[MausArt] = match *name {
|
||||
"MOUSEDOWN" => &[MausArt::Druck],
|
||||
"MOUSEMOVE" | "DRAGOVER" => &[MausArt::Bewegung],
|
||||
"MOUSEUP" | "DRAGDROP" => &[MausArt::Bewegung, MausArt::Loslassen],
|
||||
"CLICK" => &[MausArt::Druck, MausArt::Loslassen],
|
||||
"DBLCLICK" => &[
|
||||
MausArt::Druck,
|
||||
MausArt::Loslassen,
|
||||
MausArt::Druck,
|
||||
MausArt::Loslassen,
|
||||
],
|
||||
_ => &[],
|
||||
};
|
||||
for art in events {
|
||||
host.ereignis(Ereignis::Maus(MausEreignis {
|
||||
art: *art,
|
||||
taste: 1,
|
||||
shift: 0,
|
||||
zeile: 1,
|
||||
spalte: 1,
|
||||
}));
|
||||
}
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended, "FORM_{name}");
|
||||
event_nachgewiesen(&format!("FORM_{name}"), integer(&vm, "n")).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registrierte_control_ereignisse_erreichen_basic_aus_realen_quellen() {
|
||||
use tb_frontend::forms::{self, EventParamType};
|
||||
let mut failures = Vec::new();
|
||||
for class in ObjectClass::ALL
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|c| *c != ObjectClass::Form)
|
||||
{
|
||||
for name in forms::events(class) {
|
||||
let mut catalog = FormCatalog::default();
|
||||
catalog.add("Form1", ObjectClass::Form, None, false);
|
||||
if class == ObjectClass::Menu {
|
||||
catalog.add("Bar", ObjectClass::Menu, Some("Form1"), false);
|
||||
}
|
||||
catalog.add(
|
||||
"Probe",
|
||||
class,
|
||||
Some(if class == ObjectClass::Menu {
|
||||
"Bar"
|
||||
} else {
|
||||
"Form1"
|
||||
}),
|
||||
false,
|
||||
);
|
||||
catalog.add("Source", ObjectClass::TextBox, Some("Form1"), false);
|
||||
let args = forms::event_params(name)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(n, t)| {
|
||||
format!(
|
||||
"{n} AS {}",
|
||||
match t {
|
||||
EventParamType::Integer => "INTEGER",
|
||||
EventParamType::Single => "SINGLE",
|
||||
EventParamType::Control => "CONTROL",
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let mut setup = String::from(
|
||||
"Form1.Width=60\nForm1.Height=15\nForm1.Show\nSource.Left=40\nSource.Top=2\n",
|
||||
);
|
||||
if !matches!(class, ObjectClass::Timer | ObjectClass::Menu) {
|
||||
setup.push_str("Probe.Left=10\nProbe.Top=4\n");
|
||||
}
|
||||
let operation = match *name {
|
||||
"GOTFOCUS" => String::new(),
|
||||
"LOSTFOCUS" => "Source.SetFocus".into(),
|
||||
"PAINT" => "Probe.Refresh".into(),
|
||||
"DRAGOVER" | "DRAGDROP" => "Source.Drag 1".into(),
|
||||
"CHANGE" => match class {
|
||||
ObjectClass::Label => "Probe.Caption=\"changed\"".into(),
|
||||
ObjectClass::HScrollBar | ObjectClass::VScrollBar => "Probe.Value=1".into(),
|
||||
ObjectClass::DirListBox => {
|
||||
format!("Probe.Path=\"{}\"", std::env::temp_dir().display())
|
||||
}
|
||||
ObjectClass::DriveListBox => "Probe.Drive=\"/\"".into(),
|
||||
_ => "Probe.Text=\"changed\"".into(),
|
||||
},
|
||||
"PATHCHANGE" => format!("Probe.Path=\"{}\"", std::env::temp_dir().display()),
|
||||
"PATTERNCHANGE" => "Probe.Pattern=\"*.bas\"".into(),
|
||||
"TIMER" => "Probe.Interval=1\nProbe.Enabled=-1".into(),
|
||||
"CLICK" if class == ObjectClass::Menu => {
|
||||
setup.push_str("Probe.Caption=\"&Go\"\nProbe.Shortcut=\"F3\"\n");
|
||||
String::new()
|
||||
}
|
||||
"CLICK" | "DBLCLICK" | "MOUSEDOWN" | "MOUSEMOVE" | "MOUSEUP" | "KEYDOWN"
|
||||
| "KEYPRESS" | "KEYUP" | "DROPDOWN" | "CUSTOM" => String::new(),
|
||||
other => panic!(
|
||||
"{}_{other}: Status implementiert, Auslöser fehlt",
|
||||
class.name()
|
||||
),
|
||||
};
|
||||
let src=format!("DIM SHARED n%\n{setup}\nn%=0\nSTOP\n{operation}\nSTOP\nDOEVENTS\nEND\nSUB Probe_{name}({args})\nSHARED n%\nn%=n%+1\nEND SUB");
|
||||
let mut vm = Vm::new(
|
||||
tb_vm::compile_source_with_forms("FORM1", &src, &catalog)
|
||||
.unwrap_or_else(|d| panic!("{}_{name}: {d:?}", class.name())),
|
||||
);
|
||||
let mut host = CaptureHost::default();
|
||||
let initial = vm.run(&mut host);
|
||||
assert!(
|
||||
matches!(initial, RunEvent::Stopped { .. }),
|
||||
"{}_{name}: {initial:?}",
|
||||
class.name()
|
||||
);
|
||||
if *name == "LOSTFOCUS" {
|
||||
vm.forms.focus((1, None)).unwrap();
|
||||
}
|
||||
let second = vm.run(&mut host);
|
||||
assert!(
|
||||
matches!(second, RunEvent::Stopped { .. }),
|
||||
"{}_{name}: {second:?}",
|
||||
class.name()
|
||||
);
|
||||
if name.starts_with("KEY") || matches!(*name, "DROPDOWN" | "CUSTOM") {
|
||||
vm.forms.focus((1, None)).unwrap();
|
||||
}
|
||||
if *name == "TIMER" {
|
||||
host.uhr_vorruecken(2);
|
||||
}
|
||||
if name.starts_with("KEY") {
|
||||
host.ereignis(key("a"));
|
||||
}
|
||||
if *name == "DROPDOWN" {
|
||||
host.ereignis(Ereignis::Taste("\0P".into(), 4));
|
||||
}
|
||||
if *name == "CUSTOM" {
|
||||
host.ereignis(key("\0H"));
|
||||
}
|
||||
if class == ObjectClass::Menu {
|
||||
host.ereignis(key("\0="));
|
||||
}
|
||||
let events: &[MausArt] = match *name {
|
||||
"MOUSEDOWN" | "GOTFOCUS" => &[MausArt::Druck],
|
||||
"MOUSEMOVE" | "DRAGOVER" => &[MausArt::Bewegung],
|
||||
"MOUSEUP" | "DRAGDROP" => &[MausArt::Bewegung, MausArt::Loslassen],
|
||||
"CLICK" if class != ObjectClass::Menu => &[MausArt::Druck, MausArt::Loslassen],
|
||||
"DBLCLICK" => &[
|
||||
MausArt::Druck,
|
||||
MausArt::Loslassen,
|
||||
MausArt::Druck,
|
||||
MausArt::Loslassen,
|
||||
],
|
||||
_ => &[],
|
||||
};
|
||||
for art in events {
|
||||
host.ereignis(Ereignis::Maus(MausEreignis {
|
||||
art: *art,
|
||||
taste: 1,
|
||||
shift: 0,
|
||||
zeile: 5,
|
||||
spalte: 11,
|
||||
}));
|
||||
}
|
||||
let result = vm.run(&mut host);
|
||||
if result != RunEvent::Ended || integer(&vm, "n") == 0 {
|
||||
failures.push(format!(
|
||||
"{}_{name}: Status implementiert, Handler unerreicht: {result:?}",
|
||||
class.name()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(failures.is_empty(), "{}", failures.join("\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shell_und_irr_funktionssignaturen_erreichen_die_runtime() {
|
||||
let mut vm = vm_for_source(
|
||||
"DIM a(1) AS DOUBLE\na(0)=-100\na(1)=110\nr#=IRR#(a,.1)\ns&=SHELL(\"exit 7\")\nEND",
|
||||
);
|
||||
assert_eq!(vm.run(&mut CaptureHost::default()), RunEvent::Ended);
|
||||
assert!(matches!(vm.inspect("r"),Some(Value::Dbl(n)) if (n-0.1).abs()<1e-8));
|
||||
assert!(matches!(vm.inspect("s"), Some(Value::Lng(7))));
|
||||
}
|
||||
|
||||
fn event_nachgewiesen(name: &str, count: i16) -> Result<(), String> {
|
||||
if count > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
"{name}: Status implementiert, fehlender Auslösepfad zum BASIC-Handler"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fehlender_ereignispfad_wird_namentlich_erkannt() {
|
||||
let mut catalog = FormCatalog::default();
|
||||
catalog.add("Form1", ObjectClass::Form, None, false);
|
||||
let mut module=tb_vm::compile_source_with_forms("FORM1","DIM SHARED n%\nForm1.Show\nSTOP\nDOEVENTS\nEND\nSUB Form_KeyPress(KeyAscii AS INTEGER)\nSHARED n%\nn%=n%+1\nEND SUB",&catalog).unwrap();
|
||||
module.event_procs.clear(); // künstlich fehlende Dispatch-Bindung
|
||||
let mut vm = Vm::new(module);
|
||||
let mut host = CaptureHost::default();
|
||||
stop(&mut vm, &mut host);
|
||||
host.ereignis(key("a"));
|
||||
assert_eq!(vm.run(&mut host), RunEvent::Ended);
|
||||
let error = event_nachgewiesen("FORM_KEYPRESS", integer(&vm, "n")).unwrap_err();
|
||||
assert!(
|
||||
error.contains("FORM_KEYPRESS")
|
||||
&& error.contains("implementiert")
|
||||
&& error.contains("Auslösepfad")
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user