#![cfg(feature = "wasm-runtime")]
use std::path::PathBuf;
use rustledger_plugin::{PluginManager, RuntimeConfig};
use rustledger_plugin_types::{
DirectiveData, DirectiveWrapper, OpenData, PluginInput, PluginOp, PluginOptions,
TransactionData,
};
fn fixture_wasm_path() -> Option<PathBuf> {
let p = PathBuf::from(env!("OUT_DIR")).join("sample_stub.wasm");
p.exists().then_some(p)
}
fn txn_wrapper(narration: &str) -> DirectiveWrapper {
DirectiveWrapper {
directive_type: String::new(),
date: "2024-01-15".to_string(),
filename: None,
lineno: None,
data: DirectiveData::Transaction(TransactionData {
flag: "*".to_string(),
payee: None,
narration: narration.to_string(),
tags: vec![],
links: vec![],
metadata: vec![],
postings: vec![],
}),
}
}
fn open_wrapper(account: &str) -> DirectiveWrapper {
DirectiveWrapper {
directive_type: String::new(),
date: "2024-01-01".to_string(),
filename: None,
lineno: None,
data: DirectiveData::Open(OpenData {
account: account.to_string(),
currencies: vec![],
booking: None,
metadata: vec![],
}),
}
}
#[test]
fn stub_wasm_plugin_round_trips_process() {
if std::env::var_os("CARGO_LLVM_COV").is_some() {
eprintln!(
"skip: running under cargo-llvm-cov; wasm32 fixture skipped by build.rs (Test job covers e2e)"
);
return;
}
let Some(wasm_path) = fixture_wasm_path() else {
assert!(
std::env::var_os("CI").is_none(),
"sample_stub.wasm sentinel missing in CI — wasm32-unknown-unknown \
target not installed, build.rs gracefully skipped. Install it via \
`targets: wasm32-unknown-unknown` on the rust-toolchain step in \
.github/workflows/ci.yml + quality.yml."
);
eprintln!(
"skip: sample_stub.wasm sentinel missing — wasm32-unknown-unknown not installed?"
);
return;
};
let bytes = std::fs::read(&wasm_path).expect("read stub wasm");
let mut manager = PluginManager::with_config(RuntimeConfig::default());
let index = manager
.load_bytes("sample-stub", &bytes)
.expect("load stub wasm");
let input = PluginInput {
directives: vec![
txn_wrapper("Coffee shop"),
open_wrapper("Assets:Bank:Checking"),
],
options: PluginOptions::default(),
config: None,
};
let output = manager.execute(index, &input).expect("execute round-trips");
assert!(
output.errors.is_empty(),
"stub plugin should not emit errors, got: {:?}",
output.errors,
);
assert_eq!(output.ops.len(), 2);
match &output.ops[0] {
PluginOp::Modify(i, wrapper) => {
assert_eq!(*i, 0);
let DirectiveData::Transaction(txn) = &wrapper.data else {
panic!("expected transaction in Modify, got {:?}", wrapper.data);
};
assert_eq!(txn.tags, vec!["stub-processed".to_string()]);
assert_eq!(txn.narration, "Coffee shop");
}
other => panic!("expected Modify on transaction, got {other:?}"),
}
match &output.ops[1] {
PluginOp::Keep(i) => assert_eq!(*i, 1),
other => panic!("expected Keep on non-transaction, got {other:?}"),
}
}