Skip to content

Commit

Permalink
Add ignore until dates for test case attribute and test case source
Browse files Browse the repository at this point in the history
  • Loading branch information
abborg committed Jul 21, 2019
1 parent f96460d commit a070958
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 70 deletions.
45 changes: 43 additions & 2 deletions src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs
Expand Up @@ -23,6 +23,7 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using NUnit.Compatibility;
using NUnit.Framework.Interfaces;
Expand Down Expand Up @@ -143,6 +144,13 @@ public object ExpectedResult

#endregion

#region Instance Fields

private RunState _originalRunState;
private DateTimeOffset? _untilDate;

#endregion

#region Other Properties

/// <summary>
Expand Down Expand Up @@ -219,6 +227,7 @@ public string IgnoreReason
get { return Reason; }
set
{
_originalRunState = RunState;
RunState = RunState.Ignored;
Reason = value;
}
Expand Down Expand Up @@ -250,6 +259,24 @@ public string Category
}
}

/// <summary>
/// Gets and sets the ignore until date for this test case.
/// </summary>
public string Until
{
get { return Properties.Get(PropertyNames.IgnoreUntilDate) as string; }
set
{
if (!string.IsNullOrEmpty(IgnoreReason))
{
_untilDate = DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
Properties.Set(PropertyNames.IgnoreUntilDate, _untilDate.Value.ToString("u"));
}
else
this.RunState = RunState.NotRunnable;
}
}

#endregion

#region Helper Methods
Expand All @@ -268,7 +295,7 @@ private TestCaseParameters GetParametersForTestCase(IMethodInfo method)

