测试代码

测试代码1

  1 using DefaultUnDo;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading.Tasks;
  7 
  8 namespace TestDemo
  9 {
 10     class Program
 11     {
 12         static void Main()
 13         {
 14             Console.WriteLine("========== DefaultUnDo 完整测试(.NET 4.8 修正版) ==========\n");
 15 
 16             RunTest("基本值类型操作", TestBasicValue);
 17             RunTest("Do 便捷重载(设置值)", TestDoSetter);
 18             RunTest("字符串操作", TestString);
 19             RunTest("集合操作", TestCollection);
 20             RunTest("多个连续操作", TestMultipleOperations);
 21             RunTest("边界情况 - 无操作可撤销/重做", TestBoundary);
 22             RunTest("Clear 清理历史", TestClear);
 23             RunTest("复杂对象操作", TestComplexObject);
 24             RunTest("嵌套操作", TestNestedOperation);
 25             RunTest("状态查询", TestStateQuery);
 26             RunTest("事务操作(Transaction)", TestTransaction);
 27             RunTest("事务嵌套与混合", TestTransactionNested);
 28 
 29             Console.WriteLine("\n========== 所有测试通过 ==========");
 30             Console.ReadKey();
 31         }
 32 
 33         // ----- 辅助方法 -----
 34         static void RunTest(string name, Action testAction)
 35         {
 36             Console.WriteLine($"▶ {name}");
 37             try
 38             {
 39                 testAction();
 40                 Console.WriteLine($"  ✓ 通过\n");
 41             }
 42             catch (Exception ex)
 43             {
 44                 Console.WriteLine($"  ✗ 失败: {ex.Message}\n");
 45                 throw;
 46             }
 47         }
 48 
 49         static void AssertEqual<T>(T expected, T actual, string message = "")
 50         {
 51             if (!EqualityComparer<T>.Default.Equals(expected, actual))
 52             {
 53                 throw new Exception($"断言失败: {message},期望值: {expected},实际值: {actual}");
 54             }
 55         }
 56 
 57         static void AssertTrue(bool condition, string message = "")
 58         {
 59             if (!condition)
 60             {
 61                 throw new Exception($"断言失败: {message}");
 62             }
 63         }
 64 
 65         static void AssertFalse(bool condition, string message = "")
 66         {
 67             if (condition)
 68             {
 69                 throw new Exception($"断言失败: {message}");
 70             }
 71         }
 72 
 73         // 断言调用 action 会抛出指定类型的异常,并可验证异常消息包含指定片段
 74         static void AssertThrows<TException>(Action action, string expectedMessagePart = null) where TException : Exception
 75         {
 76             try
 77             {
 78                 action();
 79                 throw new Exception($"预期抛出 {typeof(TException).Name},但未抛出任何异常");
 80             }
 81             catch (TException ex)
 82             {
 83                 if (!string.IsNullOrEmpty(expectedMessagePart) && !ex.Message.Contains(expectedMessagePart))
 84                 {
 85                     throw new Exception($"异常消息应包含 \"{expectedMessagePart}\",实际为: {ex.Message}");
 86                 }
 87                 // 符合预期
 88             }
 89             catch (Exception ex)
 90             {
 91                 throw new Exception($"预期抛出 {typeof(TException).Name},但抛出了 {ex.GetType().Name}: {ex.Message}");
 92             }
 93         }
 94 
 95         // ========== 测试1: 基本值类型操作 ==========
 96         static void TestBasicValue()
 97         {
 98             IUnDoManager manager = new UnDoManager();
 99             int number = 42;
100 
101             manager.Do(
102                 () => number = 100,
103                 () => number = 42
104             );
105             AssertEqual(100, number, "执行后 number 应为 100");
106 
107             manager.Undo();
108             AssertEqual(42, number, "撤销后 number 应为 42");
109 
110             manager.Redo();
111             AssertEqual(100, number, "重做后 number 应为 100");
112         }
113 
114         // ========== 测试2: Do 便捷重载 ==========
115         static void TestDoSetter()
116         {
117             IUnDoManager manager = new UnDoManager();
118             int score = 10;
119 
120             manager.Do(v => score = v, 99, score);
121             AssertEqual(99, score, "执行后 score 应为 99");
122 
123             manager.Undo();
124             AssertEqual(10, score, "撤销后 score 应为 10");
125 
126             manager.Redo();
127             AssertEqual(99, score, "重做后 score 应为 99");
128         }
129 
130         // ========== 测试3: 字符串操作 ==========
131         static void TestString()
132         {
133             IUnDoManager manager = new UnDoManager();
134             string name = "Alice";
135 
136             manager.Do(
137                 () => name = "Bob",
138                 () => name = "Alice"
139             );
140             AssertEqual("Bob", name, "执行后 name 应为 Bob");
141 
142             manager.Undo();
143             AssertEqual("Alice", name, "撤销后 name 应为 Alice");
144 
145             manager.Redo();
146             AssertEqual("Bob", name, "重做后 name 应为 Bob");
147         }
148 
149         // ========== 测试4: 集合操作 ==========
150         static void TestCollection()
151         {
152             IUnDoManager manager = new UnDoManager();
153             var list = new List<string> { "A", "B", "C" };
154 
155             string itemToAdd = "D";
156             manager.Do(
157                 () => list.Add(itemToAdd),
158                 () => list.RemoveAt(list.Count - 1)
159             );
160             AssertEqual(4, list.Count, "添加后列表长度应为 4");
161             AssertEqual("D", list[3], "最后一个元素应为 D");
162 
163             manager.Undo();
164             AssertEqual(3, list.Count, "撤销后列表长度应为 3");
165             AssertEqual("C", list[2], "最后一个元素应为 C");
166 
167             manager.Redo();
168             AssertEqual(4, list.Count, "重做后列表长度应为 4");
169         }
170 
171         // ========== 测试5: 多个连续操作 ==========
172         static void TestMultipleOperations()
173         {
174             IUnDoManager manager = new UnDoManager();
175             int a = 1, b = 2;
176 
177             manager.Do(() => a = 10, () => a = 1);
178             manager.Do(() => b = 20, () => b = 2);
179 
180             AssertEqual(10, a, "a 应为 10");
181             AssertEqual(20, b, "b 应为 20");
182 
183             manager.Undo();
184             AssertEqual(10, a, "撤销一次后 a 应为 10");
185             AssertEqual(2, b, "撤销一次后 b 应为 2");
186 
187             manager.Undo();
188             AssertEqual(1, a, "撤销两次后 a 应为 1");
189             AssertEqual(2, b, "撤销两次后 b 应为 2");
190 
191             manager.Redo();
192             AssertEqual(10, a, "重做一次后 a 应为 10");
193             AssertEqual(2, b, "重做一次后 b 应为 2");
194 
195             manager.Redo();
196             AssertEqual(10, a, "重做两次后 a 应为 10");
197             AssertEqual(20, b, "重做两次后 b 应为 20");
198         }
199 
200         // ========== 测试6: 边界情况 - 无操作可撤销/重做 ==========
201         static void TestBoundary()
202         {
203             IUnDoManager manager = new UnDoManager();
204 
205             AssertFalse(manager.CanUndo, "初始 CanUndo 应为 false");
206             AssertFalse(manager.CanRedo, "初始 CanRedo 应为 false");
207 
208             // 调用 Undo 应抛出 InvalidOperationException
209             AssertThrows<InvalidOperationException>(() => manager.Undo(), "No operation to undo");
210             AssertThrows<InvalidOperationException>(() => manager.Redo(), "No operation to redo");
211 
212             // 再检查状态仍为 false
213             AssertFalse(manager.CanUndo, "操作后 CanUndo 仍应为 false");
214             AssertFalse(manager.CanRedo, "操作后 CanRedo 仍应为 false");
215         }
216 
217         // ========== 测试7: Clear 清理历史 ==========
218         static void TestClear()
219         {
220             IUnDoManager manager = new UnDoManager();
221             int x = 5;
222 
223             manager.Do(() => x = 100, () => x = 5);
224             AssertEqual(100, x, "执行后 x 应为 100");
225             AssertTrue(manager.CanUndo, "Clear 前 CanUndo 应为 true");
226 
227             manager.Clear();
228             AssertEqual(100, x, "Clear 后 x 仍为 100");
229             AssertFalse(manager.CanUndo, "Clear 后 CanUndo 应为 false");
230 
231             // Clear 后调用 Undo 应抛出异常
232             AssertThrows<InvalidOperationException>(() => manager.Undo(), "No operation to undo");
233             // 确保 x 未变
234             AssertEqual(100, x, "Clear 后 Undo 不应改变 x");
235         }
236 
237         // ========== 测试8: 复杂对象操作 ==========
238         static void TestComplexObject()
239         {
240             IUnDoManager manager = new UnDoManager();
241             var person = new Person { Name = "John", Age = 30 };
242 
243             string oldName = person.Name;
244             int oldAge = person.Age;
245 
246             manager.Do(
247                 () => { person.Name = "Jane"; person.Age = 25; },
248                 () => { person.Name = oldName; person.Age = oldAge; }
249             );
250             AssertEqual("Jane", person.Name, "执行后 Name 应为 Jane");
251             AssertEqual(25, person.Age, "执行后 Age 应为 25");
252 
253             manager.Undo();
254             AssertEqual("John", person.Name, "撤销后 Name 应为 John");
255             AssertEqual(30, person.Age, "撤销后 Age 应为 30");
256 
257             manager.Redo();
258             AssertEqual("Jane", person.Name, "重做后 Name 应为 Jane");
259             AssertEqual(25, person.Age, "重做后 Age 应为 25");
260         }
261 
262         // ========== 测试9: 嵌套操作 ==========
263         static void TestNestedOperation()
264         {
265             IUnDoManager manager = new UnDoManager();
266             int counter = 0;
267 
268             manager.Do(() =>
269             {
270                 counter++;
271                 // 在操作内部再执行一个操作
272                 manager.Do(() => counter += 10, () => counter -= 10);
273             }, () => counter = 0);
274 
275             AssertEqual(11, counter, "执行后 counter 应为 11");
276 
277             // 一次撤销会回退整个嵌套操作,直接回到初始状态
278             manager.Undo();
279             AssertEqual(0, counter, "撤销一次后 counter 应为 0");
280 
281             // 重做会重放整个嵌套操作
282             manager.Redo();
283             AssertEqual(11, counter, "重做后 counter 应为 11");
284         }
285 
286         // ========== 测试10: 状态查询 ==========
287         static void TestStateQuery()
288         {
289             IUnDoManager manager = new UnDoManager();
290 
291             AssertFalse(manager.CanUndo, "初始 CanUndo 应为 false");
292             AssertFalse(manager.CanRedo, "初始 CanRedo 应为 false");
293 
294             int testVal = 0;
295             manager.Do(() => testVal = 1, () => testVal = 0);
296             AssertTrue(manager.CanUndo, "执行后 CanUndo 应为 true");
297             AssertFalse(manager.CanRedo, "执行后 CanRedo 应为 false");
298 
299             manager.Undo();
300             AssertFalse(manager.CanUndo, "撤销后 CanUndo 应为 false");
301             AssertTrue(manager.CanRedo, "撤销后 CanRedo 应为 true");
302 
303             manager.Redo();
304             AssertTrue(manager.CanUndo, "重做后 CanUndo 应为 true");
305             AssertFalse(manager.CanRedo, "重做后 CanRedo 应为 false");
306         }
307 
308         // ========== 测试11: 事务操作 ==========
309         static void TestTransaction()
310         {
311             IUnDoManager manager = new UnDoManager();
312             int value = 0;
313 
314             // 使用事务将多个操作合并为一个原子操作
315             using (IUnDoTransaction transaction = manager.BeginTransaction())
316             {
317                 manager.Do(() => value = 10, () => value = 0);
318                 manager.Do(() => value = 20, () => value = 10);
319                 // 提交事务,将操作合并到历史中
320                 transaction.Commit();
321             }
322 
323             AssertEqual(20, value, "事务执行后 value 应为 20");
324             AssertTrue(manager.CanUndo, "事务提交后应可撤销");
325 
326             // 一次撤销应回退整个事务
327             manager.Undo();
328             AssertEqual(0, value, "撤销事务后 value 应为 0");
329             AssertFalse(manager.CanUndo, "撤销后 CanUndo 应为 false");
330 
331             // 重做应重放整个事务
332             manager.Redo();
333             AssertEqual(20, value, "重做事后 value 应为 20");
334         }
335 
336         // ========== 测试12: 事务嵌套与混合 ==========
337         static void TestTransactionNested()
338         {
339             IUnDoManager manager = new UnDoManager();
340             int a = 0, b = 0;
341 
342             // 外层事务
343             using (IUnDoTransaction outer = manager.BeginTransaction())
344             {
345                 manager.Do(() => a = 5, () => a = 0);
346 
347                 // 内层事务
348                 using (IUnDoTransaction inner = manager.BeginTransaction())
349                 {
350                     manager.Do(() => b = 10, () => b = 0);
351                     inner.Commit(); // 内层提交
352                 }
353 
354                 outer.Commit(); // 外层提交
355             }
356 
357             AssertEqual(5, a, "a 应为 5");
358             AssertEqual(10, b, "b 应为 10");
359             AssertTrue(manager.CanUndo, "应可撤销");
360 
361             // 一次撤销回退所有
362             manager.Undo();
363             AssertEqual(0, a, "撤销后 a 应为 0");
364             AssertEqual(0, b, "撤销后 b 应为 0");
365         }
366     }
367 
368     // 辅助类
369     public class Person
370     {
371         public string Name { get; set; }
372         public int Age { get; set; }
373     }
374 }
View Code

 

