#![allow(dead_code)]
use std::ffi::OsString;
use std::path::PathBuf;
use std::sync::Mutex;
use assert_cmd::Command;
use tempfile::TempDir;
pub fn rusty_figlet_cmd() -> Command {
Command::cargo_bin("rusty-figlet").expect("rusty-figlet binary not built")
}
pub fn sandbox() -> (TempDir, PathBuf) {
let dir = tempfile::tempdir().expect("create tempdir");
let path = dir.path().to_path_buf();
(dir, path)
}
pub fn strip_for_snapshot(raw: &[u8]) -> Vec<u8> {
const FROM: &[u8] = b"figlet:";
const TO: &[u8] = b"rusty-figlet:";
let mut out = Vec::with_capacity(raw.len());
let mut i = 0;
while i < raw.len() {
if i + FROM.len() <= raw.len() && &raw[i..i + FROM.len()] == FROM {
if i >= b"rusty-".len() && &raw[i - b"rusty-".len()..i] == b"rusty-" {
out.push(raw[i]);
i += 1;
continue;
}
out.extend_from_slice(TO);
i += FROM.len();
} else {
out.push(raw[i]);
i += 1;
}
}
out
}
pub fn assert_bytes_equal(actual: &[u8], expected: &[u8]) {
if actual != expected {
let actual_repr = String::from_utf8_lossy(actual);
let expected_repr = String::from_utf8_lossy(expected);
panic!(
"byte mismatch:\nexpected ({} bytes):\n{expected_repr}\nactual ({} bytes):\n{actual_repr}",
expected.len(),
actual.len()
);
}
}
static ENV_LOCK: Mutex<()> = Mutex::new(());
pub struct EnvGuard {
key: OsString,
prior: Option<OsString>,
_lock: std::sync::MutexGuard<'static, ()>,
}
impl Drop for EnvGuard {
fn drop(&mut self) {
unsafe {
match self.prior.take() {
Some(prev) => std::env::set_var(&self.key, prev),
None => std::env::remove_var(&self.key),
}
}
}
}
pub fn env_guard(key: &str, value: Option<&str>) -> EnvGuard {
let lock = ENV_LOCK.lock().unwrap_or_else(|poison| poison.into_inner());
let key_os = OsString::from(key);
let prior = std::env::var_os(&key_os);
unsafe {
match value {
Some(v) => std::env::set_var(&key_os, v),
None => std::env::remove_var(&key_os),
}
}
EnvGuard {
key: key_os,
prior,
_lock: lock,
}
}
pub fn make_minimal_flf(height: u32, hardblank: char) -> Vec<u8> {
let mut out = String::new();
out.push_str(&format!(
"flf2a{hardblank} {height} {h} 8 0 2 0 0 7\n",
h = height
));
out.push_str("Minimal fixture font line 1\n");
out.push_str("Minimal fixture font line 2\n");
let endmark = '@';
for cp in 32..=126u32 {
let c = char::from_u32(cp).unwrap();
let cell = format!("{c}{pad}", pad = hardblank.to_string().repeat(7));
for row in 0..height {
let suffix = if row == height - 1 {
format!("{endmark}{endmark}")
} else {
endmark.to_string()
};
out.push_str(&cell);
out.push_str(&suffix);
out.push('\n');
}
}
for cp in [196u32, 214, 220, 228, 246, 252, 223] {
out.push_str(&format!("{cp:X} FIXTURE U+{cp:04X}\n"));
let cell = format!("X{pad}", pad = hardblank.to_string().repeat(7));
for row in 0..height {
let suffix = if row == height - 1 {
format!("{endmark}{endmark}")
} else {
endmark.to_string()
};
out.push_str(&cell);
out.push_str(&suffix);
out.push('\n');
}
}
out.into_bytes()
}
pub fn make_malformed_flf_bad_signature() -> Vec<u8> {
b"NOTflf2a$ 1 1 8 0 0\nbody\n".to_vec()
}
pub fn make_malformed_flf_truncated_header() -> Vec<u8> {
b"flf2a$ 1 1\n".to_vec()
}
pub fn make_malformed_flf_comment_mismatch() -> Vec<u8> {
b"flf2a$ 1 1 8 0 99\nonly one comment\n".to_vec()
}
pub fn make_malformed_flf_short_glyph() -> Vec<u8> {
b"flf2a$ 3 1 8 0 0\nrow1@@\n".to_vec()
}
pub fn make_malformed_flf_missing_endmark() -> Vec<u8> {
let mut out = b"flf2a$ 1 1 8 0 0\n".to_vec();
out.extend_from_slice(b"single@\n");
out
}
pub fn make_malformed_flf_codetag_divergence() -> Vec<u8> {
let mut bytes = make_minimal_flf(1, '$');
let text = String::from_utf8(bytes).expect("ascii fixture");
let mut lines: Vec<&str> = text.split('\n').collect();
while lines.len() > 1 && (lines.last() == Some(&"") || !lines.last().unwrap().ends_with("@@")) {
lines.pop();
}
let mut joined = lines.join("\n");
joined.push('\n');
joined = joined.replacen("flf2a$ 1 1 8 0 2 0 0 7", "flf2a$ 1 1 8 0 2 0 0 5", 1);
bytes = joined.into_bytes();
bytes
}
#[cfg(test)]
mod self_tests {
use super::*;
#[test]
fn minimal_flf_parses() {
let bytes = make_minimal_flf(1, '$');
let _ = bytes;
}
#[test]
fn strip_for_snapshot_substitutes_program_name() {
assert_eq!(
strip_for_snapshot(b"figlet: invalid option"),
b"rusty-figlet: invalid option".to_vec()
);
assert_eq!(
strip_for_snapshot(b"rusty-figlet: invalid option"),
b"rusty-figlet: invalid option".to_vec()
);
}
}