Lines
99.19 %
Functions
100 %
Branches
use chrono::Utc;
use finance::split::Split;
use finance::transaction::Transaction;
use scripting::executor::ScriptExecutor;
use scripting::format::{ContextType, EntityType, Operation};
use scripting::parser::EntityData;
use scripting::serializer::MemorySerializer;
use uuid::Uuid;
const TEST_WASM: &[u8] = include_bytes!("../../web/static/wasm/groceries_markup.wasm");
#[test]
fn test_groceries_script_tags_splits() {
let executor = ScriptExecutor::new();
let tx = Transaction {
id: Uuid::new_v4(),
post_date: Utc::now(),
enter_date: Utc::now(),
};
let account1_id = Uuid::new_v4();
let account2_id = Uuid::new_v4();
let commodity_id = Uuid::new_v4();
let split1 = Split {
tx_id: tx.id,
account_id: account1_id,
commodity_id,
value_num: -5000,
value_denom: 100,
reconcile_state: None,
reconcile_date: None,
lot_id: None,
let split2 = Split {
account_id: account2_id,
value_num: 5000,
let mut serializer = MemorySerializer::new();
serializer.set_context(ContextType::EntityCreate, EntityType::Transaction);
// Transaction with 2 splits and 1 tag
let tx_idx = serializer.add_transaction_from(&tx, true, 2, 1, false);
serializer.set_primary(tx_idx);
let split1_idx = serializer.add_split_from(&split1, tx_idx as i32);
let split2_idx = serializer.add_split_from(&split2, tx_idx as i32);
// Add "note" = "groceries" tag to transaction
serializer.add_tag(
Uuid::new_v4().into_bytes(),
tx_idx as i32,
false,
"note",
"groceries",
);
let input = serializer.finalize(4096);
println!("Input size: {} bytes", input.len());
let entities = executor
.execute(TEST_WASM, &input, Some(4096))
.expect("Execution failed");
println!("Output entities: {entities:?}");
assert_eq!(
entities.len(),
2,
"Expected 2 output entities (category tags for each split)"
for (i, entity) in entities.iter().enumerate() {
assert_eq!(entity.entity_type, EntityType::Tag);
assert_eq!(entity.operation, Operation::Create);
if let EntityData::Tag { name, value } = &entity.data {
assert_eq!(name, "category", "Tag {i} name mismatch");
assert_eq!(value, "groceries", "Tag {i} value mismatch");
} else {
panic!("Expected Tag entity data, got {:?}", entity.data);
}
let parent_indices: Vec<i32> = entities.iter().map(|e| e.parent_idx).collect();
assert!(
parent_indices.contains(&(split1_idx as i32)),
"Missing tag for split1"
parent_indices.contains(&(split2_idx as i32)),
"Missing tag for split2"
fn test_groceries_script_skips_non_groceries() {
// Transaction with tag "note" = "other" (not groceries)
let tx_idx = serializer.add_transaction_from(&tx, true, 0, 1, false);
"other",
entities.is_empty(),
"Expected 0 output entities for non-groceries transaction"
fn test_groceries_script_skips_non_transaction() {
serializer.set_context(ContextType::EntityCreate, EntityType::Account);
let account_id = [1u8; 16];
let parent_account_id = [0u8; 16];
let account_idx = serializer.add_account(
account_id,
-1,
true,
parent_account_id,
"Test Account",
"Assets:Test Account",
0,
serializer.set_primary(account_idx);
"Expected 0 output entities for Account"
fn test_groceries_script_skips_no_note_tag() {
// Transaction without any tags
let tx_idx = serializer.add_transaction_from(&tx, true, 0, 0, false);
"Expected 0 output entities for transaction without note tag"