add export test so we dont break cli / kcl.py (#5553)
* add export test so we dont break cli / kcl.py Signed-off-by: Jess Frazelle <github@jessfraz.com> Overwrite created date (#5602) * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
mod cache;
|
mod cache;
|
||||||
|
|
||||||
use kcl_lib::{
|
use kcl_lib::{
|
||||||
test_server::{execute_and_snapshot, execute_and_snapshot_no_auth},
|
test_server::{execute_and_export_step, execute_and_snapshot, execute_and_snapshot_no_auth},
|
||||||
ExecError, UnitLength,
|
ExecError, UnitLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2081,3 +2081,17 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
|
|||||||
assert!(ctx.engine.batch().read().await.is_empty());
|
assert!(ctx.engine.batch().read().await.is_empty());
|
||||||
assert!(ctx.engine.batch_end().read().await.is_empty());
|
assert!(ctx.engine.batch_end().read().await.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn kcl_test_exporting_step_file() {
|
||||||
|
// This tests export like how we do it in cli and kcl.py.
|
||||||
|
let code = kcl_input!("helix_defaults_negative_extrude");
|
||||||
|
|
||||||
|
let (_, _, files) = execute_and_export_step(code, UnitLength::Mm, None).await.unwrap();
|
||||||
|
for file in files {
|
||||||
|
expectorate::assert_contents(
|
||||||
|
format!("e2e/executor/outputs/helix_defaults_negative_extrude_{}", file.name),
|
||||||
|
std::str::from_utf8(&file.contents).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
ISO-10303-21;
|
||||||
|
HEADER;
|
||||||
|
FILE_DESCRIPTION((('zoo.dev export')), '2;1');
|
||||||
|
FILE_NAME('test.step', '2021-01-01T00:00:00Z', ('Test'), ('Zoo'), 'zoo.dev beta', 'zoo.dev', 'Test');
|
||||||
|
FILE_SCHEMA(('AP203_CONFIGURATION_CONTROLLED_3D_DESIGN_OF_MECHANICAL_PARTS_AND_ASSEMBLIES_MIM_LF'));
|
||||||
|
ENDSEC;
|
||||||
|
DATA;
|
||||||
|
#1 = (
|
||||||
|
LENGTH_UNIT()
|
||||||
|
NAMED_UNIT(*)
|
||||||
|
SI_UNIT($, .METRE.)
|
||||||
|
);
|
||||||
|
#2 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
|
||||||
|
#3 = (
|
||||||
|
GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#2))
|
||||||
|
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1))
|
||||||
|
REPRESENTATION_CONTEXT('', '3D')
|
||||||
|
);
|
||||||
|
#4 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
||||||
|
#5 = VERTEX_POINT('NONE', #4);
|
||||||
|
#6 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
|
||||||
|
#7 = VERTEX_POINT('NONE', #6);
|
||||||
|
#8 = DIRECTION('NONE', (1, 0, -0));
|
||||||
|
#9 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#10 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
|
||||||
|
#11 = AXIS2_PLACEMENT_3D('NONE', #10, #9, #8);
|
||||||
|
#12 = CIRCLE('NONE', #11, 0.01);
|
||||||
|
#13 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#14 = VECTOR('NONE', #13, 1);
|
||||||
|
#15 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
||||||
|
#16 = LINE('NONE', #15, #14);
|
||||||
|
#17 = DIRECTION('NONE', (1, 0, -0));
|
||||||
|
#18 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#19 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
|
||||||
|
#20 = AXIS2_PLACEMENT_3D('NONE', #19, #18, #17);
|
||||||
|
#21 = CIRCLE('NONE', #20, 0.01);
|
||||||
|
#22 = EDGE_CURVE('NONE', #5, #5, #12, .T.);
|
||||||
|
#23 = EDGE_CURVE('NONE', #5, #7, #16, .T.);
|
||||||
|
#24 = EDGE_CURVE('NONE', #7, #7, #21, .T.);
|
||||||
|
#25 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
|
||||||
|
#26 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#27 = DIRECTION('NONE', (1, 0, -0));
|
||||||
|
#28 = AXIS2_PLACEMENT_3D('NONE', #25, #26, #27);
|
||||||
|
#29 = CYLINDRICAL_SURFACE('NONE', #28, 0.01);
|
||||||
|
#30 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
|
||||||
|
#31 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#32 = AXIS2_PLACEMENT_3D('NONE', #30, #31, $);
|
||||||
|
#33 = PLANE('NONE', #32);
|
||||||
|
#34 = CARTESIAN_POINT('NONE', (0, 0, -0));
|
||||||
|
#35 = DIRECTION('NONE', (0, 1, 0));
|
||||||
|
#36 = AXIS2_PLACEMENT_3D('NONE', #34, #35, $);
|
||||||
|
#37 = PLANE('NONE', #36);
|
||||||
|
#38 = ORIENTED_EDGE('NONE', *, *, #22, .T.);
|
||||||
|
#39 = ORIENTED_EDGE('NONE', *, *, #24, .F.);
|
||||||
|
#40 = EDGE_LOOP('NONE', (#38));
|
||||||
|
#41 = FACE_BOUND('NONE', #40, .T.);
|
||||||
|
#42 = EDGE_LOOP('NONE', (#39));
|
||||||
|
#43 = FACE_BOUND('NONE', #42, .T.);
|
||||||
|
#44 = ADVANCED_FACE('NONE', (#41, #43), #29, .T.);
|
||||||
|
#45 = ORIENTED_EDGE('NONE', *, *, #22, .F.);
|
||||||
|
#46 = EDGE_LOOP('NONE', (#45));
|
||||||
|
#47 = FACE_BOUND('NONE', #46, .T.);
|
||||||
|
#48 = ADVANCED_FACE('NONE', (#47), #33, .F.);
|
||||||
|
#49 = ORIENTED_EDGE('NONE', *, *, #24, .T.);
|
||||||
|
#50 = EDGE_LOOP('NONE', (#49));
|
||||||
|
#51 = FACE_BOUND('NONE', #50, .T.);
|
||||||
|
#52 = ADVANCED_FACE('NONE', (#51), #37, .T.);
|
||||||
|
#53 = CLOSED_SHELL('NONE', (#44, #48, #52));
|
||||||
|
#54 = MANIFOLD_SOLID_BREP('NONE', #53);
|
||||||
|
#55 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
|
||||||
|
#56 = PRODUCT_DEFINITION_CONTEXT('part definition', #55, 'design');
|
||||||
|
#57 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
|
||||||
|
#58 = PRODUCT_DEFINITION_FORMATION('', $, #57);
|
||||||
|
#59 = PRODUCT_DEFINITION('design', $, #58, #56);
|
||||||
|
#60 = PRODUCT_DEFINITION_SHAPE('NONE', $, #59);
|
||||||
|
#61 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#54), #3);
|
||||||
|
#62 = SHAPE_DEFINITION_REPRESENTATION(#60, #61);
|
||||||
|
ENDSEC;
|
||||||
|
END-ISO-10303-21;
|
@ -20,6 +20,8 @@ pub enum ExecError {
|
|||||||
Connection(#[from] ConnectionError),
|
Connection(#[from] ConnectionError),
|
||||||
#[error("PNG snapshot could not be decoded: {0}")]
|
#[error("PNG snapshot could not be decoded: {0}")]
|
||||||
BadPng(String),
|
BadPng(String),
|
||||||
|
#[error("Bad export: {0}")]
|
||||||
|
BadExport(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KclErrorWithOutputs> for ExecError {
|
impl From<KclErrorWithOutputs> for ExecError {
|
||||||
|
@ -129,3 +129,88 @@ pub async fn new_context(
|
|||||||
.map_err(ConnectionError::Establishing)?;
|
.map_err(ConnectionError::Establishing)?;
|
||||||
Ok(ctx)
|
Ok(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn execute_and_export_step(
|
||||||
|
code: &str,
|
||||||
|
units: UnitLength,
|
||||||
|
current_file: Option<PathBuf>,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
ExecState,
|
||||||
|
EnvironmentRef,
|
||||||
|
Vec<kittycad_modeling_cmds::websocket::RawFile>,
|
||||||
|
),
|
||||||
|
ExecErrorWithState,
|
||||||
|
> {
|
||||||
|
let ctx = new_context(units, true, current_file).await?;
|
||||||
|
let mut exec_state = ExecState::new(&ctx.settings);
|
||||||
|
let program = Program::parse_no_errs(code)
|
||||||
|
.map_err(|err| ExecErrorWithState::new(KclErrorWithOutputs::no_outputs(err).into(), exec_state.clone()))?;
|
||||||
|
let result = ctx
|
||||||
|
.run_with_ui_outputs(&program, &mut exec_state)
|
||||||
|
.await
|
||||||
|
.map_err(|err| ExecErrorWithState::new(err.into(), exec_state.clone()))?;
|
||||||
|
for e in exec_state.errors() {
|
||||||
|
if e.severity.is_err() {
|
||||||
|
return Err(ExecErrorWithState::new(
|
||||||
|
KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(),
|
||||||
|
exec_state.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp = ctx
|
||||||
|
.engine
|
||||||
|
.send_modeling_cmd(
|
||||||
|
uuid::Uuid::new_v4(),
|
||||||
|
crate::SourceRange::default(),
|
||||||
|
&kittycad_modeling_cmds::ModelingCmd::Export(kittycad_modeling_cmds::Export {
|
||||||
|
entity_ids: vec![],
|
||||||
|
format: kittycad_modeling_cmds::format::OutputFormat3d::Step(
|
||||||
|
kittycad_modeling_cmds::format::step::export::Options {
|
||||||
|
coords: *kittycad_modeling_cmds::coord::KITTYCAD,
|
||||||
|
// We want all to have the same timestamp.
|
||||||
|
created: Some(
|
||||||
|
chrono::DateTime::parse_from_rfc3339("2021-01-01T00:00:00Z")
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|err| ExecErrorWithState::new(KclErrorWithOutputs::no_outputs(err).into(), exec_state.clone()))?;
|
||||||
|
|
||||||
|
let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { mut files } = resp else {
|
||||||
|
return Err(ExecErrorWithState::new(
|
||||||
|
ExecError::BadExport(format!("Expected export response, got: {:?}", resp)),
|
||||||
|
exec_state.clone(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
for kittycad_modeling_cmds::websocket::RawFile { contents, .. } in &mut files {
|
||||||
|
use std::fmt::Write;
|
||||||
|
let utf8 = std::str::from_utf8(contents).unwrap();
|
||||||
|
let mut postprocessed = String::new();
|
||||||
|
for line in utf8.lines() {
|
||||||
|
if line.starts_with("FILE_NAME") {
|
||||||
|
let name = "test.step";
|
||||||
|
let time = "2021-01-01T00:00:00Z";
|
||||||
|
let author = "Test";
|
||||||
|
let org = "Zoo";
|
||||||
|
let version = "zoo.dev beta";
|
||||||
|
let system = "zoo.dev";
|
||||||
|
let authorization = "Test";
|
||||||
|
writeln!(&mut postprocessed, "FILE_NAME('{name}', '{time}', ('{author}'), ('{org}'), '{version}', '{system}', '{authorization}');").unwrap();
|
||||||
|
} else {
|
||||||
|
writeln!(&mut postprocessed, "{line}").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*contents = postprocessed.into_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.close().await;
|
||||||
|
|
||||||
|
Ok((exec_state, result.0, files))
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user