use crate::geometry::analytic::{LineCurve, PlaneSurface};
use crate::geometry::pcurve::{
LinePcurve, OffsetPcurve, PcurveGeometry, PlacedPcurve, TrimmedPcurve,
};
use crate::geometry::{
PlacedCurve, PlacedSurface, SolvedCurveGeometry, SolvedSurfaceGeometry, MAX_GEOMETRY_NESTING,
};
use crate::math::{Point3, Vector3};
use crate::transform::{Transform, Transform2};
fn placed_plane(placements: usize) -> Result<SolvedSurfaceGeometry, &'static str> {
let mut geometry = SolvedSurfaceGeometry::Plane(
PlaneSurface::try_new(
Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, 0.0, 1.0),
Vector3::new(1.0, 0.0, 0.0),
)
.expect("a unit-axis plane"),
);
for _ in 0..placements {
geometry = SolvedSurfaceGeometry::Transformed(PlacedSurface::try_new(
Box::new(geometry),
Transform::identity(),
)?);
}
Ok(geometry)
}
fn placed_line(placements: usize) -> Result<SolvedCurveGeometry, &'static str> {
let mut geometry = SolvedCurveGeometry::Line(
LineCurve::try_new(Point3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 0.0, 0.0))
.expect("a unit-direction line"),
);
for _ in 0..placements {
geometry = SolvedCurveGeometry::Transformed(PlacedCurve::try_new(
Box::new(geometry),
Transform::identity(),
)?);
}
Ok(geometry)
}
fn nested_pcurve(carriers: usize) -> Result<PcurveGeometry, &'static str> {
let mut geometry = PcurveGeometry::Line(LinePcurve::U_AXIS);
for index in 0..carriers {
geometry = match index % 3 {
0 => PcurveGeometry::Transformed(PlacedPcurve::try_new(
Box::new(geometry),
Transform2::identity(),
)?),
1 => PcurveGeometry::Trimmed(TrimmedPcurve::try_new(
[0.0, 1.0],
true,
Box::new(geometry),
)?),
_ => PcurveGeometry::Offset(OffsetPcurve::try_new(1.0, Box::new(geometry))?),
};
}
Ok(geometry)
}
#[test]
fn a_surface_placement_chain_one_past_the_bound_is_refused() {
assert!(placed_plane(MAX_GEOMETRY_NESTING).is_ok());
assert_eq!(
placed_plane(MAX_GEOMETRY_NESTING + 1),
Err("PlacedSurface.basis nests past the admitted inline basis depth")
);
}
#[test]
fn a_curve_placement_chain_one_past_the_bound_is_refused() {
assert!(placed_line(MAX_GEOMETRY_NESTING).is_ok());
assert_eq!(
placed_line(MAX_GEOMETRY_NESTING + 1),
Err("PlacedCurve.basis nests past the admitted inline basis depth")
);
}
#[test]
fn a_pcurve_nesting_chain_one_past_the_bound_is_refused() {
assert!(nested_pcurve(MAX_GEOMETRY_NESTING).is_ok());
assert_eq!(
nested_pcurve(MAX_GEOMETRY_NESTING + 1),
Err("TrimmedPcurve.basis nests past the admitted inline basis depth")
);
}
#[test]
fn the_json_parser_refuses_a_chain_well_under_the_bound() {
let deep = placed_plane(MAX_GEOMETRY_NESTING).expect("admitted nesting");
let json = serde_json::to_string(&deep).expect("serialized");
let error = serde_json::from_str::<SolvedSurfaceGeometry>(&json)
.expect_err("serde_json refuses this nesting depth");
assert!(
error.to_string().contains("recursion limit exceeded"),
"unexpected parser error: {error}"
);
let shallow_chain = placed_plane(60).expect("admitted nesting");
let shallow = serde_json::to_string(&shallow_chain).expect("serialized");
assert_eq!(
serde_json::from_str::<SolvedSurfaceGeometry>(&shallow).expect("admitted nesting"),
shallow_chain
);
}
#[test]
fn deserialization_refuses_a_surface_placement_past_the_bound() {
let admitted =
serde_json::to_value(placed_plane(MAX_GEOMETRY_NESTING).expect("admitted nesting"))
.expect("serialized");
let past_the_bound = serde_json::json!({
"kind": "transformed",
"basis": admitted,
"transform": serde_json::to_value(Transform::identity()).expect("serialized"),
});
let error = serde_json::from_value::<SolvedSurfaceGeometry>(past_the_bound)
.expect_err("one placement past the bound");
assert_eq!(
error.to_string(),
"PlacedSurface.basis nests past the admitted inline basis depth"
);
}
#[test]
fn a_scaled_pcurve_chain_at_the_bound_keeps_its_depth() {
let mut chain = nested_pcurve(MAX_GEOMETRY_NESTING).expect("admitted nesting");
chain
.try_scale_coordinates([25.4, 25.4])
.expect("finite scaled chain");
assert_eq!(
PlacedPcurve::try_new(Box::new(chain), Transform2::identity()).err(),
Some("PlacedPcurve.basis nests past the admitted inline basis depth")
);
}