// Special handling for ExpectedResult (see if it needs to be converted into method return type)
if (parms.HasExpectedResult
&& ParamAttributeTypeConversions.TryConvert(parms.ExpectedResult, method.ReturnType.Type, out var expectedResultInTargetType))
&& ParamAttributeTypeConversions.TryConvert(parms.ExpectedResult, method.ReturnType.Type, out var expectedResultInTargetType))
{
parms.ExpectedResult = expectedResultInTargetType;
}
Expand Down Expand Up @@ -368,7 +395,7 @@ private static void PerformSpecialConversions(object[] arglist, IParameterInfo[]
{
object arg = arglist[i];
Type targetType = parameters[i].ParameterType;
if (ParamAttributeTypeConversions.TryConvert(arg, targetType, out var argAsTargetType))
if (ParamAttributeTypeConversions.TryConvert(arg, targetType, out var argAsTargetType))
{
arglist[i] = argAsTargetType;
}
Expand All @@ -387,6 +414,20 @@ public IEnumerable<TestMethod> BuildFrom(IMethodInfo method, Test suite)
{
TestMethod test = new NUnitTestCaseBuilder().BuildTestMethod(method, suite, GetParametersForTestCase(method));

if (_untilDate.HasValue)
{
if (_untilDate > DateTimeOffset.UtcNow)
{
test.RunState = RunState.Ignored;
string reason = string.Format("Ignoring until {0}. {1}", _untilDate.Value.ToString("u"), IgnoreReason);
test.Properties.Set(PropertyNames.SkipReason, reason);
}
else
{
test.RunState = _originalRunState;
}
}

#if PLATFORM_DETECTION
if (IncludePlatform != null || ExcludePlatform != null)
{
Expand Down
95 changes: 95 additions & 0 deletions src/NUnitFramework/framework/Internal/IgnoredTestCaseData.cs
@@ -0,0 +1,95 @@
// ***********************************************************************
// Copyright (c) 2008–2018 Charlie Poole, Rob Prouse
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************

using System;
using System.ComponentModel;
using System.Globalization;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;

namespace NUnit.Framework
{
/// <summary>
/// The IgnoredTestCaseData class represents a ignored TestCaseData. It adds
/// the ability to set an ignore until date on a test case.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class IgnoredTestCaseData : TestCaseData
{
#region Instance Fields

/// <summary>
/// The previous RunState
/// </summary>
private RunState _prevRunState;

#endregion

#region Constructors

internal IgnoredTestCaseData(TestCaseData data, RunState prevRunState)
{
this.Arguments = data.Arguments;
this.ArgDisplayNames = data.ArgDisplayNames;
this.ExpectedResult = data.ExpectedResult;
this.HasExpectedResult = data.HasExpectedResult;
this.OriginalArguments = data.OriginalArguments;
this.Properties = data.Properties;
this.RunState = data.RunState;
this.TestName = data.TestName;
this._prevRunState = prevRunState;
}

#endregion

#region Fluent Instance Modifiers

/// <summary>
///
/// </summary>
/// <param name="datetime">The ignore until date</param>
/// <returns>A modified TestCaseData.</returns>
public TestCaseData Until(DateTimeOffset datetime)
{
if (this._prevRunState != RunState.NotRunnable)
{
if (datetime > DateTimeOffset.UtcNow)
{
this.RunState = RunState.Ignored;
string reason = (string)this.Properties.Get(PropertyNames.SkipReason);
reason = string.Format("Ignoring until {0}. {1}", datetime.ToString("u"), reason);
this.Properties.Set(PropertyNames.SkipReason, reason);
}
else
{
this.RunState = this._prevRunState;
}
this.Properties.Set(PropertyNames.IgnoreUntilDate, datetime.ToString("u") );
}
return this;
}

#endregion

}
}
4 changes: 2 additions & 2 deletions src/NUnitFramework/framework/Internal/TestParameters.cs
Expand Up @@ -126,7 +126,7 @@ public string TestName
/// <summary>
/// Gets the property dictionary for this test
/// </summary>
public IPropertyBag Properties { get; }
public IPropertyBag Properties { get; protected internal set; }

/// <summary>
/// Applies ParameterSet values to the test itself.
Expand All @@ -146,7 +146,7 @@ public void ApplyToTest(Test test)
/// The original arguments provided by the user,
/// used for display purposes.
/// </summary>
public object[] OriginalArguments { get; private set; }
public object[] OriginalArguments { get; protected internal set; }

private string[] _argDisplayNames;

Expand Down
39 changes: 4 additions & 35 deletions src/NUnitFramework/framework/TestCaseData.cs
Expand Up @@ -194,44 +194,13 @@ public TestCaseData Explicit(string reason)
/// </summary>
/// <param name="reason">The reason.</param>
/// <returns></returns>
public TestCaseData Ignore(string reason)
public IgnoredTestCaseData Ignore(string reason)
{
RunState prevRunState = this.RunState;
this.RunState = RunState.Ignored;
this.Properties.Set(PropertyNames.SkipReason, reason);
return this;
}

/// <summary>
/// Ignores this TestCase, specifying the reason until the specified date.
/// </summary>
/// <param name="reason">The reason.</param>
/// <param name="until">
/// The date in the future to stop ignoring the test as a string in UTC time.
/// For example for a date and time, "2014-12-25 08:10:00Z" or for just a date,
/// "2014-12-25". If just a date is given, the Ignore will expire at midnight UTC.
/// </param>
/// <remarks>
/// Once the ignore until date has passed, the test will be marked
/// as runnable. Tests with an ignore until date will have an IgnoreUntilDate
/// property set which will appear in the test results.
/// </remarks>
public TestCaseData Ignore(string reason, string until)
{
DateTime untilDate;
if (this.RunState != RunState.NotRunnable)
{
if (DateTime.TryParse(until, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out untilDate))
{
if (untilDate > DateTime.Now)
{
this.RunState = RunState.Ignored;
reason = string.Format("Ignoring until {0}. {1}", untilDate.ToString("u"), reason);
this.Properties.Set(PropertyNames.SkipReason, reason);
}
this.Properties.Set(PropertyNames.IgnoreUntilDate, untilDate.ToString("u") );
}
}
return this;
var ignoredData = new IgnoredTestCaseData(this, prevRunState);
return ignoredData;
}

#endregion
Expand Down
9 changes: 9 additions & 0 deletions src/NUnitFramework/testdata/TestCaseAttributeFixture.cs
Expand Up @@ -76,6 +76,15 @@ public void MethodWithIgnoredTestCases(int num)
{
}

[TestCase(1)]
[TestCase(2, Ignore = "Should not run", Until = "4242-01-01")]
[TestCase(3, Ignore = "Run me after 1942", Until = "1942-01-01")]
[TestCase(4, Ignore = "Don't Run Me!", Until = "4242-01-01T01:23:45Z")]
[TestCase(5, Until = "This should err!")]
public void MethodWithIgnoredWithUntilDateTestCases(int num)
{
}

[TestCase(1)]
[TestCase(2, Explicit = true)]
[TestCase(3, Explicit = true, Reason = "Connection failing")]
Expand Down
12 changes: 6 additions & 6 deletions src/NUnitFramework/testdata/TestCaseSourceAttributeFixture.cs
Expand Up @@ -62,10 +62,7 @@ private static IEnumerable IgnoredSource
return new object[] {
new TestCaseData(1),
new TestCaseData(2).Ignore("Don't Run Me!"),
new TestCaseData(3).Ignore("Ignore Me Until The Future", "4242-01-01"),
new TestCaseData(4).Ignore("Ignore Me Until The Future", "4242-01-01 00:00:00"),
new TestCaseData(5).Ignore("Ignore Me Until The Future", "4242-01-01 00:00:00Z"),
new TestCaseData(6).Ignore("I Was Ignored in the Past", "1492-01-01")

};
}
}
Expand All @@ -74,9 +71,12 @@ private static IEnumerable IgnoredWithDateSource
{
get
{
DateTimeOffset utcTime = DateTimeOffset.UtcNow;
TimeSpan timeZoneOffset = utcTime - utcTime.ToLocalTime();
return new object[] {
new TestCaseData(7).Ignore("Ignore Me Until The Future", "4242-01-01 12:42:33"),
new TestCaseData(8).Ignore("Ignore Me Until The Future", "4242-01-01 12:42:33Z"),
new TestCaseData(3).Ignore("Ignore Me Until The Future").Until(new DateTimeOffset(4242, 01, 01, 0, 0, 0, timeZoneOffset)),
new TestCaseData(4).Ignore("I Was Ignored in the Past").Until(new DateTimeOffset(1492, 01, 01, 0, 0, 0, timeZoneOffset)),
new TestCaseData(5).Ignore("Ignore Me Until The Future").Until(new DateTimeOffset(4242, 01, 01, 12, 42, 33, timeZoneOffset)),
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/NUnitFramework/tests/Api/FrameworkControllerTests.cs
Expand Up @@ -57,7 +57,7 @@ public static IEnumerable EmptyFilters
{
get
{
yield return new TestCaseData(null);
yield return new TestCaseData((object[])null);
yield return new TestCaseData("");
yield return new TestCaseData(EMPTY_FILTER);
}
Expand Down
33 changes: 33 additions & 0 deletions src/NUnitFramework/tests/Attributes/TestCaseAttributeTests.cs
Expand Up @@ -23,6 +23,7 @@

using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
Expand Down Expand Up @@ -325,6 +326,38 @@ public void CanIgnoreIndividualTestCases()
Assert.That(testCase.Properties.Get(PropertyNames.SkipReason), Is.EqualTo("Don't Run Me!"));
}

[Test]
public void CanIgnoreIndividualTestCasesWithUntilDate()
{
var methodName = nameof(TestCaseAttributeFixture.MethodWithIgnoredWithUntilDateTestCases);
TestSuite suite = TestBuilder.MakeParameterizedMethodSuite(
typeof(TestCaseAttributeFixture), methodName);
Test testCase = TestFinder.Find($"{methodName}(1)", suite, false);
Assert.That(testCase.RunState, Is.EqualTo(RunState.Runnable));

string untilDateString = DateTimeOffset.Parse("4242-01-01", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal).ToString("u");
testCase = TestFinder.Find($"{methodName}(2)", suite, false);
Assert.That(testCase.RunState, Is.EqualTo(RunState.Ignored));
Assert.That(testCase.Properties.Get(PropertyNames.SkipReason), Is.EqualTo(string.Format("Ignoring until {0}. Should not run", untilDateString)));
Assert.That(testCase.Properties.Get(PropertyNames.IgnoreUntilDate), Is.EqualTo(untilDateString));

untilDateString = DateTimeOffset.Parse("1942-01-01", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal).ToString("u");

testCase = TestFinder.Find($"{methodName}(3)", suite, false);
Assert.That(testCase.RunState, Is.EqualTo(RunState.Runnable));
Assert.That(testCase.Properties.Get(PropertyNames.IgnoreUntilDate), Is.EqualTo(untilDateString));

untilDateString = DateTimeOffset.Parse("4242-01-01T01:23:45Z", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal).ToString("u");

testCase = TestFinder.Find($"{methodName}(4)", suite, false);
Assert.That(testCase.RunState, Is.EqualTo(RunState.Ignored));
Assert.That(testCase.Properties.Get(PropertyNames.SkipReason), Is.EqualTo(string.Format("Ignoring until {0}. Don't Run Me!", untilDateString)));
Assert.That(testCase.Properties.Get(PropertyNames.IgnoreUntilDate), Is.EqualTo(untilDateString));

testCase = TestFinder.Find($"{methodName}(5)", suite, false);
Assert.That(testCase.RunState, Is.EqualTo(RunState.NotRunnable));
}

[Test]
public void CanMarkIndividualTestCasesExplicit()
{
Expand Down

0 comments on commit a070958

Please sign in to comment.