weavatrix-rust 2.16.2

Protocol-independent Rust repository intelligence: typed evidence graphs for impact, architecture, APIs, Git, n8n, Dify, Agent catalogs, Mermaid, and Web3 ABI
Documentation
mod n8n_support;

use blazingly_json::json;
use n8n_support::{Fixture, dump, engine, labels};
use weavatrix_rust::{Analyzer, SourceInput, tools};

#[test]
fn cyclic_workflow_is_not_an_infinite_execution_error() {
    let (_fixture, mut engine) = engine();
    let trace = tools::call(
        &mut engine,
        "n8n_trace",
        json!({"label": "Loop A", "depth": 8}),
    )
    .unwrap();
    let text = dump(&trace);
    assert!(!text.to_ascii_lowercase().contains("infinite"));
    assert_eq!(trace["cycle"], true);
    assert!(
        engine
            .state()
            .snapshot()
            .diagnostics
            .iter()
            .all(|item| !item.message.to_ascii_lowercase().contains("infinite"))
    );
}

#[test]
fn unknown_community_node_keeps_structure_and_marks_limits() {
    let (_fixture, mut engine) = engine();
    assert_eq!(labels(&engine, "Vendor Sync").len(), 1);
    let context = tools::call(&mut engine, "n8n_context", json!({"label": "Vendor Sync"})).unwrap();
    let text = dump(&context);
    assert!(
        text.contains("structure_only") || text.contains("unsupported") || text.contains("runtime"),
        "{text}"
    );
}

#[test]
fn missing_subworkflow_is_not_declared_deleted() {
    let (_fixture, mut engine) = engine();
    let inventory = tools::call(&mut engine, "n8n_inventory", json!({})).unwrap();
    let text = dump(&inventory);
    assert!(
        text.contains("wf-not-provided") || text.contains("subworkflow:database:wf-not-provided")
    );
    assert!(!text.to_ascii_lowercase().contains("deleted"));
    assert!(
        engine
            .state()
            .snapshot()
            .diagnostics
            .iter()
            .all(|item| !item.message.to_ascii_lowercase().contains("deleted"))
    );
    assert!(
        engine
            .state()
            .graph()
            .nodes()
            .iter()
            .any(|node| node.label == "subworkflow:no-wait")
    );
}

#[test]
fn historical_blobs_are_not_reread_from_the_worktree() {
    let fixture = Fixture::empty();
    let old = include_str!("fixtures/n8n/load-customer.json");
    fixture.write("workflows/load-customer.json", old);
    let snapshot = Analyzer::default()
        .analyze_sources(
            &fixture.root,
            "old",
            [SourceInput {
                path: "workflows/load-customer.json".into(),
                bytes: old.as_bytes().to_vec(),
                content_hash: None,
            }],
        )
        .unwrap();
    fixture.write(
        "workflows/load-customer.json",
        r#"{"id":"wf-load-customer","name":"NEW WORKTREE","nodes":[{"id":"x","name":"New","type":"n8n-nodes-base.noOp","typeVersion":1,"parameters":{}}],"connections":{}}"#,
    );
    assert!(
        snapshot
            .nodes
            .iter()
            .any(|node| node.label == "Fetch Record")
    );
    assert!(
        snapshot
            .nodes
            .iter()
            .all(|node| node.label != "NEW WORKTREE")
    );
    assert!(snapshot.nodes.iter().all(|node| node.label != "New"));
}

#[test]
fn secret_http_values_do_not_reach_default_context() {
    let (_fixture, mut engine) = engine();
    let context = tools::call(&mut engine, "n8n_context", json!({"label": "Paid API"})).unwrap();
    let text = dump(&context);
    assert!(!text.contains("super-secret"), "{text}");
    assert!(!text.contains("leaked-token"), "{text}");
    assert!(!text.contains("user:super-secret@"), "{text}");
    let inventory = tools::call(&mut engine, "n8n_inventory", json!({})).unwrap();
    let inventory_text = dump(&inventory);
    assert!(!inventory_text.contains("super-secret"));
    assert!(!inventory_text.contains("leaked-token"));
}

#[test]
fn clipboard_export_is_partial_not_full() {
    let (_fixture, engine) = engine();
    assert!(
        engine
            .state()
            .graph()
            .nodes()
            .iter()
            .any(|node| node.label == "completeness:partial")
    );
    assert!(
        engine
            .state()
            .snapshot()
            .diagnostics
            .iter()
            .any(|item| item.code == "n8n.partial")
    );
}

#[test]
fn invalid_n8n_shape_stays_visible_with_diagnostics() {
    let snapshot = Analyzer::default()
        .analyze_sources(
            std::env::current_dir().unwrap(),
            "invalid",
            [SourceInput {
                path: "workflows/broken.json".into(),
                bytes: br#"{"nodes":[{"id":1}],"connections":{"left":"right"}}"#.to_vec(),
                content_hash: None,
            }],
        )
        .unwrap();
    assert!(
        snapshot
            .diagnostics
            .iter()
            .any(|item| item.code == "n8n.invalid_workflow")
    );
}