#[cfg(any(test, feature = "test-utils"))]
#[derive(Debug, Default, Clone)]
pub struct TestPrinter {
output: Vec<String>,
buffer: String,
}
#[cfg(any(test, feature = "test-utils"))]
impl TestPrinter {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn get_output(&self) -> String {
let mut result = self.buffer.clone();
for line in &self.output {
result.push_str(line);
}
result
}
#[must_use]
pub fn get_lines(&self) -> Vec<String> {
let mut result: Vec<String> = self.output.clone();
if !self.buffer.is_empty() {
result.push(self.buffer.clone());
}
result
}
#[must_use]
pub fn clear(self) -> Self {
Self {
output: Vec::new(),
buffer: String::new(),
}
}
pub fn has_line(&self, line: &str) -> bool {
self.get_lines().iter().any(|l| l.contains(line))
}
pub fn count_pattern(&self, pattern: &str) -> usize {
self.get_lines()
.iter()
.filter(|l| l.contains(pattern))
.count()
}
pub fn has_duplicate_consecutive_lines(&self) -> bool {
let lines = self.get_lines();
for i in 1..lines.len() {
if lines[i] == lines[i - 1] && !lines[i].is_empty() {
return true;
}
}
false
}
pub fn find_duplicate_consecutive_lines(&self) -> Vec<(usize, String)> {
let mut duplicates = Vec::new();
let lines = self.get_lines();
for i in 1..lines.len() {
if lines[i] == lines[i - 1] && !lines[i].is_empty() {
duplicates.push((i - 1, lines[i - 1].clone()));
}
}
duplicates
}
pub fn get_stats(&self) -> (usize, usize) {
let lines = self.get_lines();
let char_count: usize = lines.iter().map(String::len).sum();
(lines.len(), char_count)
}
#[must_use]
pub fn write_text(self, text: &str) -> Self {
let mut new_buffer = self.buffer.clone();
new_buffer.push_str(text);
let mut new_output = self.output.clone();
while let Some(newline_pos) = new_buffer.find('\n') {
let line = new_buffer.drain(..=newline_pos).collect::<String>();
new_output.push(line);
}
Self {
output: new_output,
buffer: new_buffer,
}
}
fn write_raw(&mut self, buf: &[u8]) -> io::Result<()> {
let s =
std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
self.buffer.push_str(s);
while let Some(newline_pos) = self.buffer.find('\n') {
let line = self.buffer.drain(..=newline_pos).collect::<String>();
self.output.push(line);
}
Ok(())
}
#[must_use]
pub fn flush(self) -> Self {
let mut new_output = self.output;
if !self.buffer.is_empty() {
new_output.push(self.buffer.clone());
}
Self {
output: new_output,
buffer: String::new(),
}
}
}
#[cfg(any(test, feature = "test-utils"))]
impl std::io::Write for TestPrinter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_raw(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
if !self.buffer.is_empty() {
self.output.push(self.buffer.clone());
self.buffer.clear();
}
Ok(())
}
}
#[cfg(any(test, feature = "test-utils"))]
impl Printable for TestPrinter {
fn is_terminal(&self) -> bool {
false
}
}