6 using System.Collections.Generic;
10 using System.Diagnostics.Contracts.Internal;
11 using System.Diagnostics.Contracts;
12 using MonoTests.System.Diagnostics.Contracts.Helpers;
13 using NUnit.Framework.Constraints;
15 namespace MonoTests.System.Diagnostics.Contracts {
18 public class ContractHelperTest : TestContractBase {
20 private void CheckAllMessages (ContractFailureKind kind, string messageStart, Action<string, Exception, string, ContractFailureKind, Func<string>> fnAssert)
23 foreach (Exception ex in new [] { null, new ArgumentNullException () }) {
24 fnAssert (messageStart + ".", ex, null, kind, () => {
25 return ContractHelper.RaiseContractFailedEvent (kind, null, null, ex);
28 fnAssert (messageStart + ". Message", ex, null, kind, () => {
29 return ContractHelper.RaiseContractFailedEvent (kind, "Message", null, ex);
32 fnAssert (messageStart + ": Condition", ex, "Condition", kind, () => {
33 return ContractHelper.RaiseContractFailedEvent (kind, null, "Condition", ex);
36 fnAssert (messageStart + ": Condition Message", ex, "Condition", kind, () => {
37 return ContractHelper.RaiseContractFailedEvent (kind, "Message", "Condition", ex);
43 private void CheckAllKinds (Action<string, Exception, string, ContractFailureKind, Func<string>> fnAssert)
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);
53 private void CheckAllKinds (Action<string, Exception, Func<string>> fnAssert)
55 this.CheckAllKinds ((expected, ex, condition, kind, fnTest) => fnAssert (expected, ex, fnTest));
59 /// If no event handler is present, then the string returned describes the condition failure.
61 [Test, RunAgainstReference]
62 public void TestRaiseContractFailedEventNoHandler ()
64 this.CheckAllKinds ((expected, ex, fnTest) => {
65 string msg = fnTest ();
66 Assert.AreEqual (expected, msg, "TestRaiseContractFailedEventNoHandler() incorrect message");
71 /// When SetHandled() is called, null is returned.
72 /// The event args are also checked.
74 [Test, RunAgainstReference]
75 public void TestRaiseContractFailedEventHandled ()
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");
89 this.CheckAllKinds ((expected, ex, condition, kind, fnTest) => {
90 expectedMsg = expected;
91 originalException = ex;
92 expectedCondition = condition;
94 string msg = fnTest ();
95 Assert.IsNull (msg, "TestRaiseContractFailedEventHandled() expected null message");
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.
103 [Test, RunAgainstReference]
104 public void TestRaiseContractFailedEventUnwind ()
106 Contract.ContractFailed += (sender, e) => {
110 this.CheckAllKinds ((expected, expectedEx, 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");
119 Assert.AreSame (expectedEx, ex.InnerException, "TestRaiseContractFailedEventUnwind() wrong inner exception type");
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.
130 [Test, RunAgainstReference]
131 public void TestRaiseContractFailedEventThrows ()
133 Contract.ContractFailed += (sender, e) => {
134 throw new InvalidOperationException ();
137 this.CheckAllKinds ((expected, expectedEx, 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");
150 /// Both event handlers should be called, constraint is not handled.
152 [Test, RunAgainstReference]
153 public void TestRaiseContractMultipleHandlers1 ()
155 bool visited1, visited2;
156 Contract.ContractFailed += (sender, e) => {
159 Contract.ContractFailed += (sender, e) => {
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");
173 /// Both event handlers should be called. SetUnwind() takes precedent over SetHandled().
175 [Test, RunAgainstReference]
176 public void TestRaiseContractMultipleHandlers2 ()
178 bool visited1, visited2;
179 Contract.ContractFailed += (sender, e) => {
183 Contract.ContractFailed += (sender, e) => {
188 this.CheckAllKinds ((expected, expectedEx, fnTest) => {
189 visited1 = visited2 = false;
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");
198 Assert.AreSame (expectedEx, ex.InnerException, "TestRaiseContractMultipleHandlers2() wrong inner exception");
200 Assert.IsTrue (visited1, "TestRaiseContractMultipleHandlers2() handler 1 not visited");
201 Assert.IsTrue (visited2, "TestRaiseContractMultipleHandlers2() handler 2 not visited");
207 /// Both event handlers should be called. The exceptions are treated as calls to SetUnwind(), with
208 /// the exception being put in the InnerException.
210 [Test, RunAgainstReference]
211 public void TestRaiseContractMultipleHandlers3 ()
213 bool visited1, visited2;
214 Contract.ContractFailed += (sender, e) => {
216 throw new InvalidOperationException ();
218 Contract.ContractFailed += (sender, e) => {
220 throw new InvalidOperationException ();
223 this.CheckAllKinds ((expected, expectedEx, fnTest) => {
224 visited1 = visited2 = false;
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");
239 /// Contract.TriggerFailure() triggers the assert. Check that the assert is triggered, with the correct text.
242 // [Ignore ("This causes NUnit crash on .NET 4.0")]
243 public void TestTriggerFailure ()
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");