use std::path::Path;
const MAX_FILE_SIZE: u64 = 5 * 1024 * 1024;
pub fn read(path: &Path) -> anyhow::Result<String> {
let metadata = std::fs::metadata(path)?;
if metadata.len() > MAX_FILE_SIZE {
anyhow::bail!(
"file too large: {} bytes (max {MAX_FILE_SIZE})",
metadata.len()
);
}
let bytes = std::fs::read(path)?;
String::from_utf8(bytes).map_err(|e| anyhow::anyhow!("file is not valid UTF-8: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn happy_path() {
let mut f = NamedTempFile::new().unwrap();
writeln!(f, "hello world").unwrap();
let content = read(f.path()).unwrap();
assert!(content.contains("hello world"));
}
#[test]
fn missing_file() {
let err = read(Path::new("/tmp/newt-tools-does-not-exist-xyz")).unwrap_err();
let io = err
.downcast_ref::<std::io::Error>()
.expect("missing file should return an io error");
assert_eq!(io.kind(), std::io::ErrorKind::NotFound);
}
#[test]
fn non_utf8() {
let mut f = NamedTempFile::new().unwrap();
f.write_all(&[0xFF, 0xFE]).unwrap();
let err = read(f.path()).unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("UTF-8"), "expected UTF-8 error, got: {msg}");
}
#[test]
fn empty_file() {
let f = NamedTempFile::new().unwrap();
let content = read(f.path()).unwrap();
assert!(content.is_empty());
}
#[test]
fn small_file_within_limit() {
let mut f = NamedTempFile::new().unwrap();
let data = "a".repeat(1024); write!(f, "{data}").unwrap();
let content = read(f.path()).unwrap();
assert_eq!(content.len(), 1024);
}
}