/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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]); } } }