Files
Akhil Velagapudi 8e9c355a3f Disallow dots in names (#150)
* Disallow dots in names

Signed-off-by: akhilles <akhilvelagapudi@gmail.com>

* Bump stdlib

Signed-off-by: akhilles <akhilvelagapudi@gmail.com>

* Simplify is_instance_position

Signed-off-by: akhilles <akhilvelagapudi@gmail.com>

* Update snapshot

Signed-off-by: akhilles <akhilvelagapudi@gmail.com>

---------

Signed-off-by: akhilles <akhilvelagapudi@gmail.com>
2025-09-15 18:06:28 -04:00

386 lines
11 KiB
Rust

#![cfg(not(target_os = "windows"))]
use std::fs::File;
use pcb_test_utils::assert_snapshot;
use pcb_test_utils::sandbox::{cargo_bin, Sandbox};
use serde_json::Value;
const LED_MODULE_ZEN: &str = r#"
load("@stdlib/interfaces.zen", "Gpio", "Ground", "Power")
Resistor = Module("@stdlib/generics/Resistor.zen")
Led = Module("@stdlib/generics/Led.zen")
led_color = config("led_color", str, default = "red")
r_value = config("r_value", str, default = "330Ohm")
package = config("package", str, default = "0603")
VCC = io("VCC", Power)
GND = io("GND", Ground)
CTRL = io("CTRL", Gpio)
led_anode = Net("LED_ANODE")
Resistor(name = "R1", value = r_value, package = package, P1 = VCC.NET, P2 = led_anode)
Led(name = "D1", color = led_color, package = package, A = led_anode, K = CTRL.NET)
"#;
const TEST_BOARD_ZEN: &str = r#"
load("@stdlib/interfaces.zen", "Gpio", "Ground", "Power")
add_property("layout_path", "build/TestBoard")
LedModule = Module("../modules/LedModule.zen")
Resistor = Module("@stdlib/generics/Resistor.zen")
Capacitor = Module("@stdlib/generics/Capacitor.zen")
vcc_3v3 = Power("VCC_3V3")
gnd = Ground("GND")
led_ctrl = Gpio("LED_CTRL")
Capacitor(name = "C1", value = "100nF", package = "0402", P1 = vcc_3v3.NET, P2 = gnd.NET)
Capacitor(name = "C2", value = "10uF", package = "0805", P1 = vcc_3v3.NET, P2 = gnd.NET)
LedModule(name = "LED1", led_color = "green", VCC = vcc_3v3, GND = gnd, CTRL = led_ctrl)
Resistor(name = "R1", value = "10kOhm", package = "0603", P1 = vcc_3v3.NET, P2 = led_ctrl.NET)
"#;
const PCB_TOML: &str = r#"
[workspace]
name = "test_workspace"
[packages]
stdlib = "@github/diodeinc/stdlib:v0.2.10"
"#;
const BOARD_PCB_TOML: &str = r#"
[board]
name = "TestBoard"
path = "TestBoard.zen"
[packages]
stdlib = "@github/diodeinc/stdlib:v0.2.10"
"#;
const TB0001_BOARD_PCB_TOML: &str = r#"
[board]
name = "TB0001"
path = "TB0001.zen"
[packages]
stdlib = "@github/diodeinc/stdlib:v0.2.10"
"#;
const CASE_BOARD_PCB_TOML: &str = r#"
[board]
name = "CaseBoard"
path = "CaseBoard.zen"
"#;
const TB0002_BOARD_PCB_TOML: &str = r#"
[board]
name = "TB0002"
path = "TB0002.zen"
"#;
const SIMPLE_COMPONENT: &str = r#"
value = config("value", str, default = "10kOhm")
P1 = io("P1", Net)
P2 = io("P2", Net)
Component(
name = "R",
prefix = "R",
footprint = File("test.kicad_mod"),
pin_defs = {"P1": "1", "P2": "2"},
pins = {"P1": P1, "P2": P2},
properties = {
"value": value,
"type": "resistor",
"datasheet": File("datasheet.txt"),
}
)
"#;
const TEST_KICAD_MOD: &str = r#"(footprint "test"
(layer "F.Cu")
(pad "1" smd rect (at -1 0) (size 1 1) (layers "F.Cu"))
(pad "2" smd rect (at 1 0) (size 1 1) (layers "F.Cu"))
)
"#;
const SIMPLE_BOARD_ZEN: &str = r#"
SimpleComponent = Module("../modules/component.zen")
add_property("layout_path", "build/TestBoard")
vcc_3v3 = Net("VCC_3V3")
gnd = Net("GND")
SimpleComponent(name = "foo", P1 = vcc_3v3, P2 = gnd)
"#;
#[test]
fn test_pcb_release_source_only() {
let mut sb = Sandbox::new();
sb.cwd("src")
.seed_stdlib(&["v0.2.10"])
.seed_kicad(&["9.0.0"])
.write("pcb.toml", PCB_TOML)
.write("boards/pcb.toml", BOARD_PCB_TOML)
.write("modules/LedModule.zen", LED_MODULE_ZEN)
.write("boards/TestBoard.zen", TEST_BOARD_ZEN)
.hash_globs(["*.kicad_mod", "**/diodeinc/stdlib/*.zen"])
.ignore_globs(["layout/*"]);
// Run source-only release with JSON output
let output = sb
.cmd(
cargo_bin!("pcb"),
[
"release",
"--board",
"TestBoard",
"--source-only",
"-f",
"json",
],
)
.read()
.expect("Failed to run pcb release command");
// Parse JSON output to get staging directory
let json: Value = serde_json::from_str(&output).expect("Failed to parse JSON output");
let staging_dir = json["release"]["staging_directory"]
.as_str()
.expect("Missing staging_directory in JSON");
// Snapshot the staging directory contents
assert_snapshot!("release_basic", sb.snapshot_dir(staging_dir));
// Snapshot the build from release contents
let build_ouput = sb.snapshot_run(
"pcb",
[
"build",
"--offline",
&format!("{staging_dir}/src/boards/TestBoard.zen"),
],
);
assert_snapshot!("release_basic_build", build_ouput);
}
#[test]
fn test_pcb_release_with_git() {
let mut sb = Sandbox::new();
let output = sb
.cwd("src")
.ignore_globs(["layout/*"])
.hash_globs(["*.kicad_mod", "**/diodeinc/stdlib/*.zen"])
.seed_stdlib(&["v0.2.10"])
.seed_kicad(&["9.0.0"])
.write(".gitignore", ".pcb")
.write("pcb.toml", PCB_TOML)
.write("boards/pcb.toml", TB0001_BOARD_PCB_TOML)
.write("modules/LedModule.zen", LED_MODULE_ZEN)
.write("boards/TB0001.zen", TEST_BOARD_ZEN)
.init_git()
.commit("Initial commit")
.tag("TB0001/v1.2.3")
.cmd(
cargo_bin!("pcb"),
[
"release",
"--board",
"TB0001",
"--source-only",
"-f",
"json",
],
)
.read()
.expect("Failed to run pcb release command");
// Parse JSON output to get staging directory and verify git version
let json: Value = serde_json::from_str(&output).expect("Failed to parse JSON output");
let staging_dir = json["release"]["staging_directory"].as_str().unwrap();
let metadata_file = File::open(format!("{staging_dir}/metadata.json")).unwrap();
let metadata_json: Value = serde_json::from_reader(metadata_file).unwrap();
let git_version = metadata_json["release"]["git_version"].as_str().unwrap();
// Verify git version is detected properly
assert_eq!(git_version, "v1.2.3");
// Snapshot the staging directory contents
assert_snapshot!("release_with_git", sb.snapshot_dir(staging_dir));
// Snapshot the build from release contents
let build_ouput = sb.snapshot_run(
"pcb",
[
"build",
"--offline",
&format!("{staging_dir}/src/boards/TB0001.zen"),
],
);
assert_snapshot!("release_with_git_build", build_ouput);
}
#[test]
#[ignore]
fn test_pcb_release_full() {
let mut sb = Sandbox::new();
sb.cwd("src")
.seed_stdlib(&["v0.2.10"])
.seed_kicad(&["9.0.0"])
.write("pcb.toml", PCB_TOML)
.write("boards/pcb.toml", BOARD_PCB_TOML)
.write("modules/LedModule.zen", LED_MODULE_ZEN)
.write("boards/TestBoard.zen", TEST_BOARD_ZEN)
.hash_globs(["*.kicad_mod", "**/diodeinc/stdlib/*.zen"])
.ignore_globs(["layout/*", "3d/*"]);
// Run full release with JSON output
let output = sb
.cmd(
cargo_bin!("pcb"),
["release", "--board", "TestBoard", "-f", "json"],
)
.read()
.expect("Failed to run pcb release command");
// Parse JSON output to get staging directory
let json: Value = serde_json::from_str(&output).expect("Failed to parse JSON output");
let staging_dir = json["release"]["staging_directory"]
.as_str()
.expect("Missing staging_directory in JSON");
// Snapshot the staging directory contents
assert_snapshot!("release_full", sb.snapshot_dir(staging_dir));
// Snapshot the build from release contents
let build_ouput = sb.snapshot_run(
"pcb",
[
"build",
"--offline",
&format!("{staging_dir}/src/boards/TestBoard.zen"),
],
);
assert_snapshot!("release_full_build", build_ouput);
}
#[test]
fn test_pcb_release_case_insensitive_tag() {
let board_zen = r#"
add_property("layout_path", "build/CaseBoard")
n1 = Net("N1")
n2 = Net("N2")
"#;
// Board name is CaseBoard; tag uses upper-case prefix to test case-insensitivity
let mut sb = Sandbox::new();
let output = sb
.cwd("src")
.ignore_globs(["layout/*"])
.write("boards/pcb.toml", CASE_BOARD_PCB_TOML)
.write("boards/CaseBoard.zen", board_zen)
.init_git()
.commit("Initial commit")
.tag("CASEBOARD/v9.9.9")
.cmd(
cargo_bin!("pcb"),
[
"release",
"--board",
"CaseBoard",
"--source-only",
"-f",
"json",
],
)
.read()
.expect("Failed to run pcb release command");
// Parse JSON output to get staging directory
let json: Value = serde_json::from_str(&output).expect("Failed to parse JSON output");
let staging_dir = json["release"]["staging_directory"].as_str().unwrap();
// Snapshot the build from release contents
let build_ouput = sb.snapshot_run(
"pcb",
[
"build",
"--offline",
&format!("{staging_dir}/src/CaseBoard.zen"),
],
);
assert_snapshot!("case_insensitive_tag_build", build_ouput);
// Load and sanitize metadata.json for stable snapshot
let metadata_path = format!("{staging_dir}/metadata.json");
let metadata_file = File::open(&metadata_path).unwrap();
let meta: Value = serde_json::from_reader(metadata_file).unwrap();
// Ensure git tag was detected
let git_version = meta["release"]["git_version"].as_str().unwrap();
assert_eq!(git_version, "v9.9.9");
assert_snapshot!("case_insensitive_tag", sb.snapshot_dir(staging_dir));
}
#[test]
fn test_pcb_release_with_file() {
let mut sb = Sandbox::new();
const DATASHEET_CONTENTS: &str = "Simple component datasheet.";
sb.cwd("src")
.write("pcb.toml", PCB_TOML)
.write("boards/pcb.toml", TB0002_BOARD_PCB_TOML)
.write("modules/component.zen", SIMPLE_COMPONENT)
.write("modules/test.kicad_mod", TEST_KICAD_MOD)
.write("modules/datasheet.txt", DATASHEET_CONTENTS)
.write("boards/TB0002.zen", SIMPLE_BOARD_ZEN)
.ignore_globs(["layout/*"]);
// Run source-only release with JSON output
let output = sb
.cmd(
cargo_bin!("pcb"),
[
"release",
"--board",
"TB0002",
"--source-only",
"-f",
"json",
],
)
.read()
.expect("Failed to run pcb release command");
// Parse JSON output to get staging directory
let json: Value = serde_json::from_str(&output).expect("Failed to parse JSON output");
let staging_dir = json["release"]["staging_directory"]
.as_str()
.expect("Missing staging_directory in JSON");
let datasheet_path = format!("{staging_dir}/src/modules/datasheet.txt");
let datasheet_contents = std::fs::read_to_string(&datasheet_path).unwrap();
assert_eq!(datasheet_contents, DATASHEET_CONTENTS);
// Snapshot the staging directory contents
assert_snapshot!("release_with_file", sb.snapshot_dir(staging_dir));
// Snapshot the build from release contents
let build_ouput = sb.snapshot_run(
"pcb",
[
"build",
"--offline",
&format!("{staging_dir}/src/boards/TB0002.zen"),
],
);
assert_snapshot!("release_with_file_build", build_ouput);
}