weavatrix-parse 0.3.5

Dependency-free source tokenizer and structural extractor for repository intelligence
Documentation
use super::*;

#[test]
fn extracts_typed_proto3_rpc_and_streaming_with_exact_spans() {
    let source = concat!(
        "syntax = \"proto3\";\n",
        "package shop.v1;\n",
        "message Outer { message Request {} }\n",
        "message Reply {}\n",
        "service Inventory { rpc Watch(stream Outer.Request) returns (stream Reply); }\n",
    );
    let facts = extract(source);
    assert!(facts.diagnostics.is_empty());
    assert!(
        !facts.contracts.is_empty(),
        "advertised valid proto3 cannot fall back to empty facts"
    );
    assert!(facts.contracts.iter().any(|fact| {
        matches!(
            fact.kind,
            ContractKind::ProtobufRpc {
                ref input,
                ref output,
                client_streaming: true,
                server_streaming: true,
            } if input == "Outer.Request" && output == "Reply"
        ) && &source[fact.span.start..fact.span.end] == "Watch"
    }));
    assert!(facts.contracts.iter().any(|fact| {
        fact.name == "Outer.Request"
            && fact.owner.as_deref() == Some("Outer")
            && fact.kind == ContractKind::ProtobufMessage
    }));
}

#[test]
fn extracts_proto2_and_supported_editions_service_contracts() {
    for (source, option_import) in [
        (
            concat!(
                "syntax = \"proto2\";\n",
                "message Request { optional string id = 1; }\n",
                "message Reply {}\n",
                "service Legacy { rpc Get(Request) returns (Reply); }\n",
            ),
            None,
        ),
        (
            concat!(
                "edition = \"2023\";\n",
                "message Request { string id = 1; }\n",
                "message Reply {}\n",
                "service EditionApi { rpc Get(Request) returns (Reply); }\n",
            ),
            None,
        ),
        (
            concat!(
                "edition = \"2024\";\n",
                "import option \"custom_options.proto\";\n",
                "message Request { string id = 1; }\n",
                "message Reply {}\n",
                "service EditionApi { rpc Get(Request) returns (Reply); }\n",
            ),
            Some("custom_options.proto"),
        ),
    ] {
        let facts = extract(source);
        assert!(facts.diagnostics.is_empty(), "{facts:?}");
        assert!(facts.contracts.iter().any(|fact| {
            matches!(fact.kind, ContractKind::ProtobufRpc { .. }) && fact.name == "Get"
        }));
        if let Some(option_import) = option_import {
            let import = facts
                .imports
                .iter()
                .find(|import| import.specifier == option_import)
                .expect("Edition 2024 option import");
            assert!(!import.reexport);
            assert_eq!(
                source[import.span.start..import.span.end].trim_matches(['"', '\'']),
                option_import
            );
        }
    }
}

#[test]
fn invalid_dialects_fail_closed_with_exact_diagnostics() {
    for source in [
        "syntax = \"proto1\"; message Legacy {}",
        "edition = \"future\"; message Legacy {}",
        "edition = \"2022\"; message Legacy {}",
        "edition = \"2026\"; message Legacy {}",
        "package misplaced; syntax = \"proto3\"; message Legacy {}",
        "syntax = \"proto3\"; edition = \"2023\"; message Legacy {}",
    ] {
        let facts = extract(source);
        assert!(facts.contracts.is_empty());
        assert_eq!(facts.diagnostics.len(), 1);
        assert_eq!(facts.diagnostics[0].code, "protobuf.invalid_dialect");
        let span = facts.diagnostics[0].span;
        assert_eq!((span.line, span.column), (1, 1));
        assert!(!source[span.start..span.end].is_empty());
    }
}

#[test]
fn field_names_that_match_declaration_keywords_keep_earlier_rpcs() {
    let source = concat!(
        "syntax = \"proto3\";\n",
        "package demo;\n",
        "import \"google/protobuf/empty.proto\";\n",
        "service Test {\n",
        "  rpc SayHello (HelloRequest) returns (HelloReply) {}\n",
        "}\n",
        "message HelloReply {\n",
        "  string message = 1;\n",
        "  string service = 2;\n",
        "}\n",
        "enum Status {\n",
        "  package = 0;\n",
        "  import = 1;\n",
        "}\n",
        "message Log {\n",
        "  enum Kind { service = 0; }\n",
        "  message Nested { string enum = 1; }\n",
        "  string message = 5;\n",
        "}\n",
    );
    let facts = extract(source);
    assert!(facts.diagnostics.is_empty(), "{facts:?}");
    assert!(facts.contracts.iter().any(|fact| {
        matches!(fact.kind, ContractKind::ProtobufRpc { .. }) && fact.name == "SayHello"
    }));
    assert!(facts.contracts.iter().any(|fact| {
        fact.name == "Log.Nested"
            && fact.owner.as_deref() == Some("Log")
            && fact.kind == ContractKind::ProtobufMessage
    }));
    assert_eq!(
        facts
            .contracts
            .iter()
            .filter(|fact| fact.kind == ContractKind::ProtobufPackage)
            .count(),
        1
    );
    assert!(!facts.contracts.iter().any(|fact| fact.name == "message"));
}

#[test]
fn malformed_supported_dialects_fail_closed() {
    for source in [
        "syntax = \"proto3\"; service Broken {",
        "syntax = \"proto3\"; package bad message X {};",
        "syntax = \"proto3\"; service Bad { rpc Call(Request) (Reply); }",
    ] {
        let facts = extract(source);
        assert!(facts.contracts.is_empty());
        assert_eq!(facts.diagnostics.len(), 1);
        assert_eq!(facts.diagnostics[0].code, "protobuf.syntax_error");
        let span = facts.diagnostics[0].span;
        assert!(
            span.end > span.start,
            "diagnostic must identify the exact offending token"
        );
        assert!(!source[span.start..span.end].is_empty());
    }
}