relay-knowledge 1.1.14

Graph-database-based knowledge graph project.
Documentation
use super::*;

#[test]
fn initial_map_routes_the_repository_software_model() {
    let map = KnowledgeMap::initial("now".to_owned());

    let route = map
        .routes
        .iter()
        .find(|route| route.topic == "software-model")
        .expect("software-model route should exist");
    let source = map
        .sources
        .iter()
        .find(|source| source.id == "repository-software-model")
        .expect("repository software-model source should exist");

    assert_eq!(route.source_order, ["repository-software-model"]);
    assert_eq!(source.kind, KnowledgeMapSourceKind::Repo);
    assert_eq!(source.uri, ".");
    assert_eq!(source.source_scope.as_deref(), Some("repo"));
    map.validate().expect("initial map should validate");
}

#[test]
fn initial_map_routes_the_repository_business_glossary() {
    let map = KnowledgeMap::initial("now".to_owned());
    let route = map
        .routes
        .iter()
        .find(|route| route.topic == "business-knowledge")
        .unwrap();
    let source = map
        .sources
        .iter()
        .find(|source| source.id == "repository-business-glossary")
        .unwrap();

    assert_eq!(route.source_order, ["repository-business-glossary"]);
    assert_eq!(source.kind, KnowledgeMapSourceKind::File);
    assert_eq!(source.uri, ".knowledge/business-glossary.yaml");
    assert_eq!(source.source_scope.as_deref(), Some("repo"));
}

#[test]
fn business_route_upgrade_is_idempotent_and_rejects_reserved_drift() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.remove_source("repository-business-glossary").unwrap();
    assert!(map.ensure_business_knowledge_route().unwrap());
    assert!(!map.ensure_business_knowledge_route().unwrap());

    map.sources
        .iter_mut()
        .find(|source| source.id == "repository-business-glossary")
        .unwrap()
        .uri = "other.yaml".to_owned();
    assert!(
        map.validate()
            .unwrap_err()
            .to_string()
            .contains("reserved source")
    );
}

#[test]
fn software_model_route_upgrade_is_idempotent() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.remove_source("repository-software-model")
        .expect("legacy fixture should remove the new default");

    assert!(
        map.ensure_software_model_route()
            .expect("legacy map should upgrade")
    );
    assert!(
        !map.ensure_software_model_route()
            .expect("upgraded map should remain valid")
    );
}

#[test]
fn rejects_conflicting_reserved_software_model_source() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.sources
        .iter_mut()
        .find(|source| source.id == "repository-software-model")
        .expect("reserved source should exist")
        .uri = "docs/generated-model.yaml".to_owned();

    let error = map.validate().expect_err("reserved source must not drift");

    assert!(error.to_string().contains("reserved source"));
    assert!(error.to_string().contains("uri '.'"));
}

#[test]
fn adds_source_and_route() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.add_source(
        KnowledgeMapSource::new(
            "build-cargo".to_owned(),
            "build".to_owned(),
            KnowledgeMapSourceKind::Config,
            "Cargo.toml".to_owned(),
            Some("repo".to_owned()),
            None,
        )
        .expect("source should parse"),
    )
    .expect("source should add");

    assert!(map.topics.iter().any(|topic| topic.id == "build"));
    assert_eq!(
        map.routes
            .iter()
            .find(|route| route.topic == "build")
            .unwrap()
            .source_order,
        ["build-cargo"]
    );
    map.validate().expect("map should validate");
}

#[test]
fn keeps_multiple_sources_under_one_topic() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    for (id, uri) in [
        (
            "cli-reference",
            "docs/zh/01-user-guide/03-cli-command-reference.md",
        ),
        (
            "cli-skill",
            "skills/relay-knowledge-cli/references/knowledge-map-workflows.md",
        ),
    ] {
        map.add_source(
            KnowledgeMapSource::new(
                id.to_owned(),
                "cli".to_owned(),
                KnowledgeMapSourceKind::Doc,
                uri.to_owned(),
                Some("docs".to_owned()),
                None,
            )
            .expect("source should parse"),
        )
        .expect("source should add");
    }

    assert_eq!(
        map.routes
            .iter()
            .find(|route| route.topic == "cli")
            .unwrap()
            .source_order,
        ["cli-reference".to_owned(), "cli-skill".to_owned()]
    );
    assert_eq!(
        map.sources
            .iter()
            .filter(|source| source.topic == "cli")
            .count(),
        2
    );
}

