#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resolved {
pub text: String,
pub from_file: bool,
}
pub fn resolve(raw: &str) -> Result<Resolved, String> {
if let Some(path) = raw.strip_prefix("file:") {
let text = std::fs::read_to_string(path)
.map_err(|e| format!("reading payload file '{path}': {e}"))?;
Ok(Resolved {
text,
from_file: true,
})
} else if let Some(rest) = raw.strip_prefix("text:") {
Ok(Resolved {
text: rest.to_string(),
from_file: false,
})
} else {
Ok(Resolved {
text: raw.to_string(),
from_file: false,
})
}
}
pub fn to_lines(payload: &str) -> Vec<String> {
if payload.is_empty() {
return Vec::new();
}
let body = payload.strip_suffix('\n').unwrap_or(payload);
body.split('\n').map(str::to_string).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unprefixed_values_pass_through_verbatim() {
for raw in ["plain", "http://x/y", "std::fmt", "a file: in the middle"] {
let r = resolve(raw).unwrap();
assert_eq!(r.text, raw);
assert!(!r.from_file);
}
}
#[test]
fn text_prefix_strips_once_and_only_once() {
assert_eq!(resolve("text:text:x").unwrap().text, "text:x");
assert_eq!(resolve("text:").unwrap().text, "");
}
#[test]
fn file_prefix_reads_exact_bytes() {
let dir = std::env::temp_dir().join("ct-payload-test");
std::fs::create_dir_all(&dir).unwrap();
let p = dir.join("payload.block");
std::fs::write(&p, " indented(line),\nnext\n").unwrap();
let r = resolve(&format!("file:{}", p.display())).unwrap();
assert!(r.from_file);
assert_eq!(r.text, " indented(line),\nnext\n");
}
#[test]
fn missing_payload_file_is_an_error() {
assert!(resolve("file:/no/such/payload").is_err());
}
}