forked from 1b-agent/opencadstudio-upstream
Merge pull request #1350 from helenkwok/fix/set-properties-number-expected
set_properties: compare expected numbers by value
This commit is contained in:
commit
752894e82b
1 file changed
+83
-1
+83
-1
@@ -1136,7 +1136,7 @@ fn apply_updates(
|
||||
.pointer_mut(path)
|
||||
.ok_or_else(|| format!("property does not exist: {path}"))?;
|
||||
if let Some(expected) = update.get("expected") {
|
||||
if target != expected {
|
||||
if !json_values_match(target, expected) {
|
||||
return Err(format!("property changed before update: {path}"));
|
||||
}
|
||||
}
|
||||
@@ -1151,6 +1151,27 @@ fn apply_updates(
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
/// Structural equality in which numbers compare by value. serde_json keeps
|
||||
/// `10` and `10.0` as different `Number`s, and a JavaScript client cannot send
|
||||
/// `10.0` at all (`JSON.stringify(10.0) === "10"`), so a stored whole-number
|
||||
/// float would otherwise never match its `expected` value.
|
||||
fn json_values_match(actual: &Value, expected: &Value) -> bool {
|
||||
match (actual, expected) {
|
||||
(Value::Number(a), Value::Number(b)) if a.is_f64() || b.is_f64() => {
|
||||
a.as_f64() == b.as_f64()
|
||||
}
|
||||
(Value::Array(a), Value::Array(b)) => {
|
||||
a.len() == b.len() && a.iter().zip(b).all(|(a, b)| json_values_match(a, b))
|
||||
}
|
||||
(Value::Object(a), Value::Object(b)) => {
|
||||
a.len() == b.len()
|
||||
&& a.iter()
|
||||
.all(|(key, a)| b.get(key).is_some_and(|b| json_values_match(a, b)))
|
||||
}
|
||||
_ => actual == expected,
|
||||
}
|
||||
}
|
||||
|
||||
fn patched_table_entry<T>(
|
||||
table: &Table<T>,
|
||||
request: &Value,
|
||||
@@ -1729,6 +1750,67 @@ mod tests {
|
||||
assert!(app.tabs[i].scene.document.summary_info.author.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_properties_expected_matches_whole_number_floats_by_value() {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.automation_op(r#"{"op":"new"}"#);
|
||||
let i = app.active_tab;
|
||||
let insert = Insert::new("A_CPT", Vector3::new(12.0, 34.0, 5.0));
|
||||
let entity = app.tabs[i].scene.add_entity(EntityType::Insert(insert));
|
||||
let handle = format!("{:X}", entity.value());
|
||||
|
||||
// `12` is how every JSON client sends the stored `12.0`.
|
||||
let scalar = execute(
|
||||
&mut app,
|
||||
json!({
|
||||
"op":"set_properties",
|
||||
"collection":"entities",
|
||||
"handle":handle,
|
||||
"updates":[{"path":"/insert_point/x","expected":12,"value":20.0}]
|
||||
}),
|
||||
"whole-number-scalar",
|
||||
);
|
||||
assert_eq!(scalar["status"], "completed", "{scalar}");
|
||||
|
||||
let nested = execute(
|
||||
&mut app,
|
||||
json!({
|
||||
"op":"set_properties",
|
||||
"collection":"entities",
|
||||
"handle":handle,
|
||||
"updates":[{
|
||||
"path":"/insert_point",
|
||||
"expected":{"x":20,"y":34,"z":5},
|
||||
"value":{"x":1.5,"y":2.0,"z":3.0}
|
||||
}]
|
||||
}),
|
||||
"whole-number-nested",
|
||||
);
|
||||
assert_eq!(nested["status"], "completed", "{nested}");
|
||||
let EntityType::Insert(insert) = app.tabs[i].scene.document.get_entity(entity).unwrap()
|
||||
else {
|
||||
panic!("expected insert")
|
||||
};
|
||||
assert_eq!(insert.insert_point.x, 1.5);
|
||||
|
||||
let stale = execute(
|
||||
&mut app,
|
||||
json!({
|
||||
"op":"set_properties",
|
||||
"collection":"entities",
|
||||
"handle":handle,
|
||||
"updates":[{"path":"/insert_point/x","expected":2,"value":9.0}]
|
||||
}),
|
||||
"stale-number",
|
||||
);
|
||||
assert_ne!(stale["status"], "completed", "{stale}");
|
||||
let EntityType::Insert(insert) = app.tabs[i].scene.document.get_entity(entity).unwrap()
|
||||
else {
|
||||
panic!("expected insert")
|
||||
};
|
||||
assert_eq!(insert.insert_point.x, 1.5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_schema_describes_absent_types_fields_enums_units_and_write_rules() {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
|
||||
Reference in new issue
Block a user