Skip to content

Commit 59b1549

Browse files
hughbestephentoub
authored andcommitted
Add DesignerTransaction tests and fix debug assertions (dotnet#30107)
* Add DesignerTransaction tests and fix debug assertions * Address PR feedback
1 parent e5bb0b5 commit 59b1549

File tree

3 files changed

+149
-61
lines changed

3 files changed

+149
-61
lines changed

src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerTransaction.cs

+18-61
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,29 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System;
6-
using System.Security.Permissions;
7-
85
namespace System.ComponentModel.Design
96
{
107
/// <summary>
11-
/// Identifies a transaction within a designer. Transactions are
12-
/// used to wrap several changes into one unit of work, which
13-
/// helps performance.
8+
/// Identifies a transaction within a designer. Transactions are
9+
/// used to wrap several changes into one unit of work, which
10+
/// helps performance.
1411
/// </summary>
1512
public abstract class DesignerTransaction : IDisposable
1613
{
1714
private bool _suppressedFinalization;
1815

19-
/// <summary>
20-
/// <para>[To be supplied.]</para>
21-
/// </summary>
2216
protected DesignerTransaction() : this("")
2317
{
2418
}
19+
20+
protected DesignerTransaction(string description) => Description = description;
2521

26-
27-
/// <summary>
28-
/// <para>[To be supplied.]</para>
29-
/// </summary>
30-
protected DesignerTransaction(string description)
31-
{
32-
Description = description;
33-
}
34-
35-
36-
/// <summary>
37-
/// <para>[To be supplied.]</para>
38-
/// </summary>
3922
public bool Canceled { get; private set; }
4023

41-
/// <summary>
42-
/// <para>[To be supplied.]</para>
43-
/// </summary>
4424
public bool Committed { get; private set; }
4525

46-
/// <summary>
47-
/// <para>[To be supplied.]</para>
48-
/// </summary>
4926
public string Description { get; }
5027

51-
/// <summary>
52-
/// <para>[To be supplied.]</para>
53-
/// </summary>
5428
public void Cancel()
5529
{
5630
if (!Canceled && !Committed)
@@ -63,11 +37,9 @@ public void Cancel()
6337
}
6438

6539
/// <summary>
66-
/// Commits this transaction. Once a transaction has
67-
/// been committed, further calls to this method
68-
/// will do nothing. You should always call this
69-
/// method after creating a transaction to ensure
70-
/// that the transaction is closed properly.
40+
/// Commits this transaction. Once a transaction has been committed, further
41+
/// calls to this method will do nothing. You should always call this method
42+
/// after creating a transaction to ensure that the transaction is closed properly.
7143
/// </summary>
7244
public void Commit()
7345
{
@@ -81,51 +53,36 @@ public void Commit()
8153
}
8254

8355
/// <summary>
84-
/// User code should implement this method to perform
85-
/// the actual work of committing a transaction.
56+
/// User code should implement this method to perform the actual work of
57+
/// committing a transaction.
8658
/// </summary>
8759
protected abstract void OnCancel();
8860

8961
/// <summary>
90-
/// User code should implement this method to perform
91-
/// the actual work of committing a transaction.
62+
/// User code should implement this method to perform the actual work of
63+
/// committing a transaction.
9264
/// </summary>
9365
protected abstract void OnCommit();
9466

9567
/// <summary>
96-
/// Overrides Object to commit this transaction
97-
/// in case the user forgot.
68+
/// Overrides Object to commit this transaction in case the user forgot.
9869
/// </summary>
99-
~DesignerTransaction()
100-
{
101-
Dispose(false);
102-
}
70+
~DesignerTransaction() => Dispose(false);
10371

104-
/// <internalonly/>
10572
/// <summary>
106-
/// Private implementation of IDisaposable.
107-
/// When a transaction is disposed it is
108-
/// committed.
73+
/// Private implementation of IDisaposable. When a transaction is disposed
74+
/// it is committed.
10975
/// </summary>
11076
void IDisposable.Dispose()
11177
{
11278
Dispose(true);
11379

114-
// note - Dispose calls Cancel which sets this bit, so
115-
// this should never be hit.
116-
//
11780
if (!_suppressedFinalization)
11881
{
119-
System.Diagnostics.Debug.Fail("Invalid state. Dispose(true) should have called cancel which does the SuppressFinalize");
12082
GC.SuppressFinalize(this);
12183
}
12284
}
123-
protected virtual void Dispose(bool disposing)
124-
{
125-
System.Diagnostics.Debug.Assert(disposing, "Designer transaction garbage collected, unable to cancel, please Cancel, Close, or Dispose your transaction.");
126-
System.Diagnostics.Debug.Assert(disposing || Canceled || Committed, "Disposing DesignerTransaction that has not been comitted or canceled; forcing Cancel");
127-
Cancel();
128-
}
85+
86+
protected virtual void Dispose(bool disposing) => Cancel();
12987
}
13088
}
131-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Xunit;
6+
7+
namespace System.ComponentModel.Design.Tests
8+
{
9+
public class DesignerTransactionTests
10+
{
11+
[Fact]
12+
public void Ctor_Default()
13+
{
14+
using (var transaction = new TestDesignerTransaction())
15+
{
16+
Assert.Empty(transaction.Description);
17+
Assert.False(transaction.Canceled);
18+
Assert.False(transaction.Committed);
19+
}
20+
}
21+
22+
[Theory]
23+
[InlineData(null)]
24+
[InlineData("Description")]
25+
public void Ctor_Default(string description)
26+
{
27+
using (var transaction = new TestDesignerTransaction(description))
28+
{
29+
Assert.Same(description, transaction.Description);
30+
Assert.False(transaction.Canceled);
31+
Assert.False(transaction.Committed);
32+
}
33+
}
34+
35+
[Fact]
36+
public void Cancel_NotCommitted_Success()
37+
{
38+
using (var transaction = new TestDesignerTransaction())
39+
{
40+
transaction.Cancel();
41+
Assert.Equal(1, transaction.CancelCount);
42+
Assert.True(transaction.Canceled);
43+
44+
transaction.Cancel();
45+
Assert.Equal(1, transaction.CancelCount);
46+
Assert.True(transaction.Canceled);
47+
}
48+
}
49+
50+
[Fact]
51+
public void Cancel_Committed_Success()
52+
{
53+
using (var transaction = new TestDesignerTransaction())
54+
{
55+
transaction.Commit();
56+
57+
transaction.Cancel();
58+
Assert.Equal(0, transaction.CancelCount);
59+
Assert.False(transaction.Canceled);
60+
}
61+
}
62+
63+
[Fact]
64+
public void Commit_NotCommitted_Success()
65+
{
66+
using (var transaction = new TestDesignerTransaction())
67+
{
68+
transaction.Commit();
69+
Assert.Equal(1, transaction.CommitCount);
70+
Assert.True(transaction.Committed);
71+
72+
transaction.Commit();
73+
Assert.Equal(1, transaction.CommitCount);
74+
Assert.True(transaction.Committed);
75+
}
76+
}
77+
78+
[Fact]
79+
public void Commit_Cancelled_Success()
80+
{
81+
using (var transaction = new TestDesignerTransaction())
82+
{
83+
transaction.Cancel();
84+
85+
transaction.Commit();
86+
Assert.Equal(0, transaction.CommitCount);
87+
Assert.False(transaction.Committed);
88+
}
89+
}
90+
91+
[Fact]
92+
public void Dispose_FinalizeSuppressed_Success()
93+
{
94+
var transaction = new NonDisposingDesignerTransaction();
95+
transaction.Cancel();
96+
((IDisposable)transaction).Dispose();
97+
98+
Assert.True(transaction.Canceled);
99+
}
100+
101+
[Fact]
102+
public void Dispose_FinalizeNotSuppressed_Success()
103+
{
104+
var transaction = new NonDisposingDesignerTransaction();
105+
((IDisposable)transaction).Dispose();
106+
107+
Assert.False(transaction.Canceled);
108+
}
109+
110+
private class NonDisposingDesignerTransaction : DesignerTransaction
111+
{
112+
protected override void Dispose(bool disposing) { }
113+
114+
protected override void OnCancel() { }
115+
protected override void OnCommit() { }
116+
}
117+
118+
private class TestDesignerTransaction : DesignerTransaction
119+
{
120+
public TestDesignerTransaction() : base() { }
121+
public TestDesignerTransaction(string description) : base(description) { }
122+
123+
public int CancelCount { get; set; }
124+
protected override void OnCancel() => CancelCount++;
125+
126+
public int CommitCount { get; set; }
127+
protected override void OnCommit() => CommitCount++;
128+
}
129+
}
130+
}

src/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<Compile Include="ContextStackTests.cs" />
8585
<Compile Include="InstanceDescriptorTests.cs" />
8686
<Compile Include="Design\DesignerOptionServiceTests.cs" />
87+
<Compile Include="Design\DesignerTransactionTests.cs" />
8788
<Compile Include="Security\Authentication\ExtendedProtection\ExtendedProtectionPolicyTypeConverterTests.cs" />
8889
</ItemGroup>
8990
<ItemGroup>

0 commit comments

Comments
 (0)