Skip to content

Commit

Permalink
Adding filtering support at discovery (#271)
Browse files Browse the repository at this point in the history
* Filter support at discovery

* removing unnecessary line
  • Loading branch information
abhishekkumawat23 authored and AbhitejJohn committed Sep 20, 2017
1 parent 4dd29c6 commit 28dd7cd
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 36 deletions.
39 changes: 30 additions & 9 deletions src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -17,24 +18,30 @@ internal class UnitTestDiscoverer
internal UnitTestDiscoverer()
{
this.assemblyEnumeratorWrapper = new AssemblyEnumeratorWrapper();
this.TestMethodFilter = new TestMethodFilter();
}

/// <summary>
/// Gets or sets method filter for filtering tests
/// </summary>
private TestMethodFilter TestMethodFilter { get; set; }

/// <summary>
/// Discovers the tests available from the provided sources.
/// </summary>
/// <param name="sources"> The sources. </param>
/// <param name="logger"> The logger. </param>
/// <param name="discoverySink"> The discovery Sink. </param>
/// <param name="runSettings"> The run settings. </param>
/// <param name="discoveryContext"> The discovery context. </param>
internal void DiscoverTests(
IEnumerable<string> 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);
}
}

Expand All @@ -44,16 +51,16 @@ internal void DiscoverTests(
/// <param name="source"> The source. </param>
/// <param name="logger"> The logger. </param>
/// <param name="discoverySink"> The discovery Sink. </param>
/// <param name="runSettings"> The run settings. </param>
/// <param name="discoveryContext"> The discovery context. </param>
internal virtual void DiscoverTestsInSource(
string source,
IMessageLogger logger,
ITestCaseDiscoverySink discoverySink,
IRunSettings runSettings)
IDiscoveryContext discoveryContext)
{
ICollection<string> 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)
Expand All @@ -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<UnitTestElement> testElements, ITestCaseDiscoverySink discoverySink)
internal void SendTestCases(string source, IEnumerable<UnitTestElement> testElements, ITestCaseDiscoverySink discoverySink, IDiscoveryContext discoveryContext, IMessageLogger logger)
{
var shouldCollectSourceInformation = MSTestSettings.RunConfigurationSettings.CollectSourceInformation;

Expand All @@ -91,11 +98,25 @@ internal void SendTestCases(string source, IEnumerable<UnitTestElement> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void RunTests(IEnumerable<string> 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
Expand Down
2 changes: 1 addition & 1 deletion src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<Compile Include="Execution\TestAssemblyInfo.cs" />
<Compile Include="Execution\TestClassInfo.cs" />
<Compile Include="ObjectModel\TestFailedException.cs" />
<Compile Include="Execution\TestMethodFilter.cs" />
<Compile Include="TestMethodFilter.cs" />
<Compile Include="Execution\TestMethodRunner.cs" />
<Compile Include="Execution\TypeCache.cs" />
<Compile Include="Execution\UnitTestRunner.cs" />
Expand Down
2 changes: 1 addition & 1 deletion src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void DiscoverTests(
return;
}

new UnitTestDiscoverer().DiscoverTests(sources, logger, discoverySink, discoveryContext?.RunSettings);
new UnitTestDiscoverer().DiscoverTests(sources, logger, discoverySink, discoveryContext);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -34,24 +34,24 @@ internal TestMethodFilter()
/// <summary>
/// Returns ITestCaseFilterExpression for TestProperties supported by adapter.
/// </summary>
/// <param name="runContext">The current context of the run.</param>
/// <param name="testExecutionRecorder">Handler to report test messages/start/end and results.</param>
/// <param name="context">The current context of the run.</param>
/// <param name="logger">Handler to report test messages/start/end and results.</param>
/// <param name="filterHasError">Indicates that the filter is unsupported/has an error.</param>
/// <returns>A filter expression.</returns>
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);
}
}

Expand Down Expand Up @@ -95,5 +95,34 @@ internal object PropertyValueProvider(TestCase currentTest, string propertyName)

return null;
}

/// <summary>
/// Gets filter expression from run context.
/// </summary>
/// <param name="context">Run context</param>
/// <returns>Filter expression.</returns>
private ITestCaseFilterExpression GetTestCaseFilterFromRunContext(IRunContext context)
{
return context.GetTestCaseFilter(this.supportedProperties.Keys, this.PropertyProvider);
}

/// <summary>
/// Gets filter expression from discovery context.
/// </summary>
/// <param name="context">Discovery context</param>
/// <returns>Filter expression.</returns>
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<string>), typeof(Func<string, TestProperty>) });
return (ITestCaseFilterExpression)methodGetTestCaseFilter?.Invoke(context, new object[] { this.supportedProperties.Keys, (Func<string, TestProperty>)this.PropertyProvider });
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
}
}
Loading

0 comments on commit 28dd7cd

Please sign in to comment.