Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add One-Shot test batch strategy #101

Open
wants to merge 1 commit into
base: dev15
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ public BoostTestRunnerCommandLineArgs()
/// <summary>
/// List of fully qualified name tests which are to be executed.
/// </summary>
/// <remarks>The semantics of this property follow the documentation of Boost.Test's --run_test argument for Boost 1.61</remarks>
/// <remarks>This property cannot handle multiple filter definitions as described in documentation of Boost.Test's --run_test argument for Boost 1.63</remarks>
public IList<string> Tests { get; private set; }

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions BoostTestAdapter/BoostTestAdapter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
<Compile Include="TestBatch\SourceTestBatchStrategy.cs" />
<Compile Include="TestBatch\TestBatchStrategy.cs" />
<Compile Include="TestBatch\TestSuiteTestBatchStrategy.cs" />
<Compile Include="TestBatch\OneShotTestBatchStrategy.cs" />
<Compile Include="Utility\Code.cs" />
<Compile Include="Utility\CommandEvaluator.cs" />
<Compile Include="Utility\CommandLine.cs" />
Expand Down
1 change: 1 addition & 0 deletions BoostTestAdapter/BoostTestAdapterSettings.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<xsd:enumeration value="Source" />
<xsd:enumeration value="TestSuite" />
<xsd:enumeration value="TestCase" />
<xsd:enumeration value="One" />
</xsd:restriction>
</xsd:simpleType>

