Compare commits

..

1 Commits

Author SHA1 Message Date
c44f81aa1e Disable rectangle tool 2024-07-30 13:10:12 -04:00
50 changed files with 1614 additions and 1034 deletions

View File

@ -4179,15 +4179,12 @@ test.describe('Sketch tests', () => {
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click()
await expect(async () => {
await page.mouse.click(700, 200)
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeEnabled({ timeout: 1000 })
await page.getByRole('button', { name: 'Edit Sketch' }).click()
}).toPass({ timeout: 40_000, intervals: [1_000] })
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeEnabled()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(600) // wait for animation
@ -7293,15 +7290,15 @@ test.describe('Test network and connection issues', () => {
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([-8.84, 8.75], %)`)
|> line([-9.16, 8.81], %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([-8.84, 8.75], %)
|> line([-5.6, 0], %)`)
|> line([-9.16, 8.81], %)
|> line([-5.28, 0], %)`)
// Unequip line tool
await page.keyboard.press('Escape')
@ -8097,34 +8094,3 @@ test('Sketch on face', async ({ page }) => {
const sketch002 = extrude(${[5, 5]} + 7, sketch002)`
await expect(page.locator('.cm-content')).toHaveText(result2.regExp)
})
test('Typing KCL errors induces a badge on the error logs pane button', async ({
page,
}) => {
const u = await getUtils(page)
// Load the app with the working starter code
await page.addInitScript((code) => {
localStorage.setItem('persistCode', code)
}, bracket)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
// wait for execution done
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// Ensure no badge is present
const errorLogsButton = page.getByRole('button', { name: 'KCL Errors pane' })
await expect(errorLogsButton).not.toContainText('notification')
// Delete a character to break the KCL
await u.openKclCodePanel()
await page.getByText('extrude(').click()
await page.keyboard.press('Backspace')
// Ensure that a badge appears on the button
await expect(errorLogsButton).toContainText('notification')
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -266,7 +266,7 @@ export async function getUtils(page: Page) {
getSegmentBodyCoords: async (locator: string, px = 30) => {
const overlay = page.locator(locator)
const bbox = await overlay
.boundingBox({ timeout: 5000 })
.boundingBox()
.then((box) => ({ ...box, x: box?.x || 0, y: box?.y || 0 }))
const angle = Number(await overlay.getAttribute('data-overlay-angle'))
const angleXOffset = Math.cos(((angle - 180) * Math.PI) / 180) * px

View File

@ -1,340 +0,0 @@
{
"components": {
"responses": {
"Error": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": "Error"
}
},
"schemas": {
"Error": {
"description": "Error information from a response.",
"properties": {
"error_code": {
"type": "string"
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
}
},
"required": [
"message",
"request_id"
],
"type": "object"
},
"Machine": {
"description": "Details for a 3d printer connected over USB.",
"oneOf": [
{
"description": "Details for a 3d printer connected over USB.",
"properties": {
"id": {
"type": "string"
},
"manufacturer": {
"type": "string"
},
"model": {
"type": "string"
},
"port": {
"type": "string"
},
"type": {
"enum": [
"UsbPrinter"
],
"type": "string"
}
},
"required": [
"id",
"manufacturer",
"model",
"port",
"type"
],
"type": "object"
},
{
"description": "Details for a 3d printer connected over USB.",
"properties": {
"hostname": {
"description": "The hostname of the printer.",
"nullable": true,
"type": "string"
},
"ip": {
"description": "The IP address of the printer.",
"format": "ip",
"type": "string"
},
"manufacturer": {
"allOf": [
{
"$ref": "#/components/schemas/NetworkPrinterManufacturer"
}
],
"description": "The manufacturer of the printer."
},
"model": {
"description": "The model of the printer.",
"nullable": true,
"type": "string"
},
"port": {
"description": "The port of the printer.",
"format": "uint16",
"minimum": 0,
"nullable": true,
"type": "integer"
},
"serial": {
"description": "The serial number of the printer.",
"nullable": true,
"type": "string"
},
"type": {
"enum": [
"NetworkPrinter"
],
"type": "string"
}
},
"required": [
"ip",
"manufacturer",
"type"
],
"type": "object"
}
]
},
"NetworkPrinterManufacturer": {
"description": "Network printer manufacturer.",
"oneOf": [
{
"description": "Bambu.",
"enum": [
"Bambu"
],
"type": "string"
},
{
"description": "Formlabs.",
"enum": [
"Formlabs"
],
"type": "string"
}
]
},
"Pong": {
"description": "The response from the `/ping` endpoint.",
"properties": {
"message": {
"description": "The pong response.",
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
},
"PrintJobResponse": {
"description": "The response from the `/print` endpoint.",
"properties": {
"job_id": {
"description": "The job id used for this print.",
"type": "string"
},
"parameters": {
"allOf": [
{
"$ref": "#/components/schemas/PrintParameters"
}
],
"description": "The parameters used for this print."
}
},
"required": [
"job_id",
"parameters"
],
"type": "object"
},
"PrintParameters": {
"description": "Parameters for printing.",
"properties": {
"machine_id": {
"type": "string"
}
},
"required": [
"machine_id"
],
"type": "object"
}
}
},
"info": {
"contact": {
"email": "machine-api@zoo.dev",
"url": "https://zoo.dev"
},
"description": "",
"title": "machine-api",
"version": "0.1.0"
},
"openapi": "3.0.3",
"paths": {
"/": {
"get": {
"operationId": "api_get_schema",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {}
}
},
"description": "successful operation"
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
},
"summary": "Return the OpenAPI schema in JSON format.",
"tags": [
"meta"
]
}
},
"/machines": {
"get": {
"operationId": "get_machines",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"$ref": "#/components/schemas/Machine"
},
"title": "Map_of_Machine",
"type": "object"
}
}
},
"description": "successful operation"
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
},
"summary": "List available machines and their statuses",
"tags": [
"print"
]
}
},
"/ping": {
"get": {
"operationId": "ping",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pong"
}
}
},
"description": "successful operation"
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
},
"summary": "Return pong.",
"tags": [
"meta"
]
}
},
"/print": {
"post": {
"operationId": "print_file",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"format": "binary",
"type": "string"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PrintJobResponse"
}
}
},
"description": "successful operation"
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
},
"summary": "Print a given file. File must be a sliceable 3D model.",
"tags": [
"print"
]
}
}
},
"tags": [
{
"description": "Meta information about the API.",
"externalDocs": {
"url": "https://docs.zoo.dev/api/meta"
},
"name": "meta"
},
{
"description": "Utilities for printing and discovering printers.",
"externalDocs": {
"url": "https://docs.zoo.dev/api/print"
},
"name": "print"
}
]
}

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.24.6",
"version": "0.24.4",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.17.0",