测试代码2

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using DefaultUnDo;

namespace TestDemo1
{
    internal static class Program
    {
        private static int _passed, _failed;

        private static void Main()
        {
            Console.WriteLine("================ DefaultUnDo 降级后功能验证 ================");
            Console.WriteLine();

            Run("1. 基本 Do/Undo/Redo", Test_BasicDoUndoRedo);
            Run("2. Version 属性变更通知", Test_VersionNotify);
            Run("3. GroupUnDo (params 数组)", Test_GroupUnDo);
            Run("4. ValueUnDo<T>", Test_ValueUnDo);
            Run("5. UnDoField<T>", Test_UnDoField);
            Run("6. 事务 Commit (多操作合并)", Test_TransactionCommit);
            Run("7. 事务回滚 (不 Commit 自动撤销)", Test_TransactionRollback);
            Run("8. 嵌套事务", Test_NestedTransaction);
            Run("9. 集合扩展 IList.AsUnDo", Test_IListAsUnDo);
            Run("10. 集合扩展 ICollection.DoClear", Test_DoClear);
            Run("11. 集合扩展 ISet.AsUnDo (IntersectWith)", Test_ISetAsUnDo);
            Run("12. 集合扩展 IDictionary.AsUnDo", Test_IDictAsUnDo);
            Run("13. 合并 TryMerge (ValueUnDo 连续合并)", Test_Merge);
            Run("14. Clear 清空历史", Test_Clear);
            Run("15. 参数校验 (null 抛异常)", Test_ArgumentNullChecks);
            Run("16. struct 值相等性", Test_StructEquality);

            Console.WriteLine();
            Console.WriteLine($"================ 汇总:通过 {_passed},失败 {_failed} ================");
            if (_failed > 0) { Console.WriteLine("❌ 存在失败,库有问题!"); Console.ReadKey(); Environment.Exit(1); }
            else { Console.WriteLine("✅ 全部通过,降级改造未破坏功能。"); Console.ReadKey(); }
        }

