I'm just having a play with the code contracts in .Net 4.0 and must be missing something obvious as they are not behaving as I would expect.
I have always used a simple if... then.. throw statement to perform any validation at the start of a function.
if (hours < 0 || hours > 8)
throw new ArgumentOutOfRangeException("hours", "Hours must be between 0 and 8");
I have simply replaced this with
Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");
but it never seems to throw an issue on my unit tests.
public static DurationUnit HoursAsDuration(int hours)
{
Contract.Requires<ArgumentOutOfRangeException>(hours >= 0 && hours <= 8, "Hours must be between 0 and 8");
switch (hours)
{
case 1:
case 2:
return DurationUnit.Quarter;
case 3:
case 4:
return DurationUnit.Half;
case 5:
case 6:
return DurationUnit.ThreeQuarter;
case 7:
case 8:
return DurationUnit.Full;
default:
return DurationUnit.None;
}
}
[Test]
public void CanConvertToDuration()
{
Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(0));
Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(1));
Assert.AreEqual(DurationUnit.Quarter, DateTimeUtility.HoursAsDuration(2));
Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(3));
Assert.AreEqual(DurationUnit.Half, DateTimeUtility.HoursAsDuration(4));
Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(5));
Assert.AreEqual(DurationUnit.ThreeQuarter, DateTimeUtility.HoursAsDuration(6));
Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(7));
Assert.AreEqual(DurationUnit.Full, DateTimeUtility.HoursAsDuration(8));
//Would expect this to cause an issue
Assert.AreEqual(DurationUnit.None, DateTimeUtility.HoursAsDuration(9));
}
The test returns true but I would have expected the code contract to stop the value of "9" getting into the switch statement. Is this the expected behaviour?
If your function's specification, expressed in English, is that it accepts any value for hours
and throws an exception when hours
is not in the range 0..8, then its contract (expressed in Code Contracts language) is not that it requires hours
to be between 0 and 8. The proper translation is that the function doesn't require anything, and it ensures that if hours
was in the wrong range, an exception has been raised, and it ensures that if hours
was in the correct range, the proper computation was done.
I would expect there is a way to express these things in Code Contracts, but I am not familiar with this contract language, only with another one. The philosophy is the same though: if you want the check to be part of the production build, then the condition of the check is not a pre-condition. On the other hand, the contract may (should) express that the check is made and that each case is handled appropriately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With