kimun 0.13.0

Code metrics tool — health score, complexity, duplication, hotspots, ownership
use super::*;
use crate::ai::schema::tool_definitions;
use serde_json::json;
use std::path::PathBuf;

#[test]
fn build_args_no_named_uses_project_path() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({});
    let args = build_args(&input, &[], &project);
    assert_eq!(args, vec!["/tmp/project"]);
}

#[test]
fn build_args_with_named_integer() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({"top": 10});
    let args = build_args(&input, &["top"], &project);
    assert_eq!(args, vec!["--top", "10", "/tmp/project"]);
}

#[test]
fn build_args_with_named_string() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({"since": "6m"});
    let args = build_args(&input, &["since"], &project);
    assert_eq!(args, vec!["--since", "6m", "/tmp/project"]);
}

#[test]
fn build_args_ignores_missing_named() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({});
    let args = build_args(&input, &["top", "since"], &project);
    assert_eq!(args, vec!["/tmp/project"]);
}

#[test]
fn resolve_path_empty_returns_project() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({});
    assert_eq!(resolve_path(&input, &project), "/tmp/project");
}

#[test]
fn resolve_path_rejects_absolute_outside_project() {
    let project = std::env::current_dir().unwrap();
    let input = json!({"path": "/etc"});
    let result = resolve_path(&input, &project);
    assert_eq!(result, project.to_string_lossy());
}

#[test]
fn resolve_path_rejects_traversal() {
    let project = std::env::current_dir().unwrap();
    let input = json!({"path": "../../../../etc"});
    let result = resolve_path(&input, &project);
    assert_eq!(result, project.to_string_lossy());
}

#[test]
fn resolve_path_accepts_subdirectory() {
    let project = std::env::current_dir().unwrap();
    let input = json!({"path": "src"});
    let result = resolve_path(&input, &project);
    let expected = project.join("src").canonicalize().unwrap();
    assert_eq!(result, expected.to_string_lossy());
}

#[test]
fn resolve_path_nonexistent_falls_back() {
    let project = std::env::current_dir().unwrap();
    let input = json!({"path": "nonexistent_dir_xyz_12345"});
    let result = resolve_path(&input, &project);
    assert_eq!(result, project.to_string_lossy());
}

#[test]
fn execute_tool_unknown_returns_error() {
    let project = PathBuf::from("/tmp/project");
    let input = json!({});
    let result = execute_tool("km_unknown", &input, &project);
    assert!(result.starts_with("Unknown tool:"));
}

#[test]
fn tool_definitions_has_11_tools() {
    let defs = tool_definitions();
    assert_eq!(defs.len(), 11);
}

#[test]
fn tool_definitions_all_have_required_fields() {
    for def in tool_definitions() {
        assert!(def.get("name").is_some(), "missing name");
        assert!(def.get("description").is_some(), "missing description");
        assert!(def.get("input_schema").is_some(), "missing input_schema");
    }
}