        private static void Run(string title, Action test)
        {
            Console.WriteLine($"[{title}]");
            try { test(); }
            catch (Exception ex) { Check("未抛异常完成", false, $"抛出 {ex.GetType().Name}: {ex.Message}"); }
            Console.WriteLine();
        }

        private static void Check(string name, bool ok, string detail = "")
        {
            if (ok) { _passed++; Console.WriteLine($"   [PASS] {name}"); }
            else { _failed++; Console.WriteLine($"   [FAIL] {name}  {detail}"); }
        }

        // 1. 基本 Do/Undo/Redo
        private static void Test_BasicDoUndoRedo()
        {
            var m = new UnDoManager();
            int v = 0;
            var cmd = new UnDo(() => v = 1, () => v = 0);
            m.Do(cmd);
            Check("Do 后 v=1", v == 1, $"v={v}");
            m.Undo();
            Check("Undo 后 v=0", v == 0, $"v={v}");
            m.Redo();
            Check("Redo 后 v=1", v == 1, $"v={v}");
            Check("CanUndo", m.CanUndo);
            Check("CanRedo=false (Redo后无可Redo)", !m.CanRedo);
        }

        // 2. Version 属性变更通知(覆盖 field 关键字改后备字段)
        private static void Test_VersionNotify()
        {
            var m = new UnDoManager();
            int notifies = 0;
            ((INotifyPropertyChanged)m).PropertyChanged += (s, e) => notifies++;
            int v = m.Version;
            m.Do(new UnDo(() => { }, () => { }));
            Check("Do 后触发 PropertyChanged", notifies > 0, $"notifies={notifies}");
            Check("Version 递增", m.Version == v + 1, $"期望{v + 1} 实际{m.Version}");
            notifies = 0;
            m.Undo();
            Check("Undo 触发 PropertyChanged", notifies > 0, $"notifies={notifies}");
        }