#[test]
fn moving_source_prunes_old_topic_route() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.add_source(
        KnowledgeMapSource::new(
            "shared-doc".to_owned(),
            "build".to_owned(),
            KnowledgeMapSourceKind::Doc,
            "docs/build.md".to_owned(),
            None,
            None,
        )
        .expect("source should parse"),
    )
    .expect("source should add");

    map.update_source(KnowledgeMapChange {
        id: "shared-doc".to_owned(),
        topic: Some("cli".to_owned()),
        kind: None,
        uri: None,
        source_scope: None,
        description: None,
    })
    .expect("source should move");

    assert!(
        map.routes
            .iter()
            .find(|route| route.topic == "build")
            .is_none_or(|route| route.source_order.is_empty())
    );
    assert_eq!(
        map.routes
            .iter()
            .find(|route| route.topic == "cli")
            .expect("new route should exist")
            .source_order,
        ["shared-doc".to_owned()]
    );
}

#[test]
fn rejects_duplicate_sources_and_bad_routes() {
    let mut map = KnowledgeMap::initial("now".to_owned());
    let source = KnowledgeMapSource::new(
        "docs".to_owned(),
        "architecture".to_owned(),
        KnowledgeMapSourceKind::Doc,
        "docs/README.md".to_owned(),
        None,
        None,
    )
    .expect("source should parse");
    map.add_source(source.clone())
        .expect("first add should work");
    assert!(map.add_source(source).is_err());

    map.routes
        .iter_mut()
        .find(|route| route.topic == "architecture")
        .unwrap()
        .source_order
        .push("missing".to_owned());
    assert!(map.validate().is_err());
}

#[test]
fn rejects_duplicate_route_topics() {
    let mut map = routed_map();
    map.routes.push(KnowledgeMapRoute {
        topic: "architecture".to_owned(),
        source_order: Vec::new(),
        fallback: None,
    });

    let error = map.validate().expect_err("duplicate route should fail");

    assert!(error.to_string().contains("route topics must be unique"));
}

#[test]
fn rejects_duplicate_sources_inside_route_order() {
    let mut map = routed_map();
    map.routes
        .iter_mut()
        .find(|route| route.topic == "architecture")
        .unwrap()
        .source_order
        .push("docs".to_owned());

    let error = map
        .validate()
        .expect_err("duplicate route source should fail");

    assert!(error.to_string().contains("repeats source 'docs'"));
}

#[test]
fn rejects_unrouted_sources() {
    let mut map = routed_map();
    map.sources.push(
        KnowledgeMapSource::new(
            "unrouted".to_owned(),
            "architecture".to_owned(),
            KnowledgeMapSourceKind::Doc,
            "docs/unrouted.md".to_owned(),
            None,
            None,
        )
        .expect("source should parse"),
    );

    let error = map.validate().expect_err("unrouted source should fail");

    assert!(
        error
            .to_string()
            .contains("source 'unrouted' is not routed")
    );
}

#[test]
fn rejects_invalid_history_contracts() {
    let mut map = routed_map();
    map.history[0].summary.clear();
    assert!(map.validate().is_err());

    let mut map = routed_map();
    map.history.push(KnowledgeMapHistoryEntry {
        version: 3,
        action: "source.add".to_owned(),
        actor: "cli".to_owned(),
        summary: "Skipped a version.".to_owned(),
    });
    map.map_version = 3;
    let error = map.validate().expect_err("skipped history should fail");
    assert!(error.to_string().contains("contiguous"));

    let mut map = routed_map();
    map.map_version = 2;
    let error = map
        .validate()
        .expect_err("mismatched map version should fail");
    assert!(error.to_string().contains("must match map_version 2"));
}

fn routed_map() -> KnowledgeMap {
    let mut map = KnowledgeMap::initial("now".to_owned());
    map.add_source(
        KnowledgeMapSource::new(
            "docs".to_owned(),
            "architecture".to_owned(),
            KnowledgeMapSourceKind::Doc,
            "docs/README.md".to_owned(),
            None,
            None,
        )
        .expect("source should parse"),
    )
    .expect("source should add");
    map
}