2024-07-15 19:20:32 +10:00
|
|
|
import {
|
|
|
|
parse,
|
|
|
|
recast,
|
|
|
|
initPromise,
|
|
|
|
PathToNode,
|
|
|
|
Program,
|
|
|
|
CallExpression,
|
2024-08-26 08:07:20 +02:00
|
|
|
makeDefaultPlanes,
|
|
|
|
PipeExpression,
|
2024-10-02 14:19:40 -05:00
|
|
|
VariableDeclarator,
|
2024-07-15 19:20:32 +10:00
|
|
|
} from '../wasm'
|
2024-07-18 08:33:49 +02:00
|
|
|
import {
|
2024-08-26 08:07:20 +02:00
|
|
|
getPathToExtrudeForSegmentSelection,
|
2024-07-18 08:33:49 +02:00
|
|
|
hasValidFilletSelection,
|
|
|
|
isTagUsedInFillet,
|
2024-11-21 15:04:30 +11:00
|
|
|
modifyAstWithFilletAndTag,
|
2024-07-18 08:33:49 +02:00
|
|
|
} from './addFillet'
|
2024-07-15 19:20:32 +10:00
|
|
|
import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst'
|
|
|
|
import { createLiteral } from 'lang/modifyAst'
|
|
|
|
import { err } from 'lib/trap'
|
2024-07-18 08:33:49 +02:00
|
|
|
import { Selections } from 'lib/selections'
|
2024-08-26 08:07:20 +02:00
|
|
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
|
|
|
import { VITE_KC_DEV_TOKEN } from 'env'
|
2024-09-12 21:45:26 +02:00
|
|
|
import { KclCommandValue } from 'lib/commandTypes'
|
2024-11-21 15:04:30 +11:00
|
|
|
import { isOverlap } from 'lib/utils'
|
|
|
|
import { codeRefFromRange } from 'lang/std/artifactGraph'
|
2024-07-15 19:20:32 +10:00
|
|
|
|
|
|
|
beforeAll(async () => {
|
2024-08-26 08:07:20 +02:00
|
|
|
await initPromise
|
|
|
|
|
|
|
|
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
|
|
await new Promise((resolve) => {
|
|
|
|
engineCommandManager.start({
|
|
|
|
token: VITE_KC_DEV_TOKEN,
|
|
|
|
width: 256,
|
|
|
|
height: 256,
|
|
|
|
makeDefaultPlanes: () => makeDefaultPlanes(engineCommandManager),
|
|
|
|
setMediaStream: () => {},
|
|
|
|
setIsStreamReady: () => {},
|
|
|
|
modifyGrid: async () => {},
|
2024-09-09 18:17:45 -04:00
|
|
|
callbackOnEngineLiteConnect: () => {
|
2024-08-26 08:07:20 +02:00
|
|
|
resolve(true)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
2024-10-18 04:31:00 -04:00
|
|
|
}, 30_000)
|
2024-08-26 08:07:20 +02:00
|
|
|
|
|
|
|
afterAll(() => {
|
|
|
|
engineCommandManager.tearDown()
|
|
|
|
})
|
|
|
|
|
|
|
|
const runGetPathToExtrudeForSegmentSelectionTest = async (
|
|
|
|
code: string,
|
|
|
|
selectedSegmentSnippet: string,
|
|
|
|
expectedExtrudeSnippet: string
|
|
|
|
) => {
|
|
|
|
// helpers
|
|
|
|
function getExtrudeExpression(
|
|
|
|
ast: Program,
|
|
|
|
pathToExtrudeNode: PathToNode
|
|
|
|
): CallExpression | PipeExpression | undefined | Error {
|
|
|
|
if (pathToExtrudeNode.length === 0) return undefined // no extrude node
|
|
|
|
|
2024-09-12 21:45:26 +02:00
|
|
|
const extrudeNodeResult = getNodeFromPath<CallExpression>(
|
|
|
|
ast,
|
|
|
|
pathToExtrudeNode
|
|
|
|
)
|
2024-08-26 08:07:20 +02:00
|
|
|
if (err(extrudeNodeResult)) {
|
|
|
|
return extrudeNodeResult
|
|
|
|
}
|
2024-09-12 21:45:26 +02:00
|
|
|
return extrudeNodeResult.node
|
2024-08-26 08:07:20 +02:00
|
|
|
}
|
|
|
|
function getExpectedExtrudeExpression(
|
|
|
|
ast: Program,
|
|
|
|
code: string,
|
|
|
|
expectedExtrudeSnippet: string
|
|
|
|
): CallExpression | PipeExpression | Error {
|
|
|
|
const extrudeRange: [number, number] = [
|
|
|
|
code.indexOf(expectedExtrudeSnippet),
|
|
|
|
code.indexOf(expectedExtrudeSnippet) + expectedExtrudeSnippet.length,
|
|
|
|
]
|
2024-11-19 21:30:26 +01:00
|
|
|
const expectedExtrudePath = getNodePathFromSourceRange(ast, extrudeRange)
|
|
|
|
const expectedExtrudeNodeResult = getNodeFromPath<
|
|
|
|
VariableDeclarator | CallExpression
|
|
|
|
>(ast, expectedExtrudePath)
|
|
|
|
if (err(expectedExtrudeNodeResult)) {
|
|
|
|
return expectedExtrudeNodeResult
|
|
|
|
}
|
|
|
|
const expectedExtrudeNode = expectedExtrudeNodeResult.node
|
|
|
|
|
|
|
|
// check whether extrude is in the sketch pipe
|
|
|
|
const extrudeInSketchPipe = expectedExtrudeNode.type === 'CallExpression'
|
|
|
|
if (extrudeInSketchPipe) {
|
|
|
|
return expectedExtrudeNode
|
2024-08-26 08:07:20 +02:00
|
|
|
}
|
2024-11-19 21:30:26 +01:00
|
|
|
if (!extrudeInSketchPipe) {
|
|
|
|
const init = expectedExtrudeNode.init
|
|
|
|
if (init.type !== 'CallExpression' && init.type !== 'PipeExpression') {
|
|
|
|
return new Error(
|
|
|
|
'Expected extrude expression is not a CallExpression or PipeExpression'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return init
|
2024-09-12 21:45:26 +02:00
|
|
|
}
|
2024-11-19 21:30:26 +01:00
|
|
|
return new Error('Expected extrude expression not found')
|
2024-08-26 08:07:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ast
|
|
|
|
const astOrError = parse(code)
|
|
|
|
if (err(astOrError)) return new Error('AST not found')
|
2024-09-12 21:45:26 +02:00
|
|
|
const ast = astOrError
|
2024-08-26 08:07:20 +02:00
|
|
|
|
|
|
|
// selection
|
|
|
|
const segmentRange: [number, number] = [
|
|
|
|
code.indexOf(selectedSegmentSnippet),
|
|
|
|
code.indexOf(selectedSegmentSnippet) + selectedSegmentSnippet.length,
|
|
|
|
]
|
|
|
|
const selection: Selections = {
|
2024-11-21 15:04:30 +11:00
|
|
|
graphSelections: [
|
2024-08-26 08:07:20 +02:00
|
|
|
{
|
2024-11-21 15:04:30 +11:00
|
|
|
codeRef: codeRefFromRange(segmentRange, ast),
|
2024-08-26 08:07:20 +02:00
|
|
|
},
|
|
|
|
],
|
|
|
|
otherSelections: [],
|
|
|
|
}
|
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
// executeAst and artifactGraph
|
2024-08-26 08:07:20 +02:00
|
|
|
await kclManager.executeAst({ ast })
|
|
|
|
const artifactGraph = engineCommandManager.artifactGraph
|
|
|
|
|
|
|
|
// get extrude expression
|
|
|
|
const pathResult = getPathToExtrudeForSegmentSelection(
|
|
|
|
ast,
|
|
|
|
selection,
|
|
|
|
artifactGraph
|
|
|
|
)
|
|
|
|
if (err(pathResult)) return pathResult
|
|
|
|
const { pathToExtrudeNode } = pathResult
|
|
|
|
const extrudeExpression = getExtrudeExpression(ast, pathToExtrudeNode)
|
|
|
|
|
|
|
|
// test
|
|
|
|
if (expectedExtrudeSnippet) {
|
|
|
|
const expectedExtrudeExpression = getExpectedExtrudeExpression(
|
|
|
|
ast,
|
|
|
|
code,
|
|
|
|
expectedExtrudeSnippet
|
|
|
|
)
|
|
|
|
if (err(expectedExtrudeExpression)) return expectedExtrudeExpression
|
|
|
|
expect(extrudeExpression).toEqual(expectedExtrudeExpression)
|
|
|
|
} else {
|
|
|
|
expect(extrudeExpression).toBeUndefined()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
describe('Testing getPathToExtrudeForSegmentSelection', () => {
|
|
|
|
it('should return the correct paths for a valid selection and extrusion', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)`
|
2024-08-26 08:07:20 +02:00
|
|
|
const selectedSegmentSnippet = `line([20, 0], %)`
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedExtrudeSnippet = `extrude001 = extrude(-15, sketch001)`
|
2024-08-26 08:07:20 +02:00
|
|
|
await runGetPathToExtrudeForSegmentSelectionTest(
|
|
|
|
code,
|
|
|
|
selectedSegmentSnippet,
|
|
|
|
expectedExtrudeSnippet
|
|
|
|
)
|
2024-08-28 06:38:14 -04:00
|
|
|
}, 5_000)
|
2024-11-19 21:30:26 +01:00
|
|
|
it('should return the correct paths when extrusion occurs within the sketch pipe', async () => {
|
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
|> extrude(15, %)`
|
|
|
|
const selectedSegmentSnippet = `line([20, 0], %)`
|
|
|
|
const expectedExtrudeSnippet = `extrude(15, %)`
|
|
|
|
await runGetPathToExtrudeForSegmentSelectionTest(
|
|
|
|
code,
|
|
|
|
selectedSegmentSnippet,
|
|
|
|
expectedExtrudeSnippet
|
|
|
|
)
|
|
|
|
}, 5_000)
|
2024-08-26 08:07:20 +02:00
|
|
|
it('should return the correct paths for a valid selection and extrusion in case of several extrusions and sketches', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([-30, 30], %)
|
|
|
|
|> line([15, 0], %)
|
|
|
|
|> line([0, -15], %)
|
|
|
|
|> line([-15, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch002 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([30, 30], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch003 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([30, -30], %)
|
|
|
|
|> line([25, 0], %)
|
|
|
|
|> line([0, -25], %)
|
|
|
|
|> line([-25, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
|
|
|
extrude002 = extrude(-15, sketch002)
|
|
|
|
extrude003 = extrude(-15, sketch003)`
|
2024-08-26 08:07:20 +02:00
|
|
|
const selectedSegmentSnippet = `line([20, 0], %)`
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedExtrudeSnippet = `extrude002 = extrude(-15, sketch002)`
|
2024-08-26 08:07:20 +02:00
|
|
|
await runGetPathToExtrudeForSegmentSelectionTest(
|
|
|
|
code,
|
|
|
|
selectedSegmentSnippet,
|
|
|
|
expectedExtrudeSnippet
|
|
|
|
)
|
|
|
|
})
|
|
|
|
it('should not return any path for missing extrusion', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([-30, 30], %)
|
|
|
|
|> line([15, 0], %)
|
|
|
|
|> line([0, -15], %)
|
|
|
|
|> line([-15, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch002 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([30, 30], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch003 = startSketchOn('XY')
|
2024-08-26 08:07:20 +02:00
|
|
|
|> startProfileAt([30, -30], %)
|
|
|
|
|> line([25, 0], %)
|
|
|
|
|> line([0, -25], %)
|
|
|
|
|> line([-25, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
|
|
|
extrude003 = extrude(-15, sketch003)`
|
2024-08-26 08:07:20 +02:00
|
|
|
const selectedSegmentSnippet = `line([20, 0], %)`
|
|
|
|
const expectedExtrudeSnippet = ``
|
|
|
|
await runGetPathToExtrudeForSegmentSelectionTest(
|
|
|
|
code,
|
|
|
|
selectedSegmentSnippet,
|
|
|
|
expectedExtrudeSnippet
|
|
|
|
)
|
|
|
|
})
|
2024-07-15 19:20:32 +10:00
|
|
|
})
|
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
const runModifyAstCloneWithFilletAndTag = async (
|
2024-09-12 21:45:26 +02:00
|
|
|
code: string,
|
|
|
|
selectionSnippets: Array<string>,
|
|
|
|
radiusValue: number,
|
|
|
|
expectedCode: string
|
|
|
|
) => {
|
|
|
|
// ast
|
|
|
|
const astOrError = parse(code)
|
|
|
|
if (err(astOrError)) {
|
|
|
|
return new Error('AST not found')
|
|
|
|
}
|
|
|
|
const ast = astOrError
|
|
|
|
|
|
|
|
// selection
|
|
|
|
const segmentRanges: Array<[number, number]> = selectionSnippets.map(
|
|
|
|
(selectionSnippet) => [
|
|
|
|
code.indexOf(selectionSnippet),
|
|
|
|
code.indexOf(selectionSnippet) + selectionSnippet.length,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
// radius
|
|
|
|
const radius: KclCommandValue = {
|
|
|
|
valueAst: createLiteral(radiusValue),
|
|
|
|
valueText: radiusValue.toString(),
|
|
|
|
valueCalculated: radiusValue.toString(),
|
|
|
|
}
|
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
// executeAst
|
2024-09-12 21:45:26 +02:00
|
|
|
await kclManager.executeAst({ ast })
|
2024-11-21 15:04:30 +11:00
|
|
|
const artifactGraph = engineCommandManager.artifactGraph
|
|
|
|
|
|
|
|
const selection: Selections = {
|
|
|
|
graphSelections: segmentRanges.map((segmentRange) => {
|
|
|
|
const maybeArtifact = [...artifactGraph].find(([, a]) => {
|
|
|
|
if (!('codeRef' in a)) return false
|
|
|
|
return isOverlap(a.codeRef.range, segmentRange)
|
|
|
|
})
|
|
|
|
return {
|
|
|
|
codeRef: codeRefFromRange(segmentRange, ast),
|
|
|
|
artifact: maybeArtifact ? maybeArtifact[1] : undefined,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
otherSelections: [],
|
|
|
|
}
|
2024-09-12 21:45:26 +02:00
|
|
|
|
|
|
|
// apply fillet to selection
|
2024-11-21 15:04:30 +11:00
|
|
|
const result = modifyAstWithFilletAndTag(ast, selection, radius)
|
2024-09-12 21:45:26 +02:00
|
|
|
if (err(result)) {
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
const { modifiedAst } = result
|
|
|
|
|
|
|
|
const newCode = recast(modifiedAst)
|
|
|
|
|
|
|
|
expect(newCode).toContain(expectedCode)
|
|
|
|
}
|
|
|
|
describe('Testing applyFilletToSelection', () => {
|
2024-10-03 11:14:02 +02:00
|
|
|
it('should add a fillet to a specific segment', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)`
|
2024-09-12 21:45:26 +02:00
|
|
|
const segmentSnippets = ['line([0, -20], %)']
|
|
|
|
const radiusValue = 3
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %, $seg01)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
2024-11-19 21:30:26 +01:00
|
|
|
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
|
|
|
|
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
|
|
|
it('should add a fillet to the sketch pipe', async () => {
|
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
|> extrude(-15, %)`
|
|
|
|
const segmentSnippets = ['line([0, -20], %)']
|
|
|
|
const radiusValue = 3
|
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %, $seg01)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
|> extrude(-15, %)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
2024-09-12 21:45:26 +02:00
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
2024-10-03 11:14:02 +02:00
|
|
|
it('should add a fillet to an already tagged segment', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([0, -20], %, $seg01)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
extrude001 = extrude(-15, sketch001)`
|
|
|
|
const segmentSnippets = ['line([0, -20], %, $seg01)']
|
|
|
|
const radiusValue = 3
|
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %, $seg01)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
extrude001 = extrude(-15, sketch001)
|
|
|
|
|> fillet({ radius: 3, tags: [seg01] }, %)`
|
|
|
|
|
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
|
|
|
it('should add a fillet with existing tag on other segment', async () => {
|
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %, $seg01)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)`
|
2024-10-03 11:14:02 +02:00
|
|
|
const segmentSnippets = ['line([-20, 0], %)']
|
2024-09-12 21:45:26 +02:00
|
|
|
const radiusValue = 3
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %, $seg01)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %, $seg02)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> fillet({ radius: 3, tags: [seg02] }, %)`
|
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
2024-09-12 21:45:26 +02:00
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
2024-10-03 11:14:02 +02:00
|
|
|
it('should add a fillet with existing fillet on other segment', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([20, 0], %, $seg01)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
extrude001 = extrude(-15, sketch001)
|
|
|
|
|> fillet({ radius: 5, tags: [seg01] }, %)`
|
|
|
|
const segmentSnippets = ['line([-20, 0], %)']
|
|
|
|
const radiusValue = 3
|
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %, $seg01)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> line([0, -20], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([-20, 0], %, $seg02)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> fillet({ radius: 5, tags: [seg01] }, %)
|
|
|
|
|> fillet({ radius: 3, tags: [seg02] }, %)`
|
|
|
|
|
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
|
|
|
it('should add a fillet to two segments of a single extrusion', async () => {
|
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
extrude001 = extrude(-15, sketch001)`
|
|
|
|
const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)']
|
2024-09-12 21:45:26 +02:00
|
|
|
const radiusValue = 3
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([20, 0], %, $seg01)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> line([0, -20], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([-20, 0], %, $seg02)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> fillet({ radius: 3, tags: [seg01, seg02] }, %)`
|
2024-09-12 21:45:26 +02:00
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
2024-09-12 21:45:26 +02:00
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
2024-10-03 11:14:02 +02:00
|
|
|
it('should add fillets to two bodies', async () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
|
|
|
|> line([20, 0], %)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
|
|
|
sketch002 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([30, 10], %)
|
|
|
|
|> line([15, 0], %)
|
|
|
|
|> line([0, -15], %)
|
|
|
|
|> line([-15, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude002 = extrude(-25, sketch002)` // <--- body 2
|
2024-10-03 11:14:02 +02:00
|
|
|
const segmentSnippets = [
|
|
|
|
'line([20, 0], %)',
|
|
|
|
'line([-20, 0], %)',
|
|
|
|
'line([0, -15], %)',
|
|
|
|
]
|
2024-09-12 21:45:26 +02:00
|
|
|
const radiusValue = 3
|
2024-10-02 14:19:40 -05:00
|
|
|
const expectedCode = `sketch001 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([-10, 10], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([20, 0], %, $seg01)
|
|
|
|
|> line([0, -20], %)
|
|
|
|
|> line([-20, 0], %, $seg02)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-15, sketch001)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> fillet({ radius: 3, tags: [seg01, seg02] }, %)
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch002 = startSketchOn('XY')
|
2024-09-12 21:45:26 +02:00
|
|
|
|> startProfileAt([30, 10], %)
|
|
|
|
|> line([15, 0], %)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> line([0, -15], %, $seg03)
|
2024-09-12 21:45:26 +02:00
|
|
|
|> line([-15, 0], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude002 = extrude(-25, sketch002)
|
2024-10-03 11:14:02 +02:00
|
|
|
|> fillet({ radius: 3, tags: [seg03] }, %)` // <-- able to add a new one
|
2024-09-12 21:45:26 +02:00
|
|
|
|
2024-10-03 11:14:02 +02:00
|
|
|
await runModifyAstCloneWithFilletAndTag(
|
2024-09-12 21:45:26 +02:00
|
|
|
code,
|
|
|
|
segmentSnippets,
|
|
|
|
radiusValue,
|
|
|
|
expectedCode
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2024-07-15 19:20:32 +10:00
|
|
|
describe('Testing isTagUsedInFillet', () => {
|
2024-10-02 14:19:40 -05:00
|
|
|
const code = `sketch001 = startSketchOn('XZ')
|
2024-07-15 19:20:32 +10:00
|
|
|
|> startProfileAt([7.72, 4.13], %)
|
|
|
|
|> line([7.11, 3.48], %, $seg01)
|
|
|
|
|> line([-3.29, -13.85], %)
|
|
|
|
|> line([-6.37, 3.88], %, $seg02)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-5, sketch001)
|
2024-07-15 19:20:32 +10:00
|
|
|
|> fillet({
|
|
|
|
radius: 1.11,
|
|
|
|
tags: [
|
2024-07-27 22:56:46 -07:00
|
|
|
getOppositeEdge(seg01),
|
2024-07-15 19:20:32 +10:00
|
|
|
seg01,
|
2024-07-27 22:56:46 -07:00
|
|
|
getPreviousAdjacentEdge(seg02)
|
2024-07-15 19:20:32 +10:00
|
|
|
]
|
|
|
|
}, %)
|
|
|
|
`
|
|
|
|
it('should correctly identify getOppositeEdge and baseEdge edges', () => {
|
|
|
|
const ast = parse(code)
|
|
|
|
if (err(ast)) return
|
|
|
|
const lineOfInterest = `line([7.11, 3.48], %, $seg01)`
|
|
|
|
const range: [number, number] = [
|
|
|
|
code.indexOf(lineOfInterest),
|
|
|
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
|
|
|
]
|
|
|
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
|
|
|
if (err(pathToNode)) return
|
|
|
|
const callExp = getNodeFromPath<CallExpression>(
|
|
|
|
ast,
|
|
|
|
pathToNode,
|
|
|
|
'CallExpression'
|
|
|
|
)
|
|
|
|
if (err(callExp)) return
|
|
|
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
|
|
|
expect(edges).toEqual(['getOppositeEdge', 'baseEdge'])
|
|
|
|
})
|
|
|
|
it('should correctly identify getPreviousAdjacentEdge edges', () => {
|
|
|
|
const ast = parse(code)
|
|
|
|
if (err(ast)) return
|
|
|
|
const lineOfInterest = `line([-6.37, 3.88], %, $seg02)`
|
|
|
|
const range: [number, number] = [
|
|
|
|
code.indexOf(lineOfInterest),
|
|
|
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
|
|
|
]
|
|
|
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
|
|
|
if (err(pathToNode)) return
|
|
|
|
const callExp = getNodeFromPath<CallExpression>(
|
|
|
|
ast,
|
|
|
|
pathToNode,
|
|
|
|
'CallExpression'
|
|
|
|
)
|
|
|
|
if (err(callExp)) return
|
|
|
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
|
|
|
expect(edges).toEqual(['getPreviousAdjacentEdge'])
|
|
|
|
})
|
|
|
|
it('should correctly identify no edges', () => {
|
|
|
|
const ast = parse(code)
|
|
|
|
if (err(ast)) return
|
|
|
|
const lineOfInterest = `line([-3.29, -13.85], %)`
|
|
|
|
const range: [number, number] = [
|
|
|
|
code.indexOf(lineOfInterest),
|
|
|
|
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
|
|
|
]
|
|
|
|
const pathToNode = getNodePathFromSourceRange(ast, range)
|
|
|
|
if (err(pathToNode)) return
|
|
|
|
const callExp = getNodeFromPath<CallExpression>(
|
|
|
|
ast,
|
|
|
|
pathToNode,
|
|
|
|
'CallExpression'
|
|
|
|
)
|
|
|
|
if (err(callExp)) return
|
|
|
|
const edges = isTagUsedInFillet({ ast, callExp: callExp.node })
|
|
|
|
expect(edges).toEqual([])
|
|
|
|
})
|
|
|
|
})
|
2024-07-18 08:33:49 +02:00
|
|
|
|
|
|
|
describe('Testing button states', () => {
|
|
|
|
const runButtonStateTest = async (
|
|
|
|
code: string,
|
|
|
|
segmentSnippet: string,
|
|
|
|
expectedState: boolean
|
|
|
|
) => {
|
|
|
|
// ast
|
|
|
|
const astOrError = parse(code)
|
|
|
|
if (err(astOrError)) {
|
|
|
|
return new Error('AST not found')
|
|
|
|
}
|
2024-09-12 21:45:26 +02:00
|
|
|
const ast = astOrError
|
2024-07-18 08:33:49 +02:00
|
|
|
|
|
|
|
const range: [number, number] = segmentSnippet
|
|
|
|
? [
|
|
|
|
code.indexOf(segmentSnippet),
|
|
|
|
code.indexOf(segmentSnippet) + segmentSnippet.length,
|
|
|
|
]
|
|
|
|
: [ast.end, ast.end] // empty line in the end of the code
|
|
|
|
|
|
|
|
const selectionRanges: Selections = {
|
2024-11-21 15:04:30 +11:00
|
|
|
graphSelections: [
|
2024-07-18 08:33:49 +02:00
|
|
|
{
|
2024-11-21 15:04:30 +11:00
|
|
|
codeRef: codeRefFromRange(range, ast),
|
2024-07-18 08:33:49 +02:00
|
|
|
},
|
|
|
|
],
|
|
|
|
otherSelections: [],
|
|
|
|
}
|
|
|
|
|
|
|
|
// state
|
|
|
|
const buttonState = hasValidFilletSelection({
|
|
|
|
ast,
|
|
|
|
selectionRanges,
|
|
|
|
code,
|
|
|
|
})
|
|
|
|
|
|
|
|
expect(buttonState).toEqual(expectedState)
|
|
|
|
}
|
|
|
|
const codeWithBody: string = `
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch001 = startSketchOn('XY')
|
2024-07-18 08:33:49 +02:00
|
|
|
|> startProfileAt([-20, -5], %)
|
|
|
|
|> line([0, 10], %)
|
|
|
|
|> line([10, 0], %)
|
|
|
|
|> line([0, -10], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
2024-10-02 14:19:40 -05:00
|
|
|
extrude001 = extrude(-10, sketch001)
|
2024-07-18 08:33:49 +02:00
|
|
|
`
|
|
|
|
const codeWithoutBodies: string = `
|
2024-10-02 14:19:40 -05:00
|
|
|
sketch001 = startSketchOn('XY')
|
2024-07-18 08:33:49 +02:00
|
|
|
|> startProfileAt([-20, -5], %)
|
|
|
|
|> line([0, 10], %)
|
|
|
|
|> line([10, 0], %)
|
|
|
|
|> line([0, -10], %)
|
|
|
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
|
|
|> close(%)
|
|
|
|
`
|
|
|
|
// body is missing
|
|
|
|
it('should return false when body is missing and nothing is selected', async () => {
|
|
|
|
await runButtonStateTest(codeWithoutBodies, '', false)
|
|
|
|
})
|
|
|
|
it('should return false when body is missing and segment is selected', async () => {
|
|
|
|
await runButtonStateTest(codeWithoutBodies, `line([10, 0], %)`, false)
|
|
|
|
})
|
|
|
|
|
|
|
|
// body exists
|
|
|
|
it('should return true when body exists and nothing is selected', async () => {
|
|
|
|
await runButtonStateTest(codeWithBody, '', true)
|
|
|
|
})
|
|
|
|
it('should return true when body exists and segment is selected', async () => {
|
|
|
|
await runButtonStateTest(codeWithBody, `line([10, 0], %)`, true)
|
|
|
|
})
|
2024-10-11 23:25:51 +02:00
|
|
|
it('should return false when body exists and not a segment is selected', async () => {
|
2024-07-18 08:33:49 +02:00
|
|
|
await runButtonStateTest(codeWithBody, `close(%)`, false)
|
|
|
|
})
|
|
|
|
})
|