//! A2-03 — `spec.correlation.tenantId` admission gate.
//!
//! `validate_tenant_id_for_subject_token` is a pure function (no env access,
//! no I/O) that rejects values which would either fan a NATS subject across
//! tenants or produce an unroutable wire string when substituted into a
//! `{tenantId}` subject template. Reserved chars: `.`, `*`, `>`, any
//! whitespace.

use cellos_core::error::CellosError;
use cellos_core::validate_tenant_id_for_subject_token;

#[test]
fn legitimate_tenant_id_is_accepted() {
    // Typical operator-supplied identifiers — alphanumerics with `-` / `_`.
    for ok in ["t-acme", "tenant_42", "TENANT-A", "abc123", "a"] {
        validate_tenant_id_for_subject_token(ok)
            .unwrap_or_else(|e| panic!("expected {ok:?} to validate, got {e}"));
    }
}

#[test]
fn dot_is_rejected_as_subject_token_separator() {
    let err = validate_tenant_id_for_subject_token("evil.tenant").expect_err("must reject");
    let CellosError::InvalidSpec(msg) = err else {
        panic!("expected InvalidSpec");
    };
    assert!(
        msg.contains("NATS-reserved char"),
        "message should mention NATS-reserved char, got: {msg}"
    );
    assert!(
        msg.contains("\"evil.tenant\""),
        "message should echo input, got: {msg}"
    );
}

#[test]
fn nats_wildcards_are_rejected() {
    for bad in ["foo*", "bar>", "*", ">"] {
        validate_tenant_id_for_subject_token(bad).expect_err(&format!("must reject {bad:?}"));
    }
}

#[test]
fn whitespace_is_rejected() {
    for bad in ["a b", "tab\tin", "newline\nhere", " leading", "trailing "] {
        validate_tenant_id_for_subject_token(bad).expect_err(&format!("must reject {bad:?}"));
    }
}

#[test]
fn empty_tenant_id_is_rejected() {
    let err = validate_tenant_id_for_subject_token("").expect_err("must reject empty");
    let CellosError::InvalidSpec(msg) = err else {
        panic!("expected InvalidSpec");
    };
    assert!(msg.contains("non-empty"), "got: {msg}");
}
