mod web3_support;
use blazingly_json::json;
use weavatrix_rust::tools;
use web3_support::{dump, engine};
#[test]
fn deposit_indexed_mask_change_reaches_old_viem_consumers() {
let (_fixture, mut engine) = engine();
let inventory = tools::call(&mut engine, "web3_inventory", json!({})).unwrap();
let text = dump(&inventory);
assert!(text.contains("Deposit"), "{text}");
assert!(
text.contains("web3.consumer") || text.contains("decodeEventLog"),
"{text}"
);
assert_eq!(inventory["coverage"]["deployment"], "not_provided");
let events = engine
.state()
.graph()
.nodes()
.iter()
.filter(|node| node.kind.as_str() == "web3.consumer")
.count();
assert!(
events >= 2,
"both proven decodeEventLog sites must remain: {events}"
);
let impact = tools::call(
&mut engine,
"web3_impact",
json!({
"task": "change-event",
"baseline": "app/abis/Vault.json",
"candidate": "out/Vault.sol/Vault.json"
}),
)
.unwrap();
let report = dump(&impact);
assert!(report.contains("EVENT_LAYOUT_CHANGED"), "{report}");
assert_eq!(impact["changes"][0]["silent_misdecode"], true, "{report}");
assert!(
!report.contains("0x000000000000000000000000000000000000002a"),
"educational example must not be a computed witness: {report}"
);
assert!(report.contains("not_provided"), "{report}");
assert!(
!report.contains("deployed implementation was verified"),
"{report}"
);
}
#[test]
fn same_selector_does_not_merge_two_contracts() {
let (_fixture, engine) = engine();
let transfers = engine
.state()
.graph()
.nodes()
.iter()
.filter(|node| node.label == "transfer(address,uint256)")
.count();
assert_eq!(
transfers, 2,
"two contracts must keep separate transfer members"
);
}
#[test]
fn output_change_is_kept_when_selector_matches() {
let (_fixture, mut engine) = engine();
let left = engine
.state()
.graph()
.nodes()
.iter()
.find(|node| {
node.label == "transfer(address,uint256)"
&& node
.span
.as_ref()
.is_some_and(|span| span.file.contains("Other.json"))
})
.unwrap()
.id
.clone();
let impact = tools::call(
&mut engine,
"web3_impact",
json!({
"baseline": "contracts/Other.json",
"candidate": "contracts/Copy.json"
}),
)
.unwrap();
let text = dump(&impact);
assert!(text.contains("OUTPUT_CHANGED"), "{text}");
let context = tools::call(
&mut engine,
"web3_context",
json!({"label": left.as_str(), "task": "change-output"}),
)
.unwrap();
let context_text = dump(&context);
assert!(
context_text.contains("(bool)") || context_text.contains("web3.return"),
"{context_text}"
);
}
#[test]
fn unknown_spread_stays_unresolved() {
let (_fixture, engine) = engine();
let unresolved = engine.state().graph().nodes().iter().any(|node| {
node.kind.as_str() == "web3.consumer"
&& engine
.state()
.graph()
.nodes()
.iter()
.any(|domain| domain.label == "web3.unresolved:dynamic_or_spread")
});
assert!(unresolved, "spread after abi must not invent a target");
}
#[test]
fn package_manifest_is_not_an_abi() {
let (_fixture, engine) = engine();
assert!(
engine
.state()
.graph()
.nodes()
.iter()
.filter(|node| node.label == "web3-fixtures")
.all(|node| node.kind.as_str() != "web3.abi")
);
}