diff --git a/src/Adapter/PlatformServices.Desktop/Services/DesktopTestContextImplementation.cs b/src/Adapter/PlatformServices.Desktop/Services/DesktopTestContextImplementation.cs index 365dd15478..3fc57d069f 100644 --- a/src/Adapter/PlatformServices.Desktop/Services/DesktopTestContextImplementation.cs +++ b/src/Adapter/PlatformServices.Desktop/Services/DesktopTestContextImplementation.cs @@ -249,6 +249,53 @@ public override void EndTimer(string timerName) throw new NotSupportedException(); } + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The formatted string that contains the trace message. + public override void Write(string message) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + var msg = message?.Replace("\0", "\\0"); + this.stringWriter.Write(msg); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The string that contains the trace message. + /// Arguments to add to the trace message. + public override void Write(string format, params object[] args) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + string message = string.Format(CultureInfo.CurrentCulture, format?.Replace("\0", "\\0"), args); + this.stringWriter.Write(message); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + /// /// When overridden in a derived class, used to write trace messages while the /// test is running. diff --git a/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs b/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs index b1f11a2dc9..40595a6bee 100644 --- a/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs +++ b/src/Adapter/PlatformServices.NetCore/Services/NetCoreTestContextImplementation.cs @@ -289,6 +289,53 @@ public IList GetResultFiles() return results; } + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The formatted string that contains the trace message. + public override void Write(string message) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + var msg = message?.Replace("\0", "\\0"); + this.stringWriter.Write(msg); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The string that contains the trace message. + /// Arguments to add to the trace message. + public override void Write(string format, params object[] args) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + string message = string.Format(CultureInfo.CurrentCulture, format?.Replace("\0", "\\0"), args); + this.stringWriter.Write(message); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + /// /// When overridden in a derived class, used to write trace messages while the /// test is running. diff --git a/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10TestContextImplementation.cs b/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10TestContextImplementation.cs index 7018ad4550..acdc11a496 100644 --- a/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10TestContextImplementation.cs +++ b/src/Adapter/PlatformServices.Shared/netstandard1.0/Services/ns10TestContextImplementation.cs @@ -187,6 +187,53 @@ public void AddProperty(string propertyName, string propertyValue) this.properties.Add(propertyName, propertyValue); } + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The formatted string that contains the trace message. + public override void Write(string message) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + var msg = message?.Replace("\0", "\\0"); + this.stringWriter.Write(msg); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + + /// + /// When overridden in a derived class, used to write trace messages while the + /// test is running. + /// + /// The string that contains the trace message. + /// Arguments to add to the trace message. + public override void Write(string format, params object[] args) + { + if (this.stringWriterDisposed) + { + return; + } + + try + { + string message = string.Format(CultureInfo.CurrentCulture, format?.Replace("\0", "\\0"), args); + this.stringWriter.Write(message); + } + catch (ObjectDisposedException) + { + this.stringWriterDisposed = true; + } + } + /// /// When overridden in a derived class, used to write trace messages while the /// test is running. diff --git a/src/TestFramework/Extension.Core/NetCoreTestContext.cs b/src/TestFramework/Extension.Core/NetCoreTestContext.cs index ebecd7fb76..140116e780 100644 --- a/src/TestFramework/Extension.Core/NetCoreTestContext.cs +++ b/src/TestFramework/Extension.Core/NetCoreTestContext.cs @@ -105,6 +105,19 @@ public abstract class TestContext /// public abstract void AddResultFile(string fileName); + /// + /// Used to write trace messages while the test is running + /// + /// formatted message string + public abstract void Write(string message); + + /// + /// Used to write trace messages while the test is running + /// + /// format string + /// the arguments + public abstract void Write(string format, params object[] args); + /// /// Used to write trace messages while the test is running /// diff --git a/src/TestFramework/Extension.Desktop/DesktopTestContext.cs b/src/TestFramework/Extension.Desktop/DesktopTestContext.cs index 1b95acd060..6829575609 100644 --- a/src/TestFramework/Extension.Desktop/DesktopTestContext.cs +++ b/src/TestFramework/Extension.Desktop/DesktopTestContext.cs @@ -111,6 +111,19 @@ public abstract class TestContext /// public virtual UnitTestOutcome CurrentTestOutcome => UnitTestOutcome.Unknown; + /// + /// Used to write trace messages while the test is running + /// + /// formatted message string + public abstract void Write(string message); + + /// + /// Used to write trace messages while the test is running + /// + /// format string + /// the arguments + public abstract void Write(string format, params object[] args); + /// /// Used to write trace messages while the test is running /// diff --git a/src/TestFramework/Extension.Shared/TestContext.cs b/src/TestFramework/Extension.Shared/TestContext.cs index 73996020eb..4de71f3bf4 100644 --- a/src/TestFramework/Extension.Shared/TestContext.cs +++ b/src/TestFramework/Extension.Shared/TestContext.cs @@ -48,6 +48,19 @@ public abstract class TestContext /// public virtual UnitTestOutcome CurrentTestOutcome => UnitTestOutcome.Unknown; + /// + /// Used to write trace messages while the test is running + /// + /// formatted message string + public abstract void Write(string message); + + /// + /// Used to write trace messages while the test is running + /// + /// format string + /// the arguments + public abstract void Write(string format, params object[] args); + /// /// Used to write trace messages while the test is running /// diff --git a/test/UnitTests/PlatformServices.Desktop.Unit.Tests/Services/DesktopTestContextImplTests.cs b/test/UnitTests/PlatformServices.Desktop.Unit.Tests/Services/DesktopTestContextImplTests.cs index e5d26ae794..e164d16f5b 100644 --- a/test/UnitTests/PlatformServices.Desktop.Unit.Tests/Services/DesktopTestContextImplTests.cs +++ b/test/UnitTests/PlatformServices.Desktop.Unit.Tests/Services/DesktopTestContextImplTests.cs @@ -25,7 +25,7 @@ namespace MSTestAdapter.PlatformServices.Desktop.UnitTests.Services using UnitTestOutcome = FrameworkV2::Microsoft.VisualStudio.TestTools.UnitTesting.UnitTestOutcome; [TestClass] - public class DEsktopTestContextImplTests + public class DesktopTestContextImplTests { private Mock testMethod; @@ -215,6 +215,76 @@ public void AddResultFileShouldAddMultipleFilestoResultsFiles() CollectionAssert.Contains(resultsFiles.ToList(), "C:\\temp2.txt"); } + [TestMethod] + public void WriteShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing write", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing \0 write \0", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("{0} Testing write", 1); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("{0} Testing write", 1); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing write"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing \0 write \0"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteWithMessageShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("1 Testing write"); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForReturnCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("2 Testing write \n\r"); + this.testContextImplementation.Write("3 Testing write\n\r"); + StringAssert.Equals(stringWriter.ToString(), "2 Testing write 3 Testing write"); + } + [TestMethod] public void WriteLineShouldWriteToStringWriter() { diff --git a/test/UnitTests/PlatformServices.NetCore.Unit.Tests/Services/NetCoreTestContextImplementationTests.cs b/test/UnitTests/PlatformServices.NetCore.Unit.Tests/Services/NetCoreTestContextImplementationTests.cs index b375b9470c..4c06dfba8f 100644 --- a/test/UnitTests/PlatformServices.NetCore.Unit.Tests/Services/NetCoreTestContextImplementationTests.cs +++ b/test/UnitTests/PlatformServices.NetCore.Unit.Tests/Services/NetCoreTestContextImplementationTests.cs @@ -164,6 +164,76 @@ public void AddPropertyShouldAddPropertiesToThePropertyBag() new KeyValuePair("SomeNewProperty", "SomeValue")); } + [TestMethod] + public void WriteShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing write", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing \0 write \0", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("{0} Testing write", 1); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("{0} Testing write", 1); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing write"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing \0 write \0"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteWithMessageShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("1 Testing write"); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForReturnCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("2 Testing write \n\r"); + this.testContextImplementation.Write("3 Testing write\n\r"); + StringAssert.Equals(stringWriter.ToString(), "2 Testing write 3 Testing write"); + } + [TestMethod] public void WriteLineShouldWriteToStringWriter() { diff --git a/test/UnitTests/PlatformServices.Shared.Unit.Tests/netstandard1.0/ns10TestContextImplementationTests.cs b/test/UnitTests/PlatformServices.Shared.Unit.Tests/netstandard1.0/ns10TestContextImplementationTests.cs index e0c26889da..e29c15dda9 100644 --- a/test/UnitTests/PlatformServices.Shared.Unit.Tests/netstandard1.0/ns10TestContextImplementationTests.cs +++ b/test/UnitTests/PlatformServices.Shared.Unit.Tests/netstandard1.0/ns10TestContextImplementationTests.cs @@ -161,6 +161,76 @@ public void AddPropertyShouldAddPropertiesToThePropertyBag() new KeyValuePair("SomeNewProperty", "SomeValue")); } + [TestMethod] + public void WriteShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing write", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("{0} Testing \0 write \0", 1); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("{0} Testing write", 1); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("{0} Testing write", 1); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriter() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing write"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForNullCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("1 Testing \0 write \0"); + StringAssert.Contains(stringWriter.ToString(), "1 Testing \\0 write \\0"); + } + + [TestMethod] + public void WriteWithMessageShouldNotThrowIfStringWriterIsDisposed() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + stringWriter.Dispose(); + this.testContextImplementation.Write("1 Testing write"); + + // Calling it twice to cover the direct return when we know the object has been disposed. + this.testContextImplementation.Write("1 Testing write"); + } + + [TestMethod] + public void WriteWithMessageShouldWriteToStringWriterForReturnCharacters() + { + var stringWriter = new StringWriter(); + this.testContextImplementation = new TestContextImplementation(this.testMethod.Object, stringWriter, this.properties); + this.testContextImplementation.Write("2 Testing write \n\r"); + this.testContextImplementation.Write("3 Testing write\n\r"); + StringAssert.Equals(stringWriter.ToString(), "2 Testing write 3 Testing write"); + } + [TestMethod] public void WriteLineShouldWriteToStringWriter() {