        // 3. GroupUnDo(覆盖 params IUnDo[] 改动)
        private static void Test_GroupUnDo()
        {
            var m = new UnDoManager();
            var log = new List<int>();
            var g = new GroupUnDo(
                new UnDo(() => log.Add(1), () => log.Add(-1)),
                new UnDo(() => log.Add(2), () => log.Add(-2)),
                new UnDo(() => log.Add(3), () => log.Add(-3)));
            m.Do(g);
            Check("Group Do 顺序 1,2,3", log.SequenceEqual(new[] { 1, 2, 3 }), string.Join(",", log));
            log.Clear();
            m.Undo();
            Check("Group Undo 倒序 -3,-2,-1", log.SequenceEqual(new[] { -3, -2, -1 }), string.Join(",", log));
            log.Clear();
            m.Redo();
            Check("Group Redo 顺序 1,2,3", log.SequenceEqual(new[] { 1, 2, 3 }), string.Join(",", log));
        }

        // 4. ValueUnDo<T>
        private static void Test_ValueUnDo()
        {
            var m = new UnDoManager();
            int v = 10;
            m.Do(new ValueUnDo<int>(x => v = x, 20, 10));
            Check("Do 后 v=20", v == 20, $"v={v}");
            m.Undo();
            Check("Undo 后 v=10", v == 10, $"v={v}");
            m.Redo();
            Check("Redo 后 v=20", v == 20, $"v={v}");
        }

