use std::collections::BTreeMap;
use espforge_core::answers::Overrides;
use espforge_core::pipeline;
fn generated_for(src: &str) -> BTreeMap<String, String> {
let checked = pipeline::validate(src, &Overrides::default())
.ok()
.unwrap_or_else(|| panic!("the test source validates:\n{src}"));
let board = pipeline::board(&checked)
.ok()
.unwrap_or_else(|| panic!("the test source lowers:\n{src}"));
let generated = espforge_emit::generate_from_board(
&board,
&checked.meta,
&checked.resolved,
&espforge_emit::RuntimeSource::Published,
&[],
)
.unwrap();
generated
.artifacts
.into_iter()
.map(|a| (a.path, a.content))
.collect()
}
fn project(runtime: &str, body: &str) -> String {
format!(
"# espforge\n <project name=\"t\" />\n <chip type=\"esp32c3\" />\n <runtime type=\"{runtime}\" />\n{body}"
)
}
const LED_BUTTON_BODY: &str = "# peripherals\n <gpio id=\"g18\" pin=\"18\" direction=\"output\" />\n <gpio id=\"g9\" pin=\"9\" direction=\"input\" />\n# components\n <led id=\"red_led\" gpio=\"$g18\" />\n <button id=\"btn\" gpio=\"$g9\" pull_up=\"true\" />\n# devices\n# services\n";
const I2C_BODY: &str = "# peripherals\n <i2c id=\"i2c0\" sda=\"4\" scl=\"5\" />\n# components\n <i2c_component id=\"oled\" i2c=\"$i2c0\" address=\"0x48\" />\n# devices\n# services\n";
const SPI_WRITE_ONLY_BODY: &str = "# peripherals\n <spi id=\"spi2\" sclk=\"8\" mosi=\"7\" />\n# components\n <spi_component id=\"display\" spi=\"$spi2\" cs=\"9\" />\n# devices\n# services\n";
const UART_BODY: &str = "# peripherals\n <uart id=\"uart1\" tx=\"20\" rx=\"21\" />\n# components\n <uart_component id=\"serial\" uart=\"$uart1\" baud_rate=\"9600\" parity=\"even\" stop_bits=\"2\" />\n# devices\n# services\n";
const WIFI_BODY: &str = "# peripherals\n# components\n# devices\n# services\n <wifi id=\"wifi0\" network1.ssid=\"Wokwi-GUEST\" />\n";
#[test]
fn leds_and_buttons_reach_generated_rs() {
let files = generated_for(&project("blocking", LED_BUTTON_BODY));
let generated = &files["src/generated.rs"];
assert!(
generated.contains("pub red_led: espforge_runtime::Led,"),
"{generated}"
);
assert!(
generated.contains("GPIO18.clone_unchecked()"),
"{generated}"
);
assert!(
generated.contains("pub btn: espforge_runtime::Button,"),
"{generated}"
);
assert!(generated.contains("Button::new("), "{generated}");
}
#[test]
fn the_runtime_picks_the_blocking_or_async_bus_type() {
let blocking = generated_for(&project("blocking", I2C_BODY));
assert!(
blocking["src/generated.rs"].contains("I2cBus<esp_hal::Blocking>"),
"{}",
blocking["src/generated.rs"]
);
let embassy = generated_for(&project("embassy", I2C_BODY));
let generated = &embassy["src/generated.rs"];
assert!(generated.contains("I2cBus<esp_hal::Async>"), "{generated}");
assert!(!generated.contains("esp_hal::Blocking"), "{generated}");
}
#[test]
fn a_spi_bus_without_miso_is_write_only() {
let files = generated_for(&project("blocking", SPI_WRITE_ONLY_BODY));
let generated = &files["src/generated.rs"];
assert!(
generated.contains("SpiBus::build_write_only("),
"{generated}"
);
assert!(!generated.contains("SpiBus::build("), "{generated}");
}
#[test]
fn uart_framing_reaches_generated_rs() {
let files = generated_for(&project("blocking", UART_BODY));
let generated = &files["src/generated.rs"];
assert!(generated.contains("baudrate: 9600"), "{generated}");
assert!(
generated.contains("parity: esp_hal::uart::Parity::Even"),
"{generated}"
);
assert!(
generated.contains("stop_bits: esp_hal::uart::StopBits::_2"),
"{generated}"
);
}
#[test]
fn the_wifi_service_reaches_main_and_cargo_toml() {
let files = generated_for(&project("embassy", WIFI_BODY));
let main = &files["src/bin/main.rs"];
assert!(
main.contains("Services::new(registry.peripherals.WIFI, &spawner)"),
"{main}"
);
assert!(main.contains("esp_alloc::heap_allocator!"), "{main}");
let cargo = &files["Cargo.toml"];
assert!(cargo.contains("esp-radio"), "{cargo}");
assert!(cargo.contains("\"wifi\""), "{cargo}");
assert!(files["src/generated.rs"].contains("pub wifi: espforge_runtime::Wifi,"));
}