108 lines
7.7 KiB
TypeScript
108 lines
7.7 KiB
TypeScript
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { unzipSync } from 'fflate'
|
|
import { createWebCadFacade } from '../src/facade/mockFacade'
|
|
import { decodeFcstdPropertyValue, serializeFcstdMetadataArchive } from '../src/facade/fcstd'
|
|
import type { ColorValue, DocumentSnapshot, FacadeEvent, ObjectPropertySnapshot } from '../src/facade/types'
|
|
|
|
const hosts: Array<[string, string, string, ColorValue]> = [
|
|
['FeatureTestColor', 'App::FeatureTest', 'Colour', [0, 0, 0, 1]],
|
|
['FeatureTestExceptionColor', 'App::FeatureTestException', 'Colour', [0, 0, 0, 1]],
|
|
['PartColor', 'App::Part', 'Color', [1, 1, 1, 0]],
|
|
['AssemblyLinkColor', 'Assembly::AssemblyLink', 'Color', [1, 1, 1, 0]],
|
|
['AssemblyObjectColor', 'Assembly::AssemblyObject', 'Color', [1, 1, 1, 0]],
|
|
['AnnotationColor', 'TechDraw::DrawViewAnnotation', 'TextColor', [0, 0, 0, 1]],
|
|
['DraftColor', 'TechDraw::DrawViewDraft', 'Color', [0, 0, 0, 1]],
|
|
['SpreadsheetColor', 'TechDraw::DrawViewSpreadsheet', 'TextColor', [0, 0, 0, 1]],
|
|
]
|
|
|
|
const colorProperty = (name: string, value: ColorValue): ObjectPropertySnapshot => ({ name, label: name, group: 'Color', scope: 'data', type: 'App::PropertyColor', value: [...value] as ColorValue, recompute: true })
|
|
|
|
const fixture = (): DocumentSnapshot => ({
|
|
id: 'property-color-facade',
|
|
label: 'PropertyColor Facade',
|
|
version: 1,
|
|
dirty: false,
|
|
readOnly: false,
|
|
units: 'mm',
|
|
tree: hosts.map(([id]) => ({ id, label: id, type: 'feature', state: 'valid' })),
|
|
objects: hosts.map(([id, typeId, propertyName, value], index) => ({
|
|
id,
|
|
typeId,
|
|
properties: [
|
|
colorProperty(propertyName, value),
|
|
...(index === 0 ? [{ name: 'LineColor', label: 'Line color', group: 'Appearance', scope: 'view' as const, type: 'App::PropertyColor' as const, value: '#123456' }] : []),
|
|
],
|
|
})),
|
|
dependencies: [],
|
|
recompute: { generation: 0, status: 'idle', objectStates: Object.fromEntries(hosts.map(([id]) => [id, 'up-to-date'])), dirtyObjects: [], order: [], errors: [] },
|
|
})
|
|
|
|
const valueOf = (facade: ReturnType<typeof createWebCadFacade>, objectId: string, propertyName: string) => facade.app.document.getObject(objectId)?.properties.find((property) => property.name === propertyName)?.value
|
|
|
|
test('App::PropertyColor data values use four RGBA channels while view values retain #RRGGBB', () => {
|
|
const facade = createWebCadFacade({ initialDocument: fixture(), initialSelectedObjectIds: ['FeatureTestColor'], runtimeMode: 'mock' })
|
|
const events: FacadeEvent[] = []
|
|
facade.subscribe((event) => {
|
|
if (event.type === 'property.before-change' || event.type === 'property.changed' || event.type === 'transaction.committed') events.push(event)
|
|
})
|
|
const target: ColorValue = [17 / 255, 34 / 255, 51 / 255, 68 / 255]
|
|
facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: target })
|
|
target[0] = 1
|
|
assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [17 / 255, 34 / 255, 51 / 255, 68 / 255])
|
|
const exposed = valueOf(facade, 'FeatureTestColor', 'Colour') as number[]
|
|
exposed[1] = 1
|
|
assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [17 / 255, 34 / 255, 51 / 255, 68 / 255])
|
|
assert.equal(facade.app.document.getActive().version, 2)
|
|
assert.equal(facade.app.document.getActive().recompute?.objectStates.FeatureTestColor, 'touched')
|
|
assert.deepEqual(events.map((event) => event.type), ['property.before-change', 'property.changed', 'transaction.committed'])
|
|
|
|
facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [2, -1, 0.5, 1.5] })
|
|
assert.deepEqual(valueOf(facade, 'FeatureTestColor', 'Colour'), [2, -1, 0.5, 1.5])
|
|
facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'LineColor', value: '#abcdef' })
|
|
assert.equal(valueOf(facade, 'FeatureTestColor', 'LineColor'), '#abcdef')
|
|
|
|
const stable = JSON.stringify(facade.app.document.getActive())
|
|
assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: '#112233' }), /four finite RGBA channels/)
|
|
assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0] }), /four finite RGBA channels/)
|
|
assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0, Number.NaN] }), /four finite RGBA channels/)
|
|
assert.throws(() => facade.app.document.setProperty({ objectId: 'FeatureTestColor', propertyName: 'LineColor', value: [0, 0, 0, 1] }), /#RRGGBB color/)
|
|
assert.equal(JSON.stringify(facade.app.document.getActive()), stable)
|
|
})
|
|
|
|
test('App::PropertyColor serializes all eight native hosts with packed RRGGBBAA values', () => {
|
|
const document = fixture()
|
|
;(document.objects[0].properties[0].value as ColorValue) = [17 / 255, 34 / 255, 51 / 255, 68 / 255]
|
|
const archive = serializeFcstdMetadataArchive(document)
|
|
const documentXml = new TextDecoder().decode(unzipSync(archive)['Document.xml'])
|
|
const guiXml = new TextDecoder().decode(unzipSync(archive)['GuiDocument.xml'])
|
|
assert.equal((documentXml.match(/type="App::PropertyColor"/g) ?? []).length, 8)
|
|
assert.match(documentXml, /<Property name="Colour" type="App::PropertyColor"><PropertyColor value="287454020"\/><\/Property>/)
|
|
assert.match(documentXml, /<Property name="Color" type="App::PropertyColor"><PropertyColor value="4294967040"\/><\/Property>/)
|
|
assert.match(documentXml, /<Property name="TextColor" type="App::PropertyColor"><PropertyColor value="255"\/><\/Property>/)
|
|
assert.doesNotMatch(documentXml, /<Property name="(?:Colour|Color|TextColor)"[^>]+(?:group|doc|attr|ro|hide)=/)
|
|
assert.match(guiXml, /<Property name="LineColor" type="App::PropertyColor" status="1"><PropertyColor value="305420031"\/><\/Property>/)
|
|
|
|
const inspection = createWebCadFacade({ initialDocument: document, runtimeMode: 'mock' }).project.fcstd.inspect(archive)
|
|
assert.equal(inspection.objects.length, 8)
|
|
assert.ok(inspection.objects.every((object) => object.support === 'recognized'))
|
|
const summary = inspection.objects[0].properties.find((property) => property.name === 'Colour')
|
|
assert.deepEqual({ typeId: summary?.typeId, element: summary?.element, value: summary?.value }, { typeId: 'App::PropertyColor', element: 'PropertyColor', value: '287454020' })
|
|
assert.deepEqual(decodeFcstdPropertyValue(summary!), { value: [17 / 255, 34 / 255, 51 / 255, 68 / 255], decoded: true })
|
|
assert.equal(decodeFcstdPropertyValue({ name: 'Colour', typeId: 'App::PropertyColor', element: 'PropertyColor', value: '4294967296' }).decoded, false)
|
|
assert.equal(decodeFcstdPropertyValue({ name: 'Colour', typeId: 'App::PropertyColor', element: 'String', value: '287454020' }).decoded, false)
|
|
|
|
const target: ColorValue = [51 / 255, 102 / 255, 153 / 255, 204 / 255]
|
|
const rewritten = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, {
|
|
objectName: 'FeatureTestColor',
|
|
propertyName: 'Colour',
|
|
value: target,
|
|
expectedValue: [17 / 255, 34 / 255, 51 / 255, 68 / 255],
|
|
})
|
|
const rewrittenProperty = createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.inspect(rewritten).objects[0].properties.find((property) => property.name === 'Colour')
|
|
assert.equal(rewrittenProperty?.value, '862362060')
|
|
assert.deepEqual(decodeFcstdPropertyValue(rewrittenProperty!), { value: target, decoded: true })
|
|
assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, { objectName: 'FeatureTestColor', propertyName: 'Colour', value: target, expectedValue: [0, 0, 0, 1] }), /does not match expectedValue/)
|
|
assert.throws(() => createWebCadFacade({ runtimeMode: 'mock' }).project.fcstd.rewriteColor(archive, { objectName: 'FeatureTestColor', propertyName: 'Colour', value: [0, 0, 0, Number.NaN] }), /four finite RGBA channels/)
|
|
})
|