tscircuit/ti
ti tscircuit library
- Version
- 1.0.195
- License
- unset
- Stars
- 0
system-block-ui/src/model/model.test.ts
import { describe, expect, test } from "bun:test";
import {
createConsumerWirelessModuleDesign,
createSubcircuitCatalog,
createSystemBlockExamples,
generateSystemDesignArtifacts,
generateTsx,
getSubcircuitDefinition,
resolveConnection,
resolveDesignConnections,
SUBCIRCUIT_CATALOG,
} from "./index";
import type {
BlockInstance,
PortDefinition,
SubcircuitDefinition,
} from "./types";
import { ConnectionResolutionError } from "./types";
const definition = (id: string): SubcircuitDefinition => {
const result = getSubcircuitDefinition(id);
if (!result) throw new Error(`Missing test definition: ${id}`);
return result;
};
const block = (id: string, definitionId: string): BlockInstance => ({
id,
definitionId,
});
describe("automatic connection resolution", () => {
test("fans one 1.8 V rail out to every TAS2505 supply endpoint", () => {
const ldo = definition("power-management-tps7a2018");
const amplifier = definition("audio-amplifier-tas2505");
const resolved = resolveConnection({
kind: "Power",
from: { block: block("ldo", ldo.id), definition: ldo },
to: { block: block("amplifier", amplifier.id), definition: amplifier },
});
expect(resolved.fromPortId).toBe("power-1v8-out");
expect(resolved.toPortId).toBe("logic-power");
expect(resolved.traces).toHaveLength(5);
expect(
resolved.traces
.filter((trace) => trace.signal === "positive")
.map((trace) => trace.toSelector),
).toEqual([".U1 > .AVDD", ".U1 > .DVDD", ".U1 > .IOVDD", ".R1 > .pin1"]);
expect(resolved.traces.at(-1)).toMatchObject({
signal: "ground",
fromSelector: ".U1 > .GND",
toSelector: ".U1 > .AVSS",
});
});
test("crosses HCI UART TX/RX and RTS/CTS while preserving controls", () => {
const controller = definition("bluetooth-controller-cc2564c");
const host = definition("bluetooth-audio-host-msp430f5229");
const resolved = resolveConnection({
kind: "Data",
from: {
block: block("controller", controller.id),
definition: controller,
},
to: { block: block("host", host.id), definition: host },
});
expect(resolved.protocol).toBe("hci-uart");
expect(resolved.traces).toHaveLength(6);
expect(resolved.traces).toContainEqual(
expect.objectContaining({
fromSelector: ".U1A > .HCI_TX",
toSelector: ".U10 > .UART_RXD",
}),
);
expect(resolved.traces).toContainEqual(
expect.objectContaining({
fromSelector: ".U10 > .UART_TXD",
toSelector: ".U1A > .HCI_RX",
}),
);
expect(resolved.traces).toContainEqual(
expect.objectContaining({
fromSelector: ".U1A > .HCI_RTS",
toSelector: ".U10 > .P1_4",
}),
);
expect(resolved.traces).toContainEqual(
expect.objectContaining({
fromSelector: ".U10 > .P1_5",
toSelector: ".U1A > .HCI_CTS",
}),
);
});
test("rejects incompatible voltage and tied best candidates", () => {
const ldo = definition("power-management-tps7a2018");
const motor = definition("motor-driver-drv8833");
expect(() =>
resolveConnection({
kind: "Power",
from: { block: block("ldo", ldo.id), definition: ldo },
to: { block: block("motor", motor.id), definition: motor },
}),
).toThrow(ConnectionResolutionError);
const providerPort = (id: string): PortDefinition => ({
id,
label: id,
kind: "power",
role: "provider",
protocol: "power",
voltage: 3.3,
requiredSignals: ["positive", "ground"],
signals: [
{
name: "positive",
direction: "output",
selectors: [`.${id} > .VCC`],
},
{
name: "ground",
direction: "passive",
selectors: [`.${id} > .GND`],
},
],
});
const source: SubcircuitDefinition = {
id: "ambiguous-source",
title: "Ambiguous Source",
category: "Test",
componentName: "AmbiguousSource",
importPath: "test",
sourcePath: "test.tsx",
ports: [providerPort("a"), providerPort("b")],
};
const sink: SubcircuitDefinition = {
id: "sink",
title: "Sink",
category: "Test",
componentName: "Sink",
importPath: "test",
sourcePath: "test.tsx",
ports: [
{
...providerPort("input"),
role: "consumer",
signals: [
{
name: "positive",
direction: "input",
selectors: [".U1 > .VCC"],
},
{
name: "ground",
direction: "passive",
selectors: [".U1 > .GND"],
},
],
},
],
};
try {
resolveConnection({
kind: "power",
from: { block: block("source", source.id), definition: source },
to: { block: block("sink", sink.id), definition: sink },
});
throw new Error("Expected ambiguity");
} catch (error) {
expect(error).toBeInstanceOf(ConnectionResolutionError);
expect((error as ConnectionResolutionError).code).toBe(
"AMBIGUOUS_CONNECTION",
);
}
});
test("rejects a source range that only partly overlaps a consumer range", () => {
const charger = definition("battery-management-bq24074");
const sensor = definition("environmental-sensor-hdc2080");
try {
resolveConnection({
kind: "Power",
from: { block: block("charger", charger.id), definition: charger },
to: { block: block("sensor", sensor.id), definition: sensor },
});
throw new Error("Expected an unsafe voltage range to be rejected");
} catch (error) {
expect(error).toBeInstanceOf(ConnectionResolutionError);
expect((error as ConnectionResolutionError).code).toBe(
"NO_COMPATIBLE_PORTS",
);
}
});
test("rejects reusing a single-use consumer port", () => {
const blocks = [
block("ldo_a", "power-management-tps7a2018"),
block("ldo_b", "power-management-tps7a2018"),
block("amplifier", "audio-amplifier-tas2505"),
];
const connections = [
{
id: "a",
fromBlockId: "ldo_a",
toBlockId: "amplifier",
kind: "Power" as const,
},
{
id: "b",
fromBlockId: "ldo_b",
toBlockId: "amplifier",
kind: "Power" as const,
},
];
try {
resolveDesignConnections(blocks, connections);
throw new Error("Expected a reused input port to be rejected");
} catch (error) {
expect(error).toBeInstanceOf(ConnectionResolutionError);
expect((error as ConnectionResolutionError).code).toBe("PORT_IN_USE");
}
});
test("falls through to a compatible free port on a multi-rail block", () => {
const canInterface = definition(
"communication-interface-tcan1042-tida01428",
);
const source: SubcircuitDefinition = {
id: "five-volt-source",
title: "5 V source",
category: "Test",
componentName: "FiveVoltSource",
importPath: "test",
sourcePath: "test.tsx",
ports: [
{
id: "output",
label: "5 V",
kind: "power",
role: "provider",
protocol: "power",
voltage: 5,
signals: [
{ name: "positive", direction: "output", selectors: [".VOUT"] },
{ name: "ground", direction: "passive", selectors: [".GND"] },
],
},
],
};
const blocks = [
block("source_a", source.id),
block("source_b", source.id),
block("can", canInterface.id),
];
const resolved = resolveDesignConnections(
blocks,
[
{
id: "a",
fromBlockId: "source_a",
toBlockId: "can",
kind: "Power",
},
{
id: "b",
fromBlockId: "source_b",
toBlockId: "can",
kind: "Power",
},
],
[source, canInterface],
);
expect(resolved.map((connection) => connection.toPortId)).toEqual([
"transceiver-power",
"logic-power",
]);
});
test("uses bytewise ordering for connection IDs and tied port diagnostics", () => {
const ordered = resolveDesignConnections(
[
block("ldo", "power-management-tps7a2018"),
block("amplifier", "audio-amplifier-tas2505"),
block("host", "bluetooth-audio-host-msp430f5229"),
block("controller", "bluetooth-controller-cc2564c"),
],
[
{
id: "ä-connection",
fromBlockId: "ldo",
toBlockId: "amplifier",
kind: "power",
},
{
id: "z-connection",
fromBlockId: "host",
toBlockId: "controller",
kind: "data",
},
],
);
expect(ordered.map(({ id }) => id)).toEqual([
"z-connection",
"ä-connection",
]);
const source: SubcircuitDefinition = {
id: "bytewise-source",
title: "Bytewise source",
category: "Test",
componentName: "BytewiseSource",
importPath: "test",
sourcePath: "test.tsx",
ports: ["ä-port", "z-port"].map((id) => ({
id,
label: id,
kind: "data" as const,
role: "host" as const,
protocol: "gpio",
signals: [
{
name: "signal",
direction: "output" as const,
selectors: [`.${id}`],
},
],
})),
};
const sink: SubcircuitDefinition = {
id: "bytewise-sink",
title: "Bytewise sink",
category: "Test",
componentName: "BytewiseSink",
importPath: "test",
sourcePath: "test.tsx",
ports: [
{
id: "input",
label: "input",
kind: "data",
role: "device",
protocol: "gpio",
signals: [
{
name: "signal",
direction: "input",
selectors: [".input"],
},
],
},
],
};
try {
resolveConnection({
kind: "data",
from: { block: block("source", source.id), definition: source },
to: { block: block("sink", sink.id), definition: sink },
});
throw new Error("Expected bytewise candidates to remain ambiguous");
} catch (error) {
expect(error).toBeInstanceOf(ConnectionResolutionError);
const candidates = (
(error as ConnectionResolutionError).details?.candidates as
| Array<{ fromPortId: string }>
| undefined
)?.map(({ fromPortId }) => fromPortId);
expect(candidates).toEqual(["z-port", "ä-port"]);
}
});
});
describe("catalog and TSX generation", () => {
test("loads every registered example as a resolvable semantic graph", async () => {
const examples = createSystemBlockExamples(SUBCIRCUIT_CATALOG);
expect(examples.map(({ sourcePath }) => sourcePath)).toEqual([
"examples/ConsumerWirelessModule.circuit.tsx",
"examples/BluetoothSpeaker_CC2564C_TAS2505.circuit.tsx",
"examples/PersonalElectronics_ConnectedPeripheralAndPrinters_Powerbank.circuit.tsx",
"examples/RearviewMirrorModule.circuit.tsx",
"examples/SeatPositionModule.circuit.tsx",
"examples/BloodPressureAndHeartRateMonitor_TIDA010266.circuit.tsx",
]);
expect(
examples
.find(({ id }) => id === "bluetooth-speaker")
?.graph.connections.find(({ protocol }) => protocol === "hci-uart"),
).toMatchObject({
fromBlockId: "bluetooth_host",
toBlockId: "bluetooth_controller",
});
for (const example of examples) {
expect(
await Bun.file(
new URL(`../../../${example.sourcePath}`, import.meta.url),
).exists(),
).toBe(true);
expect(
resolveDesignConnections(
example.graph.blocks,
example.graph.connections,
SUBCIRCUIT_CATALOG,
),
).toHaveLength(example.graph.connections.length);
}
});
test("builds the Power Bank from all five application blocks", () => {
const example = createSystemBlockExamples(SUBCIRCUIT_CATALOG).find(
({ id }) => id === "power-bank",
);
if (!example) throw new Error("Missing Power Bank example");
expect(example.graph.blocks.map(({ id }) => id)).toEqual([
"battery_management",
"battery_charging",
"system_power",
"microcontroller",
"usb_c_output",
]);
const resolved = resolveDesignConnections(
example.graph.blocks,
example.graph.connections,
SUBCIRCUIT_CATALOG,
);
expect(resolved).toHaveLength(7);
expect(
resolved.find(({ id }) => id === "data_i2c_charger")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U4 > .pin14",
toSelector: ".U1 > .pin13",
}),
expect.objectContaining({
fromSelector: ".U4 > .pin15",
toSelector: ".U1 > .pin12",
}),
]),
);
expect(
resolved.find(({ id }) => id === "data_boost_control")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U4 > .pin12",
toSelector: ".Q2 > .gate",
}),
expect.objectContaining({
fromSelector: ".U4 > .pin13",
toSelector: ".Q1 > .gate",
}),
]),
);
});
test("builds the Seat Position Module from all six application blocks", () => {
const example = createSystemBlockExamples(SUBCIRCUIT_CATALOG).find(
({ id }) => id === "seat-position-module",
);
if (!example) throw new Error("Missing Seat Position Module example");
expect(example.graph.blocks.map(({ id }) => id)).toEqual([
"power_supply",
"communication_interface",
"microcontroller",
"motor_driver",
"position_feedback",
"light_driver",
]);
const resolved = resolveDesignConnections(
example.graph.blocks,
example.graph.connections,
SUBCIRCUIT_CATALOG,
);
expect(resolved).toHaveLength(7);
expect(
resolved.find(({ id }) => id === "data_can_controller")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U6 > .PA8",
toSelector: ".U6 > .TXD",
}),
expect.objectContaining({
fromSelector: ".U6 > .RXD",
toSelector: ".U6 > .PA9",
}),
]),
);
expect(
resolved.find(({ id }) => id === "data_motor_control")?.traces,
).toHaveLength(13);
expect(
resolved.find(({ id }) => id === "power_protected_to_motor_driver")
?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U1 > .OUT",
toSelector: ".U1 > .PVDD",
}),
]),
);
const artifacts = generateSystemDesignArtifacts({
blocks: example.graph.blocks,
connections: example.graph.connections,
catalog: SUBCIRCUIT_CATALOG,
boardName: "seat_position_module",
});
for (const componentName of [
"PowerSupply_LM5050_TIDA00992",
"CommunicationInterface_TCAN1042_TIDA01428",
"Microcontroller_MSPM0L1306Q1_TIDA020065",
"MotorDriver_DRV8305_TIDA01330",
"PositionFeedback_DRV5013_TIDA01389",
"LightDriver_TIDA01330",
]) {
expect(artifacts.tsx).toContain(componentName);
}
expect(artifacts.systemDiagramSvg).toContain(
'data-connection-id="data_motor_control" data-kind="data"',
);
});
test("builds the Rearview Mirror Module from all seven application blocks", () => {
const example = createSystemBlockExamples(SUBCIRCUIT_CATALOG).find(
({ id }) => id === "rearview-mirror-module",
);
if (!example) throw new Error("Missing Rearview Mirror Module example");
expect(example.graph.blocks.map(({ id }) => id)).toEqual([
"power_supply",
"communication_interface",
"microcontroller",
"mirror_driver",
"light_sensor",
"lamp_driver",
"temperature_sensor",
]);
const resolved = resolveDesignConnections(
example.graph.blocks,
example.graph.connections,
SUBCIRCUIT_CATALOG,
);
expect(resolved).toHaveLength(16);
expect(
resolved.find(({ id }) => id === "data_can_controller")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U1 > .CAN_TX",
toSelector: ".U6 > .TXD",
}),
]),
);
expect(
resolved.find(({ id }) => id === "data_i2c_light_sensor")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U1 > .I2C0_SCL",
toSelector: ".U4Sensor .U4 > .SCL",
}),
expect.objectContaining({
fromSelector: ".U1 > .I2C0_SCL",
toSelector: ".U5Sensor .U5 > .SCL",
}),
]),
);
expect(
resolved.find(({ id }) => id === "power_3v3_to_lamp_driver")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U2 > .OUT",
toSelector: ".J3 > .pin3",
}),
expect.objectContaining({
fromSelector: ".U2 > .OUT",
toSelector: ".R9 > .pin1",
}),
]),
);
expect(
resolved.find(({ id }) => id === "power_protected_to_mirror_driver")
?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U1 > .OUT",
toSelector: ".Q2 > .collector",
}),
]),
);
const artifacts = generateSystemDesignArtifacts({
blocks: example.graph.blocks,
connections: example.graph.connections,
catalog: SUBCIRCUIT_CATALOG,
boardName: "rearview_mirror_module",
});
for (const componentName of [
"PowerSupply_LM74202_TPS7E81_Q1",
"CommunicationInterface_TCAN1042_TIDA01428",
"Microcontroller_MSPM0G3507",
"ElectrochromicMirrorDriver_TIDA01539",
"LightSensor_OPT3001_TIDA01539",
"LampDriver_TPS92638_TIDA00356",
"TemperatureSensor_LM50HV_Q1",
]) {
expect(artifacts.tsx).toContain(componentName);
}
expect(artifacts.tsx).toContain(
'<PowerSupply_LM74202_TPS7E81_Q1\n name="power_supply"\n schSheetName="power_supply"\n schX={-3.6}',
);
expect(artifacts.tsx).toContain('to=".light_sensor .U5Sensor .U5 > .SDA"');
expect(artifacts.systemDiagramSvg).toContain(
'data-connection-id="data_power_monitor" data-kind="data"',
);
});
test("builds the Consumer wireless module with an active radio block", () => {
const design = createConsumerWirelessModuleDesign(SUBCIRCUIT_CATALOG);
expect(design.blocks.map(({ id }) => id)).toEqual([
"input_power_protection",
"dc_dc_power_supply",
"io_connection",
"wireless_connectivity",
"io_protection",
"logic_control",
"sensors",
]);
const resolved = resolveDesignConnections(
design.blocks,
design.connections,
SUBCIRCUIT_CATALOG,
);
expect(resolved.map(({ id }) => id)).toEqual([
"data_io_connection_to_io_protection",
"data_logic_to_io_connection",
"power_dc_dc_to_io_connection",
"power_dc_dc_to_logic_control",
"power_dc_dc_to_sensors",
"power_dc_dc_to_wireless_connectivity",
"power_protection_to_dc_dc",
]);
expect(
resolved.find(({ id }) => id === "power_protection_to_dc_dc")?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U7 > .IN1",
toSelector: ".U3P3 > .VIN",
}),
expect.objectContaining({
fromSelector: ".U7 > .IN1",
toSelector: ".U3P3 > .EN",
}),
expect.objectContaining({
fromSelector: ".U7 > .GND1",
toSelector: ".U3P3 > .GND",
}),
]),
);
expect(
resolved.find(({ id }) => id === "data_io_connection_to_io_protection")
?.traces,
).toEqual(
expect.arrayContaining([
expect.objectContaining({
fromSelector: ".U1 > .OUT1_P",
toSelector: ".UESD > .D1",
}),
expect.objectContaining({
fromSelector: ".U1 > .OUT1_N",
toSelector: ".UESD > .D2",
}),
]),
);
const artifacts = generateSystemDesignArtifacts({
blocks: design.blocks,
connections: design.connections,
catalog: SUBCIRCUIT_CATALOG,
boardName: "consumer_wireless_module",
});
for (const componentName of [
"InputPowerProtection_TPS25910_TIDA00890",
"BuckConverter_TPS62086_TIDA00399",
"LVDSDriver_SN65LVDS31_TIDA060017",
"WirelessConnectivity_CC2540_TIDCCC2540BLEUSB",
"InputOutputProtection_TPD2E009_TIDA00399",
"LogicBuffer_SN74LVC1G34",
"TemperatureSensor_TMP103_TIDA00399",
]) {
expect(artifacts.tsx).toContain(componentName);
}
expect(artifacts.tsx).not.toContain(
"WirelessAntenna_W3006_TIDCWL1837MODCOM8I",
);
expect(artifacts.systemDiagramSvg).toContain(
'data-connection-id="power_protection_to_dc_dc" data-kind="power"',
);
expect(artifacts.systemDiagramSvg).toContain(
'data-connection-id="data_io_connection_to_io_protection" data-kind="data"',
);
expect(artifacts.tsx).toContain(
'from=".logic_control > net.MCU_OR_LOGIC_OUT"',
);
expect(artifacts.tsx).toContain('to=".logic_control > net.VCC"');
});
test("does not connect the protected 5 V rail directly to the TMP103", () => {
const inputProtection = definition(
"input-power-protection-tps25910-tida00890",
);
const sensor = definition("temperature-sensor-tmp103-tida00399");
expect(() =>
resolveConnection({
kind: "Power",
from: {
block: block("input_power_protection", inputProtection.id),
definition: inputProtection,
},
to: {
block: block("sensors", sensor.id),
definition: sensor,
},
}),
).toThrow(ConnectionResolutionError);
});
test("enriches discovered raw sources with curated adapters", () => {
const catalog = createSubcircuitCatalog({
"../../../lib/subcircuits/FutureSensor_X1.circuit.tsx":
"export const FutureSensor_X1 = (props: unknown) => null",
"../../../lib/subcircuits/Microcontroller_MSP430G2332.circuit.tsx":
"export const Microcontroller_MSP430G2332 = () => null",
});
expect(
catalog.find((item) => item.componentName === "FutureSensor_X1"),
).toMatchObject({
sourcePath: "lib/subcircuits/FutureSensor_X1.circuit.tsx",
canInstantiate: true,
});
expect(
catalog.find(
(item) => item.componentName === "Microcontroller_MSP430G2332",
),
).toMatchObject({ canInstantiate: true });
});
test("generates stable TSX regardless of graph array ordering", () => {
const blocks = [
block("power_1v8", "power-management-tps7a2018"),
block("audio_amplifier", "audio-amplifier-tas2505"),
];
const connections = [
{
id: "power",
fromBlockId: "power_1v8",
toBlockId: "audio_amplifier",
kind: "Power" as const,
},
];
const first = generateTsx({ blocks, connections });
const second = generateTsx({
blocks: [...blocks].reverse(),
connections: [...connections].reverse(),
});
expect(first).toBe(second);
expect(first).toContain("<board routingDisabled>");
expect(first).toContain("PowerManagement_TPS7A2018,");
expect(first).toContain(
'import { SYSTEM_DIAGRAM_SVG } from "./GeneratedSystem.system-diagram"',
);
expect(first).not.toContain("const SYSTEM_DIAGRAM_SVG");
expect(first).not.toContain("<svg");
expect(first).toContain(
"<schematicgraphic svgContent={SYSTEM_DIAGRAM_SVG} />",
);
expect(first).toContain('displayName="System Diagram"');
expect(first).toContain("sheetIndex={0}");
expect(first).toContain("sheetIndex={1}");
expect(first).toContain("sheetIndex={2}");
expect(first).toContain('from=".power_1v8 > .U1 > .VOUT"');
expect(first).toContain('to=".audio_amplifier > .U1 > .IOVDD"');
});
test("emits canonical system artifacts deterministically", () => {
const blocks = [
{
...block("power_1v8", "power-management-tps7a2018"),
schSheetName: "system_diagram",
},
block("audio_amplifier", "audio-amplifier-tas2505"),
];
const connections = [
{
id: "power",
fromBlockId: "power_1v8",
toBlockId: "audio_amplifier",
kind: "Power" as const,
},
];
const artifacts = generateSystemDesignArtifacts({ blocks, connections });
const reversed = generateSystemDesignArtifacts({
blocks: [...blocks].reverse(),
connections: [...connections].reverse(),
});
expect(artifacts).toEqual(reversed);
expect(artifacts.systemDiagramSheetName).toBe("system_diagram_2");
expect(artifacts.systemDiagramModuleFileName).toBe(
"GeneratedSystem.system-diagram.ts",
);
expect(artifacts.tsx).toContain(
'<schematicsheet\n name="system_diagram_2"\n displayName="System Diagram"\n sheetIndex={0}\n >',
);
expect(artifacts.tsx).toContain(
"<schematicgraphic svgContent={SYSTEM_DIAGRAM_SVG} />",
);
expect(artifacts.systemDiagramSvg).toContain(
'data-connection-id="power" data-kind="power"',
);
expect(artifacts.systemDiagramSvg).not.toContain("__power-summary__");
expect(artifacts.systemDiagramModuleSource).toStartWith(
"export const SYSTEM_DIAGRAM_SVG = [",
);
expect(artifacts.systemDiagramModuleSource).toContain(
'data-connection-id=\\"power\\" data-kind=\\"power\\"',
);
expect(artifacts.tsx).not.toContain(artifacts.systemDiagramSvg);
});
test("always emits a first system diagram sheet for an empty design", () => {
const artifacts = generateSystemDesignArtifacts({
blocks: [],
connections: [],
});
expect(artifacts.systemDiagramSheetName).toBe("system_diagram");
expect(artifacts.systemDiagramSvg).toContain("No system blocks yet");
expect(artifacts.systemDiagramModuleSource).toContain(
"No system blocks yet",
);
expect(artifacts.tsx).toContain("sheetIndex={0}");
expect(artifacts.tsx).toContain(
"<schematicgraphic svgContent={SYSTEM_DIAGRAM_SVG} />",
);
expect(artifacts.tsx).not.toContain("sheetIndex={1}");
});
test("rejects explicit sheet names which collide with generated names", () => {
expect(() =>
generateTsx({
blocks: [
{
id: "generated_sheet",
name: "shared_sheet",
definitionId: "power-management-tps7a2018",
},
{
id: "explicit_sheet",
name: "different_block",
schSheetName: "shared sheet",
definitionId: "audio-amplifier-tas2505",
},
],
connections: [],
}),
).toThrow("Duplicate generated schematic sheet name: shared_sheet");
});
test("orders imports bytewise and prevents protocol JSX-comment injection", () => {
const hostileProtocol = "i2c */}<intruder />{/*";
const makeDataDefinition = ({
id,
componentName,
importPath,
role,
direction,
}: {
id: string;
componentName: string;
importPath: string;
role: "host" | "device";
direction: "input" | "output";
}): SubcircuitDefinition => ({
id,
title: componentName,
category: "Test",
componentName,
importPath,
sourcePath: `${id}.tsx`,
ports: [
{
id: "data",
label: "Data",
kind: "data",
role,
protocol: hostileProtocol,
signals: [
{
name: "signal",
direction,
selectors: [`.${direction}`],
},
],
},
],
});
const catalog = [
makeDataDefinition({
id: "source",
componentName: "ZedSource",
importPath: "@test/z-package",
role: "host",
direction: "output",
}),
makeDataDefinition({
id: "sink",
componentName: "UmlautSink",
importPath: "@test/ä-package",
role: "device",
direction: "input",
}),
];
const generated = generateTsx({
blocks: [block("source", "source"), block("sink", "sink")],
connections: [
{
id: "hostile",
fromBlockId: "source",
toBlockId: "sink",
kind: "data",
protocol: hostileProtocol,
},
],
catalog,
});
expect(generated.indexOf('from "@test/z-package"')).toBeLessThan(
generated.indexOf('from "@test/ä-package"'),
);
const comment = generated
.split("\n")
.find((line) => line.includes("{/* Data:"));
if (!comment) throw new Error("Expected a generated data comment");
expect(comment.match(/\*\//g)).toHaveLength(1);
expect(comment).not.toContain("<intruder");
expect(comment).not.toContain("}{");
expect(comment).toContain("Data: i2c _intruder _");
expect(generated).not.toContain(hostileProtocol);
});
test("curated catalog is sorted and has the reviewed starter-design blocks", () => {
const titles = SUBCIRCUIT_CATALOG.map((item) => item.title);
expect(titles).toEqual(
[...titles].sort((a, b) => a.localeCompare(b, "en")),
);
expect(definition("battery-management-bq24074")).toBeDefined();
expect(definition("bluetooth-controller-cc2564c")).toBeDefined();
expect(definition("audio-amplifier-tas2505")).toBeDefined();
expect(
definition("input-power-protection-tps25910-tida00890"),
).toBeDefined();
expect(definition("buck-converter-tps62086-tida00399")).toBeDefined();
expect(definition("lvds-driver-sn65lvds31-tida060017")).toBeDefined();
expect(
definition("wireless-antenna-w3006-tidcwl1837modcom8i"),
).toBeDefined();
expect(
definition("input-output-protection-tpd2e009-tida00399"),
).toBeDefined();
expect(definition("logic-buffer-sn74lvc1g34")).toBeDefined();
expect(definition("temperature-sensor-tmp103-tida00399")).toBeDefined();
expect(definition("power-supply-lm74202-tps7e81-q1")).toMatchObject({
sourcePath:
"lib/thirdparty-subcircuits/PowerSupply_LM74202_TPS7E81_Q1.circuit.tsx",
});
expect(definition("temperature-sensor-lm50hv-q1")).toMatchObject({
sourcePath:
"lib/thirdparty-subcircuits/TemperatureSensor_LM50HV_Q1.circuit.tsx",
});
expect(definition("electrochromic-mirror-driver-tida01539")).toBeDefined();
expect(definition("light-sensor-opt3001-tida01539")).toBeDefined();
expect(definition("lamp-driver-tps92638-tida00356")).toBeDefined();
});
});