/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* TestCaseExtension Library, Copyright 2015 Bryan Chadwick *
* *
* FILE: .\TestCaseInvoker.cs *
* *
* This file is part of TestCaseExtension. *
* *
* TestCaseExtension is free software: you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation, either version *
* 3 of the License, or (at your option) any later version. *
* *
* TestCaseExtension is distributed in the hope that it will be useful,*
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with TestCaseExtension. *
* If not, see . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestCaseExtension.Internal;
namespace TestCaseExtension
{
/// Responsible for Invoking TestMethods within a TestCaseClass. Handles
/// both methods with and without TestCase/TestCaseSource attrubutes.
public class TestCaseInvoker : ITestMethodInvoker
{
private readonly TestMethodInvokerContext invokerContext;
/// Create a TestInvoker with the given invokerContext
public TestCaseInvoker(TestMethodInvokerContext invokerContext)
{
this.invokerContext = invokerContext;
}
/// Invokes a TestMethod with the given arguments.
public TestMethodInvokerResult Invoke(params object[] args)
{
MethodInfo method = invokerContext.TestMethodInfo;
var results = new TestMethodInvokerResult();
if (method.IsExplicitOrIgnored())
{
return results;
}
IList testCases = method.GetAttributes();
IList testCaseSources = method.GetAttributes();
if (!testCases.Any() && !testCaseSources.Any())
{
// Default: invoke the TestMethod mormally
return invokerContext.InnerInvoker.Invoke(null);
}
// Invoke each TestCase(...) with its arguments
var failures = new TestCaseFailureException();
foreach (TestCaseData testCase in GetTestCaseData(testCases, testCaseSources))
{
TestMethodInvokerResult result = invokerContext.InnerInvoker.Invoke(testCase.TestArguments);
var failure = result.Exception.DeepestException();
if (failure != null)
{
failures.LogFailure(testCase.TestArguments, invokerContext.TestMethodInfo, failure);
}
}
if (failures.HasFailures)
{
results.Exception = failures;
}
return results;
}
private IEnumerable GetTestCaseData(IEnumerable cases, IEnumerable sources)
{
return cases.Select(attr => new TestCaseData(attr.TestArguments).SetName(attr.Description))
.Concat(sources.SelectMany(GetTestCaseDataFromSource));
}
private IEnumerable GetTestCaseDataFromSource(TestCaseSourceAttribute source)
{
string typeName = invokerContext.TestContext.FullyQualifiedTestClassName;
string sourceName = source.MethodOrPropertyName;
Type sourceProvider = source.ProvidingType ?? TestExtensionUtil.GetType(typeName);
if (sourceProvider == null)
{
throw new TestCaseSourceException("TestCaseClass type {0} could not be found for TestCaseSource {1}",
typeName, sourceName);
}
MemberInfo[] members = sourceProvider.GetStaticMembers(sourceName);
if (members.Length == 0)
{
throw new TestCaseSourceException("No static member found for TestCaseSource {0}.{1}",
sourceProvider.GenericTypeString(), sourceName);
}
if (members.Length > 1)
{
throw new TestCaseSourceException("Multiple members found matching TestCaseSource {0}.{1}",
sourceProvider.GenericTypeString(), sourceName);
}
MemberInfo testCaseSource = members[0];
Type memberType = testCaseSource.GetMemberType();
if (!typeof(IEnumerable).IsAssignableFrom(memberType))
{
throw new TestCaseSourceException("TestCaseSource {0} type {1} is incompatible with {2}",
sourceName, memberType.GenericTypeString(), typeof(IEnumerable).GenericTypeString());
}
return sourceProvider.ValueOf>(members[0]);
}
}
}