#![cfg(feature = "builtin-kernels")]
use std::time::Duration;
use lmflow::{Graph, Packet, Timestamp};
fn init() {
lmflow::register_builtin_kernels();
}
#[test]
fn bad_dtype_option_fails_at_start() {
init();
for kernel in ["CastKernel", "AffineKernel"] {
let g = Graph::from_yaml(&format!(
"nodes:\n - {{ name: k, kernel: {kernel}, input_ports: [\"in\"], output_ports: [\"out\"], options: {{ dtype: \"nosuchtype\" }} }}\n\
input_ports: [\"in\"]\noutput_ports: [\"out\"]\n"
))
.unwrap();
let err = g
.start()
.expect_err(&format!("{kernel}: 非法 dtype 必须让 start() 失败"));
let msg = err.to_string();
assert!(msg.contains("dtype"), "{kernel}: 原因里应提到 dtype:{msg}");
assert!(
msg.contains("check failed") && msg.contains(".cc:"),
"{kernel}: 应带上表达式与 file:line:{msg}"
);
}
}
#[derive(Default)]
struct NeedsOpt;
impl lmflow::Kernel for NeedsOpt {
fn open(&mut self, cc: &mut lmflow::KernelCtx) -> lmflow::Result<()> {
if !cc.has_option("scale") {
return Err(cc.fail("options.scale missing (required)"));
}
Ok(())
}
fn process(&mut self, cc: &mut lmflow::KernelCtx) -> lmflow::Result<()> {
cc.forward(0, 0)
}
}
#[test]
fn missing_required_option_fails_at_start() {
init();
let _ = lmflow::register_kernel::<NeedsOpt>("NeedsOptTestKernel");
let g = Graph::from_yaml(
"nodes:\n - { name: n, kernel: NeedsOptTestKernel, input_ports: [\"in\"], output_ports: [\"out\"] }\n\
input_ports: [\"in\"]\noutput_ports: [\"out\"]\n",
)
.unwrap();
let msg = g
.start()
.expect_err("缺必需 option 必须让 start() 失败")
.to_string();
assert!(msg.contains("scale"), "原因里应提到 scale:{msg}");
}
#[test]
fn mux_selector_range_is_enforced() {
init();
let yaml = "nodes:\n - { name: m, kernel: MuxKernel, input_ports: [\"ctl\", \"a\", \"b\"], output_ports: [\"out\"] }\n\
input_ports: [\"ctl\", \"a\", \"b\"]\noutput_ports: [\"out\"]\n";
let g = Graph::from_yaml(yaml).unwrap();
let out = g.add_poller("out").unwrap();
g.start().unwrap();
g.input("ctl")
.unwrap()
.send(Packet::from_i64(1).at(Timestamp(0)))
.unwrap();
g.input("a")
.unwrap()
.send(Packet::from_i64(10).at(Timestamp(0)))
.unwrap();
g.input("b")
.unwrap()
.send(Packet::from_i64(20).at(Timestamp(0)))
.unwrap();
assert_eq!(
out.next().and_then(|p| p.as_i64()),
Some(20),
"合法选择器必须照常工作(取反写反了这里就错)"
);
g.close_all_inputs();
g.wait_done_timeout(Duration::from_secs(5)).unwrap();
let g2 = Graph::from_yaml(yaml).unwrap();
g2.add_poller("out").unwrap();
g2.start().unwrap();
g2.input("ctl")
.unwrap()
.send(Packet::from_i64(5).at(Timestamp(0)))
.unwrap();
g2.input("a")
.unwrap()
.send(Packet::from_i64(10).at(Timestamp(0)))
.unwrap();
g2.input("b")
.unwrap()
.send(Packet::from_i64(20).at(Timestamp(0)))
.unwrap();
g2.close_all_inputs();
let msg = g2
.wait_done_timeout(Duration::from_secs(5))
.expect_err("越界选择器必须让图报错")
.to_string();
assert!(msg.contains("out of range"), "原因应说明越界:{msg}");
assert!(msg.contains("check failed"), "应经 RET_CHECK 报出:{msg}");
}