diff --git a/build.cake b/build.cake index 476eecd..d12411b 100644 --- a/build.cake +++ b/build.cake @@ -177,7 +177,7 @@ Task("InitializeForIntegrationTests") CleanDirectories(TEST_NUNIT_DIR + "**/*.*"); CleanDirectories(TEST_PACKAGES_DIR + "**/*.*"); - NuGetInstall(new [] {"NUnit.Runners", "NUnit"}, new NuGetInstallSettings() + NuGetInstall(new [] {"NUnit.Runners", "NUnit", "NUnitLite"}, new NuGetInstallSettings() { OutputDirectory = TEST_NUNIT_DIR, Source = PRERELEASE_PACKAGE_SOURCE, diff --git a/restore.cmd b/restore.cmd new file mode 100644 index 0000000..31ada7d --- /dev/null +++ b/restore.cmd @@ -0,0 +1 @@ +tools\nuget.exe install NUnit.Runners -Prerelease -Source "https://www.myget.org/F/nunit/api/v2" -OutputDirectory packages \ No newline at end of file diff --git a/src/extension/TeamCityEventListener.cs b/src/extension/TeamCityEventListener.cs index 122a6a5..fe702f3 100644 --- a/src/extension/TeamCityEventListener.cs +++ b/src/extension/TeamCityEventListener.cs @@ -42,6 +42,7 @@ namespace NUnit.Engine.Listeners public class TeamCityEventListener : ITestEventListener { private static readonly ServiceMessageWriter ServiceMessageWriter = new ServiceMessageWriter(); + private readonly TeamCityMessageConverter _messageConverter = new TeamCityMessageConverter(); private readonly TextWriter _outWriter; private readonly Dictionary _refs = new Dictionary(); private readonly Dictionary _blockCounters = new Dictionary(); @@ -63,138 +64,27 @@ public void OnTestEvent(string report) doc.LoadXml(report); var testEvent = doc.FirstChild; - RegisterMessage(testEvent); - } - - #endregion - public void RegisterMessage(XmlNode testEvent) - { - if (testEvent == null) throw new ArgumentNullException("testEvent"); - - var messageName = testEvent.Name; - if (string.IsNullOrEmpty(messageName)) + TeamCityMessageConverter.NUnitMessage message; + if (!TeamCityMessageConverter.NUnitMessage.TryParse(testEvent, out message)) { return; } - messageName = messageName.ToLowerInvariant(); - if (messageName == "start-run") - { - _refs.Clear(); - return; - } - - var fullName = testEvent.GetAttribute("fullname"); - if (string.IsNullOrEmpty(fullName)) - { - return; - } - - var id = testEvent.GetAttribute("id"); - if (id == null) - { - id = string.Empty; - } - - var parentId = testEvent.GetAttribute("parentId"); - var flowId = "."; - if (parentId != null) - { - // NUnit 3 case - string rootId; - flowId = TryFindRootId(parentId, out rootId) ? rootId : id; - } - else - { - // NUnit 2 case - if (!string.IsNullOrEmpty(id)) - { - var idParts = id.Split('-'); - if (idParts.Length == 2) - { - flowId = idParts[0]; - } - } - } - - string testFlowId; - if (id != flowId && parentId != null) - { - testFlowId = id; - } - else + var sb = new StringBuilder(); + using (var writer = new StringWriter(sb)) { - testFlowId = flowId; - if (testFlowId == null) + foreach (var tcMessage in _messageConverter.ConvertMessage(message)) { - testFlowId = id; + ServiceMessageWriter.Write(writer, tcMessage); } } - switch (messageName.ToLowerInvariant()) - { - case "start-suite": - _refs[id] = parentId; - StartSuiteCase(parentId, flowId, fullName); - break; - - case "test-suite": - _refs.Remove(id); - TestSuiteCase(parentId, flowId, fullName); - break; - - case "start-test": - _refs[id] = parentId; - CaseStartTest(id, flowId, parentId, testFlowId, fullName); - break; - - case "test-case": - try - { - if (!_refs.Remove(id)) - { - // When test without starting - CaseStartTest(id, flowId, parentId, testFlowId, fullName); - } - - var result = testEvent.GetAttribute("result"); - if (string.IsNullOrEmpty(result)) - { - break; - } - - switch (result.ToLowerInvariant()) - { - case "passed": - OnTestFinished(testFlowId, testEvent, fullName); - break; - - case "inconclusive": - OnTestInconclusive(testFlowId, testEvent, fullName); - break; - - case "skipped": - OnTestSkipped(testFlowId, testEvent, fullName); - break; - - case "failed": - OnTestFailed(testFlowId, testEvent, fullName); - break; - } - } - finally - { - if (id != flowId && parentId != null) - { - OnFlowFinished(id); - } - } - - break; - } + _outWriter.WriteLine(sb.ToString()); } + #endregion + private void CaseStartTest(string id, string flowId, string parentId, string testFlowId, string fullName) { if (id != flowId && parentId != null) @@ -282,7 +172,7 @@ private bool TryFindRootId(string id, out string rootId) private void TrySendOutput(string flowId, XmlNode message, string fullName) { - if (message == null) throw new ArgumentNullException("message"); + if (message == null) throw new ArgumentNullException("message"); var output = message.SelectSingleNode("output"); if (output == null) @@ -415,15 +305,6 @@ private void OnTestInconclusive(string flowId, XmlNode message, string fullName) new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId))); } - private void Write(ServiceMessage serviceMessage) - { - var sb = new StringBuilder(); - using (var writer = new StringWriter(sb)) - { - ServiceMessageWriter.Write(writer, serviceMessage); - } - - _outWriter.WriteLine(sb.ToString()); - } + } } diff --git a/src/extension/TeamCityMessageConverter.cs b/src/extension/TeamCityMessageConverter.cs new file mode 100644 index 0000000..d170c83 --- /dev/null +++ b/src/extension/TeamCityMessageConverter.cs @@ -0,0 +1,482 @@ +// *********************************************************************** +// Copyright (c) 2015 Charlie Poole +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// *********************************************************************** + +namespace NUnit.Engine.Listeners +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Xml; + + internal class TeamCityMessageConverter + { + private readonly Dictionary _refs = new Dictionary(); + private readonly Dictionary _blockCounters = new Dictionary(); + + public IEnumerable ConvertMessage(NUnitMessage message) + { + if (message == null) throw new ArgumentNullException("message"); + + if (message.Name.ToLowerInvariant() == "start-run") + { + _refs.Clear(); + yield break; + } + + var flowId = "."; + if (message.ParentId != null) + { + // NUnit 3 case + string rootId; + flowId = TryFindRootId(message.ParentId, out rootId) ? rootId : message.Id; + } + else + { + // NUnit 2 case + if (!string.IsNullOrEmpty(message.Id)) + { + var idParts = message.Id.Split('-'); + if (idParts.Length == 2) + { + flowId = idParts[0]; + } + } + } + + string testFlowId; + if (message.Id != flowId && message.ParentId != null) + { + testFlowId = message.Id; + } + else + { + testFlowId = flowId; + if (testFlowId == null) + { + testFlowId = message.Id; + } + } + + switch (message.Name.ToLowerInvariant()) + { + case "start-suite": + _refs[message.Id] = message.ParentId; + foreach (var tcMessage in StartSuiteCase(message.ParentId, flowId, message.FullName)) + { + yield return tcMessage; + } + + break; + + case "test-suite": + _refs.Remove(message.Id); + foreach (var tcMessage in TestSuiteCase(message.ParentId, flowId, message.FullName)) + { + yield return tcMessage; + } + + break; + + case "start-test": + _refs[message.Id] = message.ParentId; + foreach (var tcMessage in CaseStartTest(message.Id, flowId, message.ParentId, testFlowId, message.FullName)) + { + yield return tcMessage; + } + + break; + + case "test-case": + if (!_refs.Remove(message.Id)) + { + // When test without starting + foreach (var tcMessage in CaseStartTest(message.Id, flowId, message.ParentId, testFlowId, message.FullName)) + { + yield return tcMessage; + } + } + + if (string.IsNullOrEmpty(message.Result)) + { + break; + } + + switch (message.Result.ToLowerInvariant()) + { + case "passed": + foreach (var tcMessage in OnTestFinished(testFlowId, message)) + { + yield return tcMessage; + } + + break; + + case "inconclusive": + foreach (var tcMessage in OnTestInconclusive(testFlowId, message)) + { + yield return tcMessage; + } + + break; + + case "skipped": + foreach (var tcMessage in OnTestSkipped(testFlowId, message)) + { + yield return tcMessage; + } + + break; + + case "failed": + foreach (var tcMessage in OnTestFailed(testFlowId, message)) + { + yield return tcMessage; + } + + break; + } + + if (message.Id != flowId && message.ParentId != null) + { + foreach (var tcMessage in OnFlowFinished(message.Id)) + { + yield return tcMessage; + } + } + + break; + } + } + + private IEnumerable CaseStartTest(string id, string flowId, string parentId, string testFlowId, string fullName) + { + if (id != flowId && parentId != null) + { + foreach (var tcMessage in OnFlowStarted(id, flowId)) + { + yield return tcMessage; + } + } + + foreach (var tcMessage in OnTestStart(testFlowId, fullName)) + { + yield return tcMessage; + } + } + + private IEnumerable TestSuiteCase(string parentId, string flowId, string fullName) + { + // NUnit 3 case + if (parentId == string.Empty) + { + foreach (var tcMessage in OnRootSuiteFinish(flowId, fullName)) + { + yield return tcMessage; + } + } + + // NUnit 2 case + if (parentId == null) + { + if (ChangeBlockCounter(flowId, -1) == 0) + { + foreach (var tcMessage in OnRootSuiteFinish(flowId, fullName)) + { + yield return tcMessage; + } + } + } + } + + private IEnumerable StartSuiteCase(string parentId, string flowId, string fullName) + { + // NUnit 3 case + if (parentId == string.Empty) + { + foreach (var tcMessage in OnRootSuiteStart(flowId, fullName)) + { + yield return tcMessage; + } + } + + // NUnit 2 case + if (parentId == null) + { + if (ChangeBlockCounter(flowId, 1) == 1) + { + foreach (var tcMessage in OnRootSuiteStart(flowId, fullName)) + { + yield return tcMessage; + } + } + } + } + + private int ChangeBlockCounter(string flowId, int changeValue) + { + int currentBlockCounter; + if (!_blockCounters.TryGetValue(flowId, out currentBlockCounter)) + { + currentBlockCounter = 0; + } + + currentBlockCounter += changeValue; + _blockCounters[flowId] = currentBlockCounter; + return currentBlockCounter; + } + + private bool TryFindParentId(string id, out string parentId) + { + if (id == null) + { + throw new ArgumentNullException("id"); + } + + return _refs.TryGetValue(id, out parentId) && !string.IsNullOrEmpty(parentId); + } + + private bool TryFindRootId(string id, out string rootId) + { + if (id == null) + { + throw new ArgumentNullException("id"); + } + + while (TryFindParentId(id, out rootId) && id != rootId) + { + id = rootId; + } + + rootId = id; + return !string.IsNullOrEmpty(id); + } + + private IEnumerable TrySendOutput(string flowId, NUnitMessage message) + { + if (message == null) throw new ArgumentNullException("message"); + + var output = message.Output; + if (string.IsNullOrEmpty(output)) + { + yield break; + } + + yield return new ServiceMessage(ServiceMessage.Names.TestStdOut, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, message.FullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.Out, output), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId), + new ServiceMessageAttr(ServiceMessageAttr.Names.TcTags, "tc:parseServiceMessagesInside")); + } + + private IEnumerable OnRootSuiteStart(string flowId, string assemblyName) + { + assemblyName = Path.GetFileName(assemblyName); + + yield return new ServiceMessage(ServiceMessage.Names.TestSuiteStarted, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, assemblyName), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnRootSuiteFinish(string flowId, string assemblyName) + { + assemblyName = Path.GetFileName(assemblyName); + + yield return new ServiceMessage(ServiceMessage.Names.TestSuiteFinished, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, assemblyName), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnFlowStarted(string flowId, string parentFlowId) + { + yield return new ServiceMessage(ServiceMessage.Names.FlowStarted, + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId), + new ServiceMessageAttr(ServiceMessageAttr.Names.Parent, parentFlowId)); + } + + private IEnumerable OnFlowFinished(string flowId) + { + yield return new ServiceMessage(ServiceMessage.Names.FlowFinished, + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnTestStart(string flowId, string fullName) + { + yield return new ServiceMessage(ServiceMessage.Names.TestStarted, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, fullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.CaptureStandardOutput, "false"), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnTestFinished(string flowId, NUnitMessage message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + var durationStr = message.Duration; + double durationDecimal; + int durationMilliseconds = 0; + if (durationStr != null && double.TryParse(durationStr, NumberStyles.Any, CultureInfo.InvariantCulture, out durationDecimal)) + { + durationMilliseconds = (int)(durationDecimal * 1000d); + } + + foreach (var tcMessage in TrySendOutput(flowId, message)) + { + yield return tcMessage; + } + + yield return new ServiceMessage(ServiceMessage.Names.TestFinished, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, message.FullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.Duration, durationMilliseconds.ToString()), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnTestFailed(string flowId, NUnitMessage message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + yield return new ServiceMessage(ServiceMessage.Names.TestFailed, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, message.FullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.Message, message.ErrorMessage), + new ServiceMessageAttr(ServiceMessageAttr.Names.Details, message.StackTrace), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + + foreach (var tcMessage in OnTestFinished(flowId, message)) + { + yield return tcMessage; + } + } + + private IEnumerable OnTestSkipped(string flowId, NUnitMessage message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + foreach (var tcMessage in TrySendOutput(flowId, message)) + { + yield return tcMessage; + } + + yield return new ServiceMessage(ServiceMessage.Names.TestIgnored, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, message.FullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.Message, message.Message), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + private IEnumerable OnTestInconclusive(string flowId, NUnitMessage message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + foreach (var tcMessage in TrySendOutput(flowId, message)) + { + yield return tcMessage; + } + + yield return new ServiceMessage(ServiceMessage.Names.TestIgnored, + new ServiceMessageAttr(ServiceMessageAttr.Names.Name, message.FullName), + new ServiceMessageAttr(ServiceMessageAttr.Names.Message, "Inconclusive"), + new ServiceMessageAttr(ServiceMessageAttr.Names.FlowId, flowId)); + } + + internal class NUnitMessage + { + private readonly XmlNode _testEvent; + + public NUnitMessage(XmlNode testEvent) + { + _testEvent = testEvent; + } + + public static bool TryParse(XmlNode testEvent, out NUnitMessage message) + { + if (testEvent == null) throw new ArgumentNullException("testEvent"); + + message = default(NUnitMessage); + + var name = testEvent.Name; + if (string.IsNullOrEmpty(name)) + { + return false; + } + + var fullName = testEvent.GetAttribute("fullname"); + if (string.IsNullOrEmpty(fullName)) + { + return false; + } + + var id = testEvent.GetAttribute("id"); + if (id == null) + { + id = string.Empty; + } + + var parentId = testEvent.GetAttribute("parentId"); + + message = NUnitMessage(id, parentId, name, fullName, result, output); + return true; + } + + public string Id { + get + { + return _testEvent.GetAttribute("id") ?? string.Empty; + } + } + + public string ParentId { get; private set; } + + public string Name { get; private set; } + + public string Result { get; private set; } + + public string Output { get; private set; } + + public string FullName { get; private set; } + + public string Duration { get; private set; } + + public string ErrorMessage { get; private set; } + + public string StackTrace { get; private set; } + + public string Message { get; private set; } + + public bool Validate() + { + return !string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(FullName) && Id != null; + } + } + } +} \ No newline at end of file diff --git a/src/extension/teamcity-event-listener.csproj b/src/extension/teamcity-event-listener.csproj index 45f71ad..f69f671 100644 --- a/src/extension/teamcity-event-listener.csproj +++ b/src/extension/teamcity-event-listener.csproj @@ -49,6 +49,7 @@ + diff --git a/src/nunit.integration.tests/Dsl/Compiler.cs b/src/nunit.integration.tests/Dsl/Compiler.cs index a0cb396..4db3bfd 100644 --- a/src/nunit.integration.tests/Dsl/Compiler.cs +++ b/src/nunit.integration.tests/Dsl/Compiler.cs @@ -41,10 +41,18 @@ public void Compile(TestAssembly testAssembly, string assemblyFileName, TargetDo break; } - var assemblyInfoSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(AssemblyInfoResourceName) + Environment.NewLine + string.Join(Environment.NewLine, testAssembly.Attributes)); + var outputKind = OutputKind.DynamicallyLinkedLibrary; + switch (Path.GetExtension(assemblyFileName)?.ToLowerInvariant()) + { + case ".exe": + outputKind = OutputKind.ConsoleApplication; + break; + } + + var assemblyInfoSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(AssemblyInfoResourceName) + Environment.NewLine + string.Join(Environment.NewLine, testAssembly.Attributes)); var compilation = CSharpCompilation.Create(Path.GetFileName(assemblyFileName)) - .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + .WithOptions(new CSharpCompilationOptions(outputKind) .WithPlatform(testAssembly.Platform) .WithOptimizationLevel(OptimizationLevel.Debug)) .AddReferences(GetDotNetFrameworkReferences(dotNetFrameworkVersion, architecture)) diff --git a/src/nunit.integration.tests/Dsl/Compiler.cs.orig b/src/nunit.integration.tests/Dsl/Compiler.cs.orig new file mode 100644 index 0000000..7bb7abc --- /dev/null +++ b/src/nunit.integration.tests/Dsl/Compiler.cs.orig @@ -0,0 +1,135 @@ +namespace nunit.integration.tests.Dsl +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + + using Microsoft.Build.Utilities; + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; + + internal class Compiler + { + private static readonly SyntaxTree TestClassSyntaxTree; + private static readonly SyntaxTree UtilsSyntaxTree; + + private const string AssemblyInfoResourceName = "nunit.integration.tests.Templates.AssemblyInfo.cs"; + private const string UtilsResourceName = "nunit.integration.tests.Templates.Utils.cs"; + private const string TestFileResourceName = "nunit.integration.tests.Templates.UnitTest.cs"; + private static readonly ResourceManager ResourceManager = new ResourceManager(); + + static Compiler() + { + TestClassSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(TestFileResourceName)); + UtilsSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(UtilsResourceName)); + } + + public void Compile(TestAssembly testAssembly, string assemblyFileName, TargetDotNetFrameworkVersion dotNetFrameworkVersion) + { + var architecture = DotNetFrameworkArchitecture.Current; + switch (testAssembly.Platform) + { + case Platform.X86: + architecture = DotNetFrameworkArchitecture.Bitness32; + break; + + case Platform.X64: + architecture = DotNetFrameworkArchitecture.Bitness32; + break; + } + +<<<<<<< HEAD + var assemblyInfoSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(AssemblyInfoResourceName) + Environment.NewLine + string.Join(Environment.NewLine, testAssembly.Attributes)); +======= + var outputKind = OutputKind.DynamicallyLinkedLibrary; + switch (Path.GetExtension(assemblyFileName)?.ToLowerInvariant()) + { + case ".exe": + outputKind = OutputKind.ConsoleApplication; + break; + } + + var assemblyInfoSyntaxTree = CSharpSyntaxTree.ParseText(ResourceManager.GetContentFromResource(AssemblyInfoResourceName) + Environment.NewLine + string.Join(Environment.NewLine, testAssembly.Attributes)); +>>>>>>> #1 Handling of TeamCity messages is different between the engine and nunitlite - add tests for nunitlite + var compilation = + CSharpCompilation.Create(Path.GetFileName(assemblyFileName)) + .WithOptions(new CSharpCompilationOptions(outputKind) + .WithPlatform(testAssembly.Platform) + .WithOptimizationLevel(OptimizationLevel.Debug)) + .AddReferences(GetDotNetFrameworkReferences(dotNetFrameworkVersion, architecture)) + .AddReferences(testAssembly.References.Select(assembly => MetadataReference.CreateFromFile(assembly))) + .AddSyntaxTrees(assemblyInfoSyntaxTree) + .AddSyntaxTrees(UtilsSyntaxTree) + .AddSyntaxTrees(testAssembly.Classes.Select(CreateClassSyntaxTree)); + + using (var file = new FileStream(assemblyFileName, FileMode.Create)) + { + var result = compilation.Emit(file); + if (!result.Success) + { + var code = string.Join(Environment.NewLine + Environment.NewLine, compilation.SyntaxTrees.Select(i => i.ToString())); + throw new Exception($"Errors:\n{string.Join(Environment.NewLine, result.Diagnostics.Select(i => i.GetMessage(CultureInfo.InvariantCulture)))}\n\nCode:\n{code}"); + } + + file.Flush(true); + } + } + + private static SyntaxTree CreateClassSyntaxTree(TestClass testClass) + { + var attributes = testClass.Attributes.Select(i => CSharpSyntaxTree.ParseText(i).GetRoot().DescendantNodes().OfType().Single()).ToList(); + return + SyntaxFactory.CompilationUnit() + .AddUsings(GetUsingDirectives().ToArray()) + .AddMembers( + SyntaxFactory.NamespaceDeclaration(SyntaxFactory.IdentifierName(testClass.NamespaceName)) + .AddMembers( + SyntaxFactory.ClassDeclaration(testClass.ClassName) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("TestFixtureAttribute"))))) + .AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(attributes))) + // Ctor + .AddMembers( + SyntaxFactory.ConstructorDeclaration(testClass.ClassName) + .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + .AddBodyStatements( + testClass.CtorMethods.Select(CreateMethodStatement).ToArray())) + // Methods + .AddMembers(testClass.CtorMethods.Concat(testClass.Methods).Select(CreateMethod).ToArray()))).SyntaxTree; + } + + private static StatementSyntax CreateMethodStatement(Method method) + { + var methodAccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(method.Name)); + var arguments = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(Enumerable.Empty())); + return SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(methodAccess, arguments)); + } + + private static MemberDeclarationSyntax CreateMethod(Method method) + { + var methodTemplate = TestClassSyntaxTree.GetRoot().DescendantNodes().OfType().Single(i => string.Equals(i.Identifier.ValueText, method.Template, StringComparison.InvariantCultureIgnoreCase)); + return methodTemplate.WithIdentifier(SyntaxFactory.IdentifierName(method.Name).Identifier); + } + + private static IEnumerable GetUsingDirectives() + { + yield return SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System")); + yield return SyntaxFactory.UsingDirective(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("NUnit"), SyntaxFactory.IdentifierName("Framework"))); + } + + private IEnumerable GetDotNetFrameworkReferences(TargetDotNetFrameworkVersion dotNetFrameworkVersion, DotNetFrameworkArchitecture architecture) + { + yield return MetadataReference.CreateFromFile(ToolLocationHelper.GetPathToDotNetFrameworkFile("mscorlib.dll", dotNetFrameworkVersion, architecture)); + yield return MetadataReference.CreateFromFile(ToolLocationHelper.GetPathToDotNetFrameworkFile("System.dll", dotNetFrameworkVersion, architecture)); + if (dotNetFrameworkVersion != TargetDotNetFrameworkVersion.Version11 && dotNetFrameworkVersion != TargetDotNetFrameworkVersion.Version20) + { + yield return MetadataReference.CreateFromFile(ToolLocationHelper.GetPathToDotNetFrameworkFile("System.Core.dll", dotNetFrameworkVersion, architecture)); + } + + yield return MetadataReference.CreateFromFile(ToolLocationHelper.GetPathToDotNetFrameworkFile("System.Configuration.dll", dotNetFrameworkVersion, architecture)); + } + } +} diff --git a/src/nunit.integration.tests/Dsl/EnvironmentManager.cs b/src/nunit.integration.tests/Dsl/EnvironmentManager.cs index 813e7b1..6ec50f5 100644 --- a/src/nunit.integration.tests/Dsl/EnvironmentManager.cs +++ b/src/nunit.integration.tests/Dsl/EnvironmentManager.cs @@ -37,6 +37,7 @@ public void CopyReference(string directoryName, string referenceFileName) public IEnumerable EnumerateNUnitAssemblies(string nunitBasePath, TargetDotNetFrameworkVersion frameworkVersion) { yield return GetNUnitFrameworkPath(nunitBasePath, frameworkVersion, "nunit.framework.dll"); + yield return GetNUnitFrameworkPath(nunitBasePath, frameworkVersion, "nunitlite.dll"); var file = GetNUnitFrameworkPath(nunitBasePath, frameworkVersion, "NUnit.System.Linq.dll"); if (file != null) { diff --git a/src/nunit.integration.tests/NUnitSteps.cs b/src/nunit.integration.tests/NUnitSteps.cs index 782183b..a657953 100644 --- a/src/nunit.integration.tests/NUnitSteps.cs +++ b/src/nunit.integration.tests/NUnitSteps.cs @@ -233,6 +233,16 @@ public void RunNUnitConsole() ctx.TestSession = testSession; } + [When(@"I run (.+)")] + public void Run(string executable) + { + var ctx = ScenarioContext.Current.GetTestContext(); + var runner = new NUnitRunner(); + ICommandLineSetupFactory setupFactory = new GenericCommandLineSetupFactory(executable); + var testSession = runner.Run(ctx, setupFactory.Create(ctx)); + ctx.TestSession = testSession; + } + [Then(@"processes (.+) are finished")] public void CheckProcessesWereFinished(string processName) { diff --git a/src/nunit.integration.tests/Templates/UnitTest.cs b/src/nunit.integration.tests/Templates/UnitTest.cs index 17375cd..99feead 100644 --- a/src/nunit.integration.tests/Templates/UnitTest.cs +++ b/src/nunit.integration.tests/Templates/UnitTest.cs @@ -16,6 +16,11 @@ public void ThrowException() throw new System.Exception("Exception"); } + public static int NUnitLiteEntryPoint(string[] args) + { + return new NUnitLite.AutoRun(typeof(Program).Assembly).Execute(args, new NUnit.Common.ExtendedTextWrapper(Console.Out), Console.In); + } + [SetUp] public void FailedSeTup() { diff --git a/src/nunit.integration.tests/Templates/UnitTest.cs.orig b/src/nunit.integration.tests/Templates/UnitTest.cs.orig new file mode 100644 index 0000000..9037b42 --- /dev/null +++ b/src/nunit.integration.tests/Templates/UnitTest.cs.orig @@ -0,0 +1,111 @@ +namespace nunit.integration.tests.Templates +{ + using System; + + using NUnit.Framework; + + /// + /// Used as template for test methods. + /// The name of the methods should be equal to the TestType members. + /// + [TestFixture] + internal class UnitTest + { +<<<<<<< HEAD + public void ThrowException() + { + throw new System.Exception("Exception"); +======= + public static int NUnitLiteEntryPoint(string[] args) + { + return new NUnitLite.AutoRun(typeof(Program).Assembly).Execute(args, new NUnit.Common.ExtendedTextWrapper(Console.Out), Console.In); +>>>>>>> #1 Handling of TeamCity messages is different between the engine and nunitlite - add tests for nunitlite + } + + [SetUp] + public void FailedSeTup() + { + throw new System.Exception("Exception during setup"); + } + + [OneTimeSetUp] + public void FailedOneTimeSetUp() + { + throw new System.Exception("Exception during one time setup"); + } + + [TearDown] + public void FailedTearDown() + { + throw new System.Exception("Exception during tear down"); + } + + [Test] + public void Successful() + { + System.Console.Write("output"); + } + + [Test] + public void Failed() + { + Assert.Fail("Reason"); + } + + [Test] + public void Ignored() + { + Assert.Ignore("Reason"); + } + + [Test] + public void Inconclusive() + { + Assert.Inconclusive("Reason"); + } + + [Test, Category("CatA")] + public void SuccessfulCatA() + { + } + + [Test, Parallelizable] + public void SuccessfulParallelizable() + { + System.Console.WriteLine($"!!! ManagedThreadId = {System.Threading.Thread.CurrentThread.ManagedThreadId}"); + System.Threading.Thread.Sleep(100); + } + + [Test] + public void FailedStackOverflow() + { + System.Action[] infiniteRecursion = null; + infiniteRecursion = new System.Action[1] { () => { infiniteRecursion[0](); } }; + infiniteRecursion[0](); + } + + [Test] + public void FailedOutOfMemory() + { + System.Collections.Generic.List bytes = new System.Collections.Generic.List(); + while (true) + { + bytes.Add(new byte[0xffffff]); + } + } + + [Test] + public void SuccessfulWithConfig() + { + System.Console.Write(System.IO.Path.GetFileName(System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)); + var message = System.Configuration.ConfigurationManager.AppSettings["TestMessage"]; + Assert.IsNotNull(message); + } + + [Test] + public void UnloadingDomain() + { + UnloadingDomainUtil.Create(); + } + } +} \ No newline at end of file diff --git a/src/nunit.integration.tests/nunit.integration.tests.csproj b/src/nunit.integration.tests/nunit.integration.tests.csproj index 7d86a00..3edaad0 100644 --- a/src/nunit.integration.tests/nunit.integration.tests.csproj +++ b/src/nunit.integration.tests/nunit.integration.tests.csproj @@ -183,6 +183,7 @@ + @@ -259,6 +260,11 @@ True True + + TeamCityForNUnitlite.feature + True + True + True True @@ -299,6 +305,10 @@ SpecFlowSingleFileGenerator SupportPlatforms.feature.cs + + SpecFlowSingleFileGenerator + TeamCityForNUnitlite.feature.cs + SpecFlowSingleFileGenerator RunTests.feature.cs diff --git a/src/nunit.integration.tests/nunit.integration.tests.csproj.orig b/src/nunit.integration.tests/nunit.integration.tests.csproj.orig new file mode 100644 index 0000000..769e7bf --- /dev/null +++ b/src/nunit.integration.tests/nunit.integration.tests.csproj.orig @@ -0,0 +1,356 @@ + + + + Debug + AnyCPU + {20341411-06A1-4A0E-8896-020500C3D4E5} + Library + Properties + nunit.integration.tests + nunit.integration.tests + v4.6 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + true + full + false + ..\..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + x64 + + + pdbonly + true + ..\..\bin\Release\ + TRACE + prompt + 4 + x86 + + + + ..\..\packages\TeamCity.ServiceMessages.3.0.5.1\lib\net35\JetBrains.TeamCity.ServiceMessages.dll + True + + + + ..\..\packages\Microsoft.CodeAnalysis.Common.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.CSharp.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.CSharp.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll + True + + + ..\..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.0.0-beta3\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll + True + + + ..\..\packages\NUnit.3.4.1\lib\net45\nunit.framework.dll + True + + + + ..\..\packages\System.AppContext.4.1.0\lib\net46\System.AppContext.dll + True + + + ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + + ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll + True + + + ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll + True + + + ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll + True + + + ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll + True + + + ..\..\packages\Microsoft.Composition.1.0.30\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll + True + + + ..\..\packages\System.Console.4.0.0\lib\net46\System.Console.dll + True + + + ..\..\packages\System.Diagnostics.FileVersionInfo.4.0.0\lib\net46\System.Diagnostics.FileVersionInfo.dll + True + + + ..\..\packages\System.Diagnostics.StackTrace.4.0.1\lib\net46\System.Diagnostics.StackTrace.dll + True + + + ..\..\packages\System.IO.FileSystem.4.0.1\lib\net46\System.IO.FileSystem.dll + True + + + ..\..\packages\System.IO.FileSystem.Primitives.4.0.1\lib\net46\System.IO.FileSystem.Primitives.dll + True + + + + ..\..\packages\System.Reflection.Metadata.1.4.1-beta-24227-04\lib\portable-net45+win8\System.Reflection.Metadata.dll + True + + + ..\..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net46\System.Security.Cryptography.Algorithms.dll + True + + + ..\..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + + + ..\..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + + + ..\..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net46\System.Security.Cryptography.X509Certificates.dll + True + + + ..\..\packages\System.Text.Encoding.CodePages.4.0.1\lib\net46\System.Text.Encoding.CodePages.dll + True + + + ..\..\packages\System.Threading.Thread.4.0.0\lib\net46\System.Threading.Thread.dll + True + + + + + ..\..\packages\System.Xml.XmlDocument.4.0.1\lib\net46\System.Xml.XmlDocument.dll + True + + + ..\..\packages\System.Xml.XPath.4.0.1\lib\net46\System.Xml.XPath.dll + True + + + ..\..\packages\System.Xml.XPath.XDocument.4.0.1\lib\net46\System.Xml.XPath.XDocument.dll + True + + + ..\..\packages\SpecFlow.2.1.0\lib\net45\TechTalk.SpecFlow.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AppConfig.feature + True + True + + + + ListOfTests.feature + True + True + + + True + True + ExcludeIncludeTests.feature + + + True + True + ExitCodeForExceptionalCases.feature + + + + + True + True + RunningFromDifferentLocations.feature + + + ReleaseOSResources.feature + True + True + + + True + True + SupportPlatforms.feature + +<<<<<<< HEAD + + RunTests.feature +======= + + TeamCityForNUnitlite.feature +>>>>>>> #1 Handling of TeamCity messages is different between the engine and nunitlite - add tests for nunitlite + True + True + + + True + True + TeamCity.feature + + + + + + + SpecFlowSingleFileGenerator + AppConfig.feature.cs + + + SpecFlowSingleFileGenerator + ListOfTests.feature.cs + + + SpecFlowSingleFileGenerator + ExcludeIncludeTests.feature.cs + + + SpecFlowSingleFileGenerator + ExitCodeForExceptionalCases.feature.cs + + + Designer + + + SpecFlowSingleFileGenerator + RunningFromDifferentLocations.feature.cs + + + SpecFlowSingleFileGenerator + ReleaseOSResources.feature.cs + + + SpecFlowSingleFileGenerator + SupportPlatforms.feature.cs + +<<<<<<< HEAD + + SpecFlowSingleFileGenerator + RunTests.feature.cs +======= + + SpecFlowSingleFileGenerator + TeamCityForNUnitlite.feature.cs +>>>>>>> #1 Handling of TeamCity messages is different between the engine and nunitlite - add tests for nunitlite + + + SpecFlowSingleFileGenerator + TeamCity.feature.cs + + + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file