Spezifikationsabgleich und Regressionsnachweise abschließen
This commit is contained in:
@@ -84,8 +84,9 @@ impl FormFile {
|
||||
) -> Result<Vec<FormInitial>, tb_runtime::errors::RuntimeError> {
|
||||
fn collect(
|
||||
node: &FormNode,
|
||||
parent: Option<u16>,
|
||||
parent: Option<(u16, Option<i32>)>,
|
||||
catalog: &FormCatalog,
|
||||
form: &str,
|
||||
out: &mut Vec<FormInitial>,
|
||||
depth: usize,
|
||||
) -> Result<(), tb_runtime::errors::RuntimeError> {
|
||||
@@ -98,7 +99,8 @@ impl FormFile {
|
||||
.iter()
|
||||
.position(|o| {
|
||||
o.name.eq_ignore_ascii_case(&node.name)
|
||||
&& o.parent == parent
|
||||
&& ((o.array && catalog.belongs_to(o, form))
|
||||
|| o.parent == parent.map(|p| p.0))
|
||||
&& o.class == node.class
|
||||
})
|
||||
.ok_or(tb_runtime::errors::RuntimeError(420))? as u16;
|
||||
@@ -115,18 +117,29 @@ impl FormFile {
|
||||
if out.iter().any(|v| v.object == object && v.index == index) {
|
||||
return Err(tb_runtime::errors::RuntimeError(5));
|
||||
}
|
||||
let mut properties = node.properties.clone();
|
||||
if let Some((id, _)) = forms::property(node.class, "PARENT") {
|
||||
properties.insert(id, PropertyValue::Object(parent));
|
||||
}
|
||||
out.push(FormInitial {
|
||||
object,
|
||||
index,
|
||||
properties: node.properties.clone(),
|
||||
properties,
|
||||
});
|
||||
for child in &node.children {
|
||||
collect(child, Some(object), catalog, out, depth)?;
|
||||
collect(
|
||||
child,
|
||||
Some((object, (index != 0).then_some(index))),
|
||||
catalog,
|
||||
form,
|
||||
out,
|
||||
depth,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
let mut values = Vec::new();
|
||||
collect(&self.root, None, catalog, &mut values, 0)?;
|
||||
collect(&self.root, None, catalog, &self.root.name, &mut values, 0)?;
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
@@ -941,7 +954,7 @@ fn decode_object(symbol: &BinarySymbol, record: &BinaryRecord, bytes: &[u8]) ->
|
||||
set_property(&mut node, name, PropertyValue::Integer(value as i32));
|
||||
}
|
||||
}
|
||||
if let Some(value) = record_u16(bytes, start, end, 4) {
|
||||
if let Some(value) = record_u16(bytes, start, end, 4).filter(|_| symbol.is_array) {
|
||||
set_property(
|
||||
&mut node,
|
||||
"INDEX",
|
||||
@@ -1314,7 +1327,7 @@ fn write_node(node: &FormNode, depth: usize, out: &mut String) {
|
||||
let Some(value) = node.properties.get(&(id as u16)) else {
|
||||
continue;
|
||||
};
|
||||
if *value == default_value(spec) {
|
||||
if spec.name != "INDEX" && *value == default_value(spec) {
|
||||
continue;
|
||||
}
|
||||
out.push_str(&" ".repeat(depth + 1));
|
||||
@@ -1437,6 +1450,54 @@ mod tests {
|
||||
|
||||
const EXAMPLE: &str = "VERSION 1.00\nBegin Form Form1\n Caption = \"Beispiel\"\n Height = 15\n Begin CommandButton cmdOK\n Caption = \"&OK\"\n End\nEnd\n\nSUB cmdOK_Click ()\n UNLOAD Form1\nEND SUB\n";
|
||||
|
||||
#[test]
|
||||
fn explicit_default_is_preserved_until_canonical_write() {
|
||||
let original = "VERSION 1.00\r\nBegin Form Form1\r\n Begin CommandButton Ok\r\n Enabled = -1\r\n End\r\nEnd\r\n";
|
||||
let mut form = read_text("default.frm", original).unwrap();
|
||||
assert_eq!(write_text(&form), original);
|
||||
form.root.name = "Changed".into();
|
||||
let canonical = write_text(&form);
|
||||
assert_eq!(
|
||||
canonical,
|
||||
"VERSION 1.00\nBegin Form Changed\n Begin CommandButton Ok\n End\nEnd\n"
|
||||
);
|
||||
assert_eq!(
|
||||
write_text(&read_text("canonical.frm", &canonical).unwrap()),
|
||||
canonical
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_index_zero_remains_an_array_and_array_parents_are_preserved() {
|
||||
let mut form=read_text("array.frm", "VERSION 1.00\nBegin Form Form1\n Begin Frame A\n Begin Label Item\n Index = 0\n End\n End\n Begin Frame B\n Begin Label Item\n Index = 1\n End\n End\nEnd\n").unwrap();
|
||||
form.code = "END\n".into();
|
||||
let text = write_text(&form);
|
||||
assert!(text.contains("Index = 0"));
|
||||
let roundtrip = read_text("roundtrip.frm", &text).unwrap();
|
||||
let catalog = roundtrip.catalog();
|
||||
let item = catalog.find("Item").unwrap().0;
|
||||
assert!(catalog.objects[item as usize].array);
|
||||
let a = catalog.find("A").unwrap().0;
|
||||
let b = catalog.find("B").unwrap().0;
|
||||
let mut model = FormsModel::new(catalog.objects, 80, 25);
|
||||
roundtrip.apply(&mut model).unwrap();
|
||||
let parent = forms::property(ObjectClass::Label, "PARENT").unwrap().0;
|
||||
assert_eq!(
|
||||
model.get_at(item, Some(0), parent).unwrap(),
|
||||
PropertyValue::Object(Some((a, None)))
|
||||
);
|
||||
assert_eq!(
|
||||
model.get_at(item, Some(1), parent).unwrap(),
|
||||
PropertyValue::Object(Some((b, None)))
|
||||
);
|
||||
form.root.children.pop();
|
||||
let single = read_text("single.frm", &write_text(&form)).unwrap();
|
||||
assert!(
|
||||
single.catalog().objects[item as usize].array,
|
||||
"Einzelelement mit Index 0 bleibt Array"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_nested_form_and_preserves_source_exactly() {
|
||||
let form = read_text("test.frm", EXAMPLE).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user