        // 5. UnDoField<T>(覆盖 UnDoFieldChange struct)
        private static void Test_UnDoField()
        {
            var m = new UnDoManager();
            var f = new UnDoField<int>(m, 1);
            f.Value = 2;
            Check("set 后 Value=2", f.Value == 2, $"v={f.Value}");
            m.Undo();
            Check("Undo 后 Value=1", f.Value == 1, $"v={f.Value}");
            m.Redo();
            Check("Redo 后 Value=2", f.Value == 2, $"v={f.Value}");
            int direct = f;
            Check("隐式转换 T", direct == 2, $"v={direct}");
        }

        // 6. 事务 Commit(覆盖 _commands=new List + GroupUnDo ToArray)
        private static void Test_TransactionCommit()
        {
            var m = new UnDoManager();
            var list = new List<string>();
            using (var t = m.BeginTransaction())
            {
                m.Do(new UnDo(() => list.Add("A"), () => list.Remove("A")));
                m.Do(new UnDo(() => list.Add("B"), () => list.Remove("B")));
                m.Do(new UnDo(() => list.Add("C"), () => list.Remove("C")));
                t.Commit();
            }
            Check("Commit 后 A,B,C", list.SequenceEqual(new[] { "A", "B", "C" }), string.Join(",", list));
            m.Undo();
            Check("一次 Undo 撤销整组 (ToArray 改动点)", list.Count == 0, $"count={list.Count}");
            m.Redo();
            Check("Redo 恢复整组", list.SequenceEqual(new[] { "A", "B", "C" }), string.Join(",", list));
        }

