use crate::error::DotmaxError;
use crate::grid::BrailleGrid;
use crate::render::TerminalRenderer;
pub struct FrameBuffer {
front: BrailleGrid,
back: BrailleGrid,
}
impl FrameBuffer {
#[must_use]
pub fn new(width: usize, height: usize) -> Self {
Self {
front: BrailleGrid::new(width, height)
.expect("FrameBuffer: invalid grid dimensions"),
back: BrailleGrid::new(width, height)
.expect("FrameBuffer: invalid grid dimensions"),
}
}
#[must_use]
pub fn get_back_buffer(&mut self) -> &mut BrailleGrid {
&mut self.back
}
#[must_use]
pub const fn get_front_buffer(&self) -> &BrailleGrid {
&self.front
}
pub fn swap_buffers(&mut self) {
std::mem::swap(&mut self.front, &mut self.back);
}
pub fn render(&self, renderer: &mut TerminalRenderer) -> Result<(), DotmaxError> {
renderer.render(&self.front)
}
#[must_use]
pub const fn width(&self) -> usize {
self.front.width()
}
#[must_use]
pub const fn height(&self) -> usize {
self.front.height()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_creates_buffers_with_correct_dimensions() {
let buffer = FrameBuffer::new(80, 24);
assert_eq!(buffer.front.width(), 80);
assert_eq!(buffer.front.height(), 24);
assert_eq!(buffer.back.width(), 80);
assert_eq!(buffer.back.height(), 24);
}
#[test]
fn test_new_dimensions_1x1() {
let buffer = FrameBuffer::new(1, 1);
assert_eq!(buffer.width(), 1);
assert_eq!(buffer.height(), 1);
}
#[test]
fn test_new_dimensions_80x24() {
let buffer = FrameBuffer::new(80, 24);
assert_eq!(buffer.width(), 80);
assert_eq!(buffer.height(), 24);
}
#[test]
fn test_new_dimensions_200x50() {
let buffer = FrameBuffer::new(200, 50);
assert_eq!(buffer.width(), 200);
assert_eq!(buffer.height(), 50);
}
#[test]
fn test_get_back_buffer_returns_mutable_reference() {
let mut buffer = FrameBuffer::new(80, 24);
let back = buffer.get_back_buffer();
let result = back.set_dot(0, 0);
assert!(result.is_ok());
}
#[test]
fn test_back_buffer_modifications_dont_affect_front() {
let mut buffer = FrameBuffer::new(10, 10);
buffer.get_back_buffer().set_dot(0, 0).unwrap();
let front = buffer.get_front_buffer();
let pattern = front.cell_to_braille_char(0, 0).unwrap();
assert_eq!(pattern, '⠀', "Front buffer should be empty before swap");
}
#[test]
fn test_swap_buffers_exchanges_buffers() {
let mut buffer = FrameBuffer::new(10, 10);
buffer.get_back_buffer().set_dot(0, 0).unwrap();
let front_before = buffer.get_front_buffer().cell_to_braille_char(0, 0).unwrap();
assert_eq!(front_before, '⠀');
buffer.swap_buffers();
let front_after = buffer.get_front_buffer().cell_to_braille_char(0, 0).unwrap();
assert_ne!(front_after, '⠀', "Front should have content after swap");
}
#[test]
fn test_swap_buffers_double_swap_restores_original() {
let mut buffer = FrameBuffer::new(10, 10);
buffer.get_back_buffer().set_dot(0, 0).unwrap();
buffer.swap_buffers();
buffer.swap_buffers();
let back_char = buffer.get_back_buffer().cell_to_braille_char(0, 0).unwrap();
assert_ne!(back_char, '⠀', "Double swap should restore back buffer content");
}
#[test]
fn test_multiple_sequential_swaps() {
let mut buffer = FrameBuffer::new(10, 10);
buffer.get_back_buffer().set_dot(0, 0).unwrap();
buffer.swap_buffers();
assert_ne!(buffer.get_front_buffer().cell_to_braille_char(0, 0).unwrap(), '⠀');
buffer.get_back_buffer().set_dot(2, 0).unwrap();
buffer.swap_buffers();
assert_ne!(buffer.get_front_buffer().cell_to_braille_char(1, 0).unwrap(), '⠀');
buffer.swap_buffers();
assert_ne!(buffer.get_front_buffer().cell_to_braille_char(0, 0).unwrap(), '⠀');
}
#[test]
fn test_width_height_accessors() {
let buffer = FrameBuffer::new(100, 50);
assert_eq!(buffer.width(), 100);
assert_eq!(buffer.height(), 50);
}
#[test]
fn test_get_back_buffer_after_swap() {
let mut buffer = FrameBuffer::new(10, 10);
buffer.get_back_buffer().set_dot(0, 0).unwrap();
buffer.swap_buffers();
let new_back_char = buffer.get_back_buffer().cell_to_braille_char(0, 0).unwrap();
assert_eq!(new_back_char, '⠀', "New back buffer should be empty after swap");
}
#[test]
fn test_content_preservation_through_swap() {
let mut buffer = FrameBuffer::new(20, 20);
for i in 0..10 {
buffer.get_back_buffer().set_dot(i * 2, i * 4).unwrap();
}
buffer.swap_buffers();
for i in 0..10 {
let cell_x = i;
let cell_y = i;
let char_at_cell = buffer.get_front_buffer().cell_to_braille_char(cell_x, cell_y).unwrap();
assert_ne!(char_at_cell, '⠀', "Pattern should be preserved at ({}, {})", cell_x, cell_y);
}
}
}