use base64::{Engine as _, engine::general_purpose::STANDARD};
use std::io::{self, Write};
use super::backend::{ClipboardError, ClipboardResult};
pub fn copy(text: &str) -> ClipboardResult {
let sequence = encode_osc52(text);
io::stdout()
.write_all(sequence.as_bytes())
.map_err(|_| ClipboardError::WriteError)?;
io::stdout().flush().map_err(|_| ClipboardError::WriteError)
}
pub fn encode_osc52(text: &str) -> String {
let encoded = STANDARD.encode(text);
format!("\x1b]52;c;{}\x07", encoded)
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_osc52_encoding_roundtrip(text in ".*") {
let encoded = encode_osc52(&text);
assert!(encoded.starts_with("\x1b]52;c;"), "Should start with OSC 52 prefix");
assert!(encoded.ends_with("\x07"), "Should end with BEL terminator");
let prefix = "\x1b]52;c;";
let suffix = "\x07";
let base64_part = &encoded[prefix.len()..encoded.len() - suffix.len()];
let decoded_bytes = STANDARD.decode(base64_part)
.expect("Base64 decoding should succeed");
let decoded_text = String::from_utf8(decoded_bytes)
.expect("Decoded bytes should be valid UTF-8");
assert_eq!(decoded_text, text, "Round-trip should preserve original text");
}
}
#[test]
fn test_encode_osc52_simple() {
let result = encode_osc52("hello");
assert_eq!(result, "\x1b]52;c;aGVsbG8=\x07");
}
#[test]
fn test_encode_osc52_empty() {
let result = encode_osc52("");
assert_eq!(result, "\x1b]52;c;\x07");
}
#[test]
fn test_encode_osc52_unicode() {
let result = encode_osc52("日本語");
assert!(result.starts_with("\x1b]52;c;"));
assert!(result.ends_with("\x07"));
let base64_part = &result[7..result.len() - 1];
let decoded = STANDARD.decode(base64_part).unwrap();
assert_eq!(String::from_utf8(decoded).unwrap(), "日本語");
}
}