25
src-tauri/Cargo.lock generated
View File

@ -648,12 +648,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
version = "1.6.0"
@ -2405,18 +2399,6 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "image"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
dependencies = [
"bytemuck",
"byteorder-lite",
"num-traits",
"png",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@ -2589,7 +2571,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.2.3"
version = "0.2.2"
dependencies = [
"anyhow",
"approx",
@ -2607,7 +2589,6 @@ dependencies = [
"futures",
"git_rev",
"gltf-json",
"image",
"js-sys",
"kittycad",
"lazy_static",
@ -3539,9 +3520,9 @@ dependencies = [
[[package]]
name = "phonenumber"
version = "0.3.6+8.13.36"
version = "0.3.5+8.13.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11756237b57b8cc5e97dc8b1e70ea436324d30e7075de63b14fd15073a8f692a"
checksum = "f174c8db59b620032bd52b655fc97000458850fec0db35fcd4e802b668517ec0"
dependencies = [
"bincode",
"either",

View File

@ -80,5 +80,5 @@
}
},
"productName": "Zoo Modeling App",
"version": "0.24.6"
"version": "0.24.4"
}

View File

@ -27,7 +27,6 @@ import {
defaultPlaneColor,
getSceneScale,
INTERSECTION_PLANE_LAYER,
OnClickCallbackArgs,
OnMouseEnterLeaveArgs,
RAYCASTABLE_PLANE,
SEGMENT_LENGTH_LABEL,
@ -79,7 +78,6 @@ import {
} from 'lang/std/sketch'
import { isOverlap, normaliseAngle, roundOff, throttle } from 'lib/utils'
import {
addStartProfileAt,
createArrayExpression,
createCallExpressionStdLib,
createLiteral,
@ -298,51 +296,6 @@ export class SceneEntities {
if (intersectionPlane) this.scene.remove(intersectionPlane)
}
setupNoPointsListener({
sketchDetails,
afterClick,
}: {
sketchDetails: SketchDetails
afterClick: (args: OnClickCallbackArgs) => void
}) {
// Create a THREEjs plane to raycast clicks onto
this.createIntersectionPlane()
const quaternion = quaternionFromUpNForward(
new Vector3(...sketchDetails.yAxis),
new Vector3(...sketchDetails.zAxis)
)
// Position the click raycast plane
if (this.intersectionPlane) {
this.intersectionPlane.setRotationFromQuaternion(quaternion)
this.intersectionPlane.position.copy(
new Vector3(...(sketchDetails?.origin || [0, 0, 0]))
)
}
sceneInfra.setCallbacks({
onClick: async (args) => {
if (!args) return
if (args.mouseEvent.which !== 1) return
const { intersectionPoint } = args
if (!intersectionPoint?.twoD || !sketchDetails?.sketchPathToNode) return
const addStartProfileAtRes = addStartProfileAt(
kclManager.ast,
sketchDetails.sketchPathToNode,
[intersectionPoint.twoD.x, intersectionPoint.twoD.y]
)
if (trap(addStartProfileAtRes)) return
const { modifiedAst } = addStartProfileAtRes
await kclManager.updateAst(modifiedAst, false)
this.removeIntersectionPlane()
// Now perform the caller-specified action
afterClick(args)
},
})
}
async setupSketch({
sketchPathToNode,
forward,
@ -719,6 +672,21 @@ export class SceneEntities {
...this.mouseEnterLeaveCallbacks(),
})
}
setupRectangleOriginListener = () => {
sceneInfra.setCallbacks({
onClick: (args) => {
const twoD = args.intersectionPoint?.twoD
if (!twoD) {
console.warn(`This click didn't have a 2D intersection`, args)
return
}
sceneInfra.modelingSend({
type: 'Add rectangle origin',
data: [twoD.x, twoD.y],
})
},
})
}
setupDraftRectangle = async (
sketchPathToNode: PathToNode,
forward: [number, number, number],
@ -736,8 +704,6 @@ export class SceneEntities {
if (trap(_node1)) return Promise.reject(_node1)
const variableDeclarationName =
_node1.node?.declarations?.[0]?.id?.name || ''
const startSketchOn = _node1.node?.declarations
const startSketchOnInit = startSketchOn?.[0]?.init
const tags: [string, string, string] = [
findUniqueName(_ast, 'rectangleSegmentA'),
@ -745,6 +711,15 @@ export class SceneEntities {
findUniqueName(_ast, 'rectangleSegmentC'),
]
const _node2 = getNodeFromPath<VariableDeclaration>(
_ast,
sketchPathToNode || [],
'VariableDeclaration'
)
if (trap(_node2)) return Promise.reject(_node2)
const startSketchOn = _node2.node?.declarations
const startSketchOnInit = startSketchOn?.[0]?.init
startSketchOn[0].init = createPipeExpression([
startSketchOnInit,
...getRectangleCallExpressions(rectangleOrigin, tags),

View File

@ -72,7 +72,7 @@ interface OnDragCallbackArgs extends OnMouseEnterLeaveArgs {
}
intersects: Intersection<Object3D<Object3DEventMap>>[]
}
export interface OnClickCallbackArgs {
interface OnClickCallbackArgs {
mouseEvent: MouseEvent
intersectionPoint?: {
twoD: Vector2

View File

@ -142,9 +142,7 @@ export const ModelingMachineProvider = ({
kclManager.executeCode().then(() => {
if (engineCommandManager.engineConnection?.idleMode) return
store.videoElement?.play().catch((e) => {
console.warn('Video playing was prevented', e)
})
store.videoElement?.play()
})
})()
},

View File

@ -14,7 +14,6 @@ import { MemoryPane, MemoryPaneMenu } from './MemoryPane'
import { KclErrorsPane, LogsPane } from './LoggingPanes'
import { DebugPane } from './DebugPane'
import { FileTreeInner, FileTreeMenu } from 'components/FileTree'
import { useKclContext } from 'lang/KclProvider'
export type SidebarType =
| 'code'
@ -26,14 +25,6 @@ export type SidebarType =
| 'lspMessages'
| 'variables'
/**
* This interface can be extended as more context is needed for the panes
* to determine if they should show their badges or not.
*/
interface PaneCallbackProps {
kclContext: ReturnType<typeof useKclContext>
}
export type SidebarPane = {
id: SidebarType
title: string
@ -42,7 +33,6 @@ export type SidebarPane = {
Content: ReactNode | React.FC
Menu?: ReactNode | React.FC
hideOnPlatform?: 'desktop' | 'web'
showBadge?: (props: PaneCallbackProps) => boolean | number
}
export const sidebarPanes: SidebarPane[] = [
@ -84,7 +74,6 @@ export const sidebarPanes: SidebarPane[] = [
icon: faExclamationCircle,
Content: KclErrorsPane,
keybinding: 'Shift + E',
showBadge: ({ kclContext }) => kclContext.errors.length,
},
{
id: 'debug',

View File

@ -12,7 +12,6 @@ import { useModelingContext } from 'hooks/useModelingContext'
import { CustomIconName } from 'components/CustomIcon'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
import { useKclContext } from 'lang/KclProvider'
interface ModelingSidebarProps {
paneOpacity: '' | 'opacity-20' | 'opacity-40'
@ -20,7 +19,6 @@ interface ModelingSidebarProps {
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
const { commandBarSend } = useCommandsContext()
const kclContext = useKclContext()
const { settings } = useSettingsAuthContext()
const onboardingStatus = settings.context.app.onboardingStatus
const { send, context } = useModelingContext()
@ -64,15 +62,6 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
[sidebarPanes, showDebugPanel.current]
)
const paneBadgeMap: Record<SidebarType, number | boolean> = useMemo(() => {
return filteredPanes.reduce((acc, pane) => {
if (pane.showBadge) {
acc[pane.id] = pane.showBadge({ kclContext })
}
return acc
}, {} as Record<SidebarType, number | boolean>)
}, [kclContext.errors])
const togglePane = useCallback(
(newPane: SidebarType) => {
send({
@ -131,7 +120,6 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
paneIsOpen={context.store?.openPanes.includes(pane.id)}
onClick={() => togglePane(pane.id)}
aria-pressed={context.store?.openPanes.includes(pane.id)}
showBadge={paneBadgeMap[pane.id]}
/>
))}
</ul>
@ -198,14 +186,12 @@ interface ModelingPaneButtonProps
}
onClick: () => void
paneIsOpen?: boolean
showBadge?: boolean | number
}
function ModelingPaneButton({
paneConfig,
onClick,
paneIsOpen,
showBadge,
...props
}: ModelingPaneButtonProps) {
useHotkeys(paneConfig.keybinding, onClick, {
@ -237,23 +223,6 @@ function ModelingPaneButton({
{paneConfig.title}
{paneIsOpen !== undefined ? ` pane` : ''}
</span>
{!!showBadge && (
<p
className={
'absolute m-0 p-0 -top-1 -right-1 w-3 h-3 flex items-center justify-center text-[10px] font-semibold text-white bg-primary hue-rotate-90 rounded-full border border-chalkboard-10 dark:border-chalkboard-80'
}
>
<span className="sr-only">&nbsp;has&nbsp;</span>
{typeof showBadge === 'number' ? (
<span>{showBadge}</span>
) : (
<span className="sr-only">a</span>
)}
<span className="sr-only">
&nbsp;notification{Number(showBadge) > 1 ? 's' : ''}
</span>
</p>
)}
<Tooltip
position="right"
contentClassName="max-w-none flex items-center gap-4"

View File

@ -175,35 +175,11 @@ export const SettingsAuthProviderBase = ({
id: `${event.type}.success`,
})
},
'Execute AST': (context, event) => {
try {
const allSettingsIncludesUnitChange =
event.type === 'Set all settings' &&
event.settings?.modeling?.defaultUnit?.current !==
context.modeling.defaultUnit.current
const resetSettingsIncludesUnitChange =
event.type === 'Reset settings' &&
context.modeling.defaultUnit.current !==
settings?.modeling?.defaultUnit?.default
if (
event.type === 'set.modeling.defaultUnit' ||
allSettingsIncludesUnitChange ||
resetSettingsIncludesUnitChange
) {
kclManager.isFirstRender = true
kclManager.executeCode(true).then(() => {
kclManager.isFirstRender = false
})
} else {
// For any future logging we'd like to do
// console.log(
// 'Not re-executing AST because the settings change did not affect the code interpretation'
// )
}
} catch (e) {
console.error('Error executing AST after settings change', e)
}
'Execute AST': () => {
kclManager.isFirstRender = true
kclManager.executeCode(true).then(() => {
kclManager.isFirstRender = false
})
},
},
services: {

View File

@ -156,13 +156,7 @@ export const Stream = () => {
useEffect(() => {
setIsFirstRender(kclManager.isFirstRender)
if (!kclManager.isFirstRender)
setTimeout(() =>
// execute in the next event loop
videoRef.current?.play().catch((e) => {
console.warn('Video playing was prevented', e, videoRef.current)
})
)
if (!kclManager.isFirstRender) videoRef.current?.play()
setIsFreezeFrame(!kclManager.isFirstRender)
}, [kclManager.isFirstRender])
@ -176,12 +170,8 @@ export const Stream = () => {
if (!mediaStream) return
// Do not immediately play the stream!
try {
videoRef.current.srcObject = mediaStream
videoRef.current.pause()
} catch (e) {
console.warn('Attempted to pause stream while play was still loading', e)
}
videoRef.current.srcObject = mediaStream
videoRef.current.pause()
send({
type: 'Set context',

View File

@ -186,7 +186,6 @@ export function useSetupEngineManager(
}
function getDimensions(streamWidth?: number, streamHeight?: number) {
const factorOf = 4
const maxResolution = 2000
const width = streamWidth ? streamWidth : 0
const height = streamHeight ? streamHeight : 0
@ -194,7 +193,7 @@ function getDimensions(streamWidth?: number, streamHeight?: number) {
Math.min(maxResolution / width, maxResolution / height),
1.0
)
const quadWidth = Math.round((width * ratio) / factorOf) * factorOf
const quadHeight = Math.round((height * ratio) / factorOf) * factorOf
const quadWidth = Math.round((width * ratio) / 4) * 4
const quadHeight = Math.round((height * ratio) / 4) * 4
return { width: quadWidth, height: quadHeight }
}

View File

@ -224,7 +224,6 @@ export class KclManager {
sceneInfra.modelingSend({ type: 'code edit during sketch' })
defaultSelectionFilter(programMemory, this.engineCommandManager)
await this.engineCommandManager.waitForAllCommands()
if (zoomToFit) {
let zoomObjectId: string | undefined = ''
@ -244,15 +243,6 @@ export class KclManager {
padding: 0.1, // padding around the objects
},
})
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'zoom_to_fit',
object_ids: zoomObjectId ? [zoomObjectId] : [], // leave empty to zoom to all objects
padding: 0.1, // padding around the objects
},
})
}
this.isExecuting = false

View File

@ -24,6 +24,13 @@ export const getRectangleCallExpressions = (
rectangleOrigin: [number, number],
tags: [string, string, string]
) => [
createCallExpressionStdLib('startProfileAt', [
createArrayExpression([
createLiteral(roundOff(rectangleOrigin[0])),
createLiteral(roundOff(rectangleOrigin[1])),
]),
createPipeSubstitution(),
]),
createCallExpressionStdLib('angledLine', [
createArrayExpression([
createLiteral(0), // 0 deg

View File

@ -290,10 +290,8 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
},
}),
icon: 'line',
status: 'available',
disabled: (state) =>
state.matches('Sketch no face') ||
state.matches('Sketch.Rectangle tool.Awaiting second corner'),
status: 'unavailable',
disabled: (state) => true,
title: 'Line',
hotkey: (state) =>
state.matches('Sketch.Line tool') ? ['Esc', 'L'] : 'L',

View File

@ -1082,9 +1082,7 @@ export const modelingMachine = createMachine(
},
})
if (!engineCommandManager.engineConnection?.idleMode) {
store.videoElement?.play().catch((e) => {
console.warn('Video playing was prevented', e)
})
store.videoElement?.play()
}
if (updatedAst?.selections) {
editorManager.selectRange(updatedAst?.selections)
@ -1240,20 +1238,7 @@ export const modelingMachine = createMachine(
},
'listen for rectangle origin': ({ sketchDetails }) => {
if (!sketchDetails) return
sceneEntitiesManager.setupNoPointsListener({
sketchDetails,
afterClick: (args) => {
const twoD = args.intersectionPoint?.twoD
if (twoD) {
sceneInfra.modelingSend({
type: 'Add rectangle origin',
data: [twoD.x, twoD.y],
})
} else {
console.error('No intersection point found')
}
},
})
sceneEntitiesManager.setupRectangleOriginListener()
},
'set up draft rectangle': ({ sketchDetails }, { data }) => {
if (!sketchDetails || !data) return
@ -1283,10 +1268,39 @@ export const modelingMachine = createMachine(
},
'setup noPoints onClick listener': ({ sketchDetails }) => {
if (!sketchDetails) return
sceneEntitiesManager.createIntersectionPlane()
const quaternion = quaternionFromUpNForward(
new Vector3(...sketchDetails.yAxis),
new Vector3(...sketchDetails.zAxis)
)
sceneEntitiesManager.intersectionPlane &&
sceneEntitiesManager.intersectionPlane.setRotationFromQuaternion(
quaternion
)
sceneEntitiesManager.intersectionPlane &&
sceneEntitiesManager.intersectionPlane.position.copy(
new Vector3(...(sketchDetails?.origin || [0, 0, 0]))
)
sceneInfra.setCallbacks({
onClick: async (args) => {
if (!args) return
if (args.mouseEvent.which !== 1) return
const { intersectionPoint } = args
if (!intersectionPoint?.twoD || !sketchDetails?.sketchPathToNode)
return
const addStartProfileAtRes = addStartProfileAt(
kclManager.ast,
sketchDetails.sketchPathToNode,
[intersectionPoint.twoD.x, intersectionPoint.twoD.y]
)
sceneEntitiesManager.setupNoPointsListener({
sketchDetails,
afterClick: () => sceneInfra.modelingSend('Add start point'),
if (trap(addStartProfileAtRes)) return
const { modifiedAst } = addStartProfileAtRes
await kclManager.updateAst(modifiedAst, false)
sceneEntitiesManager.removeIntersectionPlane()
sceneInfra.modelingSend('Add start point')
},
})
},
'add axis n grid': ({ sketchDetails }) => {

View File

@ -1,7 +1,9 @@
# Each test can have at most 4 threads, but if its name contains "serial_test_", then it
# also requires 4 threads.
# This means such tests run one at a time, with 4 threads.
[test-groups]
# If a test uses the engine, we want to limit the number that can run in parallel.
# This way we don't start and stop too many engine instances, putting pressure on our cloud.
uses-engine = { max-threads = 4 }
serial-integration = { max-threads = 4 }
[profile.default]
slow-timeout = { period = "30s", terminate-after = 1 }
@ -10,15 +12,13 @@ slow-timeout = { period = "30s", terminate-after = 1 }
slow-timeout = { period = "50s", terminate-after = 5 }
[[profile.default.overrides]]
# If a test starts with kcl_test_, then it uses the engine. So, limit its parallelism.
filter = "test(kcl_test_)"
test-group = "uses-engine"
filter = "test(serial_test_)"
test-group = "serial-integration"
threads-required = 2
[[profile.ci.overrides]]
# If a test starts with kcl_test_, then it uses the engine. So, limit its parallelism.
filter = "test(kcl_test_)"
test-group = "uses-engine"
filter = "test(serial_test_)"
test-group = "serial-integration"
threads-required = 2
[[profile.default.overrides]]

View File

@ -406,9 +406,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.13"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3"
dependencies = [
"clap_builder",
"clap_derive",
@ -416,9 +416,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.13"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa"
dependencies = [
"anstream",
"anstyle",
@ -430,9 +430,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.13"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@ -3128,9 +3128,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.19"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c"
dependencies = [
"serde",
"serde_spanned",
@ -3140,24 +3140,24 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.8"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.20"
version = "0.22.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16"
dependencies = [
"indexmap 2.2.5",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.18",
"winnow 0.6.5",
]
[[package]]
@ -3851,9 +3851,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.6.18"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
dependencies = [
"memchr",
]

View File

@ -11,13 +11,13 @@ crate-type = ["cdylib"]
[dependencies]
bson = { version = "2.11.0", features = ["uuid-1", "chrono"] }
clap = "4.5.13"
clap = "4.5.11"
gloo-utils = "0.2.0"
kcl-lib = { path = "kcl" }
kittycad.workspace = true
serde_json = "1.0.121"
tokio = { version = "1.39.2", features = ["sync"] }
toml = "0.8.19"
toml = "0.8.16"
uuid = { version = "1.10.0", features = ["v4", "js", "serde"] }
wasm-bindgen = "0.2.91"
wasm-bindgen-futures = "0.4.42"

View File

@ -766,10 +766,85 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn #test_name() {
let code = #code_block;
// Note, `crate` must be kcl_lib
let result = crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm).await.unwrap();
twenty_twenty::assert_image(&format!("tests/outputs/{}.png", #test_name_str), &result, 0.99);
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 tokens = crate::token::lexer(#code_block).unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default()).await.unwrap();
ctx.run(&program, None).await.unwrap();
// Ensure it lints.
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
// Zoom to fit.
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await.unwrap();
// Send a snapshot request to the engine.
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await.unwrap();
// 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()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
// Save the snapshot locally.
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
// Read the output file.
let actual = image::io::Reader::open(output_file).unwrap().decode().unwrap();
twenty_twenty::assert_image(&format!("tests/outputs/{}.png", #test_name_str), &actual, 0.99);
}
}
}

View File

@ -21,14 +21,76 @@ mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_someFn0() {
let code = "someFn()";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("someFn()").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_someFn0() {
let code = "someFn()";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("someFn()").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_someFn0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let code = "This is another code block.\nyes sirrr.\nshow";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nshow").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
&actual,
0.99,
);
}
@ -54,14 +116,76 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show1() {
let code = "This is code.\nIt does other shit.\nshow";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show1"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let code = "This is code.\nIt does other shit.\nshow";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
&actual,
0.99,
);
}

View File

@ -22,14 +22,77 @@ mod test_examples_my_func {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_my_func0() {
let code = "This is another code block.\nyes sirrr.\nmyFunc";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens =
crate::token::lexer("This is another code block.\nyes sirrr.\nmyFunc").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_my_func0"),
&result,
&actual,
0.99,
);
}
@ -55,14 +118,76 @@ mod test_examples_my_func {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_my_func1() {
let code = "This is code.\nIt does other shit.\nmyFunc";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nmyFunc").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_my_func1"),
&result,
&actual,
0.99,
);
}

View File

@ -22,14 +22,77 @@ mod test_examples_line_to {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_line_to0() {
let code = "This is another code block.\nyes sirrr.\nlineTo";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens =
crate::token::lexer("This is another code block.\nyes sirrr.\nlineTo").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_line_to0"),
&result,
&actual,
0.99,
);
}
@ -55,14 +118,76 @@ mod test_examples_line_to {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_line_to1() {
let code = "This is code.\nIt does other shit.\nlineTo";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nlineTo").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_line_to1"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_min {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_min0() {
let code = "This is another code block.\nyes sirrr.\nmin";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nmin").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_min0"),
&result,
&actual,
0.99,
);
}
@ -54,14 +116,76 @@ mod test_examples_min {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_min1() {
let code = "This is code.\nIt does other shit.\nmin";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nmin").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_min1"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let code = "This is code.\nIt does other shit.\nshow";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_import0() {
let code = "This is code.\nIt does other shit.\nimport";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_import0() {
let code = "This is code.\nIt does other shit.\nimport";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_import0() {
let code = "This is code.\nIt does other shit.\nimport";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_import0"),
&result,
&actual,
0.99,
);
}

View File

@ -21,14 +21,76 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let code = "This is code.\nIt does other shit.\nshow";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.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)
.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");
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
client.set_base_url(addr);
}
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let ctx = crate::executor::ExecutorContext::new(&client, Default::default())
.await
.unwrap();
ctx.run(&program, None).await.unwrap();
let results = program.lint_all().unwrap();
if !results.is_empty() {
panic!("Linting failed: {:?}", results);
}
ctx.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
},
)
.await
.unwrap();
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
)
.await
.unwrap();
let output_file =
std::env::temp_dir().join(format!("kcl_output_{}.png", uuid::Uuid::new_v4()));
if let kittycad::types::OkWebSocketResponseData::Modeling {
modeling_response: kittycad::types::OkModelingCmdResponse::TakeSnapshot { data },
} = &resp
{
std::fs::write(&output_file, &data.contents.0).unwrap();
} else {
panic!("Unexpected response from engine: {:?}", resp);
}
let actual = image::io::Reader::open(output_file)
.unwrap()
.decode()
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_show0"),
&result,
&actual,
0.99,
);
}

View File

@ -16,7 +16,7 @@ async-recursion = "1.1.1"
async-trait = "0.1.81"
base64 = "0.22.1"
chrono = "0.4.38"
clap = { version = "4.5.13", default-features = false, optional = true }
clap = { version = "4.5.11", default-features = false, optional = true }
convert_case = "0.6.0"
dashmap = "6.0.1"
databake = { version = "0.1.8", features = ["derive"] }
@ -25,7 +25,6 @@ form_urlencoded = "1.2.1"
futures = { version = "0.3.30" }
git_rev = "0.1.0"
gltf-json = "1.4.1"
image = { version = "0.25.1", default-features = false, features = ["png"] }
kittycad = { workspace = true, features = ["clap"] }
lazy_static = "1.5.0"
mime_guess = "2.0.5"
@ -39,7 +38,7 @@ serde_json = "1.0.121"
sha2 = "0.10.8"
tabled = { version = "0.15.0", optional = true }
thiserror = "1.0.63"
toml = "0.8.19"
toml = "0.8.16"
ts-rs = { version = "9.0.1", features = ["uuid-impl", "url-impl", "chrono-impl", "no-serde-warnings", "serde-json-impl"] }
url = { version = "2.5.2", features = ["serde"] }
uuid = { version = "1.10.0", features = ["v4", "js", "serde"] }

View File

@ -26,7 +26,6 @@ pub mod lsp;
pub mod parser;
pub mod settings;
pub mod std;
#[cfg(not(target_arch = "wasm32"))]
pub mod test_server;
pub mod thread;
pub mod token;

View File

@ -1,70 +1,8 @@
//! Types used to send data to the test server.
use crate::{
executor::{ExecutorContext, ExecutorSettings},
settings::types::UnitLength,
};
#[derive(serde::Deserialize, serde::Serialize)]
pub struct RequestBody {
pub kcl_program: String,
#[serde(default)]
pub test_name: String,
}
/// Executes a kcl program and takes a snapshot of the result.
/// This returns the bytes of the snapshot.
pub async fn execute_and_snapshot(code: &str, units: UnitLength) -> anyhow::Result<image::DynamicImage> {
let ctx = new_context(units).await?;
let tokens = crate::token::lexer(code)?;
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast()?;
let snapshot = ctx.execute_and_prepare_snapshot(&program).await?;
// 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()));
// Save the snapshot locally, to that temporary file.
std::fs::write(&output_file, snapshot.contents.0)?;
// Decode the snapshot, return it.
let img = image::io::Reader::open(output_file).unwrap().decode()?;
Ok(img)
}
async fn new_context(units: UnitLength) -> anyhow::Result<ExecutorContext> {
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,
show_grid: false,
},
)
.await?;
Ok(ctx)
}

View File

@ -1,9 +0,0 @@
const part001 = startSketchOn('XY')
|> startProfileAt([4.83, 12.56], %)
|> line([15.1, 2.48], %)
|> line([3.15, -9.85], %, $seg01)
|> line([-15.17, -4.1], %)
|> angledLine([segAng(seg01), 12.35], %)
|> line([-13.02, 10.03], %)
|> close(%)
|> extrude(4, %)

View File

@ -1,9 +0,0 @@
const center = [0,0]
const radius = 40
const height = 3
const body = startSketchOn('XY')
|> startProfileAt([center[0]+radius, center[1]], %)
|> arc({angle_end: 360, angle_start: 0, radius: radius}, %)
|> close(%)
|> extrude(height, %)

View File

@ -1,7 +0,0 @@
const part001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)
|> extrude(10, %)

View File

@ -1,4 +0,0 @@
const part001 = startSketchOn('XY')
|> circle([5, 5], 10, %)
|> extrude(10, %)
|> helix({revolutions: 16, angle_start: 0, ccw: true}, %)

View File

@ -1,4 +0,0 @@
const part001 = startSketchOn('XY')
|> circle([5, 5], 10, %)
|> extrude(10, %)
|> helix({revolutions: 16, angle_start: 0}, %)

View File

@ -1,4 +0,0 @@
const part001 = startSketchOn('XY')
|> circle([5, 5], 10, %)
|> extrude(-10, %)
|> helix({revolutions: 16, angle_start: 0}, %)

View File

@ -1,4 +0,0 @@
const part001 = startSketchOn('XY')
|> circle([5, 5], 10, %)
|> extrude(10, %)
|> helix({revolutions: 16, angle_start: 0, length: 3}, %)

View File

@ -1,17 +0,0 @@
fn cube = (pos, scale) => {
const sg = startSketchOn('XY')
|> startProfileAt(pos, %)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
|> close(%)
return sg
}
const b1 = cube([0,0], 10)
const b2 = cube([3,3], 4)
|> extrude(10, %)
const pt1 = b1.value[0]
const pt2 = b2.value[0]

View File

@ -1,19 +0,0 @@
const width = 5
const height = 10
const length = 12
fn box = (sk1, sk2, scale) => {
const boxSketch = startSketchOn('XY')
|> startProfileAt([sk1, sk2], %)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
|> close(%)
|> extrude(scale, %)
return boxSketch
}
box(0, 0, 5)
box(10, 23, 8)
let thing = box(-12, -15, 10)
box(-20, -5, 10)

View File

@ -1,18 +0,0 @@
const sigmaAllow = 35000 // psi
const width = 9 // inch
const p = 150 // Force on shelf - lbs
const distance = 6 // inches
const FOS = 2
const leg1 = 5 // inches
const leg2 = 8 // inches
const thickness = sqrt(distance * p * FOS * 6 / sigmaAllow / width) // inches
const bracket = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([0, leg1], %)
|> line([leg2, 0], %)
|> line([0, -thickness], %)
|> line([-leg2 + thickness, 0], %)
|> line([0, -leg1 + thickness], %)
|> close(%)
|> extrude(width, %)

View File

@ -1,26 +0,0 @@
const sigmaAllow = 15000 // psi
const width = 11 // inch
const p = 150 // Force on shelf - lbs
const distance = 12 // inches
const FOS = 2
const thickness = sqrt(distance * p * FOS * 6 / ( sigmaAllow * width ))
const filletR = thickness * 2
const shelfMountL = 9
const wallMountL = 8
const bracket = startSketchAt([0, 0])
|> line([0, wallMountL], %)
|> tangentialArc({
radius: filletR,
offset: 90
}, %)
|> line([-shelfMountL, 0], %)
|> line([0, -thickness], %)
|> line([shelfMountL, 0], %)
|> tangentialArc({
radius: filletR - thickness,
offset: -90
}, %)
|> line([0, -wallMountL], %)
|> close(%)
|> extrude(width, %)

File diff suppressed because it is too large Load Diff