Compare commits
2 Commits
achalmers/
...
v0.22.2
Author | SHA1 | Date | |
---|---|---|---|
0add26cf61 | |||
b54fc534c2 |
14
.github/workflows/cargo-test.yml
vendored
@ -59,21 +59,11 @@ jobs:
|
|||||||
- uses: taiki-e/install-action@nextest
|
- uses: taiki-e/install-action@nextest
|
||||||
- name: Rust Cache
|
- name: Rust Cache
|
||||||
uses: Swatinem/rust-cache@v2.6.1
|
uses: Swatinem/rust-cache@v2.6.1
|
||||||
- name: Compile tests
|
- name: cargo test
|
||||||
run: |-
|
|
||||||
cd "${{ matrix.dir }}"
|
|
||||||
cargo nextest archive --archive-file tests.tar.zst --workspace --profile ci
|
|
||||||
- name: Start test KCL server
|
|
||||||
run: |-
|
|
||||||
cd "${{ matrix.dir }}"
|
|
||||||
cargo build --quiet --bin kcl-test-server --workspace && ./target/debug/kcl-test-server &
|
|
||||||
env:
|
|
||||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
|
||||||
- name: Run tests
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |-
|
run: |-
|
||||||
cd "${{ matrix.dir }}"
|
cd "${{ matrix.dir }}"
|
||||||
cargo llvm-cov nextest --lcov --output-path lcov.info --test-threads=1 --no-fail-fast --profile ci --archive-file tests.tar.zst 2>&1 | tee /tmp/github-actions.log
|
cargo llvm-cov nextest --all --lcov --output-path lcov.info --test-threads=1 --no-fail-fast -P ci 2>&1 | tee /tmp/github-actions.log
|
||||||
env:
|
env:
|
||||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
||||||
RUST_MIN_STACK: 10485760000
|
RUST_MIN_STACK: 10485760000
|
||||||
|
@ -9,7 +9,7 @@ A circular pattern on a 2D sketch.
|
|||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
patternCircular2d(data: CircularPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
|
patternCircular2d(data: CircularPattern2dData, sketch_group_set: SketchGroupSet) -> [SketchGroup]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@ -48,7 +48,7 @@ const example = extrude(1, exampleSketch)
|
|||||||
rotateDuplicates: string,
|
rotateDuplicates: string,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
* `sketch_group_set`: `SketchGroupSet` - A sketch group or a group of sketch groups. (REQUIRED)
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
// The plane id or face id of the sketch group.
|
// The plane id or face id of the sketch group.
|
||||||
@ -129,6 +129,7 @@ const example = extrude(1, exampleSketch)
|
|||||||
// The to point.
|
// The to point.
|
||||||
to: [number, number],
|
to: [number, number],
|
||||||
},
|
},
|
||||||
|
type: "sketchGroup",
|
||||||
// The paths in the sketch group.
|
// The paths in the sketch group.
|
||||||
value: [{
|
value: [{
|
||||||
// The from point.
|
// The from point.
|
||||||
@ -212,6 +213,9 @@ const example = extrude(1, exampleSketch)
|
|||||||
y: number,
|
y: number,
|
||||||
z: number,
|
z: number,
|
||||||
},
|
},
|
||||||
|
} |
|
||||||
|
{
|
||||||
|
type: "sketchGroups",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ A circular pattern on a 3D model.
|
|||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
patternCircular3d(data: CircularPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
|
patternCircular3d(data: CircularPattern3dData, extrude_group_set: ExtrudeGroupSet) -> [ExtrudeGroup]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@ -47,7 +47,7 @@ const example = extrude(-5, exampleSketch)
|
|||||||
rotateDuplicates: string,
|
rotateDuplicates: string,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
|
* `extrude_group_set`: `ExtrudeGroupSet` - A extrude group or a group of extrude groups. (REQUIRED)
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
// The id of the extrusion end cap
|
// The id of the extrusion end cap
|
||||||
@ -127,6 +127,7 @@ const example = extrude(-5, exampleSketch)
|
|||||||
}],
|
}],
|
||||||
// The id of the extrusion start cap
|
// The id of the extrusion start cap
|
||||||
startCapId: uuid,
|
startCapId: uuid,
|
||||||
|
type: "extrudeGroup",
|
||||||
// The extrude surfaces.
|
// The extrude surfaces.
|
||||||
value: [{
|
value: [{
|
||||||
// The face id for the extrude plane.
|
// The face id for the extrude plane.
|
||||||
@ -176,6 +177,9 @@ const example = extrude(-5, exampleSketch)
|
|||||||
y: number,
|
y: number,
|
||||||
z: number,
|
z: number,
|
||||||
},
|
},
|
||||||
|
} |
|
||||||
|
{
|
||||||
|
type: "extrudeGroups",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ A linear pattern on a 3D model.
|
|||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
patternLinear3d(data: LinearPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
|
patternLinear3d(data: LinearPattern3dData, extrude_group_set: ExtrudeGroupSet) -> [ExtrudeGroup]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@ -45,7 +45,7 @@ const example = extrude(1, exampleSketch)
|
|||||||
repetitions: number,
|
repetitions: number,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
|
* `extrude_group_set`: `ExtrudeGroupSet` - A extrude group or a group of extrude groups. (REQUIRED)
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
// The id of the extrusion end cap
|
// The id of the extrusion end cap
|
||||||
@ -125,6 +125,7 @@ const example = extrude(1, exampleSketch)
|
|||||||
}],
|
}],
|
||||||
// The id of the extrusion start cap
|
// The id of the extrusion start cap
|
||||||
startCapId: uuid,
|
startCapId: uuid,
|
||||||
|
type: "extrudeGroup",
|
||||||
// The extrude surfaces.
|
// The extrude surfaces.
|
||||||
value: [{
|
value: [{
|
||||||
// The face id for the extrude plane.
|
// The face id for the extrude plane.
|
||||||
@ -174,6 +175,9 @@ const example = extrude(1, exampleSketch)
|
|||||||
y: number,
|
y: number,
|
||||||
z: number,
|
z: number,
|
||||||
},
|
},
|
||||||
|
} |
|
||||||
|
{
|
||||||
|
type: "extrudeGroups",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2563
docs/kcl/std.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.22.1",
|
"version": "0.22.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.16.0",
|
"@codemirror/autocomplete": "^6.16.0",
|
||||||
|
1639
src-tauri/Cargo.lock
generated
@ -20,7 +20,7 @@ kittycad = "0.3.5"
|
|||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
oauth2 = "4.4.2"
|
oauth2 = "4.4.2"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tauri = { version = "2.0.0-beta.15", features = [ "devtools", "unstable"] }
|
tauri = { version = "2.0.0-beta.22", features = [ "devtools", "unstable"] }
|
||||||
tauri-plugin-cli = { version = "2.0.0-beta.3" }
|
tauri-plugin-cli = { version = "2.0.0-beta.3" }
|
||||||
tauri-plugin-deep-link = { version = "2.0.0-beta.3" }
|
tauri-plugin-deep-link = { version = "2.0.0-beta.3" }
|
||||||
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
|
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
|
||||||
|
@ -63,16 +63,17 @@
|
|||||||
"subcommands": {}
|
"subcommands": {}
|
||||||
},
|
},
|
||||||
"deep-link": {
|
"deep-link": {
|
||||||
"domains": [
|
"mobile": [],
|
||||||
{
|
"desktop": {
|
||||||
"host": "app.zoo.dev"
|
"schemes": [
|
||||||
}
|
"app.zoo.dev"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shell": {
|
"shell": {
|
||||||
"open": true
|
"open": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.22.1"
|
"version": "0.22.2"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
# experimental = ["setup-scripts"]
|
|
||||||
|
|
||||||
# [script.test-server]
|
|
||||||
# command = "just start-test-server"
|
|
||||||
|
|
||||||
# Each test can have at most 4 threads, but if its name contains "serial_test_", then it
|
# Each test can have at most 4 threads, but if its name contains "serial_test_", then it
|
||||||
# also requires 4 threads.
|
# also requires 4 threads.
|
||||||
# This means such tests run one at a time, with 4 threads.
|
# This means such tests run one at a time, with 4 threads.
|
||||||
@ -19,20 +14,12 @@ slow-timeout = { period = "50s", terminate-after = 5 }
|
|||||||
[[profile.default.overrides]]
|
[[profile.default.overrides]]
|
||||||
filter = "test(serial_test_)"
|
filter = "test(serial_test_)"
|
||||||
test-group = "serial-integration"
|
test-group = "serial-integration"
|
||||||
threads-required = 4
|
threads-required = 2
|
||||||
|
|
||||||
# [[profile.default.scripts]]
|
|
||||||
# filter = 'test(serial_test_)'
|
|
||||||
# setup = 'test-server'
|
|
||||||
|
|
||||||
[[profile.ci.overrides]]
|
[[profile.ci.overrides]]
|
||||||
filter = "test(serial_test_)"
|
filter = "test(serial_test_)"
|
||||||
test-group = "serial-integration"
|
test-group = "serial-integration"
|
||||||
threads-required = 4
|
threads-required = 2
|
||||||
|
|
||||||
# [[profile.default.scripts]]
|
|
||||||
# filter = 'test(serial_test_)'
|
|
||||||
# setup = 'test-server'
|
|
||||||
|
|
||||||
[[profile.default.overrides]]
|
[[profile.default.overrides]]
|
||||||
filter = "test(parser::parser_impl::snapshot_tests)"
|
filter = "test(parser::parser_impl::snapshot_tests)"
|
||||||
|
25
src/wasm-lib/Cargo.lock
generated
@ -1369,7 +1369,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
version = "0.1.59"
|
version = "0.1.60"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"approx",
|
"approx",
|
||||||
@ -1434,19 +1434,6 @@ dependencies = [
|
|||||||
"syn 2.0.66",
|
"syn 2.0.66",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kcl-test-server"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"hyper",
|
|
||||||
"kcl-lib",
|
|
||||||
"pico-args",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad"
|
name = "kittycad"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -1828,12 +1815,6 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pico-args"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.5"
|
version = "1.1.5"
|
||||||
@ -2511,9 +2492,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.117"
|
version = "1.0.116"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.5",
|
"indexmap 2.2.5",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -17,7 +17,7 @@ kcl-lib = { path = "kcl" }
|
|||||||
kittycad.workspace = true
|
kittycad.workspace = true
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
tokio = { version = "1.38.0", features = ["sync"] }
|
tokio = { version = "1.38.0", features = ["sync"] }
|
||||||
toml = "0.8.13"
|
toml = "0.8.14"
|
||||||
uuid = { version = "1.8.0", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.8.0", features = ["v4", "js", "serde"] }
|
||||||
wasm-bindgen = "0.2.91"
|
wasm-bindgen = "0.2.91"
|
||||||
wasm-bindgen-futures = "0.4.42"
|
wasm-bindgen-futures = "0.4.42"
|
||||||
@ -65,7 +65,6 @@ members = [
|
|||||||
"derive-docs",
|
"derive-docs",
|
||||||
"kcl",
|
"kcl",
|
||||||
"kcl-macros",
|
"kcl-macros",
|
||||||
"kcl-test-server",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
start-test-server:
|
|
||||||
cargo build --quiet --bin kcl-test-server --workspace && ./target/debug/kcl-test-server
|
|
@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "kcl-test-server"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.86"
|
|
||||||
hyper = { version = "0.14.29", features = ["server"] }
|
|
||||||
kcl-lib = { path = "../kcl" }
|
|
||||||
pico-args = "0.5.0"
|
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
|
||||||
serde_json = "1.0.117"
|
|
||||||
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
|
|
@ -1,210 +0,0 @@
|
|||||||
//! Executes KCL programs.
|
|
||||||
//! The server reuses the same engine session for each KCL program it receives.
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use hyper::body::Bytes;
|
|
||||||
use hyper::header::CONTENT_TYPE;
|
|
||||||
use hyper::service::{make_service_fn, service_fn};
|
|
||||||
use hyper::{Body, Error, Response, Server};
|
|
||||||
use kcl_lib::executor::ExecutorContext;
|
|
||||||
use kcl_lib::settings::types::UnitLength;
|
|
||||||
use kcl_lib::test_server::RequestBody;
|
|
||||||
use tokio::sync::{mpsc, oneshot};
|
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
use tokio::time::sleep;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> anyhow::Result<()> {
|
|
||||||
// Parse the CLI arguments.
|
|
||||||
let pargs = pico_args::Arguments::from_env();
|
|
||||||
let args = ServerArgs::parse(pargs)?;
|
|
||||||
// Run the actual server.
|
|
||||||
start_server(args).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ServerArgs {
|
|
||||||
/// What port this server should listen on.
|
|
||||||
listen_on: SocketAddr,
|
|
||||||
/// How many connections to establish with the engine.
|
|
||||||
num_engine_conns: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ServerArgs {
|
|
||||||
fn parse(mut pargs: pico_args::Arguments) -> Result<Self, pico_args::Error> {
|
|
||||||
let args = ServerArgs {
|
|
||||||
listen_on: pargs
|
|
||||||
.opt_value_from_str("--listen-on")?
|
|
||||||
.unwrap_or("0.0.0.0:3333".parse().unwrap()),
|
|
||||||
num_engine_conns: pargs.opt_value_from_str("--num-engine-conns")?.unwrap_or(1),
|
|
||||||
};
|
|
||||||
println!("Config is {args:?}");
|
|
||||||
Ok(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sent from the server to each worker.
|
|
||||||
struct WorkerReq {
|
|
||||||
/// A KCL program, in UTF-8.
|
|
||||||
body: Bytes,
|
|
||||||
/// A channel to send the HTTP response back.
|
|
||||||
resp: oneshot::Sender<Response<Body>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Each worker has a connection to the engine, and accepts
|
|
||||||
/// KCL programs. When it receives one (over the mpsc channel)
|
|
||||||
/// it executes it and returns the result via a oneshot channel.
|
|
||||||
fn start_worker(i: u8) -> mpsc::Sender<WorkerReq> {
|
|
||||||
println!("Starting worker {i}");
|
|
||||||
// Make a work queue for this worker.
|
|
||||||
let (tx, mut rx) = mpsc::channel(1);
|
|
||||||
tokio::task::spawn(async move {
|
|
||||||
let state = ExecutorContext::new_for_unit_test(UnitLength::Mm).await.unwrap();
|
|
||||||
println!("Worker {i} ready");
|
|
||||||
while let Some(req) = rx.recv().await {
|
|
||||||
let req: WorkerReq = req;
|
|
||||||
let resp = snapshot_endpoint(req.body, state.clone()).await;
|
|
||||||
if req.resp.send(resp).is_err() {
|
|
||||||
println!("\tWorker {i} exiting");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("\tWorker {i} exiting");
|
|
||||||
});
|
|
||||||
tx
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ServerState {
|
|
||||||
workers: Vec<mpsc::Sender<WorkerReq>>,
|
|
||||||
req_num: AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_server(args: ServerArgs) -> anyhow::Result<()> {
|
|
||||||
let ServerArgs {
|
|
||||||
listen_on,
|
|
||||||
num_engine_conns,
|
|
||||||
} = args;
|
|
||||||
let workers: Vec<_> = (0..num_engine_conns).map(start_worker).collect();
|
|
||||||
let state = Arc::new(ServerState {
|
|
||||||
workers,
|
|
||||||
req_num: 0.into(),
|
|
||||||
});
|
|
||||||
// In hyper, a `MakeService` is basically your server.
|
|
||||||
// It makes a `Service` for each connection, which manages the connection.
|
|
||||||
let make_service = make_service_fn(
|
|
||||||
// This closure is run for each connection.
|
|
||||||
move |_conn_info| {
|
|
||||||
// eprintln!("Connected to a client");
|
|
||||||
let state = state.clone();
|
|
||||||
async move {
|
|
||||||
// This is the `Service` which handles the connection.
|
|
||||||
// `service_fn` converts a function which returns a Response
|
|
||||||
// into a `Service`.
|
|
||||||
Ok::<_, Error>(service_fn(move |req| {
|
|
||||||
// eprintln!("Received a request");
|
|
||||||
let state = state.clone();
|
|
||||||
async move { handle_request(req, state).await }
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let server = Server::bind(&listen_on).serve(make_service);
|
|
||||||
println!("Listening on {listen_on}");
|
|
||||||
println!("PID is {}", std::process::id());
|
|
||||||
if let Err(e) = server.await {
|
|
||||||
eprintln!("Server error: {e}");
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_request(req: hyper::Request<Body>, state3: Arc<ServerState>) -> Result<Response<Body>, Error> {
|
|
||||||
let body = hyper::body::to_bytes(req.into_body()).await?;
|
|
||||||
|
|
||||||
// Round robin requests between each available worker.
|
|
||||||
let req_num = state3.req_num.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let worker_id = req_num % state3.workers.len();
|
|
||||||
// println!("Sending request {req_num} to worker {worker_id}");
|
|
||||||
let worker = state3.workers[worker_id].clone();
|
|
||||||
let (tx, rx) = oneshot::channel();
|
|
||||||
let req_sent = worker.send(WorkerReq { body, resp: tx }).await;
|
|
||||||
req_sent.unwrap();
|
|
||||||
let resp = rx.await.unwrap();
|
|
||||||
Ok(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute a KCL program, then respond with a PNG snapshot.
|
|
||||||
/// KCL errors (from engine or the executor) respond with HTTP Bad Gateway.
|
|
||||||
/// Malformed requests are HTTP Bad Request.
|
|
||||||
/// Successful requests contain a PNG as the body.
|
|
||||||
async fn snapshot_endpoint(body: Bytes, state: ExecutorContext) -> Response<Body> {
|
|
||||||
let body = match serde_json::from_slice::<RequestBody>(body.as_ref()) {
|
|
||||||
Ok(bd) => bd,
|
|
||||||
Err(e) => return bad_request(format!("Invalid request JSON: {e}")),
|
|
||||||
};
|
|
||||||
let RequestBody { kcl_program, test_name } = body;
|
|
||||||
let parser = match kcl_lib::token::lexer(&kcl_program) {
|
|
||||||
Ok(ts) => kcl_lib::parser::Parser::new(ts),
|
|
||||||
Err(e) => return bad_request(format!("tokenization error: {e}")),
|
|
||||||
};
|
|
||||||
let program = match parser.ast() {
|
|
||||||
Ok(pr) => pr,
|
|
||||||
Err(e) => return bad_request(format!("Parse error: {e}")),
|
|
||||||
};
|
|
||||||
eprintln!("Executing {test_name}");
|
|
||||||
if let Err(e) = state.reset_scene().await {
|
|
||||||
return kcl_err(e);
|
|
||||||
}
|
|
||||||
// Let users know if the test is taking a long time.
|
|
||||||
let (done_tx, done_rx) = oneshot::channel::<()>();
|
|
||||||
let timer = time_until(done_rx);
|
|
||||||
let snapshot = match state.execute_and_prepare_snapshot(program).await {
|
|
||||||
Ok(sn) => sn,
|
|
||||||
Err(e) => return kcl_err(e),
|
|
||||||
};
|
|
||||||
let _ = done_tx.send(());
|
|
||||||
timer.abort();
|
|
||||||
eprintln!("\tServing response");
|
|
||||||
let png_bytes = snapshot.contents.0;
|
|
||||||
let mut resp = Response::new(Body::from(png_bytes));
|
|
||||||
resp.headers_mut().insert(CONTENT_TYPE, "image/png".parse().unwrap());
|
|
||||||
resp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bad_request(msg: String) -> Response<Body> {
|
|
||||||
eprintln!("\tBad request");
|
|
||||||
let mut resp = Response::new(Body::from(msg));
|
|
||||||
*resp.status_mut() = hyper::StatusCode::BAD_REQUEST;
|
|
||||||
resp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bad_gateway(msg: String) -> Response<Body> {
|
|
||||||
eprintln!("\tBad gateway");
|
|
||||||
let mut resp = Response::new(Body::from(msg));
|
|
||||||
*resp.status_mut() = hyper::StatusCode::BAD_GATEWAY;
|
|
||||||
resp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn kcl_err(err: anyhow::Error) -> Response<Body> {
|
|
||||||
eprintln!("\tBad KCL");
|
|
||||||
bad_gateway(format!("{err}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn time_until(done: oneshot::Receiver<()>) -> JoinHandle<()> {
|
|
||||||
tokio::task::spawn(async move {
|
|
||||||
let period = 10;
|
|
||||||
tokio::pin!(done);
|
|
||||||
for i in 1..=3 {
|
|
||||||
tokio::select! {
|
|
||||||
biased;
|
|
||||||
// If the test is done, no need for this timer anymore.
|
|
||||||
_ = &mut done => return,
|
|
||||||
_ = sleep(Duration::from_secs(period)) => {
|
|
||||||
eprintln!("\tTest has taken {}s", period * i);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
description = "KittyCAD Language implementation and tools"
|
description = "KittyCAD Language implementation and tools"
|
||||||
version = "0.1.59"
|
version = "0.1.60"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/KittyCAD/modeling-app"
|
repository = "https://github.com/KittyCAD/modeling-app"
|
||||||
|
@ -63,9 +63,10 @@ impl StdLibFnArg {
|
|||||||
|
|
||||||
pub fn get_autocomplete_snippet(&self, index: usize) -> Result<Option<(usize, String)>> {
|
pub fn get_autocomplete_snippet(&self, index: usize) -> Result<Option<(usize, String)>> {
|
||||||
if self.type_ == "SketchGroup"
|
if self.type_ == "SketchGroup"
|
||||||
|| self.type_ == "ExtrudeGroup"
|
|
||||||
|| self.type_ == "SketchSurface"
|
|
||||||
|| self.type_ == "SketchGroupSet"
|
|| self.type_ == "SketchGroupSet"
|
||||||
|
|| self.type_ == "ExtrudeGroup"
|
||||||
|
|| self.type_ == "ExtrudeGroupSet"
|
||||||
|
|| self.type_ == "SketchSurface"
|
||||||
{
|
{
|
||||||
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
||||||
}
|
}
|
||||||
|
@ -40,54 +40,23 @@ pub struct TcpRead {
|
|||||||
stream: futures::stream::SplitStream<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>>,
|
stream: futures::stream::SplitStream<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Occurs when client couldn't read from the WebSocket to the engine.
|
|
||||||
// #[derive(Debug)]
|
|
||||||
pub enum WebSocketReadError {
|
|
||||||
/// Could not read a message due to WebSocket errors.
|
|
||||||
Read(tokio_tungstenite::tungstenite::Error),
|
|
||||||
/// WebSocket message didn't contain a valid message that the KCL Executor could parse.
|
|
||||||
Deser(anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<anyhow::Error> for WebSocketReadError {
|
|
||||||
fn from(e: anyhow::Error) -> Self {
|
|
||||||
Self::Deser(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TcpRead {
|
impl TcpRead {
|
||||||
pub async fn read(&mut self) -> std::result::Result<WebSocketResponse, WebSocketReadError> {
|
pub async fn read(&mut self) -> Result<WebSocketResponse> {
|
||||||
let Some(msg) = self.stream.next().await else {
|
let Some(msg) = self.stream.next().await else {
|
||||||
return Err(anyhow::anyhow!("Failed to read from WebSocket").into());
|
anyhow::bail!("Failed to read from websocket");
|
||||||
};
|
};
|
||||||
let msg = match msg {
|
let msg: WebSocketResponse = match msg? {
|
||||||
Ok(msg) => msg,
|
WsMsg::Text(text) => serde_json::from_str(&text)?,
|
||||||
Err(e) if matches!(e, tokio_tungstenite::tungstenite::Error::Protocol(_)) => {
|
WsMsg::Binary(bin) => bson::from_slice(&bin)?,
|
||||||
return Err(WebSocketReadError::Read(e))
|
other => anyhow::bail!("Unexpected websocket message from server: {}", other),
|
||||||
}
|
|
||||||
Err(e) => return Err(anyhow::anyhow!("Error reading from engine's WebSocket: {e}").into()),
|
|
||||||
};
|
|
||||||
let msg: WebSocketResponse = match msg {
|
|
||||||
WsMsg::Text(text) => serde_json::from_str(&text)
|
|
||||||
.map_err(anyhow::Error::from)
|
|
||||||
.map_err(WebSocketReadError::from)?,
|
|
||||||
WsMsg::Binary(bin) => bson::from_slice(&bin)
|
|
||||||
.map_err(anyhow::Error::from)
|
|
||||||
.map_err(WebSocketReadError::from)?,
|
|
||||||
other => return Err(anyhow::anyhow!("Unexpected WebSocket message from engine API: {other}").into()),
|
|
||||||
};
|
};
|
||||||
Ok(msg)
|
Ok(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TcpReadHandle {
|
pub struct TcpReadHandle {
|
||||||
handle: Arc<tokio::task::JoinHandle<Result<(), WebSocketReadError>>>,
|
handle: Arc<tokio::task::JoinHandle<Result<()>>>,
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for TcpReadHandle {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "TcpReadHandle")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TcpReadHandle {
|
impl Drop for TcpReadHandle {
|
||||||
@ -181,17 +150,14 @@ impl EngineConnection {
|
|||||||
match tcp_read.read().await {
|
match tcp_read.read().await {
|
||||||
Ok(ws_resp) => {
|
Ok(ws_resp) => {
|
||||||
for e in ws_resp.errors.iter().flatten() {
|
for e in ws_resp.errors.iter().flatten() {
|
||||||
println!("got error message: {} {}", e.error_code, e.message);
|
println!("got error message: {e}");
|
||||||
}
|
}
|
||||||
if let Some(id) = ws_resp.request_id {
|
if let Some(id) = ws_resp.request_id {
|
||||||
responses_clone.insert(id, ws_resp.clone());
|
responses_clone.insert(id, ws_resp.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match &e {
|
println!("got ws error: {:?}", e);
|
||||||
WebSocketReadError::Read(e) => eprintln!("could not read from WS: {:?}", e),
|
|
||||||
WebSocketReadError::Deser(e) => eprintln!("could not deserialize msg from WS: {:?}", e),
|
|
||||||
}
|
|
||||||
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ use crate::{
|
|||||||
engine::EngineManager,
|
engine::EngineManager,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
fs::FileManager,
|
fs::FileManager,
|
||||||
settings::types::UnitLength,
|
|
||||||
std::{FunctionKind, StdLib},
|
std::{FunctionKind, StdLib},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -993,7 +992,7 @@ pub struct ExecutorContext {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ExecutorSettings {
|
pub struct ExecutorSettings {
|
||||||
/// The unit to use in modeling dimensions.
|
/// The unit to use in modeling dimensions.
|
||||||
pub units: UnitLength,
|
pub units: crate::settings::types::UnitLength,
|
||||||
/// Highlight edges of 3D objects?
|
/// Highlight edges of 3D objects?
|
||||||
pub highlight_edges: bool,
|
pub highlight_edges: bool,
|
||||||
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||||
@ -1084,57 +1083,6 @@ impl ExecutorContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For executing unit tests.
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
pub async fn new_for_unit_test(units: UnitLength) -> Result<Self> {
|
|
||||||
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
|
|
||||||
let http_client = reqwest::Client::builder()
|
|
||||||
.user_agent(user_agent)
|
|
||||||
// For file conversions we need this to be long.
|
|
||||||
.timeout(std::time::Duration::from_secs(600))
|
|
||||||
.connect_timeout(std::time::Duration::from_secs(60));
|
|
||||||
let ws_client = reqwest::Client::builder()
|
|
||||||
.user_agent(user_agent)
|
|
||||||
// For file conversions we need this to be long.
|
|
||||||
.timeout(std::time::Duration::from_secs(600))
|
|
||||||
.connect_timeout(std::time::Duration::from_secs(60))
|
|
||||||
.connection_verbose(true)
|
|
||||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
|
||||||
.http1_only();
|
|
||||||
|
|
||||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
|
||||||
|
|
||||||
// Create the client.
|
|
||||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
|
||||||
// Set a local engine address if it's set.
|
|
||||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
|
||||||
client.set_base_url(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ctx = ExecutorContext::new(
|
|
||||||
&client,
|
|
||||||
ExecutorSettings {
|
|
||||||
units,
|
|
||||||
highlight_edges: true,
|
|
||||||
enable_ssao: false,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear everything in the scene.
|
|
||||||
pub async fn reset_scene(&self) -> Result<()> {
|
|
||||||
self.engine
|
|
||||||
.send_modeling_cmd(
|
|
||||||
uuid::Uuid::new_v4(),
|
|
||||||
SourceRange::default(),
|
|
||||||
kittycad::types::ModelingCmd::SceneClearAll {},
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform the execution of a program.
|
/// Perform the execution of a program.
|
||||||
/// You can optionally pass in some initialization memory.
|
/// You can optionally pass in some initialization memory.
|
||||||
/// Kurt uses this for partial execution.
|
/// Kurt uses this for partial execution.
|
||||||
@ -1361,7 +1309,7 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the units for the executor.
|
/// Update the units for the executor.
|
||||||
pub fn update_units(&mut self, units: UnitLength) {
|
pub fn update_units(&mut self, units: crate::settings::types::UnitLength) {
|
||||||
self.settings.units = units;
|
self.settings.units = units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ pub mod lsp;
|
|||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod std;
|
pub mod std;
|
||||||
pub mod test_server;
|
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
@ -31,7 +31,8 @@ use crate::{
|
|||||||
docs::StdLibFn,
|
docs::StdLibFn,
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{
|
executor::{
|
||||||
ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
|
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, MemoryItem, Metadata, SketchGroup, SketchGroupSet,
|
||||||
|
SketchSurface, SourceRange,
|
||||||
},
|
},
|
||||||
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
|
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
|
||||||
};
|
};
|
||||||
@ -773,6 +774,52 @@ impl Args {
|
|||||||
Ok((data, sketch_surface, tag))
|
Ok((data, sketch_surface, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_data_and_extrude_group_set<T: serde::de::DeserializeOwned>(&self) -> Result<(T, ExtrudeGroupSet), KclError> {
|
||||||
|
let first_value = self
|
||||||
|
.args
|
||||||
|
.first()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_json_value()?;
|
||||||
|
|
||||||
|
let data: T = serde_json::from_value(first_value).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to deserialize struct from JSON: {}", e),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let second_value = self.args.get(1).ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
|
||||||
|
self.args
|
||||||
|
),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let extrude_set = if let MemoryItem::ExtrudeGroup(eg) = second_value {
|
||||||
|
ExtrudeGroupSet::ExtrudeGroup(eg.clone())
|
||||||
|
} else if let MemoryItem::ExtrudeGroups { value } = second_value {
|
||||||
|
ExtrudeGroupSet::ExtrudeGroups(value.clone())
|
||||||
|
} else {
|
||||||
|
return Err(KclError::Type(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"Expected a ExtrudeGroup or Vector of ExtrudeGroups as the second argument, found `{:?}`",
|
||||||
|
self.args
|
||||||
|
),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((data, extrude_set))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<ExtrudeGroup>), KclError> {
|
fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<ExtrudeGroup>), KclError> {
|
||||||
let first_value = self
|
let first_value = self
|
||||||
.args
|
.args
|
||||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
|
executor::{ExtrudeGroup, ExtrudeGroupSet, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
|
||||||
std::{types::Uint, Args},
|
std::{types::Uint, Args},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ async fn inner_pattern_linear_2d(
|
|||||||
|
|
||||||
/// A linear pattern on a 3D model.
|
/// A linear pattern on a 3D model.
|
||||||
pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, extrude_group): (LinearPattern3dData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
let (data, extrude_group_set): (LinearPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||||
|
|
||||||
if data.axis == [0.0, 0.0, 0.0] {
|
if data.axis == [0.0, 0.0, 0.0] {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -152,7 +152,7 @@ pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group, args).await?;
|
let extrude_groups = inner_pattern_linear_3d(data, extrude_group_set, args).await?;
|
||||||
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,27 +178,37 @@ pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
}]
|
}]
|
||||||
async fn inner_pattern_linear_3d(
|
async fn inner_pattern_linear_3d(
|
||||||
data: LinearPattern3dData,
|
data: LinearPattern3dData,
|
||||||
extrude_group: Box<ExtrudeGroup>,
|
extrude_group_set: ExtrudeGroupSet,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||||
|
let starting_extrude_groups = match extrude_group_set {
|
||||||
|
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => vec![extrude_group],
|
||||||
|
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => extrude_groups,
|
||||||
|
};
|
||||||
|
|
||||||
if args.ctx.is_mock {
|
if args.ctx.is_mock {
|
||||||
return Ok(vec![extrude_group.clone()]);
|
return Ok(starting_extrude_groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut extrude_groups = Vec::new();
|
||||||
|
for extrude_group in starting_extrude_groups.iter() {
|
||||||
let geometries = pattern_linear(
|
let geometries = pattern_linear(
|
||||||
LinearPattern::ThreeD(data),
|
LinearPattern::ThreeD(data.clone()),
|
||||||
Geometry::ExtrudeGroup(extrude_group),
|
Geometry::ExtrudeGroup(extrude_group.clone()),
|
||||||
args.clone(),
|
args.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
|
let Geometries::ExtrudeGroups(new_extrude_groups) = geometries else {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: "Expected a vec of extrude groups".to_string(),
|
message: "Expected a vec of extrude groups".to_string(),
|
||||||
source_ranges: vec![args.source_range],
|
source_ranges: vec![args.source_range],
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extrude_groups.extend(new_extrude_groups);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(extrude_groups)
|
Ok(extrude_groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +345,9 @@ impl CircularPattern {
|
|||||||
|
|
||||||
/// A circular pattern on a 2D sketch.
|
/// A circular pattern on a 2D sketch.
|
||||||
pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, sketch_group): (CircularPattern2dData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
let (data, sketch_group_set): (CircularPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
|
||||||
|
|
||||||
let sketch_groups = inner_pattern_circular_2d(data, sketch_group, args).await?;
|
let sketch_groups = inner_pattern_circular_2d(data, sketch_group_set, args).await?;
|
||||||
Ok(MemoryItem::SketchGroups { value: sketch_groups })
|
Ok(MemoryItem::SketchGroups { value: sketch_groups })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,35 +374,45 @@ pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
}]
|
}]
|
||||||
async fn inner_pattern_circular_2d(
|
async fn inner_pattern_circular_2d(
|
||||||
data: CircularPattern2dData,
|
data: CircularPattern2dData,
|
||||||
sketch_group: Box<SketchGroup>,
|
sketch_group_set: SketchGroupSet,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Vec<Box<SketchGroup>>, KclError> {
|
) -> Result<Vec<Box<SketchGroup>>, KclError> {
|
||||||
|
let starting_sketch_groups = match sketch_group_set {
|
||||||
|
SketchGroupSet::SketchGroup(sketch_group) => vec![sketch_group],
|
||||||
|
SketchGroupSet::SketchGroups(sketch_groups) => sketch_groups,
|
||||||
|
};
|
||||||
|
|
||||||
if args.ctx.is_mock {
|
if args.ctx.is_mock {
|
||||||
return Ok(vec![sketch_group]);
|
return Ok(starting_sketch_groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut sketch_groups = Vec::new();
|
||||||
|
for sketch_group in starting_sketch_groups.iter() {
|
||||||
let geometries = pattern_circular(
|
let geometries = pattern_circular(
|
||||||
CircularPattern::TwoD(data),
|
CircularPattern::TwoD(data.clone()),
|
||||||
Geometry::SketchGroup(sketch_group),
|
Geometry::SketchGroup(sketch_group.clone()),
|
||||||
args.clone(),
|
args.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let Geometries::SketchGroups(sketch_groups) = geometries else {
|
let Geometries::SketchGroups(new_sketch_groups) = geometries else {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: "Expected a vec of sketch groups".to_string(),
|
message: "Expected a vec of sketch groups".to_string(),
|
||||||
source_ranges: vec![args.source_range],
|
source_ranges: vec![args.source_range],
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sketch_groups.extend(new_sketch_groups);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(sketch_groups)
|
Ok(sketch_groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A circular pattern on a 3D model.
|
/// A circular pattern on a 3D model.
|
||||||
pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
|
pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
let (data, extrude_group): (CircularPattern3dData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
let (data, extrude_group_set): (CircularPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||||
|
|
||||||
let extrude_groups = inner_pattern_circular_3d(data, extrude_group, args).await?;
|
let extrude_groups = inner_pattern_circular_3d(data, extrude_group_set, args).await?;
|
||||||
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,27 +436,37 @@ pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
|
|||||||
}]
|
}]
|
||||||
async fn inner_pattern_circular_3d(
|
async fn inner_pattern_circular_3d(
|
||||||
data: CircularPattern3dData,
|
data: CircularPattern3dData,
|
||||||
extrude_group: Box<ExtrudeGroup>,
|
extrude_group_set: ExtrudeGroupSet,
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||||
|
let starting_extrude_groups = match extrude_group_set {
|
||||||
|
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => vec![extrude_group],
|
||||||
|
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => extrude_groups,
|
||||||
|
};
|
||||||
|
|
||||||
if args.ctx.is_mock {
|
if args.ctx.is_mock {
|
||||||
return Ok(vec![extrude_group]);
|
return Ok(starting_extrude_groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut extrude_groups = Vec::new();
|
||||||
|
for extrude_group in starting_extrude_groups.iter() {
|
||||||
let geometries = pattern_circular(
|
let geometries = pattern_circular(
|
||||||
CircularPattern::ThreeD(data),
|
CircularPattern::ThreeD(data.clone()),
|
||||||
Geometry::ExtrudeGroup(extrude_group),
|
Geometry::ExtrudeGroup(extrude_group.clone()),
|
||||||
args.clone(),
|
args.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
|
let Geometries::ExtrudeGroups(new_extrude_groups) = geometries else {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: "Expected a vec of extrude groups".to_string(),
|
message: "Expected a vec of extrude groups".to_string(),
|
||||||
source_ranges: vec![args.source_range],
|
source_ranges: vec![args.source_range],
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extrude_groups.extend(new_extrude_groups);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(extrude_groups)
|
Ok(extrude_groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
//! Types used to send data to the test server.
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
|
||||||
pub struct RequestBody {
|
|
||||||
pub kcl_program: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub test_name: String,
|
|
||||||
}
|
|
@ -1,39 +1,58 @@
|
|||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use image::io::Reader as ImageReader;
|
use kcl_lib::{
|
||||||
use kcl_lib::{executor::ExecutorContext, settings::types::UnitLength};
|
executor::{ExecutorContext, ExecutorSettings},
|
||||||
use kittycad::types::TakeSnapshot;
|
settings::types::UnitLength,
|
||||||
|
};
|
||||||
|
|
||||||
macro_rules! test_name {
|
// mod server;
|
||||||
() => {{
|
|
||||||
fn f() {}
|
async fn new_context(units: UnitLength) -> Result<ExecutorContext> {
|
||||||
fn type_name_of<T>(_: T) -> &'static str {
|
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
|
||||||
std::any::type_name::<T>()
|
let http_client = reqwest::Client::builder()
|
||||||
|
.user_agent(user_agent)
|
||||||
|
// For file conversions we need this to be long.
|
||||||
|
.timeout(std::time::Duration::from_secs(600))
|
||||||
|
.connect_timeout(std::time::Duration::from_secs(60));
|
||||||
|
let ws_client = reqwest::Client::builder()
|
||||||
|
.user_agent(user_agent)
|
||||||
|
// For file conversions we need this to be long.
|
||||||
|
.timeout(std::time::Duration::from_secs(600))
|
||||||
|
.connect_timeout(std::time::Duration::from_secs(60))
|
||||||
|
.connection_verbose(true)
|
||||||
|
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||||
|
.http1_only();
|
||||||
|
|
||||||
|
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||||
|
|
||||||
|
// Create the client.
|
||||||
|
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||||
|
// Set a local engine address if it's set.
|
||||||
|
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||||
|
client.set_base_url(addr);
|
||||||
}
|
}
|
||||||
let name = type_name_of(f);
|
|
||||||
name.strip_suffix("::f")
|
let ctx = ExecutorContext::new(
|
||||||
.unwrap()
|
&client,
|
||||||
.strip_suffix("::{{closure}}")
|
ExecutorSettings {
|
||||||
.unwrap()
|
units,
|
||||||
.strip_prefix("executor::serial_test_")
|
highlight_edges: true,
|
||||||
.unwrap()
|
enable_ssao: false,
|
||||||
}};
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a kcl program and takes a snapshot of the result.
|
/// Executes a kcl program and takes a snapshot of the result.
|
||||||
/// This returns the bytes of the snapshot.
|
/// This returns the bytes of the snapshot.
|
||||||
async fn execute_and_snapshot(code: &str, units: UnitLength) -> Result<image::DynamicImage> {
|
async fn execute_and_snapshot(code: &str, units: UnitLength) -> Result<image::DynamicImage> {
|
||||||
let ctx = ExecutorContext::new_for_unit_test(units).await?;
|
let ctx = new_context(units).await?;
|
||||||
let tokens = kcl_lib::token::lexer(code)?;
|
let tokens = kcl_lib::token::lexer(code)?;
|
||||||
let parser = kcl_lib::parser::Parser::new(tokens);
|
let parser = kcl_lib::parser::Parser::new(tokens);
|
||||||
let program = parser.ast()?;
|
let program = parser.ast()?;
|
||||||
|
|
||||||
let snapshot = ctx.execute_and_prepare_snapshot(program).await?;
|
let snapshot = ctx.execute_and_prepare_snapshot(program).await?;
|
||||||
to_disk(snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_disk(snapshot: TakeSnapshot) -> Result<image::DynamicImage> {
|
|
||||||
// Create a temporary file to write the output to.
|
// Create a temporary file to write the output to.
|
||||||
let output_file = std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
|
let output_file = std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
|
||||||
// Save the snapshot locally, to that temporary file.
|
// Save the snapshot locally, to that temporary file.
|
||||||
@ -62,28 +81,28 @@ const part002 = startSketchOn(part001, "here")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_riddle_small() {
|
async fn serial_test_riddle_small() {
|
||||||
let code = include_str!("inputs/riddle_small.kcl");
|
let code = include_str!("inputs/riddle_small.kcl");
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_lego() {
|
async fn serial_test_lego() {
|
||||||
let code = include_str!("inputs/lego.kcl");
|
let code = include_str!("inputs/lego.kcl");
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_pipe_as_arg() {
|
async fn serial_test_pipe_as_arg() {
|
||||||
let code = include_str!("inputs/pipe_as_arg.kcl");
|
let code = include_str!("inputs/pipe_as_arg.kcl");
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pipe_as_arg.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pipe_as_arg.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,14 +137,14 @@ const part002 = startSketchOn(part001, "start")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_start.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_start.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_mike_stress_lines() {
|
async fn serial_test_mike_stress_lines() {
|
||||||
let code = include_str!("inputs/mike_stress_test.kcl");
|
let code = include_str!("inputs/mike_stress_test.kcl");
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/mike_stress_test.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/mike_stress_test.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +172,7 @@ const part002 = startSketchOn(part001, "END")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_end.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_end.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +200,7 @@ const part002 = startSketchOn(part001, "END")
|
|||||||
|> extrude(-5, %)
|
|> extrude(-5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/sketch_on_face_end_negative_extrude.png",
|
"tests/executor/outputs/sketch_on_face_end_negative_extrude.png",
|
||||||
&result,
|
&result,
|
||||||
@ -201,7 +220,7 @@ async fn serial_test_fillet_duplicate_tags() {
|
|||||||
|> fillet({radius: 0.5, tags: ["thing", "thing"]}, %)
|
|> fillet({radius: 0.5, tags: ["thing", "thing"]}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -221,7 +240,7 @@ async fn serial_test_basic_fillet_cube_start() {
|
|||||||
|> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
|
|> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_start.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_start.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +257,7 @@ async fn serial_test_basic_fillet_cube_end() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_end.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_end.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +274,7 @@ async fn serial_test_basic_fillet_cube_close_opposite() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_close_opposite.png",
|
"tests/executor/outputs/basic_fillet_cube_close_opposite.png",
|
||||||
&result,
|
&result,
|
||||||
@ -275,7 +294,7 @@ async fn serial_test_basic_fillet_cube_next_adjacent() {
|
|||||||
|> fillet({radius: 2, tags: [getNextAdjacentEdge("thing3", %)]}, %)
|
|> fillet({radius: 2, tags: [getNextAdjacentEdge("thing3", %)]}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_next_adjacent.png",
|
"tests/executor/outputs/basic_fillet_cube_next_adjacent.png",
|
||||||
&result,
|
&result,
|
||||||
@ -295,7 +314,7 @@ async fn serial_test_basic_fillet_cube_previous_adjacent() {
|
|||||||
|> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing3", %)]}, %)
|
|> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing3", %)]}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/basic_fillet_cube_previous_adjacent.png",
|
"tests/executor/outputs/basic_fillet_cube_previous_adjacent.png",
|
||||||
&result,
|
&result,
|
||||||
@ -320,7 +339,7 @@ async fn serial_test_execute_with_function_sketch() {
|
|||||||
const fnBox = box(3, 6, 10)
|
const fnBox = box(3, 6, 10)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/function_sketch.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/function_sketch.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +359,7 @@ async fn serial_test_execute_with_function_sketch_with_position() {
|
|||||||
|
|
||||||
const thing = box([0,0], 3, 6, 10)"#;
|
const thing = box([0,0], 3, 6, 10)"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/function_sketch_with_position.png",
|
"tests/executor/outputs/function_sketch_with_position.png",
|
||||||
&result,
|
&result,
|
||||||
@ -361,7 +380,7 @@ async fn serial_test_execute_with_angled_line() {
|
|||||||
|> extrude(4, %)
|
|> extrude(4, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/angled_line.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/angled_line.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +406,7 @@ const bracket = startSketchOn('XY')
|
|||||||
|> extrude(width, %)
|
|> extrude(width, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/parametric.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/parametric.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +440,7 @@ const bracket = startSketchAt([0, 0])
|
|||||||
|> extrude(width, %)
|
|> extrude(width, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/parametric_with_tan_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/parametric_with_tan_arc.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +455,7 @@ async fn serial_test_execute_engine_error_return() {
|
|||||||
|> extrude(4, %)
|
|> extrude(4, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -449,7 +468,7 @@ async fn serial_test_execute_i_shape() {
|
|||||||
// This is some code from lee that starts a pipe expression with a variable.
|
// This is some code from lee that starts a pipe expression with a variable.
|
||||||
let code = include_str!("inputs/i_shape.kcl");
|
let code = include_str!("inputs/i_shape.kcl");
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/i_shape.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/i_shape.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +477,7 @@ async fn serial_test_execute_i_shape() {
|
|||||||
async fn serial_test_execute_pipes_on_pipes() {
|
async fn serial_test_execute_pipes_on_pipes() {
|
||||||
let code = include_str!("inputs/pipes_on_pipes.kcl");
|
let code = include_str!("inputs/pipes_on_pipes.kcl");
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/pipes_on_pipes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/pipes_on_pipes.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,7 +485,7 @@ async fn serial_test_execute_pipes_on_pipes() {
|
|||||||
async fn serial_test_execute_cylinder() {
|
async fn serial_test_execute_cylinder() {
|
||||||
let code = include_str!("inputs/cylinder.kcl");
|
let code = include_str!("inputs/cylinder.kcl");
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cylinder.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/cylinder.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,7 +493,7 @@ async fn serial_test_execute_cylinder() {
|
|||||||
async fn serial_test_execute_kittycad_svg() {
|
async fn serial_test_execute_kittycad_svg() {
|
||||||
let code = include_str!("inputs/kittycad_svg.kcl");
|
let code = include_str!("inputs/kittycad_svg.kcl");
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/kittycad_svg.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/kittycad_svg.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +518,7 @@ const pt1 = b1.value[0]
|
|||||||
const pt2 = b2.value[0]
|
const pt2 = b2.value[0]
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/member_expression_sketch_group.png",
|
"tests/executor/outputs/member_expression_sketch_group.png",
|
||||||
&result,
|
&result,
|
||||||
@ -515,7 +534,7 @@ async fn serial_test_helix_defaults() {
|
|||||||
|> helix({revolutions: 16, angle_start: 0}, %)
|
|> helix({revolutions: 16, angle_start: 0}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_defaults.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_defaults.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,7 +546,7 @@ async fn serial_test_helix_defaults_negative_extrude() {
|
|||||||
|> helix({revolutions: 16, angle_start: 0}, %)
|
|> helix({revolutions: 16, angle_start: 0}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/helix_defaults_negative_extrude.png",
|
"tests/executor/outputs/helix_defaults_negative_extrude.png",
|
||||||
&result,
|
&result,
|
||||||
@ -543,7 +562,7 @@ async fn serial_test_helix_ccw() {
|
|||||||
|> helix({revolutions: 16, angle_start: 0, ccw: true}, %)
|
|> helix({revolutions: 16, angle_start: 0, ccw: true}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_ccw.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_ccw.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +574,7 @@ async fn serial_test_helix_with_length() {
|
|||||||
|> helix({revolutions: 16, angle_start: 0, length: 3}, %)
|
|> helix({revolutions: 16, angle_start: 0, length: 3}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/helix_with_length.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/helix_with_length.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +589,7 @@ async fn serial_test_dimensions_match() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/dimensions_match.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/dimensions_match.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +606,7 @@ const body = startSketchOn('XY')
|
|||||||
|> extrude(height, %)
|
|> extrude(height, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/close_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/close_arc.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +632,7 @@ box(10, 23, 8)
|
|||||||
let thing = box(-12, -15, 10)
|
let thing = box(-12, -15, 10)
|
||||||
box(-20, -5, 10)"#;
|
box(-20, -5, 10)"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/negative_args.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/negative_args.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +645,7 @@ async fn serial_test_basic_tangential_arc() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,7 +658,7 @@ async fn serial_test_basic_tangential_arc_with_point() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_with_point.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_with_point.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +671,7 @@ async fn serial_test_basic_tangential_arc_to() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_to.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/tangential_arc_to.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,7 +698,7 @@ box(30, 43, 18, '-xy')
|
|||||||
let thing = box(-12, -15, 10, 'yz')
|
let thing = box(-12, -15, 10, 'yz')
|
||||||
box(-20, -5, 10, 'xy')"#;
|
box(-20, -5, 10, 'xy')"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/different_planes_same_drawing.png",
|
"tests/executor/outputs/different_planes_same_drawing.png",
|
||||||
&result,
|
&result,
|
||||||
@ -741,7 +760,7 @@ const part004 = startSketchOn('YZ')
|
|||||||
|> close(%)
|
|> close(%)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/lots_of_planes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/lots_of_planes.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +777,7 @@ async fn serial_test_holes() {
|
|||||||
|> extrude(2, %)
|
|> extrude(2, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/holes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/holes.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,7 +796,7 @@ async fn optional_params() {
|
|||||||
|
|
||||||
const thing = other_circle([2, 2], 20)
|
const thing = other_circle([2, 2], 20)
|
||||||
"#;
|
"#;
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/optional_params.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/optional_params.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +832,7 @@ const part = roundedRectangle([0, 0], 20, 20, 4)
|
|||||||
|> extrude(2, %)
|
|> extrude(2, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/rounded_with_holes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/rounded_with_holes.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,7 +840,7 @@ const part = roundedRectangle([0, 0], 20, 20, 4)
|
|||||||
async fn serial_test_top_level_expression() {
|
async fn serial_test_top_level_expression() {
|
||||||
let code = r#"startSketchOn('XY') |> circle([0,0], 22, %) |> extrude(14, %)"#;
|
let code = r#"startSketchOn('XY') |> circle([0,0], 22, %) |> extrude(14, %)"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/top_level_expression.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,7 +854,7 @@ const part = startSketchOn('XY')
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_with_math.png",
|
"tests/executor/outputs/patterns_linear_basic_with_math.png",
|
||||||
&result,
|
&result,
|
||||||
@ -851,7 +870,7 @@ async fn serial_test_patterns_linear_basic() {
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,7 +886,7 @@ async fn serial_test_patterns_linear_basic_3d() {
|
|||||||
|> patternLinear3d({axis: [1, 0, 1], repetitions: 3, distance: 6}, %)
|
|> patternLinear3d({axis: [1, 0, 1], repetitions: 3, distance: 6}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_3d.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_3d.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,7 +898,7 @@ async fn serial_test_patterns_linear_basic_negative_distance() {
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_negative_distance.png",
|
"tests/executor/outputs/patterns_linear_basic_negative_distance.png",
|
||||||
&result,
|
&result,
|
||||||
@ -895,7 +914,7 @@ async fn serial_test_patterns_linear_basic_negative_axis() {
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_linear_basic_negative_axis.png",
|
"tests/executor/outputs/patterns_linear_basic_negative_axis.png",
|
||||||
&result,
|
&result,
|
||||||
@ -920,7 +939,7 @@ const rectangle = startSketchOn('XY')
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_holes.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_linear_basic_holes.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +951,7 @@ async fn serial_test_patterns_circular_basic_2d() {
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_2d.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_2d.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,7 +967,7 @@ async fn serial_test_patterns_circular_basic_3d() {
|
|||||||
|> patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %)
|
|> patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_3d.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/patterns_circular_basic_3d.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,7 +983,7 @@ async fn serial_test_patterns_circular_3d_tilted_axis() {
|
|||||||
|> patternCircular3d({axis: [1,1,0], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
|
|> patternCircular3d({axis: [1,1,0], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/patterns_circular_3d_tilted_axis.png",
|
"tests/executor/outputs/patterns_circular_3d_tilted_axis.png",
|
||||||
&result,
|
&result,
|
||||||
@ -976,7 +995,7 @@ async fn serial_test_patterns_circular_3d_tilted_axis() {
|
|||||||
async fn serial_test_import_file_doesnt_exist() {
|
async fn serial_test_import_file_doesnt_exist() {
|
||||||
let code = r#"const model = import("thing.obj")"#;
|
let code = r#"const model = import("thing.obj")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -988,7 +1007,7 @@ async fn serial_test_import_file_doesnt_exist() {
|
|||||||
async fn serial_test_import_obj_with_mtl() {
|
async fn serial_test_import_obj_with_mtl() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube.obj")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.obj")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,7 +1015,7 @@ async fn serial_test_import_obj_with_mtl() {
|
|||||||
async fn serial_test_import_obj_with_mtl_units() {
|
async fn serial_test_import_obj_with_mtl_units() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube.obj", {type: "obj", units: "m"})"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.obj", {type: "obj", units: "m"})"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl_units.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_obj_with_mtl_units.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1004,7 +1023,7 @@ async fn serial_test_import_obj_with_mtl_units() {
|
|||||||
async fn serial_test_import_gltf_with_bin() {
|
async fn serial_test_import_gltf_with_bin() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube.gltf")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.gltf")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_with_bin.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_with_bin.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,7 +1031,7 @@ async fn serial_test_import_gltf_with_bin() {
|
|||||||
async fn serial_test_import_gltf_embedded() {
|
async fn serial_test_import_gltf_embedded() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube-embedded.gltf")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube-embedded.gltf")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_embedded.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_gltf_embedded.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,7 +1039,7 @@ async fn serial_test_import_gltf_embedded() {
|
|||||||
async fn serial_test_import_glb() {
|
async fn serial_test_import_glb() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube.glb")"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.glb")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_glb.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_glb.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,7 +1047,7 @@ async fn serial_test_import_glb() {
|
|||||||
async fn serial_test_import_glb_no_assign() {
|
async fn serial_test_import_glb_no_assign() {
|
||||||
let code = r#"import("tests/executor/inputs/cube.glb")"#;
|
let code = r#"import("tests/executor/inputs/cube.glb")"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/import_glb_no_assign.png", &result, 0.999);
|
twenty_twenty::assert_image("tests/executor/outputs/import_glb_no_assign.png", &result, 0.999);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,7 +1055,7 @@ async fn serial_test_import_glb_no_assign() {
|
|||||||
async fn serial_test_import_ext_doesnt_match() {
|
async fn serial_test_import_ext_doesnt_match() {
|
||||||
let code = r#"const model = import("tests/executor/inputs/cube.gltf", {type: "obj", units: "m"})"#;
|
let code = r#"const model = import("tests/executor/inputs/cube.gltf", {type: "obj", units: "m"})"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1061,7 +1080,7 @@ async fn serial_test_cube_mm() {
|
|||||||
const myCube = cube([0,0], 10)
|
const myCube = cube([0,0], 10)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/cube_mm.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/cube_mm.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1194,7 +1213,7 @@ const part002 = startSketchOn(part001, "here")
|
|||||||
|> extrude(1, %)
|
|> extrude(1, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1235,7 +1254,7 @@ const part003 = startSketchOn(part002, "end")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_of_face.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_of_face.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1252,7 +1271,7 @@ async fn serial_test_stdlib_kcl_error_right_code_path() {
|
|||||||
|> extrude(2, %)
|
|> extrude(2, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1280,7 +1299,7 @@ const part002 = startSketchOn(part001, "end")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1304,7 +1323,7 @@ const part002 = startSketchOn(part001, "end")
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle_tagged.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/sketch_on_face_circle_tagged.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1346,7 +1365,7 @@ const part = rectShape([0, 0], 20, 20)
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1367,7 +1386,7 @@ async fn serial_test_big_number_angle_to_match_length_x() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/big_number_angle_to_match_length_x.png",
|
"tests/executor/outputs/big_number_angle_to_match_length_x.png",
|
||||||
&result,
|
&result,
|
||||||
@ -1388,7 +1407,7 @@ async fn serial_test_big_number_angle_to_match_length_y() {
|
|||||||
|> extrude(10, %)
|
|> extrude(10, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image(
|
twenty_twenty::assert_image(
|
||||||
"tests/executor/outputs/big_number_angle_to_match_length_y.png",
|
"tests/executor/outputs/big_number_angle_to_match_length_y.png",
|
||||||
&result,
|
&result,
|
||||||
@ -1412,7 +1431,7 @@ async fn serial_test_simple_revolve() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1432,7 +1451,7 @@ async fn serial_test_simple_revolve_uppercase() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_uppercase.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_uppercase.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,7 +1471,7 @@ async fn serial_test_simple_revolve_negative() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_negative.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_negative.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1472,7 +1491,7 @@ async fn serial_test_revolve_bad_angle_low() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1497,7 +1516,7 @@ async fn serial_test_revolve_bad_angle_high() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1522,7 +1541,7 @@ async fn serial_test_simple_revolve_custom_angle() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_angle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_angle.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1542,7 +1561,7 @@ async fn serial_test_simple_revolve_custom_axis() {
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_axis.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_custom_axis.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1566,7 +1585,7 @@ const sketch001 = startSketchOn(box, "end")
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_edge.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_edge.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1590,7 +1609,7 @@ const sketch001 = startSketchOn(box, "revolveAxis")
|
|||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1617,7 +1636,7 @@ const sketch001 = startSketchOn(box, "END")
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle_edge.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle_edge.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1639,7 +1658,7 @@ const sketch001 = startSketchOn(box, "END")
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face_circle.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1665,7 +1684,7 @@ const sketch001 = startSketchOn(box, "end")
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/revolve_on_face.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1679,7 +1698,7 @@ async fn serial_test_basic_revolve_circle() {
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/basic_revolve_circle.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/basic_revolve_circle.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1706,7 +1725,7 @@ const part002 = startSketchOn(part001, 'end')
|
|||||||
|> extrude(5, %)
|
|> extrude(5, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_sketch_on_edge.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/simple_revolve_sketch_on_edge.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1767,7 +1786,7 @@ const plumbus1 = make_circle(p, 'b', [0, 0], 2.5)
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/plumbus_fillets.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/plumbus_fillets.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1775,7 +1794,7 @@ const plumbus1 = make_circle(p, 'b', [0, 0], 2.5)
|
|||||||
async fn serial_test_empty_file_is_ok() {
|
async fn serial_test_empty_file_is_ok() {
|
||||||
let code = r#""#;
|
let code = r#""#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1805,7 +1824,7 @@ async fn serial_test_member_expression_in_params() {
|
|||||||
capScrew([0, 0.5, 0], 50, 37.5, 50, 25)
|
capScrew([0, 0.5, 0], 50, 37.5, 50, 25)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/member_expression_in_params.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/member_expression_in_params.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1850,7 +1869,7 @@ const bracket = startSketchOn('XY')
|
|||||||
}, %)
|
}, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1874,7 +1893,7 @@ const secondSketch = startSketchOn(part001, '')
|
|||||||
|> extrude(20, %)
|
|> extrude(20, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1905,7 +1924,7 @@ const extrusion = startSketchOn('XY')
|
|||||||
|> extrude(height, %)
|
|> extrude(height, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await;
|
let result = execute_and_snapshot(code, UnitLength::Mm).await;
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.err().unwrap().to_string(),
|
result.err().unwrap().to_string(),
|
||||||
@ -1923,7 +1942,7 @@ async fn serial_test_xz_plane() {
|
|||||||
|> extrude(5 + 7, %)
|
|> extrude(5 + 7, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/xz_plane.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/xz_plane.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1937,38 +1956,56 @@ async fn serial_test_neg_xz_plane() {
|
|||||||
|> extrude(5 + 7, %)
|
|> extrude(5 + 7, %)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = snapshot_on_test_server(code.to_owned(), test_name!()).await.unwrap();
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
twenty_twenty::assert_image("tests/executor/outputs/neg_xz_plane.png", &result, 1.0);
|
twenty_twenty::assert_image("tests/executor/outputs/neg_xz_plane.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn snapshot_on_test_server(code: String, test_name: &str) -> Result<image::DynamicImage> {
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
let default_addr = "0.0.0.0:3333";
|
async fn serial_test_linear_pattern3d_a_pattern() {
|
||||||
let server_url = std::env::var("TEST_EXECUTOR_ADDR").unwrap_or(default_addr.to_owned());
|
let code = r#"const exampleSketch = startSketchOn('XZ')
|
||||||
let client = reqwest::Client::new();
|
|> startProfileAt([0, 0], %)
|
||||||
let body = serde_json::json!({
|
|> line([0, 2], %)
|
||||||
"kcl_program": code,
|
|> line([3, 1], %)
|
||||||
"test_name": test_name,
|
|> line([0, -4], %)
|
||||||
});
|
|> close(%)
|
||||||
let body = serde_json::to_vec(&body).unwrap();
|
|> extrude(1, %)
|
||||||
let resp = match client.post(format!("http://{server_url}")).body(body).send().await {
|
|
||||||
Ok(r) => r,
|
const pattn1 = patternLinear3d({
|
||||||
Err(e) if e.is_connect() => {
|
axis: [1, 0, 0],
|
||||||
eprintln!("Received a connection error. Is the test server running?");
|
repetitions: 6,
|
||||||
eprintln!("If so, is it running at {server_url}?");
|
distance: 6
|
||||||
panic!("Connection error: {e}");
|
}, exampleSketch)
|
||||||
}
|
|
||||||
Err(e) => panic!("{e}"),
|
const pattn2 = patternLinear3d({
|
||||||
};
|
axis: [0, 0, 1],
|
||||||
let status = resp.status();
|
distance: 1,
|
||||||
let bytes = resp.bytes().await?;
|
repetitions: 6
|
||||||
if status.is_success() {
|
}, pattn1)
|
||||||
let img = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?.decode()?;
|
"#;
|
||||||
Ok(img)
|
|
||||||
} else if status == hyper::StatusCode::BAD_GATEWAY {
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
let err = String::from_utf8(bytes.into()).unwrap();
|
twenty_twenty::assert_image("tests/executor/outputs/linear_pattern3d_a_pattern.png", &result, 1.0);
|
||||||
anyhow::bail!("{err}")
|
|
||||||
} else {
|
|
||||||
let err = String::from_utf8(bytes.into()).unwrap();
|
|
||||||
panic!("{err}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_circular_pattern3d_a_pattern() {
|
||||||
|
let code = r#"const exampleSketch = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([0, 0], %)
|
||||||
|
|> line([0, 2], %)
|
||||||
|
|> line([3, 1], %)
|
||||||
|
|> line([0, -4], %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(1, %)
|
||||||
|
|
||||||
|
const pattn1 = patternLinear3d({
|
||||||
|
axis: [1, 0, 0],
|
||||||
|
repetitions: 6,
|
||||||
|
distance: 6
|
||||||
|
}, exampleSketch)
|
||||||
|
|
||||||
|
const pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||||
|
twenty_twenty::assert_image("tests/executor/outputs/circular_pattern3d_a_pattern.png", &result, 1.0);
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 289 KiB After Width: | Height: | Size: 250 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 214 KiB |
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 212 KiB |
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 225 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 125 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 120 KiB |
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 141 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 195 KiB |
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 116 KiB |