shibosoftwaredev/f1c100s-linux-nema17-stepper-controller
A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.
- Version
- 0.4.56
- License
- unset
- Stars
- 0
tests/assembly-stencil.test.ts
import { test, expect } from "bun:test"
import { pcb_solder_paste } from "circuit-json"
import { applyMissingRoundedPaste, roundedPadPaste } from "../assembly-stencil"
import { applyAssemblyPasteMetadata } from "../assembly-metadata"
import fixtureJson from "./fixtures/rounded-pad-baseline.json"
const baseline: any[] = fixtureJson
function fixture(elements: any[]) {
const items = structuredClone(elements)
const table = (type: string) => ({
list: () => items.filter(e => e.type === type),
get: (id: string) => items.find(e => e.type === type && e[`${type}_id`] === id),
insert: (value: any) => { items.push(value); return value },
delete: (id: string) => {
const i = items.findIndex(e => e.type === type && e[`${type}_id`] === id)
if (i >= 0) items.splice(i, 1)
},
})
return { items, db: Object.fromEntries(["pcb_solder_paste", "pcb_smtpad", "pcb_component", "source_component"].map(type => [type, table(type)])) }
}
test("baseline reproduces 96 missing rounded-lead apertures; all are restored without editing other records", () => {
const { items, db } = fixture(baseline)
applyMissingRoundedPaste(db)
expect(items.slice(0, baseline.length)).toEqual(baseline)
const added = items.slice(baseline.length)
expect(added).toHaveLength(96)
for (const aperture of added) expect(pcb_solder_paste.safeParse(aperture).success).toBe(true)
const sources = new Map(items.filter(e => e.type === "source_component").map(e => [e.source_component_id, e.name]))
for (const [name, expected] of [["U_ETH", 48], ["U_MOTION", 20], ["U_MOTOR", 28]] as const) {
const p = items.find(e => e.type === "pcb_component" && sources.get(e.source_component_id) === name)
expect(added.filter(e => e.pcb_component_id === p.pcb_component_id)).toHaveLength(expected)
}
applyMissingRoundedPaste(db)
expect(items).toHaveLength(baseline.length + 96)
})
test("rounded apertures retain final layer, rotation, center and land association", () => {
for (const pad of baseline.filter(e => e.type === "pcb_smtpad" && ["pill", "rotated_pill"].includes(e.shape))) {
const result = roundedPadPaste(pad as any)!
expect(result.layer).toBe(pad.layer)
expect(result.x).toBe(pad.x)
expect(result.y).toBe(pad.y)
expect(result.pcb_smtpad_id).toBe(pad.pcb_smtpad_id)
expect(result.width).toBeCloseTo(pad.width * .7, 12)
expect(result.height).toBeCloseTo(pad.height * .7, 12)
if (result.shape === "rotated_pill") expect(result.ccw_rotation).toBe(pad.ccw_rotation)
}
})
test("DNP, test features and mask-covered lands never acquire paste", () => {
const elements: any[] = [
{ type: "source_component", source_component_id: "s", name: "DNP" },
{ type: "source_component", source_component_id: "t", name: "TP", ftype: "simple_test_point" },
{ type: "pcb_component", pcb_component_id: "p", source_component_id: "s", do_not_place: true },
{ type: "pcb_component", pcb_component_id: "q", source_component_id: "t" },
...["p", "q"].map(id => ({ type: "pcb_smtpad", pcb_smtpad_id: id, pcb_component_id: id, shape: "pill", x: 0, y: 0, width: 1, height: 2, radius: .5, layer: "bottom" })),
]
const { items, db } = fixture(elements)
applyMissingRoundedPaste(db)
expect(items).toEqual(elements)
expect(roundedPadPaste({ ...elements.at(-1), is_covered_with_solder_mask: true } as any)).toBeUndefined()
})
test("existing explicit aperture is retained instead of duplicated or resized", () => {
const pad: any = baseline.find(e => e.type === "pcb_smtpad" && e.shape === "rotated_pill")
const component: any = baseline.find(e => e.type === "pcb_component" && e.pcb_component_id === pad.pcb_component_id)
const custom = { ...roundedPadPaste(pad)!, width: pad.width * .8 }
const { items, db } = fixture([pad, component, custom])
applyMissingRoundedPaste(db)
expect(items).toEqual([pad, component, custom])
})
test("full paste pass removes inherited paste from bare test points and non-SMT features", () => {
const source = { type: "source_component", source_component_id: "s", ftype: "simple_test_point" }
const part = { type: "pcb_component", pcb_component_id: "p", source_component_id: "s" }
const pad = { type: "pcb_smtpad", pcb_smtpad_id: "land", pcb_component_id: "p", layer: "top" }
const paste = { type: "pcb_solder_paste", pcb_solder_paste_id: "paste", pcb_smtpad_id: "land", layer: "top" }
const orphan = { type: "pcb_solder_paste", pcb_solder_paste_id: "pth", pcb_component_id: "p", layer: "top" }
const { items, db } = fixture([source, part, pad, paste, orphan])
applyAssemblyPasteMetadata({ root: { db } })
expect(items).toEqual([source, part, pad])
})