use std::borrow::Cow;
use std::time::{SystemTime, UNIX_EPOCH};
pub fn escape_controls(s: &str) -> Cow<'_, str> {
if !s.chars().any(|c| c.is_control() && c != '\t' && c != '\n') {
return Cow::Borrowed(s);
}
let mut out = String::with_capacity(s.len());
for c in s.chars() {
match c {
'\t' | '\n' => out.push(c),
'\0' => out.push_str(r"\0"),
c if c.is_control() => out.extend(c.escape_default()),
c => out.push(c),
}
}
Cow::Owned(out)
}
pub fn format_timestamp_iso8601(timestamp: u64) -> String {
let Ok(timestamp) = i64::try_from(timestamp) else {
return format!("invalid-timestamp({timestamp})");
};
chrono::DateTime::from_timestamp(timestamp, 0)
.map(|dt| dt.format("%Y-%m-%dT%H:%M:%SZ").to_string())
.unwrap_or_else(|| format!("invalid-timestamp({timestamp})"))
}
pub fn now_iso8601() -> String {
format_timestamp_iso8601(epoch_now())
}
pub fn epoch_now() -> u64 {
std::env::var("WORKTRUNK_TEST_EPOCH")
.ok()
.and_then(|val| val.parse::<u64>().ok())
.unwrap_or_else(|| {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system clock before Unix epoch")
.as_secs()
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_epoch_now_returns_reasonable_timestamp() {
let now = epoch_now();
assert!(now > 1577836800, "epoch_now() should return current time");
}
#[test]
fn test_epoch_now_respects_test_epoch() {
if let Ok(epoch) = std::env::var("WORKTRUNK_TEST_EPOCH") {
let expected: u64 = epoch.parse().unwrap();
assert_eq!(epoch_now(), expected);
}
}
#[test]
fn test_format_timestamp_iso8601_u64_overflow() {
let too_large = (i64::MAX as u64) + 1;
let formatted = format_timestamp_iso8601(too_large);
assert!(formatted.starts_with("invalid-timestamp("));
}
#[test]
fn test_format_timestamp_iso8601_chrono_out_of_range() {
let chrono_out_of_range: u64 = 9_000_000_000_000; let formatted = format_timestamp_iso8601(chrono_out_of_range);
assert!(formatted.starts_with("invalid-timestamp("));
}
#[test]
fn escape_controls_borrows_clean_text() {
let out = escape_controls("plain text");
assert!(matches!(out, Cow::Borrowed(_)));
assert_eq!(out, "plain text");
}
#[test]
fn escape_controls_preserves_tab_and_newline() {
let out = escape_controls("a\tb\nc");
assert!(matches!(out, Cow::Borrowed(_)));
assert_eq!(out, "a\tb\nc");
}
#[test]
fn escape_controls_renders_nul_compactly() {
assert_eq!(
escape_controls("core.bare\0false\0core.filemode\0true"),
r"core.bare\0false\0core.filemode\0true"
);
}
#[test]
fn escape_controls_escapes_other_control_bytes() {
assert_eq!(escape_controls("a\x1bb"), r"a\u{1b}b");
assert_eq!(escape_controls("a\x07b"), r"a\u{7}b");
}
#[test]
fn escape_controls_is_idempotent() {
let once = escape_controls("x\0y\x1bz").into_owned();
assert_eq!(escape_controls(&once), once);
}
}