#![cfg(test)]
#![allow(dead_code)]
#![allow(unused_imports)]
use anyhow::Result;
use std::any::Any;
use std::sync::{Arc, Mutex};
use text_document_common::undo_redo::{CompositeCommand, UndoRedoCommand, UndoRedoManager};
struct TestCommand {
counter: Arc<Mutex<i32>>,
value: i32,
}
impl TestCommand {
fn new(counter: Arc<Mutex<i32>>, value: i32) -> Self {
TestCommand { counter, value }
}
}
impl UndoRedoCommand for TestCommand {
fn undo(&mut self) -> Result<()> {
let mut counter = self.counter.lock().unwrap();
*counter -= self.value;
Ok(())
}
fn redo(&mut self) -> Result<()> {
let mut counter = self.counter.lock().unwrap();
*counter += self.value;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
struct MergeableCommand {
counter: Arc<Mutex<i32>>,
value: i32,
}
impl MergeableCommand {
fn new(counter: Arc<Mutex<i32>>, value: i32) -> Self {
MergeableCommand { counter, value }
}
}
impl UndoRedoCommand for MergeableCommand {
fn undo(&mut self) -> Result<()> {
let mut counter = self.counter.lock().unwrap();
*counter -= self.value;
Ok(())
}
fn redo(&mut self) -> Result<()> {
let mut counter = self.counter.lock().unwrap();
*counter += self.value;
Ok(())
}
fn can_merge(&self, other: &dyn UndoRedoCommand) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn merge(&mut self, other: &dyn UndoRedoCommand) -> bool {
if let Some(other_cmd) = other.as_any().downcast_ref::<Self>() {
self.value += other_cmd.value;
return true;
}
false
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[test]
fn test_new() {
let manager = UndoRedoManager::new();
assert!(!manager.can_undo(None));
assert!(!manager.can_redo(None));
}
#[test]
fn test_add_command() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
manager.add_command(Box::new(TestCommand::new(counter.clone(), 5)));
assert!(manager.can_undo(None));
assert!(!manager.can_redo(None));
assert_eq!(*counter.lock().unwrap(), 0); }
#[test]
fn test_undo() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd = TestCommand::new(counter.clone(), 5);
cmd.redo().unwrap();
manager.add_command(Box::new(cmd));
}
assert_eq!(*counter.lock().unwrap(), 5);
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 0);
assert!(!manager.can_undo(None));
assert!(manager.can_redo(None));
}
#[test]
fn test_redo() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd = TestCommand::new(counter.clone(), 5);
cmd.redo().unwrap();
manager.add_command(Box::new(cmd));
}
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 0);
manager.redo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 5);
assert!(manager.can_undo(None));
assert!(!manager.can_redo(None));
}
#[test]
fn test_undo_redo_multiple() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
assert_eq!(*counter.lock().unwrap(), 8);
manager.undo(None).unwrap(); assert_eq!(*counter.lock().unwrap(), 5);
manager.undo(None).unwrap(); assert_eq!(*counter.lock().unwrap(), 0);
manager.redo(None).unwrap(); assert_eq!(*counter.lock().unwrap(), 5);
manager.redo(None).unwrap(); assert_eq!(*counter.lock().unwrap(), 8);
}
#[test]
fn test_composite_command() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
manager.begin_composite(None);
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
manager.end_composite();
assert_eq!(*counter.lock().unwrap(), 8);
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 0);
manager.redo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 8);
}
#[test]
fn test_empty_composite() {
let mut manager = UndoRedoManager::new();
manager.begin_composite(None);
manager.end_composite();
assert!(!manager.can_undo(None));
}
#[test]
fn test_nested_composite() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
manager.begin_composite(None);
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
}
manager.begin_composite(None);
{
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
manager.end_composite();
{
let mut cmd3 = TestCommand::new(counter.clone(), 2);
cmd3.redo().unwrap();
manager.add_command(Box::new(cmd3));
}
manager.end_composite();
assert_eq!(*counter.lock().unwrap(), 10);
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 0);
}
#[test]
fn test_command_merging() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd1 = MergeableCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
}
{
let mut cmd2 = MergeableCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
assert_eq!(*counter.lock().unwrap(), 8);
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 0);
manager.redo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 8);
}
#[test]
fn test_redo_stack_cleared_on_new_command() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
}
manager.undo(None).unwrap();
assert!(manager.can_redo(None));
{
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
assert!(!manager.can_redo(None));
assert_eq!(*counter.lock().unwrap(), 3);
}
#[test]
fn test_undo_with_empty_stack() {
let mut manager = UndoRedoManager::new();
let result = manager.undo(None);
assert!(result.is_ok());
}
#[test]
fn test_redo_with_empty_stack() {
let mut manager = UndoRedoManager::new();
let result = manager.redo(None);
assert!(result.is_ok());
}
#[test]
fn test_clear() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
assert_eq!(*counter.lock().unwrap(), 8);
assert!(manager.can_undo(None));
assert!(!manager.can_redo(None));
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 5);
assert!(manager.can_undo(None));
assert!(manager.can_redo(None));
manager.clear_all_stacks();
assert!(!manager.can_undo(None));
assert!(!manager.can_redo(None));
{
let mut cmd = TestCommand::new(counter.clone(), 10);
cmd.redo().unwrap();
manager.add_command(Box::new(cmd));
}
assert!(manager.can_undo(None));
assert!(!manager.can_redo(None));
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 5); assert!(!manager.can_undo(None));
assert!(manager.can_redo(None));
}
#[test]
fn test_clear_with_in_progress_composite() {
let counter = Arc::new(Mutex::new(0));
let mut manager = UndoRedoManager::new();
manager.begin_composite(None);
{
let mut cmd1 = TestCommand::new(counter.clone(), 5);
cmd1.redo().unwrap();
manager.add_command(Box::new(cmd1));
let mut cmd2 = TestCommand::new(counter.clone(), 3);
cmd2.redo().unwrap();
manager.add_command(Box::new(cmd2));
}
assert_eq!(*counter.lock().unwrap(), 8);
manager.clear_all_stacks();
assert!(!manager.can_undo(None));
assert!(!manager.can_redo(None));
{
let mut cmd = TestCommand::new(counter.clone(), 10);
cmd.redo().unwrap();
manager.add_command(Box::new(cmd));
}
assert!(manager.can_undo(None));
manager.undo(None).unwrap();
assert_eq!(*counter.lock().unwrap(), 8); assert!(!manager.can_undo(None));
assert!(manager.can_redo(None));
}