diff --git a/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs b/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
index fb1c62ec18..1291077ddb 100644
--- a/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
@@ -7,6 +7,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
@@ -17,24 +18,30 @@ internal class UnitTestDiscoverer
internal UnitTestDiscoverer()
{
this.assemblyEnumeratorWrapper = new AssemblyEnumeratorWrapper();
+ this.TestMethodFilter = new TestMethodFilter();
}
+ ///
+ /// Gets or sets method filter for filtering tests
+ ///
+ private TestMethodFilter TestMethodFilter { get; set; }
+
///
/// Discovers the tests available from the provided sources.
///
/// The sources.
/// The logger.
/// The discovery Sink.
- /// The run settings.
+ /// The discovery context.
internal void DiscoverTests(
IEnumerable sources,
IMessageLogger logger,
ITestCaseDiscoverySink discoverySink,
- IRunSettings runSettings)
+ IDiscoveryContext discoveryContext)
{
foreach (var source in sources)
{
- this.DiscoverTestsInSource(source, logger, discoverySink, runSettings);
+ this.DiscoverTestsInSource(source, logger, discoverySink, discoveryContext);
}
}
@@ -44,16 +51,16 @@ internal void DiscoverTests(
/// The source.
/// The logger.
/// The discovery Sink.
- /// The run settings.
+ /// The discovery context.
internal virtual void DiscoverTestsInSource(
string source,
IMessageLogger logger,
ITestCaseDiscoverySink discoverySink,
- IRunSettings runSettings)
+ IDiscoveryContext discoveryContext)
{
ICollection warnings;
- var testElements = this.assemblyEnumeratorWrapper.GetTests(source, runSettings, out warnings);
+ var testElements = this.assemblyEnumeratorWrapper.GetTests(source, discoveryContext?.RunSettings, out warnings);
// log the warnings
foreach (var warning in warnings)
@@ -76,10 +83,10 @@ internal virtual void DiscoverTestsInSource(
testElements.Count,
source);
- this.SendTestCases(source, testElements, discoverySink);
+ this.SendTestCases(source, testElements, discoverySink, discoveryContext, logger);
}
- internal void SendTestCases(string source, IEnumerable testElements, ITestCaseDiscoverySink discoverySink)
+ internal void SendTestCases(string source, IEnumerable testElements, ITestCaseDiscoverySink discoverySink, IDiscoveryContext discoveryContext, IMessageLogger logger)
{
var shouldCollectSourceInformation = MSTestSettings.RunConfigurationSettings.CollectSourceInformation;
@@ -91,11 +98,25 @@ internal void SendTestCases(string source, IEnumerable testElem
navigationSessions.Add(source, PlatformServiceProvider.Instance.FileOperations.CreateNavigationSession(source));
}
+ // Get filter expression and skip discovery in case filter expression has parsing error.
+ bool filterHasError = false;
+ ITestCaseFilterExpression filterExpression = this.TestMethodFilter.GetFilterExpression(discoveryContext, logger, out filterHasError);
+ if (filterHasError)
+ {
+ return;
+ }
+
foreach (var testElement in testElements)
{
- object testNavigationSession;
var testCase = testElement.ToTestCase();
+ // Filter tests based on test case filters
+ if (filterExpression != null && filterExpression.MatchTestCase(testCase, (p) => this.TestMethodFilter.PropertyValueProvider(testCase, p)) == false)
+ {
+ continue;
+ }
+
+ object testNavigationSession;
if (shouldCollectSourceInformation)
{
string testSource = testElement.TestMethod.DeclaringAssemblyName ?? source;
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
index c3b297f8c9..74db14ba75 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
@@ -98,7 +98,7 @@ public void RunTests(IEnumerable sources, IRunContext runContext, IFrame
var logger = (IMessageLogger)frameworkHandle;
// discover the tests
- this.GetUnitTestDiscoverer().DiscoverTestsInSource(source, logger, discoverySink, runContext?.RunSettings);
+ this.GetUnitTestDiscoverer().DiscoverTestsInSource(source, logger, discoverySink, runContext);
tests.AddRange(discoverySink.Tests);
// Clear discoverSinksTests so that it just stores test for one source at one point of time
diff --git a/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj b/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
index 03689015d1..addb976c88 100644
--- a/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
+++ b/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
@@ -50,7 +50,7 @@
-
+
diff --git a/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs b/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
index 04c3e90772..f72940448c 100644
--- a/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
+++ b/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
@@ -54,7 +54,7 @@ public void DiscoverTests(
return;
}
- new UnitTestDiscoverer().DiscoverTests(sources, logger, discoverySink, discoveryContext?.RunSettings);
+ new UnitTestDiscoverer().DiscoverTests(sources, logger, discoverySink, discoveryContext);
}
///
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodFilter.cs b/src/Adapter/MSTest.CoreAdapter/TestMethodFilter.cs
similarity index 66%
rename from src/Adapter/MSTest.CoreAdapter/Execution/TestMethodFilter.cs
rename to src/Adapter/MSTest.CoreAdapter/TestMethodFilter.cs
index 062af5af36..118f645648 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodFilter.cs
+++ b/src/Adapter/MSTest.CoreAdapter/TestMethodFilter.cs
@@ -1,16 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
+namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+ using System.Reflection;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
- using Constants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants;
internal class TestMethodFilter
{
@@ -34,24 +34,24 @@ internal TestMethodFilter()
///
/// Returns ITestCaseFilterExpression for TestProperties supported by adapter.
///
- /// The current context of the run.
- /// Handler to report test messages/start/end and results.
+ /// The current context of the run.
+ /// Handler to report test messages/start/end and results.
/// Indicates that the filter is unsupported/has an error.
/// A filter expression.
- internal ITestCaseFilterExpression GetFilterExpression(IRunContext runContext, IMessageLogger testExecutionRecorder, out bool filterHasError)
+ internal ITestCaseFilterExpression GetFilterExpression(IDiscoveryContext context, IMessageLogger logger, out bool filterHasError)
{
filterHasError = false;
ITestCaseFilterExpression filter = null;
- if (runContext != null)
+ if (context != null)
{
try
{
- filter = runContext.GetTestCaseFilter(this.supportedProperties.Keys, this.PropertyProvider);
+ filter = (context is IRunContext) ? this.GetTestCaseFilterFromRunContext(context as IRunContext) : this.GetTestCaseFilterFromDiscoveryContext(context);
}
catch (TestPlatformFormatException ex)
{
filterHasError = true;
- testExecutionRecorder.SendMessage(TestMessageLevel.Error, ex.Message);
+ logger.SendMessage(TestMessageLevel.Error, ex.Message);
}
}
@@ -95,5 +95,34 @@ internal object PropertyValueProvider(TestCase currentTest, string propertyName)
return null;
}
+
+ ///
+ /// Gets filter expression from run context.
+ ///
+ /// Run context
+ /// Filter expression.
+ private ITestCaseFilterExpression GetTestCaseFilterFromRunContext(IRunContext context)
+ {
+ return context.GetTestCaseFilter(this.supportedProperties.Keys, this.PropertyProvider);
+ }
+
+ ///
+ /// Gets filter expression from discovery context.
+ ///
+ /// Discovery context
+ /// Filter expression.
+ private ITestCaseFilterExpression GetTestCaseFilterFromDiscoveryContext(IDiscoveryContext context)
+ {
+ try
+ {
+ // GetTestCaseFilter is present in DiscoveryContext but not in IDiscoveryContext interface.
+ MethodInfo methodGetTestCaseFilter = context.GetType().GetRuntimeMethod("GetTestCaseFilter", new[] { typeof(IEnumerable), typeof(Func) });
+ return (ITestCaseFilterExpression)methodGetTestCaseFilter?.Invoke(context, new object[] { this.supportedProperties.Keys, (Func)this.PropertyProvider });
+ }
+ catch (TargetInvocationException ex)
+ {
+ throw ex.InnerException;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/test/UnitTests/MSTest.CoreAdapter.Unit.Tests/Discovery/UnitTestDiscovererTests.cs b/test/UnitTests/MSTest.CoreAdapter.Unit.Tests/Discovery/UnitTestDiscovererTests.cs
index 39fd8358c5..eae996e215 100644
--- a/test/UnitTests/MSTest.CoreAdapter.Unit.Tests/Discovery/UnitTestDiscovererTests.cs
+++ b/test/UnitTests/MSTest.CoreAdapter.Unit.Tests/Discovery/UnitTestDiscovererTests.cs
@@ -34,6 +34,7 @@ public class UnitTestDiscovererTests
private Mock mockMessageLogger;
private Mock mockTestCaseDiscoverySink;
private Mock mockRunSettings;
+ private Mock mockDiscoveryContext;
private UnitTestElement test;
private List testElements;
@@ -47,6 +48,9 @@ public void TestInit()
this.mockTestCaseDiscoverySink = new Mock();
this.mockRunSettings = new Mock();
+ this.mockDiscoveryContext = new Mock();
+ this.mockDiscoveryContext.Setup(dc => dc.RunSettings).Returns(this.mockRunSettings.Object);
+
this.test = new UnitTestElement(new TestMethod("M", "C", "A", false));
this.testElements = new List { this.test };
PlatformServiceProvider.Instance = this.testablePlatformServiceProvider;
@@ -75,7 +79,7 @@ public void DiscoverTestsShouldDiscoverForAllSources()
.Returns(false);
}
- this.unitTestDiscoverer.DiscoverTests(sources, this.mockMessageLogger.Object, this.mockTestCaseDiscoverySink.Object, this.mockRunSettings.Object);
+ this.unitTestDiscoverer.DiscoverTests(sources, this.mockMessageLogger.Object, this.mockTestCaseDiscoverySink.Object, this.mockDiscoveryContext.Object);
// Assert.
this.mockMessageLogger.Verify(lm => lm.SendMessage(TestMessageLevel.Warning, It.IsAny()), Times.Exactly(2));
@@ -90,7 +94,7 @@ public void DiscoverTestsInSourceShouldSendBackAllWarnings()
this.testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.DoesFileExist(Source))
.Returns(false);
- this.unitTestDiscoverer.DiscoverTestsInSource(Source, this.mockMessageLogger.Object, this.mockTestCaseDiscoverySink.Object, this.mockRunSettings.Object);
+ this.unitTestDiscoverer.DiscoverTestsInSource(Source, this.mockMessageLogger.Object, this.mockTestCaseDiscoverySink.Object, this.mockDiscoveryContext.Object);
// Assert.
this.mockMessageLogger.Verify(lm => lm.SendMessage(TestMessageLevel.Warning, It.IsAny()), Times.Once);
@@ -114,7 +118,7 @@ public void DiscoverTestsInSourceShouldSendBackTestCasesDiscovered()
ih => ih.CreateInstanceForType(It.IsAny(), It.IsAny