use super::*;
#[test]
fn interpolate_returns_a_token_free_literal_verbatim() {
let out = interpolate_with("Bearer plain /tmp org-12345", |_| {
panic!("no token should be resolved")
})
.unwrap();
assert_eq!(out, "Bearer plain /tmp org-12345");
}
#[test]
fn interpolate_embeds_a_token_in_surrounding_literal() {
let out = interpolate_with(
"Bearer ${cmd:vault kv get -field=token secret/data/github}!",
|t| {
assert_eq!(
t,
&InterpToken::Cmd("vault kv get -field=token secret/data/github".into())
);
Ok("RESOLVED".to_string())
},
)
.unwrap();
assert_eq!(out, "Bearer RESOLVED!");
}
#[test]
fn interpolate_handles_multiple_tokens_of_every_scheme() {
let out = interpolate_with("${env:A}/${file:/p}/${X}", |t| {
Ok(match t {
InterpToken::Env(v) => format!("E<{v}>"),
InterpToken::File(p) => format!("F<{p}>"),
InterpToken::Cmd(c) => format!("C<{c}>"),
})
})
.unwrap();
assert_eq!(out, "E<A>/F</p>/E<X>");
}
#[test]
fn classify_token_maps_schemes_and_leaves_unrecognized_verbatim() {
assert_eq!(
classify_token("VAR").unwrap(),
InterpToken::Env("VAR".into())
);
assert_eq!(
classify_token("env:VAR").unwrap(),
InterpToken::Env("VAR".into())
);
assert_eq!(
classify_token("file:~/.secrets/x").unwrap(),
InterpToken::File("~/.secrets/x".into())
);
assert_eq!(
classify_token("cmd:vault kv get -field=token secret/x").unwrap(),
InterpToken::Cmd("vault kv get -field=token secret/x".into())
);
assert!(classify_token("bogus:thing").is_none());
assert!(classify_token("VAR:-https://api.example.com").is_none());
assert!(classify_token(".field").is_none());
assert!(classify_token("1abc").is_none());
assert!(classify_token("a b").is_none());
assert_eq!(
classify_token("_MY_TOKEN2").unwrap(),
InterpToken::Env("_MY_TOKEN2".into())
);
}
#[test]
fn interpolate_passes_unrecognized_tokens_through_verbatim() {
let never = |_: &InterpToken| -> Result<String> { panic!("must not resolve") };
assert_eq!(
interpolate_with("${API_BASE:-https://api.example.com}", never).unwrap(),
"${API_BASE:-https://api.example.com}"
);
assert_eq!(interpolate_with("${.field}", never).unwrap(), "${.field}");
let out = interpolate_with("${env:A}-${x:y}", |t| {
Ok(match t {
InterpToken::Env(v) => format!("E<{v}>"),
_ => unreachable!(),
})
})
.unwrap();
assert_eq!(out, "E<A>-${x:y}");
}
#[test]
fn interpolate_double_dollar_escapes_a_literal_dollar_brace() {
let never = |_: &InterpToken| -> Result<String> { panic!("must not resolve") };
assert_eq!(
interpolate_with("price $${cmd:evil}", never).unwrap(),
"price ${cmd:evil}"
);
assert_eq!(interpolate_with("$${VAR}", never).unwrap(), "${VAR}");
let out = interpolate_with("$5 then ${env:A}", |t| match t {
InterpToken::Env(v) => Ok(format!("<{v}>")),
_ => unreachable!(),
})
.unwrap();
assert_eq!(out, "$5 then <A>");
}
#[test]
fn interpolate_missing_reference_fails_loudly_not_empty() {
let err = interpolate_with("${env:MISSING}", |_| {
Err(NewtError::Config("environment variable not set".into()))
})
.unwrap_err();
assert!(format!("{err}").contains("not set"));
}
#[test]
fn interpolate_unterminated_token_errors_without_leaking_the_value() {
let err = interpolate_with("sk-live-DEADBEEF ${", |_| Ok("x".into())).unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("unterminated"), "{msg}");
assert!(
!msg.contains("sk-live-DEADBEEF"),
"the raw value leaked into the error: {msg}"
);
}