        // 7. 事务回滚(不 Commit,Dispose 倒序撤销)
        private static void Test_TransactionRollback()
        {
            var m = new UnDoManager();
            var list = new List<string>();
            int vBefore = m.Version;
            using (var t = m.BeginTransaction())
            {
                m.Do(new UnDo(() => list.Add("X"), () => list.Remove("X")));
                m.Do(new UnDo(() => list.Add("Y"), () => list.Remove("Y")));
                // 不 Commit
            }
            Check("回滚后 list 空", list.Count == 0, $"count={list.Count}");
            Check("回滚后 CanUndo=false", !m.CanUndo);
            Check("回滚后 Version 不变", m.Version == vBefore, $"期望{vBefore} 实际{m.Version}");
        }

        // 8. 嵌套事务
        private static void Test_NestedTransaction()
        {
            var m = new UnDoManager();
            var list = new List<string>();
            using (var outer = m.BeginTransaction())
            {
                m.Do(new UnDo(() => list.Add("O"), () => list.Remove("O")));
                using (var inner = m.BeginTransaction())
                {
                    m.Do(new UnDo(() => list.Add("I"), () => list.Remove("I")));
                    inner.Commit();
                }
                outer.Commit();
            }
            Check("嵌套事务提交 O,I", list.SequenceEqual(new[] { "O", "I" }), string.Join(",", list));
            m.Undo();
            Check("一次 Undo 撤销全部", list.Count == 0, $"count={list.Count}");
        }

        // 9. IList.AsUnDo
        private static void Test_IListAsUnDo()
        {
            var m = new UnDoManager();
            var list = new List<int> { 1, 2 }.AsUnDo(m);
            list.Add(3);
            Check("Add 后 1,2,3", list.SequenceEqual(new[] { 1, 2, 3 }), string.Join(",", list));
            m.Undo();
            Check("Undo Add 后 1,2", list.SequenceEqual(new[] { 1, 2 }), string.Join(",", list));
            list.Move(0, 1);
            Check("Move 后 2,1", list.SequenceEqual(new[] { 2, 1 }), string.Join(",", list));
            m.Undo();
            Check("Undo Move 后 1,2", list.SequenceEqual(new[] { 1, 2 }), string.Join(",", list));
        }

        // 10. DoClear(覆盖 source.ToArray 改动)
        private static void Test_DoClear()
        {
            var m = new UnDoManager();
            ICollection<int> col = new List<int> { 1, 2, 3 }.AsUnDo(m);
            m.DoClear(col);
            Check("DoClear 清空", col.Count == 0);
            m.Undo();
            Check("Undo DoClear 恢复 1,2,3 (ToArray 改动点)", col.SequenceEqual(new[] { 1, 2, 3 }), string.Join(",", col));
        }

        // 11. ISet.AsUnDo + IntersectWith(覆盖 [..other.Where] ToList 改动)
        private static void Test_ISetAsUnDo()
        {
            var m = new UnDoManager();
            ISet<int> set = new HashSet<int> { 1, 2, 3, 4 }.AsUnDo(m);
            set.IntersectWith(new[] { 2, 4, 6 });
            Check("IntersectWith 后 2,4", set.SequenceEqual(new[] { 2, 4 }), string.Join(",", set));
            m.Undo();
            Check("Undo IntersectWith 恢复 1,2,3,4 (ToList 改动点)", set.SequenceEqual(new[] { 1, 2, 3, 4 }), string.Join(",", set));
        }

