Files

155 lines
5.6 KiB
Rust

//! 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"));
}