ocs_doc_api: layer CRUD, per-curve layer assignment, XDATA/XRECORD support, and bulk SetXDataMany

This commit is contained in:
Sebastian committed 2026-09-10 10:43:15 +02:00
1 parent b19992cbcb
commit 8bf5eac3fc
27 files changed
+3340 -181

No files matched your search

+462 -24
View File
@@ -8,15 +8,16 @@ use std::sync::Arc;
use ocs_doc_api::backend::{DocApiBackend, KernelBody};
use ocs_doc_api::{
Aabb, ApiError, ApiResult, Curve2Spec, DocApi, EntityView, GeometryErrorKind, GeometryRevision,
HasId, ObjectId, PlacementSpec,
normalize_layer_name, Aabb, ApiError, ApiResult, Color, Curve2Spec, DocApi, EntityView,
GeometryErrorKind, GeometryRevision, HasId, LayerInfo, LineWeight, ObjectId, PlacementSpec,
XDataRecord, XDataValue,
};
/// Coarse bounds for a stored 2D curve spec (mirrors the host's entity_bounds and
/// the example mock — all three must answer curve bounds identically).
fn curve_bounds(spec: &Curve2Spec) -> Aabb {
match spec {
Curve2Spec::Line { start, end } => Aabb {
Curve2Spec::Line { start, end, .. } => Aabb {
min: [
start[0].min(end[0]),
start[1].min(end[1]),
@@ -28,11 +29,12 @@ fn curve_bounds(spec: &Curve2Spec) -> Aabb {
start[2].max(end[2]),
],
},
Curve2Spec::Circle { centre, radius } | Curve2Spec::Arc { centre, radius, .. } => Aabb {
Curve2Spec::Circle { centre, radius, .. }
| Curve2Spec::Arc { centre, radius, .. } => Aabb {
min: [centre[0] - radius, centre[1] - radius, centre[2]],
max: [centre[0] + radius, centre[1] + radius, centre[2]],
},
Curve2Spec::Point { position } => Aabb {
Curve2Spec::Point { position, .. } => Aabb {
min: *position,
max: *position,
},
@@ -72,13 +74,17 @@ fn curve_bounds(spec: &Curve2Spec) -> Aabb {
/// In-memory mock backend: HashMap<ObjectId, Body> + a tiny entity table.
/// Tracks undo steps + revision bumps to assert per-op semantics.
#[derive(Default, Clone)]
#[derive(Clone)]
struct MockBackend {
next_id: u64,
revision: u64,
undo_steps: u32,
bodies: HashMap<ObjectId, KernelBody>,
kinds: HashMap<ObjectId, String>,
/// Layer name assigned to each entity.
entity_layers: HashMap<ObjectId, String>,
/// Stored layer table.
layers: HashMap<String, ocs_doc_api::LayerInfo>,
/// Stored text content for Text/MText annotations.
text_values: HashMap<ObjectId, String>,
/// Stored hatch boundary loops.
@@ -92,6 +98,36 @@ struct MockBackend {
curves: HashMap<ObjectId, Curve2Spec>,
/// Stored viewport views (target, height).
viewport_views: HashMap<ObjectId, ([f64; 3], f64)>,
/// Stored XDATA records keyed by (entity id, application name).
xdata_store: HashMap<(ObjectId, String), ocs_doc_api::XDataRecord>,
/// Stored XRECORD payloads keyed by entity id.
xrecord_store: HashMap<ObjectId, ocs_doc_api::XRecordSpec>,
}
impl Default for MockBackend {
fn default() -> Self {
let mut backend = Self {
next_id: 0,
revision: 0,
undo_steps: 0,
bodies: HashMap::new(),
kinds: HashMap::new(),
entity_layers: HashMap::new(),
layers: HashMap::new(),
text_values: HashMap::new(),
hatch_boundaries: HashMap::new(),
dimension_measurements: HashMap::new(),
attributes_store: HashMap::new(),
curves: HashMap::new(),
viewport_views: HashMap::new(),
xdata_store: HashMap::new(),
xrecord_store: HashMap::new(),
};
backend
.layers
.insert("0".to_string(), ocs_doc_api::LayerInfo::new("0"));
backend
}
}
impl MockBackend {
@@ -104,6 +140,22 @@ impl MockBackend {
fn body(&self, id: ObjectId) -> ApiResult<&KernelBody> {
self.bodies.get(&id).ok_or(ApiError::UnknownId(id))
}
fn add_curve_only(&mut self, spec: &Curve2Spec) -> ApiResult<ObjectId> {
let kind = match spec {
Curve2Spec::Line { .. } => "Line",
Curve2Spec::Circle { .. } => "Circle",
Curve2Spec::Polyline { .. } => "LwPolyline",
Curve2Spec::Point { .. } => "Point",
Curve2Spec::Arc { .. } => "Arc",
Curve2Spec::Ellipse { .. } => "Ellipse",
Curve2Spec::Spline { .. } => "Spline",
Curve2Spec::Ray { .. } => "Ray",
Curve2Spec::XLine { .. } => "XLine",
};
let id = self.alloc(kind);
self.curves.insert(id, spec.clone());
Ok(id)
}
}
impl DocApiBackend for MockBackend {
@@ -113,6 +165,7 @@ impl DocApiBackend for MockBackend {
fn store_solid(&mut self, body: &KernelBody) -> ApiResult<ObjectId> {
let id = self.alloc("Solid3D");
self.bodies.insert(id, body.clone());
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn update_solid(&mut self, id: ObjectId, body: &KernelBody) -> ApiResult<()> {
@@ -122,6 +175,15 @@ impl DocApiBackend for MockBackend {
Ok(())
}
fn create_many(&mut self, specs: &[ocs_doc_api::EntitySpec]) -> ApiResult<Vec<ObjectId>> {
// Validate per-spec layers up front so the op is atomic.
for spec in specs {
if let Some(name) = spec.layer() {
self.lookup_layer(name).map_err(|e| ApiError::validation(
"CreateMany",
e.to_string(),
))?;
}
}
let mut next = self.clone();
let ids = specs
.iter()
@@ -151,26 +213,35 @@ impl DocApiBackend for MockBackend {
Ok(())
}
fn add_curve(&mut self, spec: &Curve2Spec) -> ApiResult<ObjectId> {
let kind = match spec {
Curve2Spec::Line { .. } => "Line",
Curve2Spec::Circle { .. } => "Circle",
Curve2Spec::Polyline { .. } => "LwPolyline",
Curve2Spec::Point { .. } => "Point",
Curve2Spec::Arc { .. } => "Arc",
Curve2Spec::Ellipse { .. } => "Ellipse",
Curve2Spec::Spline { .. } => "Spline",
Curve2Spec::Ray { .. } => "Ray",
Curve2Spec::XLine { .. } => "XLine",
};
let id = self.alloc(kind);
self.curves.insert(id, spec.clone());
let layer = spec
.layer()
.map(|name| {
self.lookup_layer(name).map(|info| info.normalized_name())
})
.transpose()?;
let id = self.add_curve_only(spec)?;
self.entity_layers
.insert(id, layer.unwrap_or_else(|| "0".to_string()));
Ok(id)
}
fn lookup_layer(&self, name: &str) -> ApiResult<ocs_doc_api::LayerInfo> {
let norm = normalize_layer_name(name);
if norm.is_empty() {
return Err(ApiError::validation("LookupLayer", "empty layer name"));
}
self.layers
.get(&norm)
.cloned()
.ok_or_else(|| ApiError::validation("LookupLayer", format!("layer '{name}' does not exist")))
}
fn add_insert(&mut self, spec: &ocs_doc_api::ops::InsertSpec) -> ApiResult<ObjectId> {
if spec.block_name.is_empty() {
return Err(ApiError::validation("CreateInsert", "empty block name"));
}
Ok(self.alloc("Insert"))
let id = self.alloc("Insert");
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn add_viewport(&mut self, spec: &ocs_doc_api::ops::ViewportSpec) -> ApiResult<ObjectId> {
let id = self.alloc("Viewport");
@@ -181,11 +252,13 @@ impl DocApiBackend for MockBackend {
fn add_text(&mut self, spec: &ocs_doc_api::ops::TextSpec) -> ApiResult<ObjectId> {
let id = self.alloc("Text");
self.text_values.insert(id, spec.value.clone());
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn add_mtext(&mut self, spec: &ocs_doc_api::ops::MTextSpec) -> ApiResult<ObjectId> {
let id = self.alloc("MText");
self.text_values.insert(id, spec.value.clone());
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn set_text_content(&mut self, id: ObjectId, value: &str) -> ApiResult<()> {
@@ -206,6 +279,7 @@ impl DocApiBackend for MockBackend {
let id = self.alloc("Hatch");
self.hatch_boundaries
.insert(id, vec![spec.boundary.clone()]);
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn hatch_boundary(&self, id: ObjectId) -> ApiResult<Vec<Vec<[f64; 2]>>> {
@@ -224,6 +298,7 @@ impl DocApiBackend for MockBackend {
+ (spec.first_point[2] - spec.second_point[2]).powi(2))
.sqrt();
self.dimension_measurements.insert(id, d);
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn add_dimension_radius(
@@ -236,13 +311,16 @@ impl DocApiBackend for MockBackend {
+ (spec.center[2] - spec.point[2]).powi(2))
.sqrt();
self.dimension_measurements.insert(id, d);
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn add_dimension_diameter(
&mut self,
spec: &ocs_doc_api::ops::DimensionRadialSpec,
) -> ApiResult<ObjectId> {
self.add_dimension_radius(spec)
let id = self.add_dimension_radius(spec)?;
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn add_dimension_angular(
&mut self,
@@ -250,6 +328,7 @@ impl DocApiBackend for MockBackend {
) -> ApiResult<ObjectId> {
let id = self.alloc("Dimension");
self.dimension_measurements.insert(id, 90.0); // mock: 90 degrees
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn dimension_measurement(&self, id: ObjectId) -> ApiResult<f64> {
@@ -286,7 +365,9 @@ impl DocApiBackend for MockBackend {
"table needs a non-empty rectangular grid",
));
}
Ok(self.alloc("Table"))
let id = self.alloc("Table");
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn set_attribute(&mut self, id: ObjectId, tag: &str, value: &str) -> ApiResult<()> {
if !self.entity_exists(id) {
@@ -313,7 +394,9 @@ impl DocApiBackend for MockBackend {
&mut self,
_spec: &ocs_doc_api::ops::RasterImageSpec,
) -> ApiResult<ObjectId> {
Ok(self.alloc("RasterImage"))
let id = self.alloc("RasterImage");
self.entity_layers.insert(id, "0".to_string());
Ok(id)
}
fn loft(
&mut self,
@@ -345,6 +428,203 @@ impl DocApiBackend for MockBackend {
.copied()
.ok_or(ApiError::UnknownId(id))
}
fn set_xdata(
&mut self,
id: ObjectId,
application_name: &str,
record: Option<&ocs_doc_api::XDataRecord>,
) -> ApiResult<()> {
if !self.entity_exists(id) {
return Err(ApiError::UnknownId(id));
}
let key = (id, application_name.to_string());
match record {
Some(r) => {
self.xdata_store.insert(key, r.clone());
}
None => {
self.xdata_store.remove(&key);
}
}
Ok(())
}
fn xdata(
&self,
id: ObjectId,
application_name: &str,
) -> ApiResult<Option<ocs_doc_api::XDataRecord>> {
if !self.entity_exists(id) {
return Err(ApiError::UnknownId(id));
}
Ok(self
.xdata_store
.get(&(id, application_name.to_string()))
.cloned())
}
fn add_xrecord(&mut self, spec: &ocs_doc_api::XRecordSpec) -> ApiResult<ObjectId> {
let id = self.alloc("XRecord");
self.xrecord_store.insert(id, spec.clone());
Ok(id)
}
fn set_xrecord(&mut self, id: ObjectId, spec: &ocs_doc_api::XRecordSpec) -> ApiResult<()> {
if !self.object_exists(id) {
return Err(ApiError::validation(
"SetXRecord",
format!("unknown ObjectId {id:?}"),
));
}
self.xrecord_store.insert(id, spec.clone());
Ok(())
}
fn xrecord(&self, id: ObjectId) -> ApiResult<Option<ocs_doc_api::XRecordSpec>> {
if !self.object_exists(id) {
return Err(ApiError::validation(
"GetXRecord",
format!("unknown ObjectId {id:?}"),
));
}
Ok(self.xrecord_store.get(&id).cloned())
}
fn create_layer(&mut self, info: &ocs_doc_api::LayerInfo) -> ApiResult<()> {
let name = normalize_layer_name(&info.name);
if name.is_empty() {
return Err(ApiError::validation("CreateLayer", "empty layer name"));
}
if self.layers.contains_key(&name) {
return Err(ApiError::validation(
"CreateLayer",
format!("layer '{name}' already exists"),
));
}
let mut stored = info.clone();
stored.name = name.clone();
self.layers.insert(name, stored);
Ok(())
}
fn update_layer(&mut self, name: &str, info: &ocs_doc_api::LayerInfo) -> ApiResult<()> {
let name_upper = normalize_layer_name(name);
if !self.layers.contains_key(&name_upper) {
return Err(ApiError::validation(
"UpdateLayer",
format!("layer '{name}' does not exist"),
));
}
let mut stored = info.clone();
stored.name = name_upper.clone();
self.layers.insert(name_upper, stored);
Ok(())
}
fn delete_layer(&mut self, name: &str) -> ApiResult<()> {
let name_upper = normalize_layer_name(name);
if name_upper == "0" {
return Err(ApiError::validation("DeleteLayer", "cannot delete layer 0"));
}
if self
.entity_layers
.values()
.any(|l| normalize_layer_name(l) == name_upper)
{
return Err(ApiError::validation(
"DeleteLayer",
format!("layer '{name_upper}' still in use"),
));
}
if self.layers.remove(&name_upper).is_none() {
return Err(ApiError::validation(
"DeleteLayer",
format!("layer '{name}' does not exist"),
));
}
Ok(())
}
fn set_entity_layer(&mut self, id: ObjectId, layer: &str) -> ApiResult<()> {
if !self.entity_exists(id) {
return Err(ApiError::UnknownId(id));
}
let layer_upper = normalize_layer_name(layer);
let target = self
.layers
.get(&layer_upper)
.ok_or_else(|| {
ApiError::validation(
"SetEntityLayer",
format!("layer '{layer_upper}' does not exist"),
)
})?;
if target.flags.locked {
return Err(ApiError::Unsupported(format!(
"entity {id:?} cannot be moved to locked layer '{layer_upper}'"
)));
}
self.entity_layers.insert(id, layer_upper);
Ok(())
}
fn layers(&self) -> ApiResult<Vec<ocs_doc_api::LayerInfo>> {
let mut v: Vec<_> = self.layers.values().cloned().collect();
v.sort_by(|a, b| a.name.cmp(&b.name));
Ok(v)
}
fn entity_layer(&self, id: ObjectId) -> ApiResult<String> {
self.entity_layers
.get(&id)
.cloned()
.ok_or(ApiError::UnknownId(id))
}
fn enumerate_entities(
&self,
kind: Option<&str>,
layer: Option<&str>,
include_bounds: bool,
) -> ApiResult<Vec<EntityView>> {
let mut out = Vec::new();
for (id, kind_name) in &self.kinds {
if let Some(k) = kind {
if !k.eq_ignore_ascii_case(kind_name) {
continue;
}
}
let entity_layer = self
.entity_layers
.get(id)
.cloned()
.unwrap_or_else(|| "0".to_string());
if let Some(l) = layer {
if !l.eq_ignore_ascii_case(&entity_layer) {
continue;
}
}
let bounds = if include_bounds {
self.curves.get(id).map(curve_bounds)
} else {
None
};
out.push(EntityView {
id: *id,
kind: kind_name.clone(),
layer: entity_layer,
bounds,
});
}
Ok(out)
}
fn point_position(&self, id: ObjectId) -> ApiResult<[f64; 3]> {
let spec = self.curves.get(&id).ok_or(ApiError::UnknownId(id))?;
match spec {
Curve2Spec::Point { position, .. } => Ok(*position),
_ => Err(ApiError::Unsupported(
"GetPointPosition is only for Point entities".into(),
)),
}
}
fn line_geometry(&self, id: ObjectId) -> ApiResult<([f64; 3], [f64; 3])> {
let spec = self.curves.get(&id).ok_or(ApiError::UnknownId(id))?;
match spec {
Curve2Spec::Line { start, end, .. } => Ok((*start, *end)),
_ => Err(ApiError::Unsupported(
"GetLineGeometry is only for Line entities".into(),
)),
}
}
fn add_vertex(&mut self, id: ObjectId, _at: usize, _point: [f64; 3]) -> ApiResult<()> {
if self.entity_exists(id) {
Ok(())
@@ -354,6 +634,9 @@ impl DocApiBackend for MockBackend {
}
fn remove_entity(&mut self, id: ObjectId) -> ApiResult<bool> {
self.bodies.remove(&id);
self.xdata_store.retain(|(k, _), _| *k != id);
self.xrecord_store.remove(&id);
self.entity_layers.remove(&id);
Ok(self.kinds.remove(&id).is_some())
}
fn get_entity(&mut self, id: ObjectId) -> ApiResult<EntityView> {
@@ -364,7 +647,17 @@ impl DocApiBackend for MockBackend {
max: bb.max,
})
});
Ok(EntityView { id, kind, bounds })
let layer = self
.entity_layers
.get(&id)
.cloned()
.unwrap_or_else(|| "0".to_string());
Ok(EntityView {
id,
kind,
layer,
bounds,
})
}
fn transform_entity(&mut self, id: ObjectId, placement: &PlacementSpec) -> ApiResult<()> {
if !self.entity_exists(id) {
@@ -412,6 +705,9 @@ impl DocApiBackend for MockBackend {
fn entity_exists(&self, id: ObjectId) -> bool {
self.kinds.contains_key(&id)
}
fn object_exists(&self, id: ObjectId) -> bool {
self.xrecord_store.contains_key(&id)
}
fn revision(&self) -> GeometryRevision {
GeometryRevision(self.revision)
}
@@ -609,3 +905,145 @@ fn typed_handles_reject_foreign_sessions_and_tabs() {
assert!(group.compensate(&doc).is_err());
assert!(first.document(11).curves().create_point([0.0; 3]).is_err());
}
#[test]
fn doc_api_layer_crud_via_facade_and_entity_assignment() {
let (api, _tp) = api();
let doc = api.document(api.active_tab());
let mut info = LayerInfo::new("Walls");
info.color = Color::Index(1);
info.line_weight = LineWeight::Value(25);
doc.create_layer(&info).unwrap();
let layers = doc.layers().unwrap();
assert!(layers.iter().any(|l| l.name == "WALLS"));
let mut updated = info.clone();
updated.color = Color::Index(2);
doc.update_layer("walls", &updated).unwrap();
let line = doc.curves().create_line([0.0; 3], [1.0; 3]).unwrap();
line.set_layer("Walls").unwrap();
assert_eq!(line.layer().unwrap(), "WALLS");
let err = doc.delete_layer("Walls").unwrap_err();
assert!(matches!(err, ApiError::Validation { .. }));
let other = LayerInfo::new("Other");
doc.create_layer(&other).unwrap();
line.set_layer("Other").unwrap();
doc.delete_layer("Walls").unwrap();
assert!(!doc.layers().unwrap().iter().any(|l| l.name == "WALLS"));
}
#[test]
fn set_xdata_many_is_atomic_and_assigns_records() {
let (api, _tp) = api();
let doc = api.document(api.active_tab());
let line = doc.curves().create_line([0.0; 3], [1.0; 3]).unwrap();
let circle = doc.curves().create_circle([0.0; 3], 1.0).unwrap();
let record1 = XDataRecord {
application_name: "APP1".to_string(),
values: vec![XDataValue::Integer32(42)],
};
let record2 = XDataRecord {
application_name: "APP2".to_string(),
values: vec![XDataValue::Real(3.14)],
};
doc.set_xdata_many([
(line.id(), "APP1", Some(record1.clone())),
(circle.id(), "APP2", Some(record2.clone())),
])
.unwrap();
let r1 = doc.entities().get(line.id()).unwrap().xdata("APP1").unwrap().unwrap();
assert_eq!(r1.values, vec![XDataValue::Integer32(42)]);
let r2 = doc.entities().get(circle.id()).unwrap().xdata("APP2").unwrap().unwrap();
assert_eq!(r2.values, vec![XDataValue::Real(3.14)]);
}
#[test]
fn set_xdata_many_with_unknown_id_fails_atomically() {
let (api, _tp) = api();
let doc = api.document(api.active_tab());
let line = doc.curves().create_line([0.0; 3], [1.0; 3]).unwrap();
let stale = ObjectId::from_u64(999_999);
let record = XDataRecord {
application_name: "APP1".to_string(),
values: vec![XDataValue::Integer32(42)],
};
let err = doc
.set_xdata_many([
(line.id(), "APP1", Some(record.clone())),
(stale, "APP2", Some(record)),
])
.unwrap_err();
assert!(matches!(err, ApiError::UnknownId(..) | ApiError::Validation { .. }));
assert!(doc.entities().get(line.id()).unwrap().xdata("APP1").unwrap().is_none());
}
#[test]
fn create_many_applies_per_curve_layer() {
let (api, _tp) = api();
let doc = api.document(api.active_tab());
doc.create_layer(&LayerInfo::new("Walls")).unwrap();
let ids = doc
.entities()
.create_many(&[
ocs_doc_api::EntitySpec::Curve(Curve2Spec::Line {
start: [0.0; 3],
end: [1.0; 3],
layer: Some("Walls".to_string()),
}),
ocs_doc_api::EntitySpec::Curve(Curve2Spec::Point {
position: [2.0; 3],
layer: None,
}),
])
.unwrap();
assert_eq!(ids[0].layer().unwrap(), "WALLS");
assert_eq!(ids[1].layer().unwrap(), "0");
}
#[test]
fn create_many_rejects_missing_layer_before_mutating() {
let (api, tp) = api();
let doc = api.document(api.active_tab());
let rev0 = doc.revision().unwrap().as_u64();
let err = doc
.entities()
.create_many(&[
ocs_doc_api::EntitySpec::Curve(Curve2Spec::Line {
start: [0.0; 3],
end: [1.0; 3],
layer: Some("Missing".to_string()),
}),
ocs_doc_api::EntitySpec::Curve(Curve2Spec::Point {
position: [2.0; 3],
layer: None,
}),
])
.unwrap_err();
assert!(matches!(err, ApiError::Validation { .. }));
let backend = tp.backend();
assert_eq!(backend.revision, rev0);
assert_eq!(backend.next_id, 0);
}
#[test]
fn create_line_on_layer_requires_existing_layer() {
let (api, _tp) = api();
let doc = api.document(api.active_tab());
let err = doc
.curves()
.create_line_on_layer([0.0; 3], [1.0; 3], "Missing")
.unwrap_err();
assert!(matches!(err, ApiError::Validation { .. }));
}
@@ -38,7 +38,8 @@ fn spec() -> Spec {
/// The variant names of the `Operation` enum, in declaration order.
fn operation_variants() -> Vec<String> {
use ocs_doc_api::ops::{
BoolOp, Curve2Spec, InsertSpec, Operation, PlacementSpec, SolidPrimitive, ViewportSpec,
BoolOp, Curve2Spec, InsertSpec, LayerInfo, Operation, PlacementSpec, SolidPrimitive,
ViewportSpec,
};
use ocs_doc_api::ObjectId;
let _marker: Vec<Operation> = vec![
@@ -46,7 +47,10 @@ fn operation_variants() -> Vec<String> {
centre: [0.0; 3],
radius: 1.0,
}),
Operation::CreateCurve(Curve2Spec::Point { position: [0.0; 3] }),
Operation::CreateCurve(Curve2Spec::Point {
position: [0.0; 3],
layer: None,
}),
Operation::Extrude {
profile: ObjectId::from_u64(0),
direction: [0.0; 3],
@@ -167,6 +171,37 @@ fn operation_variants() -> Vec<String> {
second_point: [0.0; 3],
arc_location: [0.0; 3],
}),
Operation::SetXData {
id: ObjectId::from_u64(0),
application_name: String::new(),
record: None,
},
Operation::SetXDataMany(vec![]),
Operation::CreateXRecord(ocs_doc_api::ops::XRecordSpec {
name: String::new(),
cloning_flags: ocs_doc_api::ops::XRecordCloningFlags::NotApplicable,
entries: vec![],
}),
Operation::SetXRecord {
id: ObjectId::from_u64(0),
spec: ocs_doc_api::ops::XRecordSpec {
name: String::new(),
cloning_flags: ocs_doc_api::ops::XRecordCloningFlags::NotApplicable,
entries: vec![],
},
},
Operation::CreateLayer(LayerInfo::new("LAYER")),
Operation::UpdateLayer {
name: String::new(),
info: LayerInfo::new("LAYER"),
},
Operation::DeleteLayer {
name: String::new(),
},
Operation::SetEntityLayer {
id: ObjectId::from_u64(0),
layer: String::new(),
},
];
_marker
.iter()
@@ -178,7 +213,7 @@ fn operation_variants() -> Vec<String> {
index
);
let dbg = format!("{:?}", op);
dbg.split(|c: char| c == '(' || c == ' ' || c == '{')
dbg.split(['(', ' ', '{'])
.next()
.unwrap_or("")
.to_string()
@@ -226,6 +261,17 @@ fn query_variants() -> Vec<String> {
Query::GetViewportView {
id: ObjectId::from_u64(0),
},
Query::GetXData {
id: ObjectId::from_u64(0),
application_name: String::new(),
},
Query::GetXRecord {
id: ObjectId::from_u64(0),
},
Query::ListLayers,
Query::GetEntityLayer {
id: ObjectId::from_u64(0),
},
];
marker
.iter()
@@ -237,7 +283,7 @@ fn query_variants() -> Vec<String> {
index
);
let dbg = format!("{:?}", q);
dbg.split(|c: char| c == '(' || c == ' ' || c == '{')
dbg.split(['(', ' ', '{'])
.next()
.unwrap_or("")
.to_string()
@@ -309,6 +355,14 @@ const OPERATION_BASELINE: &[&str] = &[
"CreateAttributeDefinition",
"CreateTable",
"CreateDimensionAngular2Ln",
"SetXData",
"SetXDataMany",
"CreateXRecord",
"SetXRecord",
"CreateLayer",
"UpdateLayer",
"DeleteLayer",
"SetEntityLayer",
];
/// Recorded baseline of the `Query` variant order.
@@ -325,6 +379,10 @@ const QUERY_BASELINE: &[&str] = &[
"GetAttributes",
"GetBlockEntities",
"GetViewportView",
"GetXData",
"GetXRecord",
"ListLayers",
"GetEntityLayer",
];
#[test]