        // 12. IDictionary.AsUnDo
        private static void Test_IDictAsUnDo()
        {
            var m = new UnDoManager();
            var dict = new Dictionary<string, int>().AsUnDo(m);
            dict.Add("k", 99);
            Check("Add 后 dict[k]=99", dict["k"] == 99);
            m.Undo();
            Check("Undo Add 后无 k", !dict.ContainsKey("k"));
            m.Redo();
            Check("Redo 后 dict[k]=99", dict["k"] == 99);
        }

        // 13. 合并 TryMerge(覆盖 IMergeableUnDo,UnDoStack.Push 调 TryMerge)
        private static void Test_Merge()
        {
            var old = ValueUnDo.MergeInterval;
            ValueUnDo.MergeInterval = TimeSpan.FromSeconds(5);
            try
            {
                var m = new UnDoManager();
                int v = 0;
                m.Do(new ValueUnDo<int>(x => v = x, 1, 0));
                m.Do(new ValueUnDo<int>(x => v = x, 2, 0));
                m.Do(new ValueUnDo<int>(x => v = x, 3, 0));
                Check("合并后最终 v=3", v == 3, $"v={v}");
                m.Undo();
                Check("一次 Undo 回到 v=0 (合并为一个操作)", v == 0, $"v={v}");
            }
            finally { ValueUnDo.MergeInterval = old; }
        }

        // 14. Clear 清空历史
        private static void Test_Clear()
        {
            var m = new UnDoManager();
            m.Do(new UnDo(() => { }, () => { }));
            m.Do(new UnDo(() => { }, () => { }));
            m.Clear();
            Check("Clear 后 CanUndo=false", !m.CanUndo);
            Check("Clear 后 CanRedo=false", !m.CanRedo);
        }

        // 15. 参数校验(覆盖 ThrowIfNull 替换)
        private static void Test_ArgumentNullChecks()
        {
            var m = new UnDoManager();
            Check("Do(null) 抛 ArgumentNullException", Throws<ArgumentNullException>(() => m.Do(null!)));
            Check("DoAdd(null manager) 抛 ArgumentNullException", Throws<ArgumentNullException>(() => ((IUnDoManager)null!).DoAdd(new List<int>(), 1)));
            Check("UnDoField(null manager) 抛 ArgumentNullException", Throws<ArgumentNullException>(() => new UnDoField<int>(null!)));
            Check("GroupUnDo(null 命令元素) 抛 ArgumentException", Throws<ArgumentException>(() => new GroupUnDo((IUnDo)null!)));
        }

        // 16. struct 值相等性(覆盖手写 Equals)
        private static void Test_StructEquality()
        {
            var c1 = new UnDoFieldChange<int>(1, 2);
            var c2 = new UnDoFieldChange<int>(1, 2);
            var c3 = new UnDoFieldChange<int>(1, 3);
            Check("UnDoFieldChange 相等", c1.Equals(c2));
            Check("UnDoFieldChange 不等", !c1.Equals(c3));
            Check("UnDoFieldChange GetHashCode 一致", c1.GetHashCode() == c2.GetHashCode());

            var list = new List<int>();
            var o1 = new UnDoCollectionOperation(list, UnDoCollectionAction.ICollectionAdd, 1);
            var o2 = new UnDoCollectionOperation(list, UnDoCollectionAction.ICollectionAdd, 2);
            Check("UnDoCollectionOperation.Collection", o1.Collection == list);
            Check("UnDoCollectionOperation.Action", o1.Action == UnDoCollectionAction.ICollectionAdd);
            Check("UnDoCollectionOperation.Parameters 长度", o1.Parameters.Length == 1);
            Check("UnDoCollectionOperation 自等", o1.Equals(o1));
            Check("UnDoCollectionOperation 不同参数不等", !o1.Equals(o2));
        }

        private static bool Throws<T>(Action a) where T : Exception
        {
            try { a(); return false; }
            catch (T) { return true; }
            catch { return false; }
        }
    }
}

 

posted @ 2026-08-08 15:11  家煜宝宝  阅读(3)  评论(0)    收藏  举报