openpencil/tests/engine/io/svg/export/paths.test.ts
2026-05-18 01:02:43 +03:00

135 lines
3.5 KiB
TypeScript

import { describe, expect, test } from 'bun:test'
import { geometryBlobToSVGPath, vectorNetworkToSVGPaths } from '@open-pencil/core'
// --- geometryBlobToSVGPath tests ---
describe('geometryBlobToSVGPath()', () => {
function makeBlobWithFloats(ops: Array<{ cmd: number; floats?: number[] }>): Uint8Array {
let size = 0
for (const op of ops) {
size += 1 + (op.floats?.length ?? 0) * 4
}
const buf = new ArrayBuffer(size)
const view = new DataView(buf)
let o = 0
for (const op of ops) {
view.setUint8(o, op.cmd)
o += 1
if (op.floats) {
for (const f of op.floats) {
view.setFloat32(o, f, true)
o += 4
}
}
}
return new Uint8Array(buf)
}
test('empty blob', () => {
expect(geometryBlobToSVGPath(new Uint8Array(0))).toBe('')
})
test('move + line + close', () => {
const blob = makeBlobWithFloats([
{ cmd: 1, floats: [10, 20] },
{ cmd: 2, floats: [30, 40] },
{ cmd: 0 }
])
expect(geometryBlobToSVGPath(blob)).toBe('M10 20L30 40Z')
})
test('quadratic bezier', () => {
const blob = makeBlobWithFloats([
{ cmd: 1, floats: [0, 0] },
{ cmd: 3, floats: [10, 0, 30, 30] },
{ cmd: 0 }
])
const result = geometryBlobToSVGPath(blob)
expect(result).toContain('M0 0')
expect(result).toContain('Q10 0 30 30')
expect(result).toContain('Z')
})
test('cubic bezier', () => {
const blob = makeBlobWithFloats([
{ cmd: 1, floats: [0, 0] },
{ cmd: 4, floats: [10, 0, 20, 10, 30, 30] },
{ cmd: 0 }
])
const result = geometryBlobToSVGPath(blob)
expect(result).toContain('M0 0')
expect(result).toContain('C10 0 20 10 30 30')
expect(result).toContain('Z')
})
})
// --- vectorNetworkToSVGPaths tests ---
describe('vectorNetworkToSVGPaths()', () => {
test('single straight segment', () => {
const paths = vectorNetworkToSVGPaths({
vertices: [
{ x: 0, y: 0 },
{ x: 100, y: 100 }
],
segments: [
{
start: 0,
end: 1,
tangentStart: { x: 0, y: 0 },
tangentEnd: { x: 0, y: 0 }
}
],
regions: []
})
expect(paths).toHaveLength(1)
expect(paths[0]).toContain('M0 0')
expect(paths[0]).toContain('L100 100')
})
test('curved segment', () => {
const paths = vectorNetworkToSVGPaths({
vertices: [
{ x: 0, y: 0 },
{ x: 100, y: 0 }
],
segments: [
{
start: 0,
end: 1,
tangentStart: { x: 0, y: 50 },
tangentEnd: { x: 0, y: 50 }
}
],
regions: []
})
expect(paths).toHaveLength(1)
expect(paths[0]).toContain('C')
})
test('region with loop', () => {
const paths = vectorNetworkToSVGPaths({
vertices: [
{ x: 0, y: 0 },
{ x: 100, y: 0 },
{ x: 50, y: 100 }
],
segments: [
{ start: 0, end: 1, tangentStart: { x: 0, y: 0 }, tangentEnd: { x: 0, y: 0 } },
{ start: 1, end: 2, tangentStart: { x: 0, y: 0 }, tangentEnd: { x: 0, y: 0 } },
{ start: 2, end: 0, tangentStart: { x: 0, y: 0 }, tangentEnd: { x: 0, y: 0 } }
],
regions: [{ windingRule: 'NONZERO', loops: [[0, 1, 2]] }]
})
expect(paths).toHaveLength(1)
expect(paths[0]).toContain('M0 0')
expect(paths[0]).toContain('Z')
})
test('empty network', () => {
const paths = vectorNetworkToSVGPaths({ vertices: [], segments: [], regions: [] })
expect(paths).toHaveLength(0)
})
})