/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 <http://www.gnu.org/licenses/>. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 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 { /// <summary>Responsible for Invoking <c>TestMethods</c> within a <c>TestCaseClass</c>. Handles /// both methods with and without <c>TestCase</c>/<c>TestCaseSource</c> attrubutes.</summary> public class TestCaseInvoker : ITestMethodInvoker { private readonly TestMethodInvokerContext invokerContext; /// <summary>Create a TestInvoker with the given invokerContext</summary> public TestCaseInvoker(TestMethodInvokerContext invokerContext) { this.invokerContext = invokerContext; } /// <summary>Invokes a <c>TestMethod</c> with the given arguments.</summary> public TestMethodInvokerResult Invoke(params object[] args) { MethodInfo method = invokerContext.TestMethodInfo; var results = new TestMethodInvokerResult(); if (method.IsExplicitOrIgnored()) { return results; } IList<TestCaseAttribute> testCases = method.GetAttributes<TestCaseAttribute>(); IList<TestCaseSourceAttribute> testCaseSources = method.GetAttributes<TestCaseSourceAttribute>(); 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<TestCaseData> GetTestCaseData(IEnumerable<TestCaseAttribute> cases, IEnumerable<TestCaseSourceAttribute> sources) { return cases.Select(attr => new TestCaseData(attr.TestArguments).SetName(attr.Description)) .Concat(sources.SelectMany(GetTestCaseDataFromSource)); } private IEnumerable<TestCaseData> 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<TestCaseData>).IsAssignableFrom(memberType)) { throw new TestCaseSourceException("TestCaseSource {0} type {1} is incompatible with {2}", sourceName, memberType.GenericTypeString(), typeof(IEnumerable<TestCaseData>).GenericTypeString()); } return sourceProvider.ValueOf<IEnumerable<TestCaseData>>(members[0]); } } }