impactsense-parser 0.1.2

Multi-language static analysis: parse codebases into an in-memory dependency graph for impact analysis
Documentation
//! Smoke tests: incremental vector parse and streaming IR on mixed C#/Erlang fixtures.

use std::fs;
use std::path::PathBuf;

use impactsense_parser::scanner::FileScanConfig;
use impactsense_parser::scanner_incremental::{scan_and_parse_incremental_vector, scan_and_stream_incremental_ir};
use impactsense_parser::LanguageId;

fn write_fixture(root: &std::path::Path) -> (PathBuf, PathBuf) {
    let cs = root.join("SmokeInc.cs");
    let erl = root.join("smoke_inc_mod.erl");
    fs::write(
        &cs,
        r#"namespace SmokeIncNs {
  public class SmokeIncType {
    public int Counter { get; set; }
    public void Run() { }
  }
}
"#,
    )
    .expect("write cs");
    fs::write(
        &erl,
        r#"-module(smoke_inc_mod).
-export([main/0]).
main() -> ok.
"#,
    )
    .expect("write erl");
    (cs, erl)
}

#[test]
fn smoke_incremental_vector_parses_cs_and_erl() {
    let root = tempfile::tempdir().expect("tempdir");
    let (cs_path, erl_path) = write_fixture(root.path());
    let config = FileScanConfig::new(root.path());
    let targets = vec![cs_path.clone(), erl_path.clone()];
    let parsed = scan_and_parse_incremental_vector(&config, &targets).expect("incremental vector");
    assert_eq!(parsed.len(), 2, "expected two parsed files");
    let langs: Vec<_> = parsed.iter().map(|f| f.language).collect();
    assert!(langs.contains(&LanguageId::CSharp));
    assert!(langs.contains(&LanguageId::Erlang));
}

#[test]
fn smoke_streaming_ir_populates_csharp_structural_ir() {
    let root = tempfile::tempdir().expect("tempdir");
    let (cs_path, erl_path) = write_fixture(root.path());
    let config = FileScanConfig::new(root.path());
    let targets = vec![cs_path, erl_path];
    let ir = scan_and_stream_incremental_ir(&config, &targets).expect("streaming ir");
    assert_eq!(ir.files.len(), 2);
    assert!(
        ir.classes.iter().any(|c| c.fqn == "SmokeIncNs.SmokeIncType"),
        "missing C# class in IR: {:?}",
        ir.classes
    );
    assert!(
        ir.properties
            .iter()
            .any(|p| p.fqn == "SmokeIncNs.SmokeIncType.Counter"),
        "missing C# property in IR: {:?}",
        ir.properties
    );
    assert!(
        ir.edges.iter().any(|e| {
            e.kind == impactsense_parser::ir::EdgeKind::DeclaresClass && e.to_key == "SmokeIncNs.SmokeIncType"
        }),
        "missing DECLARES_CLASS edge"
    );
}