weavatrix-parse 0.3.3

Dependency-free source tokenizer and structural extractor for repository intelligence
Documentation
use super::extract;
use crate::facts::DeclarationKind;

#[test]
fn blocks_declare_the_objects_the_rest_of_the_file_addresses() {
    let source = "resource \"aws_s3_bucket\" \"logs\" {\n\
         \x20 bucket = \"my-logs\"\n\
         }\n\
         variable \"region\" { default = \"eu-west-1\" }\n\
         data \"aws_ami\" \"ubuntu\" { most_recent = true }\n\
         output \"bucket_arn\" { value = \"x\" }\n";
    let declared = extract(source)
        .declarations
        .into_iter()
        .map(|item| (item.name, item.kind))
        .collect::<Vec<_>>();
    assert_eq!(
        declared,
        [
            ("aws_s3_bucket.logs".to_owned(), DeclarationKind::Resource),
            ("variable.region".to_owned(), DeclarationKind::Variable),
            ("data.aws_ami.ubuntu".to_owned(), DeclarationKind::Resource),
            ("bucket_arn".to_owned(), DeclarationKind::Resource),
        ],
        "a resource is addressed by type and name together"
    );
}

#[test]
fn a_module_names_the_configuration_it_pulls_in() {
    let source = "module \"vpc\" {\n\
         \x20 source  = \"./modules/vpc\"\n\
         \x20 version = \"1.2.0\"\n\
         }\n\
         terraform {\n\
         \x20 required_providers {\n\
         \x20   aws = { source = \"hashicorp/aws\" }\n\
         \x20 }\n\
         }\n";
    let facts = extract(source);
    assert_eq!(
        facts
            .imports
            .iter()
            .map(|import| import.specifier.as_str())
            .collect::<Vec<_>>(),
        ["./modules/vpc", "hashicorp/aws"],
        "a local module and a registry provider are both dependencies"
    );
    assert!(
        facts
            .declarations
            .iter()
            .any(|item| item.name == "module.vpc")
    );
}

#[test]
fn interpolations_reference_the_objects_they_name() {
    let source = "resource \"aws_instance\" \"web\" {\n\
         \x20 ami           = data.aws_ami.ubuntu.id\n\
         \x20 subnet_id     = module.vpc.public_subnet\n\
         \x20 instance_type = var.instance_type\n\
         \x20 bucket        = aws_s3_bucket.logs.arn\n\
         }\n";
    let used = extract(source)
        .references
        .into_iter()
        .map(|reference| (reference.name, reference.owner))
        .collect::<Vec<_>>();
    assert_eq!(
        used,
        [
            (
                "data.aws_ami.ubuntu".to_owned(),
                Some("aws_instance.web".to_owned())
            ),
            ("module.vpc".to_owned(), Some("aws_instance.web".to_owned())),
            (
                "var.instance_type".to_owned(),
                Some("aws_instance.web".to_owned())
            ),
            (
                "aws_s3_bucket.logs".to_owned(),
                Some("aws_instance.web".to_owned())
            ),
        ],
        "every reference belongs to the resource that makes it"
    );
}

#[test]
fn a_comment_declares_nothing() {
    let source = "# resource \"aws_s3_bucket\" \"ghost\" {}\n\
         // module \"ghost\" { source = \"./nowhere\" }\n\
         /* variable \"ghost\" {} */\n\
         resource \"aws_vpc\" \"real\" {}\n";
    let facts = extract(source);
    assert_eq!(facts.declarations.len(), 1);
    assert!(facts.imports.is_empty());
}