[bcl] Remove NET_4_0 defines from class libs
[mono.git] / mcs / class / corlib / Test / System.Diagnostics.Contracts / ContractHelperTest.cs
1
2 #define CONTRACTS_FULL
3 #define DEBUG
4
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Text;
9 using NUnit.Framework;
10 using System.Diagnostics.Contracts.Internal;
11 using System.Diagnostics.Contracts;
12 using MonoTests.System.Diagnostics.Contracts.Helpers;
13 using NUnit.Framework.Constraints;
14
15 namespace MonoTests.System.Diagnostics.Contracts {
16
17         [TestFixture]
18         public class ContractHelperTest : TestContractBase {
19
20                 private void CheckAllMessages (ContractFailureKind kind, string messageStart, Action<string, Exception, string, ContractFailureKind, Func<string>> fnAssert)
21                 {
22
23                         foreach (Exception ex in new [] { null, new ArgumentNullException () }) {
24                                 fnAssert (messageStart + ".", ex, null, kind, () => {
25                                         return ContractHelper.RaiseContractFailedEvent (kind, null, null, ex);
26                                 });
27
28                                 fnAssert (messageStart + ".  Message", ex, null, kind, () => {
29                                         return ContractHelper.RaiseContractFailedEvent (kind, "Message", null, ex);
30                                 });
31
32                                 fnAssert (messageStart + ": Condition", ex, "Condition", kind, () => {
33                                         return ContractHelper.RaiseContractFailedEvent (kind, null, "Condition", ex);
34                                 });
35
36                                 fnAssert (messageStart + ": Condition  Message", ex, "Condition", kind, () => {
37                                         return ContractHelper.RaiseContractFailedEvent (kind, "Message", "Condition", ex);
38                                 });
39                         }
40
41                 }
42
43                 private void CheckAllKinds (Action<string, Exception, string, ContractFailureKind, Func<string>> fnAssert)
44                 {
45                         this.CheckAllMessages (ContractFailureKind.Assert, "Assertion failed", fnAssert);
46                         this.CheckAllMessages (ContractFailureKind.Assume, "Assumption failed", fnAssert);
47                         this.CheckAllMessages (ContractFailureKind.Invariant, "Invariant failed", fnAssert);
48                         this.CheckAllMessages (ContractFailureKind.Postcondition, "Postcondition failed", fnAssert);
49                         this.CheckAllMessages (ContractFailureKind.PostconditionOnException, "Postcondition failed after throwing an exception", fnAssert);
50                         this.CheckAllMessages (ContractFailureKind.Precondition, "Precondition failed", fnAssert);
51                 }
52
53                 private void CheckAllKinds (Action<string, Exception, Func<string>> fnAssert)
54                 {
55                         this.CheckAllKinds ((expected, ex, condition, kind, fnTest) => fnAssert (expected, ex, fnTest));
56                 }
57
58                 /// <summary>
59                 /// If no event handler is present, then the string returned describes the condition failure.
60                 /// </summary>
61                 [Test, RunAgainstReference]
62                 public void TestRaiseContractFailedEventNoHandler ()
63                 {
64                         this.CheckAllKinds ((expected, ex, fnTest) => {
65                                 string msg = fnTest ();
66                                 Assert.AreEqual (expected, msg, "TestRaiseContractFailedEventNoHandler() incorrect message");
67                         });
68                 }
69
70                 /// <summary>
71                 /// When SetHandled() is called, null is returned.
72                 /// The event args are also checked.
73                 /// </summary>
74                 [Test, RunAgainstReference]
75                 public void TestRaiseContractFailedEventHandled ()
76                 {
77                         string expectedMsg = null;
78                         Exception originalException = null;
79                         string expectedCondition = null;
80                         ContractFailureKind expectedKind = ContractFailureKind.Assert;
81                         Contract.ContractFailed += (sender, e) => {
82                                 Assert.AreEqual (expectedMsg, e.Message, "TestRaiseContractFailedEventHandled() event message wrong");
83                                 Assert.AreSame (originalException, e.OriginalException, "TestRaiseContractFailedEventHandled() event exception wrong");
84                                 Assert.AreEqual (expectedCondition, e.Condition, "TestRaiseContractFailedEventHandled() event condition wrong");
85                                 Assert.AreEqual (expectedKind, e.FailureKind, "TestRaiseContractFailedEventHandled() event failure kind wrong");
86                                 e.SetHandled ();
87                         };
88
89                         this.CheckAllKinds ((expected, ex, condition, kind, fnTest) => {
90                                 expectedMsg = expected;
91                                 originalException = ex;
92                                 expectedCondition = condition;
93                                 expectedKind = kind;
94                                 string msg = fnTest ();
95                                 Assert.IsNull (msg, "TestRaiseContractFailedEventHandled() expected null message");
96                         });
97                 }
98
99                 /// <summary>
100                 /// When SetUnwind() is called, a ContractException is thrown. If an innerException is passed, then
101                 /// it is put in the InnerException of the ContractException. Otherwise, the InnerException is set to null.
102                 /// </summary>
103                 [Test, RunAgainstReference]
104                 public void TestRaiseContractFailedEventUnwind ()
105                 {
106                         Contract.ContractFailed += (sender, e) => {
107                                 e.SetUnwind ();
108                         };
109
110                         this.CheckAllKinds ((expected, expectedEx, fnTest) => {
111                                 try {
112                                         fnTest ();
113                                         Assert.Fail ("TestRaiseContractFailedEventUnwind() exception not thrown");
114                                 } catch (Exception ex) {
115                                         Assert.IsInstanceOfType (base.ContractExceptionType, ex, "TestRaiseContractFailedEventUnwind() wrong exception type");
116                                         if (expectedEx == null) {
117                                                 Assert.IsNull (ex.InnerException, "TestRaiseContractFailedEventUnwind() inner exception should be null");
118                                         } else {
119                                                 Assert.AreSame (expectedEx, ex.InnerException, "TestRaiseContractFailedEventUnwind() wrong inner exception type");
120                                         }
121                                 }
122                         });
123                 }
124
125                 /// <summary>
126                 /// When the ContractFailed event throws an exception, then it becomes the inner exception of the
127                 /// ContractException. Except if an exception is passed in to the call, then that exception is put
128                 /// in the InnerException.
129                 /// </summary>
130                 [Test, RunAgainstReference]
131                 public void TestRaiseContractFailedEventThrows ()
132                 {
133                         Contract.ContractFailed += (sender, e) => {
134                                 throw new InvalidOperationException ();
135                         };
136
137                         this.CheckAllKinds ((expected, expectedEx, fnTest) => {
138                                 try {
139                                         fnTest ();
140                                         Assert.Fail ("TestRaiseContractFailedEventThrows() exception not thrown");
141                                 } catch (Exception ex) {
142                                         Assert.IsInstanceOfType (base.ContractExceptionType, ex, "TestRaiseContractFailedEventThrows() wrong exception type");
143                                         Type expectedInnerExceptionType = expectedEx == null ? typeof (InvalidOperationException) : expectedEx.GetType ();
144                                         Assert.IsInstanceOfType (expectedInnerExceptionType, ex.InnerException, "TestRaiseContractFailedEventThrows() wrong inner exception type");
145                                 }
146                         });
147                 }
148
149                 /// <summary>
150                 /// Both event handlers should be called, constraint is not handled.
151                 /// </summary>
152                 [Test, RunAgainstReference]
153                 public void TestRaiseContractMultipleHandlers1 ()
154                 {
155                         bool visited1, visited2;
156                         Contract.ContractFailed += (sender, e) => {
157                                 visited1 = true;
158                         };
159                         Contract.ContractFailed += (sender, e) => {
160                                 visited2 = true;
161                         };
162
163                         this.CheckAllKinds ((expected, ex, fnTest) => {
164                                 visited1 = visited2 = false;
165                                 string msg = fnTest ();
166                                 Assert.AreEqual (expected, msg, "TestRaiseContractMultipleHandlers1() msg not as expected");
167                                 Assert.IsTrue (visited1, "TestRaiseContractMultipleHandlers1() handler 1 not visited");
168                                 Assert.IsTrue (visited2, "TestRaiseContractMultipleHandlers1() handler 2 not visited");
169                         });
170                 }
171
172                 /// <summary>
173                 /// Both event handlers should be called. SetUnwind() takes precedent over SetHandled().
174                 /// </summary>
175                 [Test, RunAgainstReference]
176                 public void TestRaiseContractMultipleHandlers2 ()
177                 {
178                         bool visited1, visited2;
179                         Contract.ContractFailed += (sender, e) => {
180                                 visited1 = true;
181                                 e.SetHandled ();
182                         };
183                         Contract.ContractFailed += (sender, e) => {
184                                 visited2 = true;
185                                 e.SetUnwind ();
186                         };
187
188                         this.CheckAllKinds ((expected, expectedEx, fnTest) => {
189                                 visited1 = visited2 = false;
190                                 try {
191                                         fnTest ();
192                                         Assert.Fail ("TestRaiseContractMultipleHandlers2() exception not thrown");
193                                 } catch (Exception ex) {
194                                         Assert.IsInstanceOfType (base.ContractExceptionType, ex, "TestRaiseContractMultipleHandlers2() wrong exception type");
195                                         if (expectedEx == null) {
196                                                 Assert.IsNull (ex.InnerException, "TestRaiseContractMultipleHandlers2() inner exception not null");
197                                         } else {
198                                                 Assert.AreSame (expectedEx, ex.InnerException, "TestRaiseContractMultipleHandlers2() wrong inner exception");
199                                         }
200                                         Assert.IsTrue (visited1, "TestRaiseContractMultipleHandlers2() handler 1 not visited");
201                                         Assert.IsTrue (visited2, "TestRaiseContractMultipleHandlers2() handler 2 not visited");
202                                 }
203                         });
204                 }
205
206                 /// <summary>
207                 /// Both event handlers should be called. The exceptions are treated as calls to SetUnwind(), with
208                 /// the exception being put in the InnerException.
209                 /// </summary>
210                 [Test, RunAgainstReference]
211                 public void TestRaiseContractMultipleHandlers3 ()
212                 {
213                         bool visited1, visited2;
214                         Contract.ContractFailed += (sender, e) => {
215                                 visited1 = true;
216                                 throw new InvalidOperationException ();
217                         };
218                         Contract.ContractFailed += (sender, e) => {
219                                 visited2 = true;
220                                 throw new InvalidOperationException ();
221                         };
222
223                         this.CheckAllKinds ((expected, expectedEx, fnTest) => {
224                                 visited1 = visited2 = false;
225                                 try {
226                                         fnTest ();
227                                         Assert.Fail ("TestRaiseContractMultipleHandlers3() failed to throw exception");
228                                 } catch (Exception ex) {
229                                         Type expectedInnerExceptionType = expectedEx == null ? typeof (InvalidOperationException) : expectedEx.GetType ();
230                                         Assert.IsInstanceOfType (base.ContractExceptionType, ex, "TestRaiseContractMultipleHandlers3() wrong exception type");
231                                         Assert.IsInstanceOfType (expectedInnerExceptionType, ex.InnerException, "TestRaiseContractMultipleHandlers3() wrong inner exception type");
232                                         Assert.IsTrue (visited1, "TestRaiseContractMultipleHandlers3() handler 1 not visited");
233                                         Assert.IsTrue (visited2, "TestRaiseContractMultipleHandlers3() handler 2 not visited");
234                                 }
235                         });
236                 }
237
238                 /// <summary>
239                 /// Contract.TriggerFailure() triggers the assert. Check that the assert is triggered, with the correct text.
240                 /// </summary>
241                 [Test]
242 //              [Ignore ("This causes NUnit crash on .NET 4.0")]
243                 public void TestTriggerFailure ()
244                 {
245                         try {
246                                 ContractHelper.TriggerFailure (ContractFailureKind.Assert, "Display", null, "Condition", null);
247                                 Assert.Fail ("TestTriggerFailure() failed to throw exception");
248                         } catch (Exception ex) {
249                                 Assert.AreEqual ("Display", ex.Message, "TestTriggerFailure() wrong message");
250                         }
251                 }
252
253         }
254
255 }
256