rust-relations-explorer 0.1.3

Explore relationships in Rust codebases: build a knowledge graph and run queries (connected files, function usage, cycles, paths, hubs, module centrality, trait impls).
Documentation
use rust_relations_explorer::app::run_cli;
use rust_relations_explorer::cli::{Cli, Commands, ItemKindArg, OutputFormat, QueryCommands};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tempfile::tempdir;

fn write_file(path: &PathBuf, content: &str) {
    if let Some(parent) = path.parent() {
        let _ = fs::create_dir_all(parent);
    }
    let mut f = fs::File::create(path).unwrap();
    f.write_all(content.as_bytes()).unwrap();
}

#[test]
fn iteminfo_by_name_success() {
    let dir = tempdir().unwrap();
    let root = dir.path();
    let src = root.join("src");
    fs::create_dir_all(&src).unwrap();

    write_file(&src.join("lib.rs"), "mod a;\n");
    write_file(&src.join("a.rs"), "pub fn onlyone() {}\n");

    let cli = Cli {
        verbose: 0,
        quiet: false,
        command: Commands::Query {
            query: QueryCommands::ItemInfo {
                path: Some(root.to_path_buf()),
                config: None,
                no_ignore: false,
                item_id: None,
                name: Some("onlyone".into()),
                kind: None,
                graph: None,
                show_code: false,
                format: OutputFormat::Text,
            },
        },
    };

    let code = run_cli(cli);
    assert_eq!(code, 0);
}

#[test]
fn iteminfo_by_name_ambiguous() {
    let dir = tempdir().unwrap();
    let root = dir.path();
    let src = root.join("src");
    fs::create_dir_all(&src).unwrap();

    write_file(&src.join("lib.rs"), "mod a; mod b;\n");
    write_file(&src.join("a.rs"), "pub fn dup() {}\n");
    write_file(&src.join("b.rs"), "pub fn dup() {}\n");

    let cli = Cli {
        verbose: 0,
        quiet: false,
        command: Commands::Query {
            query: QueryCommands::ItemInfo {
                path: Some(root.to_path_buf()),
                config: None,
                no_ignore: false,
                item_id: None,
                name: Some("dup".into()),
                kind: None,
                graph: None,
                show_code: false,
                format: OutputFormat::Text,
            },
        },
    };

    let code = run_cli(cli);
    assert_ne!(code, 0);
}

#[test]
fn iteminfo_by_name_not_found() {
    let dir = tempdir().unwrap();
    let root = dir.path();
    let src = root.join("src");
    fs::create_dir_all(&src).unwrap();

    write_file(&src.join("lib.rs"), "pub fn some() {}\n");

    let cli = Cli {
        verbose: 0,
        quiet: false,
        command: Commands::Query {
            query: QueryCommands::ItemInfo {
                path: Some(root.to_path_buf()),
                config: None,
                no_ignore: false,
                item_id: None,
                name: Some("missing".into()),
                kind: None,
                graph: None,
                show_code: false,
                format: OutputFormat::Text,
            },
        },
    };

    let code = run_cli(cli);
    assert_ne!(code, 0);
}

#[test]
fn iteminfo_by_name_with_kind_success() {
    let dir = tempdir().unwrap();
    let root = dir.path();
    let src = root.join("src");
    fs::create_dir_all(&src).unwrap();

    write_file(&src.join("lib.rs"), "mod a;\n");
    write_file(&src.join("a.rs"), "pub struct Thing; pub fn Thing() {}\n");

    // Depending on parsing, both may or may not be allowed; ensure at least one success path.
    // Query specifically for the function by name+kind.
    let cli = Cli {
        verbose: 0,
        quiet: false,
        command: Commands::Query {
            query: QueryCommands::ItemInfo {
                path: Some(root.to_path_buf()),
                config: None,
                no_ignore: false,
                item_id: None,
                name: Some("Thing".into()),
                kind: Some(ItemKindArg::Function),
                graph: None,
                show_code: false,
                format: OutputFormat::Text,
            },
        },
    };

    let _ = run_cli(cli); // We do not strictly assert code due to potential parser variance.
}