Expand Down
13 changes: 7 additions & 6 deletions BoostTestAdapter/BoostTestExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void RunTests(IEnumerable<string> sources,
// Batch tests into grouped runs based by source so that we avoid reloading symbols per test run
// Batching by source since this overload is called when 'Run All...' or equivalent is triggered
// NOTE For code-coverage speed is given preference over adapter responsiveness.
TestBatch.Strategy strategy = ((runContext.IsDataCollectionEnabled) ? TestBatch.Strategy.Source : settings.TestBatchStrategy);
Strategy strategy = ((runContext.IsDataCollectionEnabled) ? Strategy.Source : settings.TestBatchStrategy);

ITestBatchingStrategy batchStrategy = GetBatchStrategy(strategy, settings);
if (batchStrategy == null)
Expand Down Expand Up @@ -267,7 +267,7 @@ public void RunTests(IEnumerable<VSTestCase> tests, IRunContext runContext, IFra
// multiple test name specification for tests which reside in the same test suite
//
// NOTE For code-coverage speed is given preference over adapter responsiveness.
TestBatch.Strategy strategy = ((runContext.IsDataCollectionEnabled) ? TestBatch.Strategy.TestSuite : settings.TestBatchStrategy);
TestBatch.Strategy strategy = ((runContext.IsDataCollectionEnabled) ? Strategy.One : settings.TestBatchStrategy);
// Source strategy is invalid in such context since explicit tests are chosen. TestSuite is used instead.
if (strategy == Strategy.Source)
{
Expand Down Expand Up @@ -317,9 +317,10 @@ private ITestBatchingStrategy GetBatchStrategy(TestBatch.Strategy strategy, Boos

switch (strategy)
{
case Strategy.Source: return new SourceTestBatchStrategy(this._testRunnerFactory, settings, argsBuilder);
case Strategy.TestSuite: return new TestSuiteTestBatchStrategy(this._testRunnerFactory, settings, argsBuilder);
case Strategy.TestCase: return new IndividualTestBatchStrategy(this._testRunnerFactory, settings, argsBuilder);
case Strategy.Source: return new SourceTestBatchStrategy(_testRunnerFactory, settings, argsBuilder);
case Strategy.TestSuite: return new TestSuiteTestBatchStrategy(_testRunnerFactory, settings, argsBuilder);
case Strategy.TestCase: return new IndividualTestBatchStrategy(_testRunnerFactory, settings, argsBuilder);
case Strategy.One: return new OneShotTestBatchStrategy(_testRunnerFactory, settings, argsBuilder);
}

return null;
Expand Down Expand Up @@ -467,7 +468,7 @@ private BoostTestRunnerCommandLineArgs GetDefaultArguments(string source, BoostT

args.StandardOutFile = ((settings.EnableStdOutRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdOutFile) : null);
args.StandardErrorFile = ((settings.EnableStdErrRedirection) ? TestPathGenerator.Generate(source, FileExtensions.StdErrFile) : null);

return args;
}

Expand Down
250 changes: 250 additions & 0 deletions BoostTestAdapter/TestBatch/OneShotTestBatchStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
// (C) Copyright ETAS 2015.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

using System;
using System.Linq;
using System.Collections.Generic;

using BoostTestAdapter.Utility;
using BoostTestAdapter.Settings;
using BoostTestAdapter.Boost.Runner;
using BoostTestAdapter.Utility.VisualStudio;

using VSTestCase = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestCase;

namespace BoostTestAdapter.TestBatch
{
public class OneShotTestBatchStrategy : TestBatchStrategy
{
#region Constants

private static readonly Version _minimumVersion = new Version(1, 63, 0);
private static readonly Version _zero = new Version(0, 0, 0);

#endregion

#region Constructors

public OneShotTestBatchStrategy(IBoostTestRunnerFactory testRunnerFactory, BoostTestAdapterSettings settings, CommandLineArgsBuilder argsBuilder)
: base(testRunnerFactory, settings, argsBuilder)
{
_fallBackStrategy = new TestSuiteTestBatchStrategy(testRunnerFactory, settings, argsBuilder);
}

#endregion

#region Members

private readonly TestSuiteTestBatchStrategy _fallBackStrategy;

#endregion

#region TestBatchStrategy

public override IEnumerable<TestRun> BatchTests(IEnumerable<VSTestCase> tests)
{
BoostTestRunnerSettings adaptedSettings = this.Settings.TestRunnerSettings.Clone();
// Disable timeout since this batching strategy executes more than one test at a time
adaptedSettings.Timeout = -1;

// Group by source
IEnumerable<IGrouping<string, VSTestCase>> sources = tests.GroupBy(test => test.Source);
foreach (var source in sources)
{
IBoostTestRunner runner = GetTestRunner(source.Key);
if (runner == null)
{
continue;
}

// Start by batching tests by TestSuite
var batch = _fallBackStrategy.BatchTests(source);

// If the Boost.Test module supports test run filters...
if (source.Select(GetVersion).All(version => (version >= _minimumVersion)))
{
BoostTestRunnerCommandLineArgs args = BuildCommandLineArgs(source.Key);

// Generate the filter set
var filterSet = new List<TestFilter>();

foreach (var run in batch)
{
TestFilter filter = TestFilter.EnableFilter();

// Use the command-line representation of the test suite batch to allow
// for the most compact representation (i.e. fully/qualified/test_name_0,test_name_1,test_name_2)
filter.TestSet = new PathTestSet(run.Arguments.Tests);

filterSet.Add(filter);
}

// Use the environment variable rather than the command-line '--run_test' to make proper use of test run filters
args.Environment["BOOST_TEST_RUN_FILTERS"] = string.Join(":", filterSet);

yield return new TestRun(runner, source, args, adaptedSettings);
}
// Else fall-back to regular test suite batching behaviour...
else
{
foreach (var run in batch)
{
yield return run;
}
}
}
}

#endregion

/// <summary>
/// Extracts the Boost version from the provided test case
/// </summary>
/// <param name="test">The test case to extract the version from</param>
/// <returns>The version advertised by the provided test case or the zero version if the version is not available</returns>
private static Version GetVersion(VSTestCase test)
{
// Use the Zero version as a dummy to identify a missing Boost Version property
Version result = _zero;

if (test != null)
{
string value = (string)test.GetPropertyValue(VSTestModel.VersionProperty);

if (string.IsNullOrEmpty(value) || !Version.TryParse(value, out result))
{
result = _zero;
}
}

return result;
}

#region Boost Test Filtering

/// <summary>
/// Boost.Test test filter representation
/// </summary>
private class TestFilter
{
/// <summary>
/// Internal Constructor
/// </summary>
/// <param name="relativeSpec">Identifies if this is an 'enable' filter or otherwise</param>
private TestFilter(bool relativeSpec)
{
this.RelativeSpec = relativeSpec;
}

/// <summary>
/// States if this is an 'enable' filter or otherwise
/// </summary>
public bool RelativeSpec { get; private set; }

/// <summary>
/// The test set
/// </summary>
public ITestSet TestSet { get; set; }

/// <summary>
/// Named constructor which creates an 'enabled' test filter. The test set
/// represented will be executed.
/// </summary>
/// <returns>A new TestFilter instance whose TestSet will be enabled for execution</returns>
public static TestFilter EnableFilter()
{
return new TestFilter(true);
}

/// <summary>
/// Named constructor which creates a 'disabled' test filter. The test set
/// represented will not be executed.
/// </summary>
/// <returns>A new TestFilter instance whose TestSet will not be enabled for execution</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static TestFilter DisableFilter()
{
return new TestFilter(false);
}
public override string ToString()
{
return (RelativeSpec ? '+' : '!') + this.TestSet.ToString();
}
}

/// <summary>
/// Identifies a 'test_set' as specified in Boost.Test <see cref="http://www.boost.org/doc/libs/1_63_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/run_test.html">--run_test</see> documentation
/// </summary>
private interface ITestSet
{
}

/// <summary>
/// A 'label' test set which represents
/// all tests identified with said label
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
private class LabelTestSet : ITestSet
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="label">The test label</param>
public LabelTestSet(string label)
{
this.Label = label;
}

/// <summary>
/// Test label (decorator) value
/// </summary>
public string Label { get; private set; }

public override string ToString()
{
return '@' + this.Label;
}
}

/// <summary>
/// A 'path' test set which represents a collection
/// of Boost.Test paths
/// </summary>
/// <remarks>The first path is expected to be fully-qualified</remarks>
/// <remarks>Paths following the first path are relative to the parent test suite of the first fully-qualified test</remarks>
private class PathTestSet : ITestSet
{
/// <summary>
/// Default Constructor
/// </summary>
public PathTestSet()
: this(new List<string>())
{
}

/// <summary>
/// Constructor
/// </summary>
/// <param name="paths">The base list which is to be used</param>
/// <remarks>The list is shallow copied. Any modifications Paths through this instance will also affect the provided list.</remarks>
public PathTestSet(IList<string> paths)
{
this.Paths = paths;
}

/// <summary>
/// Test paths
/// </summary>
public IList<string> Paths { get; private set; }

public override string ToString()
{
return string.Join(",", this.Paths);
}
}

#endregion
}
}
3 changes: 2 additions & 1 deletion BoostTestAdapter/TestBatch/TestBatchStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public enum Strategy
{
Source,
TestSuite,
TestCase
TestCase,
One
}

/// <summary>
Expand Down
15 changes: 14 additions & 1 deletion BoostTestAdapter/Utility/VisualStudio/VSTestModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,25 @@ public static string StatusTrait
}
}

private static readonly TestProperty _version = TestProperty.Register("Boost.Test.Boost.Version", "Boost Version", typeof(string), typeof(VSTestModel));

/// <summary>
/// Boost.Test Boost Version property
/// </summary>
public static TestProperty VersionProperty
{
get
{
return _version;
}
}

/// <summary>
/// Converts forward slashes in a file path to backward slashes.
/// </summary>
/// <param name="path_in"> The input path</param>
/// <returns>The output path, modified with backward slashes </returns>

private static string ConvertSlashes(string path_in)
{
return path_in.Replace('/', '\\');
Expand Down
Loading