hyperstack-macros 0.6.7

Proc-macros for defining HyperStack streams
Documentation
mod support;

use support::{cargo_toml, escape_path, macro_manifest_dir, TempCrate};

fn run_compile_failure(name: &str, source: &str, extra_files: &[(&str, &str)], expected: &[&str]) {
    let manifest_dir = macro_manifest_dir();
    let temp_crate = TempCrate::new(
        "phase0-dynamic",
        name,
        cargo_toml(
            name,
            &[format!(
                "hyperstack-macros = {{ path = \"{}\" }}",
                escape_path(&manifest_dir)
            )],
        ),
        source,
        extra_files,
    );

    let output = temp_crate.cargo_check();

    assert!(
        !output.status.success(),
        "expected cargo check to fail for {name}"
    );

    let stderr = String::from_utf8_lossy(&output.stderr);
    for needle in expected {
        assert!(
            stderr.contains(needle),
            "expected stderr for {name} to contain {needle:?}, got:\n{stderr}"
        );
    }
}

fn run_idl_compile_failure(name: &str, module_body: &str, expected: &[&str]) {
    let source = r#"use hyperstack_macros::hyperstack;

#[hyperstack(idl = "fixture/minimal.json")]
mod broken {
__MODULE_BODY__
}

fn main() {}
"#
    .replace("__MODULE_BODY__", module_body);

    let minimal_idl = r#"{
  "name": "ore",
  "instructions": [],
  "accounts": [],
  "types": [],
  "events": [],
  "errors": [],
  "constants": []
}
"#;

    run_compile_failure(
        name,
        &source,
        &[("fixture/minimal.json", minimal_idl)],
        expected,
    );
}

#[test]
fn after_instruction_attribute_is_hard_error() {
    run_idl_compile_failure(
        "after_instruction_attribute_is_hard_error",
        "    #[after_instruction(ore_sdk::instructions::Initialize)]\n    fn bad() {}",
        &[
            "Direct use of #[after_instruction] is not allowed.",
            "Use declarative macros instead:",
        ],
    );
}

#[test]
fn resolve_key_attribute_is_hard_error() {
    run_idl_compile_failure(
        "resolve_key_attribute_is_hard_error",
        "    #[resolve_key(strategy = \"direct_field\")]\n    struct Marker;",
        &["#[resolve_key] requires 'account' parameter"],
    );
}

#[test]
fn register_pda_attribute_is_hard_error() {
    run_idl_compile_failure(
        "register_pda_attribute_is_hard_error",
        "    #[register_pda(instruction = ore_sdk::instructions::Initialize)]\n    struct Marker;",
        &["#[register_pda] requires 'pda_field' parameter"],
    );
}

#[test]
fn manual_pdas_block_is_hard_error() {
    run_idl_compile_failure(
        "manual_pdas_block_is_hard_error",
        "    #[entity(name = \"Thing\")]\n    struct Marker {}\n\n    pdas! {\n        missing_program {\n            broken = [literal(\"broken\")];\n        }\n    }",
        &["unknown program 'missing_program' in pdas! block"],
    );
}