diff --git a/global.json b/global.json index 1dc269111cae..2b0f56d196c0 100644 --- a/global.json +++ b/global.json @@ -26,6 +26,6 @@ "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "4.1.82", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.4", - "MSTest.Sdk": "4.3.0-preview.26307.5" + "MSTest.Sdk": "4.3.0-preview.26311.10" } } diff --git a/sdk.slnx b/sdk.slnx index df9722223799..07d879bec7b9 100644 --- a/sdk.slnx +++ b/sdk.slnx @@ -367,6 +367,7 @@ + diff --git a/src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs b/src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs index 74a1e15ab7a8..3d48d3fc6f5e 100644 --- a/src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs +++ b/src/Dotnet.Watch/Watch.Aspire/Properties/AssemblyInfo.cs @@ -4,4 +4,5 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.DotNet.HotReload.Watch.Aspire.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("dotnet-watch.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Dotnet.Watch/dotnet-watch.slnf b/src/Dotnet.Watch/dotnet-watch.slnf index 48e156d1458e..b5600195a12e 100644 --- a/src/Dotnet.Watch/dotnet-watch.slnf +++ b/src/Dotnet.Watch/dotnet-watch.slnf @@ -33,6 +33,7 @@ "test\\dotnet-watch-test-browser\\dotnet-watch-test-browser.csproj", "test\\Microsoft.DotNet.HotReload.Test.Utilities\\Microsoft.DotNet.HotReload.Test.Utilities.csproj", "test\\Microsoft.DotNet.HotReload.Watch.Aspire.Tests\\Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj", + "test\\Microsoft.DotNet.Test.MSTest.Utilities\\Microsoft.DotNet.Test.MSTest.Utilities.csproj", "test\\Microsoft.Extensions.DotNetDeltaApplier.Tests\\Microsoft.Extensions.DotNetDeltaApplier.Tests.csproj", "test\\dotnet-watch.Tests\\dotnet-watch.Tests.csproj" ] diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BlazorWasmHotReloadMiddlewareTest.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BlazorWasmHotReloadMiddlewareTest.cs index efdcf548c524..f72bc30a5454 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BlazorWasmHotReloadMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BlazorWasmHotReloadMiddlewareTest.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; @@ -7,6 +7,7 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh { + [TestClass] public class BlazorWasmHotReloadMiddlewareTest { private readonly ILogger _logger; @@ -19,7 +20,7 @@ public BlazorWasmHotReloadMiddlewareTest() _middleware = new BlazorWasmHotReloadMiddleware(context => throw new TimeZoneNotFoundException(), _logger); } - [Fact] + [TestMethod] public async Task DeltasAreSavedOnPost() { var context = new DefaultHttpContext(); @@ -55,7 +56,7 @@ public async Task DeltasAreSavedOnPost() AssertUpdates([update], _middleware.Updates); } - [Fact] + [TestMethod] public async Task DuplicateDeltasOnPostAreIgnored() { var updates = new BlazorWasmHotReloadMiddleware.Update[] @@ -106,7 +107,7 @@ public async Task DuplicateDeltasOnPostAreIgnored() AssertUpdates(updates, _middleware.Updates); } - [Fact] + [TestMethod] public async Task MultipleDeltaPayloadsCanBeAccepted() { var update = new BlazorWasmHotReloadMiddleware.Update() @@ -178,7 +179,7 @@ public async Task MultipleDeltaPayloadsCanBeAccepted() AssertUpdates([update, newUpdate], _middleware.Updates); } - [Fact] + [TestMethod] public async Task Get_Returns204_IfNoDeltasPresent() { var context = new DefaultHttpContext(); @@ -186,10 +187,10 @@ public async Task Get_Returns204_IfNoDeltasPresent() await _middleware.InvokeAsync(context); - Assert.Equal(204, context.Response.StatusCode); + Assert.AreEqual(204, context.Response.StatusCode); } - [Fact] + [TestMethod] public async Task GetReturnsDeltas() { var context = new DefaultHttpContext(); @@ -226,30 +227,30 @@ public async Task GetReturnsDeltas() await _middleware.InvokeAsync(context); - Assert.Equal(200, context.Response.StatusCode); - Assert.Equal( + Assert.AreEqual(200, context.Response.StatusCode); + Assert.AreSequenceEqual( JsonSerializer.SerializeToUtf8Bytes(updates, new JsonSerializerOptions(JsonSerializerDefaults.Web)), stream.ToArray()); } private static void AssertUpdates(IReadOnlyList expected, IReadOnlyList actual) { - Assert.Equal(expected.Count, actual.Count); + Assert.AreEqual(expected.Count, actual.Count); for (var u = 0; u < expected.Count; u++) { var expectedUpdate = expected[u]; var actualUpdate = actual[u]; - Assert.Equal(expectedUpdate.Id, actualUpdate.Id); - Assert.Equal(expectedUpdate.Deltas.Length, expectedUpdate.Deltas.Length); + Assert.AreEqual(expectedUpdate.Id, actualUpdate.Id); + Assert.AreEqual(expectedUpdate.Deltas.Length, expectedUpdate.Deltas.Length); for (var i = 0; i < expectedUpdate.Deltas.Length; i++) { - Assert.Equal(expectedUpdate.Deltas[i].ILDelta, actualUpdate.Deltas[i].ILDelta); - Assert.Equal(expectedUpdate.Deltas[i].PdbDelta, actualUpdate.Deltas[i].PdbDelta); - Assert.Equal(expectedUpdate.Deltas[i].MetadataDelta, actualUpdate.Deltas[i].MetadataDelta); - Assert.Equal(expectedUpdate.Deltas[i].ModuleId, actualUpdate.Deltas[i].ModuleId); - Assert.Equal(expectedUpdate.Deltas[i].UpdatedTypes, actualUpdate.Deltas[i].UpdatedTypes); + Assert.AreEqual(expectedUpdate.Deltas[i].ILDelta, actualUpdate.Deltas[i].ILDelta); + Assert.AreEqual(expectedUpdate.Deltas[i].PdbDelta, actualUpdate.Deltas[i].PdbDelta); + Assert.AreEqual(expectedUpdate.Deltas[i].MetadataDelta, actualUpdate.Deltas[i].MetadataDelta); + Assert.AreEqual(expectedUpdate.Deltas[i].ModuleId, actualUpdate.Deltas[i].ModuleId); + Assert.AreSequenceEqual(expectedUpdate.Deltas[i].UpdatedTypes, actualUpdate.Deltas[i].UpdatedTypes); } } } diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs index d04585a7113d..55416d986134 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserRefreshMiddlewareTest.cs @@ -10,12 +10,13 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh { + [TestClass] public class BrowserRefreshMiddlewareTest { - [Theory] - [InlineData("DELETE")] - [InlineData("head")] - [InlineData("Put")] + [TestMethod] + [DataRow("DELETE")] + [DataRow("head")] + [DataRow("Put")] public void IsBrowserDocumentRequest_ReturnsFalse_ForNonGetOrPostRequests(string method) { // Arrange @@ -35,10 +36,10 @@ public void IsBrowserDocumentRequest_ReturnsFalse_ForNonGetOrPostRequests(string var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public void IsBrowserDocumentRequest_ReturnsFalse_IsRequestDoesNotAcceptHtml() { // Arrange @@ -58,10 +59,10 @@ public void IsBrowserDocumentRequest_ReturnsFalse_IsRequestDoesNotAcceptHtml() var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public void IsBrowserDocumentRequest_ReturnsTrue_ForGetRequestsThatAcceptHtml() { // Arrange @@ -81,10 +82,10 @@ public void IsBrowserDocumentRequest_ReturnsTrue_ForGetRequestsThatAcceptHtml() var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Fact] + [TestMethod] public void IsBrowserDocumentRequest_ReturnsTrue_ForRequestsThatAcceptAnyHtml() { // Arrange @@ -104,10 +105,10 @@ public void IsBrowserDocumentRequest_ReturnsTrue_ForRequestsThatAcceptAnyHtml() var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Fact] + [TestMethod] public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestDoesNotHaveFetchMetadataRequestHeader() { // Arrange @@ -127,10 +128,10 @@ public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestDoesNotHaveFetchMetada var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Fact] + [TestMethod] public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHeaderIsEmpty() { // Arrange @@ -151,12 +152,12 @@ public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHe var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("document")] - [InlineData("Document")] + [TestMethod] + [DataRow("document")] + [DataRow("Document")] public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHeaderIsDocument(string headerValue) { // Arrange @@ -177,12 +178,12 @@ public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHe var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("frame")] - [InlineData("iframe")] + [TestMethod] + [DataRow("frame")] + [DataRow("iframe")] public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHeaderIsFrame(string headerValue) { // Arrange @@ -203,11 +204,11 @@ public void IsBrowserDocumentRequest_ReturnsTrue_IfRequestFetchMetadataRequestHe var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("serviceworker")] + [TestMethod] + [DataRow("serviceworker")] public void IsBrowserDocumentRequest_ReturnsFalse_IfRequestFetchMetadataRequestHeaderIsNotDocument(string headerValue) { // Arrange @@ -228,14 +229,14 @@ public void IsBrowserDocumentRequest_ReturnsFalse_IfRequestFetchMetadataRequestH var result = BrowserRefreshMiddleware.IsBrowserDocumentRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Theory] - [InlineData("DELETE")] - [InlineData("POST")] - [InlineData("head")] - [InlineData("Put")] + [TestMethod] + [DataRow("DELETE")] + [DataRow("POST")] + [DataRow("head")] + [DataRow("Put")] public void IsWebassemblyBootRequest_ReturnsFalse_ForNonGetRequests(string method) { // Arrange @@ -256,10 +257,10 @@ public void IsWebassemblyBootRequest_ReturnsFalse_ForNonGetRequests(string metho var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public void IsWebassemblyBootRequest_ReturnsFalse_IfRequestDoesNotAcceptJson() { // Arrange @@ -280,10 +281,10 @@ public void IsWebassemblyBootRequest_ReturnsFalse_IfRequestDoesNotAcceptJson() var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public void IsWebassemblyBootRequest_ReturnsTrue_ForGetRequestsThatAcceptJson() { // Arrange @@ -304,10 +305,10 @@ public void IsWebassemblyBootRequest_ReturnsTrue_ForGetRequestsThatAcceptJson() var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Fact] + [TestMethod] public void IsWebassemblyBootRequest_ReturnsTrue_ForGetRequestsThatAcceptAnyContentType() { // Arrange @@ -328,12 +329,12 @@ public void IsWebassemblyBootRequest_ReturnsTrue_ForGetRequestsThatAcceptAnyCont var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("/_framework/blazor.boot.json")] - [InlineData("/Blazor.boot.json")] + [TestMethod] + [DataRow("/_framework/blazor.boot.json")] + [DataRow("/Blazor.boot.json")] public void IsWebassemblyBootRequest_ReturnsTrue_ForFileNameRequestsToBlazorBootJson(string path) { // Arrange @@ -354,13 +355,13 @@ public void IsWebassemblyBootRequest_ReturnsTrue_ForFileNameRequestsToBlazorBoot var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("/_framework/other.txt")] - [InlineData("/other.txt")] - [InlineData("/Blazor.boot.json/other.txt")] + [TestMethod] + [DataRow("/_framework/other.txt")] + [DataRow("/other.txt")] + [DataRow("/Blazor.boot.json/other.txt")] public void IsWebassemblyBootRequest_ReturnsFalse_ForRequestsToOtherPathsThanBlazorBootJson(string path) { // Arrange @@ -381,10 +382,10 @@ public void IsWebassemblyBootRequest_ReturnsFalse_ForRequestsToOtherPathsThanBla var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestDoesNotHaveFetchMetadataRequestHeader() { // Arrange @@ -405,10 +406,10 @@ public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestDoesNotHaveFetchMetada var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Fact] + [TestMethod] public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestFetchMetadataRequestHeaderIsEmpty() { // Arrange @@ -430,12 +431,12 @@ public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestFetchMetadataRequestHe var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("empty")] - [InlineData("Empty")] + [TestMethod] + [DataRow("empty")] + [DataRow("Empty")] public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestFetchMetadataRequestHeaderIsEmptyValue(string headerValue) { // Arrange @@ -457,14 +458,14 @@ public void IsWebassemblyBootRequest_ReturnsTrue_IfRequestFetchMetadataRequestHe var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.True(result); + Assert.IsTrue(result); } - [Theory] - [InlineData("frame")] - [InlineData("iframe")] - [InlineData("serviceworker")] - [InlineData("document")] + [TestMethod] + [DataRow("frame")] + [DataRow("iframe")] + [DataRow("serviceworker")] + [DataRow("document")] public void IsWebassemblyBootRequest_ReturnsFalse_IfRequestFetchMetadataRequestHeaderIsEmptyValue(string headerValue) { // Arrange @@ -486,10 +487,10 @@ public void IsWebassemblyBootRequest_ReturnsFalse_IfRequestFetchMetadataRequestH var result = BrowserRefreshMiddleware.IsWebAssemblyBootRequest(context); // Assert - Assert.False(result); + Assert.IsFalse(result); } - [Fact] + [TestMethod] public async Task InvokeAsync_AttachesHeadersToResponse() { var stream = new MemoryStream(); @@ -528,11 +529,11 @@ public async Task InvokeAsync_AttachesHeadersToResponse() await middleware.InvokeAsync(context); // Assert - Assert.True(context.Response.Headers.ContainsKey("DOTNET-MODIFIABLE-ASSEMBLIES")); - Assert.True(context.Response.Headers.ContainsKey("ASPNETCORE-BROWSER-TOOLS")); + Assert.IsTrue(context.Response.Headers.ContainsKey("DOTNET-MODIFIABLE-ASSEMBLIES")); + Assert.IsTrue(context.Response.Headers.ContainsKey("ASPNETCORE-BROWSER-TOOLS")); } - [Fact] + [TestMethod] public async Task InvokeAsync_DoesNotAttachHeaders_WhenAlreadyAttached() { var stream = new MemoryStream(); @@ -574,16 +575,16 @@ public async Task InvokeAsync_DoesNotAttachHeaders_WhenAlreadyAttached() await middleware.InvokeAsync(context); // Assert - Assert.True(context.Response.Headers.ContainsKey("DOTNET-MODIFIABLE-ASSEMBLIES")); - Assert.Equal("true", context.Response.Headers["DOTNET-MODIFIABLE-ASSEMBLIES"]); - Assert.True(context.Response.Headers.ContainsKey("ASPNETCORE-BROWSER-TOOLS")); - Assert.Equal("true", context.Response.Headers["ASPNETCORE-BROWSER-TOOLS"]); + Assert.IsTrue(context.Response.Headers.ContainsKey("DOTNET-MODIFIABLE-ASSEMBLIES")); + Assert.AreEqual("true", context.Response.Headers["DOTNET-MODIFIABLE-ASSEMBLIES"].ToString()); + Assert.IsTrue(context.Response.Headers.ContainsKey("ASPNETCORE-BROWSER-TOOLS")); + Assert.AreEqual("true", context.Response.Headers["ASPNETCORE-BROWSER-TOOLS"].ToString()); } - [Theory] - [InlineData(500, "text/html")] - [InlineData(404, "text/html")] - [InlineData(200, "text/html")] + [TestMethod] + [DataRow(500, "text/html")] + [DataRow(404, "text/html")] + [DataRow(200, "text/html")] public async Task InvokeAsync_AddsScriptToThePage_ForSupportedStatusCodes(int statusCode, string contentType) { // Act & Assert @@ -591,11 +592,11 @@ public async Task InvokeAsync_AddsScriptToThePage_ForSupportedStatusCodes(int st Assert.Contains("", responseContent); } - [Theory] - [InlineData(400, "text/html")] // Bad Request - [InlineData(401, "text/html")] // Unauthorized - [InlineData(404, "application/json")] // 404 with wrong content type - [InlineData(200, "application/json")] // 200 with wrong content type + [TestMethod] + [DataRow(400, "text/html")] // Bad Request + [DataRow(401, "text/html")] // Unauthorized + [DataRow(404, "application/json")] // 404 with wrong content type + [DataRow(200, "application/json")] // 200 with wrong content type public async Task InvokeAsync_DoesNotAddScript_ForUnsupportedStatusCodesOrContentTypes(int statusCode, string contentType) { // Act & Assert @@ -646,7 +647,7 @@ private async Task TestBrowserRefreshMiddleware(int statusCode, string c // Return response content and verify status code var responseContent = Encoding.UTF8.GetString(stream.ToArray()); - Assert.Equal(statusCode, context.Response.StatusCode); + Assert.AreEqual(statusCode, context.Response.StatusCode); return responseContent; } diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserScriptMiddlewareTest.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserScriptMiddlewareTest.cs index 19621f84cc92..d16809efb7d4 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserScriptMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/BrowserScriptMiddlewareTest.cs @@ -6,6 +6,7 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh { + [TestClass] public class BrowserScriptMiddlewareTest { private readonly RequestDelegate _next = (context) => Task.CompletedTask; @@ -17,7 +18,7 @@ public BrowserScriptMiddlewareTest() _logger = loggerFactory.CreateLogger(); } - [Fact] + [TestMethod] public async Task InvokeAsync_ReturnsScript() { var context = new DefaultHttpContext(); @@ -38,7 +39,7 @@ public async Task InvokeAsync_ReturnsScript() Assert.Contains("'test-key'", script); } - [Fact] + [TestMethod] public async Task InvokeAsync_ConfiguresHeaders() { var context = new DefaultHttpContext(); @@ -52,23 +53,14 @@ public async Task InvokeAsync_ConfiguresHeaders() await middleware.InvokeAsync(context); var response = context.Response; - Assert.Collection( - response.Headers.OrderBy(h => h.Key), - kvp => - { - Assert.Equal("Cache-Control", kvp.Key); - Assert.Equal("no-store", kvp.Value); - }, - kvp => - { - Assert.Equal("Content-Length", kvp.Key); - Assert.NotEqual(0, kvp.Value.Count); - }, - kvp => - { - Assert.Equal("Content-Type", kvp.Key); - Assert.Equal("application/javascript; charset=utf-8", kvp.Value); - }); + var headers = response.Headers.OrderBy(h => h.Key).ToArray(); + Assert.HasCount(3, headers); + Assert.AreEqual("Cache-Control", headers[0].Key); + Assert.AreEqual("no-store", headers[0].Value.ToString()); + Assert.AreEqual("Content-Length", headers[1].Key); + Assert.AreNotEqual(0, headers[1].Value.Count); + Assert.AreEqual("Content-Type", headers[2].Key); + Assert.AreEqual("application/javascript; charset=utf-8", headers[2].Value.ToString()); } } } diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/HostingStartupTest.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/HostingStartupTest.cs index 5050e4c8dd15..40dfc35d6c85 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/HostingStartupTest.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/HostingStartupTest.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Builder; @@ -7,9 +7,10 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh { + [TestClass] public class HostingStartupTest { - [Fact] + [TestMethod] public async Task ClearSiteDataWorks() { // Arrange @@ -21,11 +22,11 @@ public async Task ClearSiteDataWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); - Assert.Equal("\"cache\"", context.Response.Headers["Clear-Site-Data"]); + Assert.AreEqual(StatusCodes.Status200OK, context.Response.StatusCode); + Assert.AreEqual("\"cache\"", context.Response.Headers["Clear-Site-Data"].ToString()); } - [Fact] + [TestMethod] public async Task GetBlazorHotReloadMiddlewareWorks() { // Arrange @@ -39,10 +40,10 @@ public async Task GetBlazorHotReloadMiddlewareWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status204NoContent, context.Response.StatusCode); + Assert.AreEqual(StatusCodes.Status204NoContent, context.Response.StatusCode); } - [Fact] + [TestMethod] public async Task PostBlazorHotReloadMiddlewareWorks() { var requestDelegate = GetRequestDelegate(); @@ -58,7 +59,7 @@ public async Task PostBlazorHotReloadMiddlewareWorks() await requestDelegate(context); - Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); + Assert.AreEqual(StatusCodes.Status200OK, context.Response.StatusCode); context.Request.Path = "/_framework/blazor-hotreload"; context.Request.Method = "GET"; @@ -70,10 +71,10 @@ public async Task PostBlazorHotReloadMiddlewareWorks() var bodyJson = Encoding.UTF8.GetString(body.ToArray()); - Assert.Equal($"[{updateJson}]", bodyJson); + Assert.AreEqual($"[{updateJson}]", bodyJson); } - [Fact] + [TestMethod] public async Task GetBlazorHotReloadJsWorks() { // Arrange @@ -87,11 +88,11 @@ public async Task GetBlazorHotReloadJsWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); - Assert.NotEmpty(responseBody.ToArray()); + Assert.AreEqual(StatusCodes.Status200OK, context.Response.StatusCode); + Assert.IsNotEmpty(responseBody.ToArray()); } - [Fact] + [TestMethod] public async Task GetAspNetCoreBrowserRefreshWorks() { // Arrange @@ -105,11 +106,11 @@ public async Task GetAspNetCoreBrowserRefreshWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); - Assert.NotEmpty(responseBody.ToArray()); + Assert.AreEqual(StatusCodes.Status200OK, context.Response.StatusCode); + Assert.IsNotEmpty(responseBody.ToArray()); } - [Fact] + [TestMethod] public async Task GetUnknownUrlWorks() { // Arrange @@ -121,10 +122,10 @@ public async Task GetUnknownUrlWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status418ImATeapot, context.Response.StatusCode); + Assert.AreEqual(StatusCodes.Status418ImATeapot, context.Response.StatusCode); } - [Fact] + [TestMethod] public async Task GetUnknownFrameworkPathWorks() { // Arrange @@ -155,7 +156,7 @@ public async Task GetUnknownFrameworkPathWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status206PartialContent, context.Response.StatusCode); + Assert.AreEqual(StatusCodes.Status206PartialContent, context.Response.StatusCode); // Act - 2 @@ -163,7 +164,7 @@ public async Task GetUnknownFrameworkPathWorks() await requestDelegate(context); // Assert - Assert.Equal(StatusCodes.Status226IMUsed, context.Response.StatusCode); + Assert.AreEqual(StatusCodes.Status226IMUsed, context.Response.StatusCode); } private static RequestDelegate GetRequestDelegate(Action? configureBuilder = null) diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj index a9b32a2352b2..0e6fe66f9235 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests.csproj @@ -1,16 +1,13 @@ - + $(SdkTargetFramework) Microsoft.AspNetCore.Watch.BrowserRefresh MicrosoftAspNetCore - Exe - false - @@ -22,4 +19,4 @@ - + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ResponseStreamWrapperCompressionTest.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ResponseStreamWrapperCompressionTest.cs index 32c39452edb2..a0735b9dff89 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ResponseStreamWrapperCompressionTest.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ResponseStreamWrapperCompressionTest.cs @@ -8,9 +8,10 @@ namespace Microsoft.AspNetCore.Watch.BrowserRefresh { + [TestClass] public class ResponseStreamWrapperCompressionTest { - [Fact] + [TestMethod] public async Task WriteAsync_HandlesGzipCompressedHtmlResponse() { // Arrange @@ -32,17 +33,17 @@ public async Task WriteAsync_HandlesGzipCompressedHtmlResponse() var wrapper = new ResponseStreamWrapper(context, NullLogger.Instance); // Act - await wrapper.WriteAsync(compressedData, TestContext.Current.CancellationToken); + await wrapper.WriteAsync(compressedData, CancellationToken.None); await wrapper.CompleteAsync(); // Assert var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task Write_HandlesGzipCompressedHtmlResponse() { // Arrange @@ -70,11 +71,11 @@ public async Task Write_HandlesGzipCompressedHtmlResponse() // Assert var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task WriteAsync_DoesNotModifyNonHtmlCompressedResponse() { // Arrange @@ -96,15 +97,15 @@ public async Task WriteAsync_DoesNotModifyNonHtmlCompressedResponse() var wrapper = new ResponseStreamWrapper(context, NullLogger.Instance); // Act - await wrapper.WriteAsync(compressedData, TestContext.Current.CancellationToken); + await wrapper.WriteAsync(compressedData, CancellationToken.None); await wrapper.CompleteAsync(); var result = outputStream.ToArray(); - Assert.Equal(compressedData, result); - Assert.True(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.AreSequenceEqual(compressedData, result); + Assert.IsTrue(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); } - [Fact] + [TestMethod] public async Task Write_DoesNotModifyNonHtmlCompressedResponse() { // Arrange @@ -130,11 +131,11 @@ public async Task Write_DoesNotModifyNonHtmlCompressedResponse() await wrapper.CompleteAsync(); var result = outputStream.ToArray(); - Assert.Equal(compressedData, result); - Assert.True(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.AreSequenceEqual(compressedData, result); + Assert.IsTrue(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); } - [Fact] + [TestMethod] public async Task WriteAsync_IgnoresNonGzipCompressionTypes() { // Arrange @@ -156,17 +157,17 @@ public async Task WriteAsync_IgnoresNonGzipCompressionTypes() var wrapper = new ResponseStreamWrapper(context, NullLogger.Instance); // Act - await wrapper.WriteAsync(data, TestContext.Current.CancellationToken); + await wrapper.WriteAsync(data, CancellationToken.None); await wrapper.CompleteAsync(); // Assert var result = Encoding.UTF8.GetString(outputStream.ToArray()); // Should treat as regular data since we only handle gzip Assert.Contains("", result); - Assert.True(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsTrue(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); } - [Fact] + [TestMethod] public async Task Write_IgnoresNonGzipCompressionTypes() { // Arrange @@ -195,10 +196,10 @@ public async Task Write_IgnoresNonGzipCompressionTypes() var result = Encoding.UTF8.GetString(outputStream.ToArray()); // Should treat as regular data since we only handle gzip Assert.Contains("", result); - Assert.True(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsTrue(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); } - [Fact] + [TestMethod] public async Task WriteAsync_PreservesNonCompressedHtmlResponse() { // Arrange @@ -219,16 +220,16 @@ public async Task WriteAsync_PreservesNonCompressedHtmlResponse() var wrapper = new ResponseStreamWrapper(context, NullLogger.Instance); // Act - await wrapper.WriteAsync(data, TestContext.Current.CancellationToken); + await wrapper.WriteAsync(data, CancellationToken.None); await wrapper.CompleteAsync(); // Assert var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task Write_PreservesNonCompressedHtmlResponse() { // Arrange @@ -255,10 +256,10 @@ public async Task Write_PreservesNonCompressedHtmlResponse() // Assert var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task WriteAsync_GzipHtml_SingleByteChunks() { // Arrange: small HTML so compressed output is reasonably small; we will feed one byte at a time. @@ -290,11 +291,11 @@ public async Task WriteAsync_GzipHtml_SingleByteChunks() // Assert: script injected and content encoding removed var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task Write_GzipHtml_SingleByteChunks() { // Arrange: small HTML so compressed output is reasonably small; we will feed one byte at a time. @@ -326,11 +327,11 @@ public async Task Write_GzipHtml_SingleByteChunks() // Assert: script injected and content encoding removed var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task WriteAsync_GzipHtml_LargeChunk32K() { // Arrange: generate largely incompressible-ish HTML body so compressed data spans >= 32K @@ -346,7 +347,7 @@ public async Task WriteAsync_GzipHtml_LargeChunk32K() sb.Append(""); var htmlContent = sb.ToString(); var compressedData = CompressWithGzip(htmlContent); - Assert.True(compressedData.Length > 0, "Expected non-empty compressed payload"); + Assert.IsTrue(compressedData.Length > 0, "Expected non-empty compressed payload"); var outputStream = new MemoryStream(); var context = new DefaultHttpContext @@ -377,11 +378,11 @@ public async Task WriteAsync_GzipHtml_LargeChunk32K() var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); Assert.Contains("", result); // Ensure full doc present - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } - [Fact] + [TestMethod] public async Task Write_GzipHtml_LargeChunk32K() { // Arrange: generate largely incompressible-ish HTML body so compressed data spans >= 32K @@ -397,7 +398,7 @@ public async Task Write_GzipHtml_LargeChunk32K() sb.Append(""); var htmlContent = sb.ToString(); var compressedData = CompressWithGzip(htmlContent); - Assert.True(compressedData.Length > 0, "Expected non-empty compressed payload"); + Assert.IsTrue(compressedData.Length > 0, "Expected non-empty compressed payload"); var outputStream = new MemoryStream(); var context = new DefaultHttpContext @@ -428,8 +429,8 @@ public async Task Write_GzipHtml_LargeChunk32K() var result = Encoding.UTF8.GetString(outputStream.ToArray()); Assert.Contains("", result); Assert.Contains("", result); // Ensure full doc present - Assert.False(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); - Assert.Null(context.Response.Headers.ContentLength); + Assert.IsFalse(context.Response.Headers.ContainsKey(HeaderNames.ContentEncoding)); + Assert.IsNull(context.Response.Headers.ContentLength); } private static byte[] CompressWithGzip(string content) diff --git a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ScriptInjectingStreamTests.cs b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ScriptInjectingStreamTests.cs index dd3bdbb24b68..7c9a65aeb2de 100644 --- a/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ScriptInjectingStreamTests.cs +++ b/test/Microsoft.AspNetCore.Watch.BrowserRefresh.Tests/ScriptInjectingStreamTests.cs @@ -1,13 +1,17 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.AspNetCore.Watch.BrowserRefresh; +[TestClass] + public class ScriptInjectingStreamTests { private static readonly string s_injectedScript = ScriptInjectingStream.InjectedScript; - [Fact] + public TestContext TestContext { get; set; } = null!; + + [TestMethod] public void Write_CompleteBodyTagInSingleWrite_InjectsScript() { // Arrange @@ -20,11 +24,11 @@ public void Write_CompleteBodyTagInSingleWrite_InjectsScript() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_CompleteBodyTagInSingleWrite_InjectsScript() { // Arrange @@ -33,25 +37,25 @@ public async Task WriteAsync_CompleteBodyTagInSingleWrite_InjectsScript() var html = "Content"; // Act - await stream.WriteAsync(Encoding.UTF8.GetBytes(html), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes(html), TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Theory] - [InlineData("Content^<", "/body>")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^", "<", "/body>")] - [InlineData("C", "o", "ntent^", "<", "/body>")] - [InlineData("Content^", "")] - [InlineData("Content", "")] + [TestMethod] + [DataRow("Content^<", "/body>")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^", "<", "/body>")] + [DataRow("C", "o", "ntent^", "<", "/body>")] + [DataRow("Content^", "")] + [DataRow("Content", "")] public void Write_BodyTagSplitAcrossMultipleWrites_InjectsScript(params string[] parts) { // Arrange @@ -67,21 +71,21 @@ public void Write_BodyTagSplitAcrossMultipleWrites_InjectsScript(params string[] // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal(expectedResult, result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual(expectedResult, result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Theory] - [InlineData("Content^<", "/body>")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^")] - [InlineData("Content^", "<", "/body>")] - [InlineData("C", "o", "ntent^", "<", "/body>")] - [InlineData("Content^", "")] - [InlineData("Content", "")] + [TestMethod] + [DataRow("Content^<", "/body>")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^")] + [DataRow("Content^", "<", "/body>")] + [DataRow("C", "o", "ntent^", "<", "/body>")] + [DataRow("Content^", "")] + [DataRow("Content", "")] public async Task WriteAsync_BodyTagSplitAcrossMultipleWrites_InjectsScript(params string[] parts) { // Arrange @@ -92,16 +96,16 @@ public async Task WriteAsync_BodyTagSplitAcrossMultipleWrites_InjectsScript(para // Act foreach (var part in parts) { - await stream.WriteAsync(Encoding.UTF8.GetBytes(part.Replace("^", "")), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes(part.Replace("^", "")), TestContext.CancellationToken); } // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal(expectedResult, result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual(expectedResult, result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Dispose_FlushesPartialBodyTagAtEndOfInput() { // Arrange @@ -116,12 +120,12 @@ public void Dispose_FlushesPartialBodyTagAtEndOfInput() var flushResult = Encoding.UTF8.GetString(baseStream.ToArray()); // Assert - Assert.Equal("Content", writeResult); - Assert.Equal("ContentContent", writeResult); + Assert.AreEqual("ContentContentContentContent", writeResult); - Assert.Equal("ContentContent", writeResult); + Assert.AreEqual("ContentContent{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_BodyTagSplitAcrossMultipleSingleByteWrites_InjectsScript() { // Arrange @@ -171,21 +175,21 @@ public async Task WriteAsync_BodyTagSplitAcrossMultipleSingleByteWrites_InjectsS var stream = new ScriptInjectingStream(baseStream); // Act - Split "" across 7 writes - await stream.WriteAsync(Encoding.UTF8.GetBytes("Content<"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("/"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("b"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("o"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("d"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("y"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes(">"), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("Content<"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("/"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("b"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("o"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("d"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("y"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes(">"), TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Write_FalsePositivePartialMatch_FlushesCorrectly() { // Arrange @@ -198,11 +202,11 @@ public void Write_FalsePositivePartialMatch_FlushesCorrectly() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content
Not a body tag{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content
Not a body tag{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_FalsePositivePartialMatch_FlushesCorrectly() { // Arrange @@ -210,16 +214,16 @@ public async Task WriteAsync_FalsePositivePartialMatch_FlushesCorrectly() var stream = new ScriptInjectingStream(baseStream); // Act - Start with partial match that turns out false - await stream.WriteAsync(Encoding.UTF8.GetBytes("ContentNot a body tag"), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("ContentNot a body tag"), TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content
Not a body tag{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content
Not a body tag{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Write_NoBodyTag_NoInjection() { // Arrange @@ -232,11 +236,11 @@ public void Write_NoBodyTag_NoInjection() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal(html, result); - Assert.False(stream.ScriptInjectionPerformed); + Assert.AreEqual(html, result); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_NoBodyTag_NoInjection() { // Arrange @@ -245,15 +249,15 @@ public async Task WriteAsync_NoBodyTag_NoInjection() var html = "
Content
"; // Act - await stream.WriteAsync(Encoding.UTF8.GetBytes(html), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes(html), TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal(html, result); - Assert.False(stream.ScriptInjectionPerformed); + Assert.AreEqual(html, result); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Write_MultipleBodyTags_InjectsOnlyOnce() { // Arrange @@ -266,11 +270,11 @@ public void Write_MultipleBodyTags_InjectsOnlyOnce() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"First{s_injectedScript}Second", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"First{s_injectedScript}Second", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_MultipleBodyTags_InjectsOnlyOnce() { // Arrange @@ -278,16 +282,16 @@ public async Task WriteAsync_MultipleBodyTags_InjectsOnlyOnce() var stream = new ScriptInjectingStream(baseStream); // Act - await stream.WriteAsync(Encoding.UTF8.GetBytes("First"), TestContext.Current.CancellationToken); - await stream.WriteAsync(Encoding.UTF8.GetBytes("Second"), TestContext.Current.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("First"), TestContext.CancellationToken); + await stream.WriteAsync(Encoding.UTF8.GetBytes("Second"), TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"First{s_injectedScript}Second", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"First{s_injectedScript}Second", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void WriteByte_PassesThroughDirectly() { // Arrange @@ -300,11 +304,11 @@ public void WriteByte_PassesThroughDirectly() // Assert var result = baseStream.ToArray(); - Assert.Equal(new byte[] { 65, 66 }, result); - Assert.False(stream.ScriptInjectionPerformed); + Assert.AreSequenceEqual(new byte[] { 65, 66 }, result); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Write_EmptyBuffer_DoesNothing() { // Arrange @@ -315,11 +319,11 @@ public void Write_EmptyBuffer_DoesNothing() stream.Write(ReadOnlySpan.Empty); // Assert - Assert.Empty(baseStream.ToArray()); - Assert.False(stream.ScriptInjectionPerformed); + Assert.IsEmpty(baseStream.ToArray()); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_EmptyBuffer_DoesNothing() { // Arrange @@ -327,14 +331,14 @@ public async Task WriteAsync_EmptyBuffer_DoesNothing() var stream = new ScriptInjectingStream(baseStream); // Act - await stream.WriteAsync(ReadOnlyMemory.Empty, TestContext.Current.CancellationToken); + await stream.WriteAsync(ReadOnlyMemory.Empty, TestContext.CancellationToken); // Assert - Assert.Empty(baseStream.ToArray()); - Assert.False(stream.ScriptInjectionPerformed); + Assert.IsEmpty(baseStream.ToArray()); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_WithCancellation_PropagatesCancellation() { // Arrange @@ -344,7 +348,7 @@ public async Task WriteAsync_WithCancellation_PropagatesCancellation() cts.Cancel(); // Act & Assert - await Assert.ThrowsAsync(async () => + await Assert.ThrowsExactlyAsync(async () => { // Use a mock stream that respects cancellation var mockStream = new CancellationTestStream(); @@ -353,7 +357,7 @@ await Assert.ThrowsAsync(async () => }); } - [Fact] + [TestMethod] public void Write_ArrayOverload_CompleteBodyTag_InjectsScript() { // Arrange @@ -367,11 +371,11 @@ public void Write_ArrayOverload_CompleteBodyTag_InjectsScript() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_ArrayOverload_CompleteBodyTag_InjectsScript() { // Arrange @@ -381,15 +385,15 @@ public async Task WriteAsync_ArrayOverload_CompleteBodyTag_InjectsScript() var bytes = Encoding.UTF8.GetBytes(html); // Act - await stream.WriteAsync(bytes, 0, bytes.Length, TestContext.Current.CancellationToken); + await stream.WriteAsync(bytes, 0, bytes.Length, TestContext.CancellationToken); // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Write_ArrayOverloadWithOffset_InjectsScript() { // Arrange @@ -402,11 +406,11 @@ public void Write_ArrayOverloadWithOffset_InjectsScript() // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task WriteAsync_ArrayOverloadWithOffset_InjectsScript() { // Arrange @@ -415,15 +419,15 @@ public async Task WriteAsync_ArrayOverloadWithOffset_InjectsScript() var buffer = Encoding.UTF8.GetBytes("XXXContentYYY"); // Act - await stream.WriteAsync(buffer, 3, buffer.Length - 6, TestContext.Current.CancellationToken); // Skip XXX and YYY + await stream.WriteAsync(buffer, 3, buffer.Length - 6, TestContext.CancellationToken); // Skip XXX and YYY // Assert var result = Encoding.UTF8.GetString(baseStream.ToArray()); - Assert.Equal($"Content{s_injectedScript}", result); - Assert.True(stream.ScriptInjectionPerformed); + Assert.AreEqual($"Content{s_injectedScript}", result); + Assert.IsTrue(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public void Flush_WithoutAnyWrites_DoesNotCrash() { // Arrange @@ -434,11 +438,11 @@ public void Flush_WithoutAnyWrites_DoesNotCrash() stream.Flush(); // Assert - Assert.Empty(baseStream.ToArray()); - Assert.False(stream.ScriptInjectionPerformed); + Assert.IsEmpty(baseStream.ToArray()); + Assert.IsFalse(stream.ScriptInjectionPerformed); } - [Fact] + [TestMethod] public async Task FlushAsync_WithoutAnyWrites_DoesNotCrash() { // Arrange @@ -446,11 +450,11 @@ public async Task FlushAsync_WithoutAnyWrites_DoesNotCrash() var stream = new ScriptInjectingStream(baseStream); // Act - await stream.FlushAsync(TestContext.Current.CancellationToken); + await stream.FlushAsync(TestContext.CancellationToken); // Assert - Assert.Empty(baseStream.ToArray()); - Assert.False(stream.ScriptInjectionPerformed); + Assert.IsEmpty(baseStream.ToArray()); + Assert.IsFalse(stream.ScriptInjectionPerformed); } private class CancellationTestStream : Stream diff --git a/test/Microsoft.DotNet.ApiCompat.Tests/Microsoft.DotNet.ApiCompat.Tests.csproj b/test/Microsoft.DotNet.ApiCompat.Tests/Microsoft.DotNet.ApiCompat.Tests.csproj index 898749c592b6..3802f96de8ab 100644 --- a/test/Microsoft.DotNet.ApiCompat.Tests/Microsoft.DotNet.ApiCompat.Tests.csproj +++ b/test/Microsoft.DotNet.ApiCompat.Tests/Microsoft.DotNet.ApiCompat.Tests.csproj @@ -1,8 +1,7 @@ - + $(SdkTargetFramework) - Exe @@ -12,10 +11,9 @@ - - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.ApiCompat.Tests/RegexStringTransformerTests.cs b/test/Microsoft.DotNet.ApiCompat.Tests/RegexStringTransformerTests.cs index bed3d912cfbd..683d3a626cbd 100644 --- a/test/Microsoft.DotNet.ApiCompat.Tests/RegexStringTransformerTests.cs +++ b/test/Microsoft.DotNet.ApiCompat.Tests/RegexStringTransformerTests.cs @@ -1,13 +1,14 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.DotNet.ApiCompat; namespace Microsoft.DotNet.ApiCompatibility.Tests { + [TestClass] public class RegexStringTransformerTests { - [Fact] + [TestMethod] public void Transform_CaptureGroupPatternDoesNotMatchInput_ReturnsInput() { const string CaptureGroupPattern = "(abc)def"; @@ -16,10 +17,10 @@ public void Transform_CaptureGroupPatternDoesNotMatchInput_ReturnsInput() string output = new RegexStringTransformer(CaptureGroupPattern, ReplacementPattern).Transform(Input); - Assert.Equal(Input, output); + Assert.AreEqual(Input, output); } - [Fact] + [TestMethod] public void Transform_ReplacementPatternWithoutCaptureGroups_ReturnsReplacementPattern() { const string CaptureGroupPattern = "(abc)d*"; @@ -28,10 +29,10 @@ public void Transform_ReplacementPatternWithoutCaptureGroups_ReturnsReplacementP string output = new RegexStringTransformer(CaptureGroupPattern, ReplacementPattern).Transform(Input); - Assert.Equal(ReplacementPattern, output); + Assert.AreEqual(ReplacementPattern, output); } - [Fact] + [TestMethod] public void Transform_ReplacementPatternWithTooManyReplacementMarkers_ReturnOutputWithoutTransformedReplacementMarkers() { const string CaptureGroupPattern = "(abc)(def)ghi"; @@ -40,10 +41,10 @@ public void Transform_ReplacementPatternWithTooManyReplacementMarkers_ReturnOutp string output = new RegexStringTransformer(CaptureGroupPattern, ReplacementPattern).Transform(Input); - Assert.Equal("1:abc, 2:def, 3:$3", output); + Assert.AreEqual("1:abc, 2:def, 3:$3", output); } - [Fact] + [TestMethod] public void Transform_SameNumberOfGroupsAndMarkers_ReturnsExpected() { const string CaptureGroupPattern = @".+\\(.+)\\(.+)"; @@ -52,10 +53,10 @@ public void Transform_SameNumberOfGroupsAndMarkers_ReturnsExpected() string output = new RegexStringTransformer(CaptureGroupPattern, ReplacementPattern).Transform(Input); - Assert.Equal("lib/net7.0-android/System.Linq.dll", output); + Assert.AreEqual("lib/net7.0-android/System.Linq.dll", output); } - [Fact] + [TestMethod] public void Transform_MultiplePatterns_ReturnsExpected() { var patterns = new (string, string)[] @@ -69,7 +70,7 @@ public void Transform_MultiplePatterns_ReturnsExpected() string output = new RegexStringTransformer(patterns).Transform(Input); - Assert.Equal("runtimes/android/lib/net7.0/System.Linq.dll", output); + Assert.AreEqual("runtimes/android/lib/net7.0/System.Linq.dll", output); } } } diff --git a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs index eeddc67ff7f5..22b94d06c38f 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs @@ -14,6 +14,7 @@ namespace Microsoft.DotNet.GenAPI.Tests { + [TestClass] public class CSharpFileBuilderTests { class AllowAllFilter : ISymbolFilter @@ -45,7 +46,7 @@ private void RunTest(string original, SyntaxTree expectedSyntaxTree = GetSyntaxTree(expected); // compare SyntaxTree and not string representation - Assert.True(resultedSyntaxTree.IsEquivalentTo(expectedSyntaxTree), + Assert.IsTrue(resultedSyntaxTree.IsEquivalentTo(expectedSyntaxTree), $"Expected:\n{expected}\nResulted:\n{resultedString}"); } @@ -63,7 +64,7 @@ private void RunTestAndCompareOutput(string original, string resultedString = GenerateOutput(original, includeInternalSymbols, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, allowUnsafe, excludedAttributeList, additionalApiInclusionFilter: null, assemblyName, header); - Assert.Equal(expected.ReplaceLineEndings("\n"), resultedString.ReplaceLineEndings("\n")); + Assert.AreEqual(expected.ReplaceLineEndings("\n"), resultedString.ReplaceLineEndings("\n")); } private static string GenerateOutput(string original, @@ -103,7 +104,7 @@ private static string GenerateOutput(string original, return stringWriter.ToString(); } - [Fact] + [TestMethod] public void TestDefaultHeader() { RunTest(original: """ @@ -121,7 +122,7 @@ namespace A.C.D {{ public partial struct Bar {{}} }} header: null); } - [Fact] + [TestMethod] public void TestCustomHeader() { string customHeader = """ @@ -145,7 +146,7 @@ namespace A.C.D {{ public partial struct Bar {{}} }} header: customHeader); } - [Fact] + [TestMethod] public void TestGlobalNamespaceDeclaration() { RunTest(original: """ @@ -158,7 +159,7 @@ public partial class Class1 """); } - [Fact] + [TestMethod] public void TestNamespaceDeclaration() { RunTest(original: """ @@ -174,7 +175,7 @@ namespace A.C.D { public partial struct Bar {} } """); } - [Fact] + [TestMethod] public void TestClassDeclaration() { RunTest(original: """ @@ -204,7 +205,7 @@ public sealed partial class PublicSealedClass { } """); } - [Fact] + [TestMethod] public void TestStructDeclaration() { RunTest(original: """ @@ -300,7 +301,7 @@ internal partial struct RecordStruct : System.IEquatable """); } - [Fact] + [TestMethod] public void TestRecordDeclaration() { RunTest(original: """ @@ -413,7 +414,7 @@ private SealedRecordWithPrivateDefaultConstructor() { } """); } - [Fact] + [TestMethod] public void TestRecordStructDeclaration() { RunTest(original: """ @@ -633,7 +634,7 @@ public RecordStructWithProperties(int i) { } """); } - [Fact] + [TestMethod] public void TestInterfaceGeneration() { RunTest(original: """ @@ -664,7 +665,7 @@ public partial interface IPoint """); } - [Fact] + [TestMethod] public void TestEnumGeneration() { RunTest(original: """ @@ -691,7 +692,7 @@ public enum Color """); } - [Fact] + [TestMethod] public void TestPropertyGeneration() { RunTest(original: """ @@ -720,7 +721,7 @@ public partial class Car """); } - [Fact] + [TestMethod] public void TestAbstractPropertyGeneration() { RunTest(original: """ @@ -745,7 +746,7 @@ internal abstract partial class Car """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceImplementation() { RunTest(original: """ @@ -790,7 +791,7 @@ public void Paint() """); } - [Fact] + [TestMethod] public void TestPartiallySpecifiedGenericClassGeneration() { RunTest(original: """ @@ -815,7 +816,7 @@ public partial class Node5 : BaseNodeMultiple { } """); } - [Fact] + [TestMethod] public void TestGenericClassWitConstraintsParameterGeneration() { RunTest(original: """ @@ -838,7 +839,7 @@ namespace Foo """); } - [Fact] + [TestMethod] public void TestNotNullGenericConstraintGeneration() { RunTest(original: """ @@ -888,7 +889,7 @@ public override void OverrideMethod() { } """); } - [Fact] + [TestMethod] public void TestNotNullConstraintClauseOrdering() { RunTest(original: """ @@ -913,7 +914,7 @@ namespace Foo """); } - [Fact] + [TestMethod] public void TestBlankLineGenerationBetweenTypes() { RunTestAndCompareOutput(original: """ @@ -971,7 +972,7 @@ public partial interface Third """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceImplementationNotNullConstraint() { RunTest(original: """ @@ -1007,7 +1008,7 @@ void Method(T value) """); } - [Fact] + [TestMethod] public void TestBlankLineGenerationBetweenNestedTypeLikeMembers() { RunTestAndCompareOutput(original: """ @@ -1040,7 +1041,7 @@ public partial class BNested """); } - [Fact] + [TestMethod] public void TestAllowsRefStructGenericConstraintGeneration() { RunTest(original: """ @@ -1084,7 +1085,7 @@ public partial class RefContainer where T : allows ref struct """); } - [Fact] + [TestMethod] public void TestPublicMembersGeneration() { RunTest(original: """ @@ -1134,7 +1135,7 @@ public Options(Kind kindVal) { } """); } - [Fact] + [TestMethod] public void TestDelegateGeneration() { RunTest(original: """ @@ -1151,7 +1152,7 @@ namespace Foo """); } - [Fact] + [TestMethod] public void TestAbstractEventGeneration() { RunTest(original: """ @@ -1184,7 +1185,7 @@ public event System.EventHandler OnNewMessage { add { } remove { } } """); } - [Fact] + [TestMethod] public void TestEventGenerationOutput() { RunTestAndCompareOutput(original: """ @@ -1207,7 +1208,7 @@ public event System.EventHandler OnNewMessage { add { } remove { } } """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceEventGeneration() { RunTest(original: """ @@ -1244,7 +1245,7 @@ public partial interface INotifications """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceEventFromInternalInterfaceIsExcluded() { RunTest(original: """ @@ -1272,7 +1273,7 @@ public partial class EventSource includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestExplicitInterfaceEventWithInaccessibleTypeArgumentIsExcluded() { RunTest(original: """ @@ -1306,7 +1307,7 @@ public partial interface IPublicNotifications """, includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestCustomAttributeGeneration() { RunTest(original: """ @@ -1376,7 +1377,7 @@ public void SayHello() { } """); } - [Fact] + [TestMethod] public void TestFullyQualifiedNamesForDefaultEnumParameters() { RunTest(original: """ @@ -1422,7 +1423,7 @@ public AnimalProperty(Animal animal = Animal.Cat) { } """); } - [Fact] + [TestMethod] public void TestCustomComparisonOperatorGeneration() { RunTest(original: """ @@ -1453,7 +1454,7 @@ public partial class Car : System.IEquatable """); } - [Fact] + [TestMethod] public void TestNestedClassGeneration() { RunTest(original: """ @@ -1483,7 +1484,7 @@ public partial class Cylinder } """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceImplementationMethodGeneration() { RunTest(original: """ @@ -1506,7 +1507,7 @@ void System.IDisposable.Dispose() { } """); } - [Fact] + [TestMethod] public void TestNullabilityGeneration() { RunTest(original: """ @@ -1535,7 +1536,7 @@ public partial class Bar """); } - [Fact] + [TestMethod] public void TestExtensionMethodsGeneration() { RunTest(original: """ @@ -1558,7 +1559,7 @@ public static partial class MyExtensions """); } - [Fact] + [TestMethod] public void TestMethodsWithVariableNumberOfArgumentsGeneration() { RunTest(original: """ @@ -1581,7 +1582,7 @@ public void Execute(params int[] list) { } """); } - [Fact] + [TestMethod] public void TestConversionOperatorGeneration() { RunTest(original: """ @@ -1617,7 +1618,7 @@ public Digit(byte digit) { } """); } - [Fact] + [TestMethod] public void TestDestructorGeneration() { RunTest(original: """ @@ -1640,7 +1641,7 @@ public partial class Bar """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceImplementationPropertyGeneration() { RunTest(original: """ @@ -1679,7 +1680,7 @@ public partial interface IFoo """); } - [Fact] + [TestMethod] public void TestAccessibilityGenerationForPropertyAccessors() { RunTest(original: """ @@ -1702,7 +1703,7 @@ public partial class Bar """); } - [Fact] + [TestMethod] public void TestConstantFieldGeneration() { RunTest(original: """ @@ -1726,7 +1727,7 @@ public partial class Bar ); } - [Fact] + [TestMethod] public void TestTypeParameterVarianceGeneration() { RunTest(original: """ @@ -1750,7 +1751,7 @@ public partial interface IAsyncEnumerable ); } - [Fact] + [TestMethod] public void TestRefMembersGeneration() { RunTest(original: """ @@ -1782,7 +1783,7 @@ public partial class Bar ); } - [Fact] + [TestMethod] public void TestDefaultConstraintOnOverrideGeneration() { RunTest(original: """ @@ -1820,7 +1821,7 @@ public sealed partial class B : A ); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsForValueTypes() { RunTest(original: """ @@ -1846,7 +1847,7 @@ public partial struct Bar """); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsForReferenceTypes() { RunTest(original: """ @@ -1871,7 +1872,7 @@ public partial struct Bar """); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsForGenericTypes() { RunTest(original: """ @@ -1895,7 +1896,7 @@ public partial struct Bar """); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsForNestedGenericTypes() { RunTest(original: """ @@ -1923,7 +1924,7 @@ public partial struct Bar where T : notnull """); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsAngleBrackets() { RunTest(original: """ @@ -1951,7 +1952,7 @@ namespace Foo """); } - [Fact] + [TestMethod] public void TestSynthesizePrivateFieldsForInaccessibleNestedGenericTypes() { RunTest(original: """ @@ -1981,7 +1982,7 @@ public partial struct Foo includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestBaseTypeWithoutExplicitDefault() { RunTest(original: """ @@ -2011,7 +2012,7 @@ public partial class C : B """); } - [Fact] + [TestMethod] public void TestBaseTypeWithExplicitDefaultConstructor() { RunTest(original: """ @@ -2042,7 +2043,7 @@ public partial class C : B """); } - [Fact] + [TestMethod] public void TestInternalParameterlessConstructors() { RunTest(original: """ @@ -2076,7 +2077,7 @@ internal C() {} includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestInternalParameterizedConstructors() { RunTest(original: """ @@ -2134,7 +2135,7 @@ internal E() {} includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestInternalParameterizedConstructorsPreserveInternals() { RunTest(original: """ @@ -2200,7 +2201,7 @@ internal partial class P includeInternalSymbols: true); } - [Fact] + [TestMethod] public void TestInternalConstructorCallingProtected() { RunTest(original: """ @@ -2234,7 +2235,7 @@ internal C() {} includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestBaseTypeWithoutDefaultConstructor() { RunTest(original: """ @@ -2275,7 +2276,7 @@ public C() : base(default, default!, default!) {} """); } - [Fact] + [TestMethod] public void TestBaseTypeWithMultipleNonDefaultConstructors() { RunTest(original: """ @@ -2320,7 +2321,7 @@ public C() : base(default) {} """); } - [Fact] + [TestMethod] public void TestBaseTypeWithAmbiguousNonDefaultConstructors() { RunTest(original: """ @@ -2357,7 +2358,7 @@ public B() : base(default(char)) {} """); } - [Fact] + [TestMethod] public void TestBaseTypeWithAmbiguousNonDefaultConstructorsRegression31655() { RunTest(original: """ @@ -2404,7 +2405,7 @@ public partial class V { } """); } - [Fact] + [TestMethod] public void TestBaseTypeConstructorWithObsoleteAttribute() { RunTest(original: """ @@ -2441,7 +2442,7 @@ public C() : base(default, default!) { } """); } - [Fact] + [TestMethod] public void TestObsoleteBaseTypeConstructorWithoutErrorParameter() { RunTest(original: """ @@ -2478,7 +2479,7 @@ public C() : base(default) { } """); } - [Fact] + [TestMethod] public void TestObsoleteBaseTypeConstructorWithoutMessageParameter() { RunTest(original: """ @@ -2515,7 +2516,7 @@ public C() : base(default) { } """); } - [Fact] + [TestMethod] public void TestFilterOutInternalExplicitInterfaceImplementation() { RunTest(original: """ @@ -2545,7 +2546,7 @@ public partial class Bar includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestMethodsWithReferenceParameterGeneration() { RunTest(original: """ @@ -2569,7 +2570,7 @@ public partial class foo includeInternalSymbols: false); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/74109")] + [TestMethod, Ignore("https://github.com/dotnet/roslyn/issues/74109")] public void TestInterfaceWithOperatorGeneration() { RunTest(original: """ @@ -2593,7 +2594,7 @@ public partial interface IntType includeInternalSymbols: false); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/74109")] + [TestMethod, Ignore("https://github.com/dotnet/roslyn/issues/74109")] public void TestInterfaceWithCheckedOperatorGeneration() { RunTest(original: """ @@ -2621,7 +2622,7 @@ public interface IAdditionOperators includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestUnsafeFieldGeneration() { RunTest(original: """ @@ -2650,7 +2651,7 @@ public partial struct Node allowUnsafe: true); } - [Fact] + [TestMethod] public void TestUnsafeMethodGeneration() { RunTest(original: """ @@ -2685,7 +2686,7 @@ public override unsafe void F(char* p) { } allowUnsafe: true); } - [Fact] + [TestMethod] public void TestUnsafeConstructorGeneration() { RunTest(original: """ @@ -2720,7 +2721,7 @@ public unsafe Foo(char* f) : base(default) { } allowUnsafe: true); } - [Fact] + [TestMethod] public void TestUnsafeBaseConstructorGeneration() { RunTest(original: """ @@ -2755,7 +2756,7 @@ public unsafe Foo() : base(default) { } allowUnsafe: true); } - [Fact] + [TestMethod] public void TestInternalDefaultConstructorGeneration() { RunTest(original: """ @@ -2813,7 +2814,7 @@ internal Foo() : base(default) { } includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestPrivateDefaultConstructorGeneration() { RunTest(original: """ @@ -2848,7 +2849,7 @@ private Foo() : base(default) { } includeEffectivelyPrivateSymbols: true); } - [Fact] + [TestMethod] public void TestInternalDefaultConstructorGenerationForGenericType() { RunTest(original: """ @@ -2882,7 +2883,7 @@ internal Foo() : base(default) { } includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestExplicitParameterlessConstructorNotRemoved() { RunTest(original: """ @@ -2908,7 +2909,7 @@ public Bar(int a) { } includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestBaseClassWithExplicitDefaultConstructor() { RunTest(original: """ @@ -2939,7 +2940,7 @@ public partial class Foo : Bar includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestGenericBaseInterfaceWithInaccessibleTypeArguments() { RunTest(original: """ @@ -2984,7 +2985,7 @@ public partial class PerLanguageOption : IOption includeInternalSymbols: false); } - [Fact] + [TestMethod] public void NewKeywordWhenBaseMethodIsHidden() { RunTest(original: """ @@ -3135,9 +3136,9 @@ public partial interface IFun { """); } - [Theory] - [InlineData(true)] - [InlineData(false)] + [TestMethod] + [DataRow(true)] + [DataRow(false)] public void TestAttributeWithInternalTypeArgumentOmitted(bool includeInternalSymbols) { string expected = includeInternalSymbols ? """ @@ -3200,7 +3201,7 @@ public class PublicClass { } includeInternalSymbols: includeInternalSymbols); } - [Fact] + [TestMethod] public void TestAttributesExcludedWithFilter() { RunTest(original: """ @@ -3241,7 +3242,7 @@ public partial class PublicClass excludedAttributeList: ["T:A.AnyTestAttribute"]); } - [Fact] + [TestMethod] public void TestGenericClassImplementsGenericInterface() { RunTest(original: """ @@ -3293,7 +3294,7 @@ void System.Collections.ICollection.CopyTo(System.Array array, int index) { } includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestTypeForwardsToGenericTypesRegression31250() { RunTest(original: """ @@ -3339,7 +3340,7 @@ public void TestTypeForwardsToGenericTypesRegression31250() includeInternalSymbols: false); } - [Fact] + [TestMethod] public void ReservedAttributesAreOmitted() { RunTest(original: """ @@ -3373,7 +3374,7 @@ public static void M(this object c, scoped System.ReadOnlySpan values) { } """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceIndexer() { RunTest(original: """ @@ -3411,7 +3412,7 @@ public partial interface IFooList includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestIndexerWithCustomName() { RunTest(original: """ @@ -3436,7 +3437,7 @@ public partial class Foo """); } - [Fact] + [TestMethod] public void TestIndexerWithDefaultNameDoesNotEmitIndexerNameAttribute() { RunTest(original: """ @@ -3459,7 +3460,7 @@ public partial class Foo """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceIndexerWithCustomNameDoesNotEmitIndexerNameAttribute() { RunTest(original: """ @@ -3494,7 +3495,7 @@ public partial interface IFoo """); } - [Fact] + [TestMethod] public void TestExplicitInterfaceNonGenericCollections() { RunTest(original: """ @@ -3572,7 +3573,7 @@ void System.Collections.IList.Remove(object? value) { } includeInternalSymbols: false); } - [Fact] + [TestMethod] public void TestIncludeApiFileEmitsInternalOOBAttribute() { using TempDirectory root = new(); @@ -3651,7 +3652,7 @@ public CollectionBuilderAttribute(Type builderType, string methodName) { } additionalApiInclusionFilter: inclusionFilter); } - [Fact] + [TestMethod] public void TestIncludeInternalCompilerAttributeByDocIdList() { ISymbolFilter inclusionFilter = new CompositeSymbolFilter(CompositeSymbolFilterMode.Or) @@ -3675,7 +3676,7 @@ internal static partial class IsExternalInit additionalApiInclusionFilter: inclusionFilter); } - [Fact] + [TestMethod] public void TestInternalOOBAttributeNotEmittedWithoutInclusionFilter() { RunTest(original: """ diff --git a/test/Microsoft.DotNet.GenAPI.Tests/Microsoft.DotNet.GenAPI.Tests.csproj b/test/Microsoft.DotNet.GenAPI.Tests/Microsoft.DotNet.GenAPI.Tests.csproj index 5fb5b54518a4..6cdfc68144b4 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/Microsoft.DotNet.GenAPI.Tests.csproj +++ b/test/Microsoft.DotNet.GenAPI.Tests/Microsoft.DotNet.GenAPI.Tests.csproj @@ -1,8 +1,7 @@ - + $(SdkTargetFramework) - Exe true @@ -10,15 +9,9 @@ - - - - - - - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.GenAPI.Tests/SymbolFactory.cs b/test/Microsoft.DotNet.GenAPI.Tests/SymbolFactory.cs new file mode 100644 index 000000000000..fd32ad4f27ec --- /dev/null +++ b/test/Microsoft.DotNet.GenAPI.Tests/SymbolFactory.cs @@ -0,0 +1,128 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Microsoft.DotNet.ApiSymbolExtensions.Tests +{ + internal static class SymbolFactory + { + public static string EmitAssemblyFromSyntax(string syntax, + bool enableNullable = false, + byte[] publicKey = null, + [CallerMemberName] string assemblyName = "", + bool allowUnsafe = false) + { + CSharpCompilation compilation = CreateCSharpCompilationFromSyntax(syntax, assemblyName, enableNullable, publicKey, allowUnsafe); + + Assert.IsEmpty(compilation.GetDiagnostics()); + + string assemblyDir = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString("D").Substring(0, 4)}-{assemblyName}"); + Directory.CreateDirectory(assemblyDir); + string assemblyPath = Path.Combine(assemblyDir, $"{assemblyName}.dll"); + compilation.Emit(assemblyPath); + + return assemblyPath; + } + + public static Stream EmitAssemblyStreamFromSyntax(string syntax, + IEnumerable> diagnosticOptions = null, + bool enableNullable = false, + byte[] publicKey = null, + [CallerMemberName] string assemblyName = "", + bool allowUnsafe = false) + { + CSharpCompilation compilation = CreateCSharpCompilationFromSyntax(syntax, assemblyName, enableNullable, publicKey, allowUnsafe, diagnosticOptions); + + Assert.IsEmpty(compilation.GetDiagnostics()); + + MemoryStream stream = new(); + compilation.Emit(stream); + stream.Seek(0, SeekOrigin.Begin); + return stream; + } + + public static IAssemblySymbol GetAssemblyFromSyntax(string syntax, + bool enableNullable = false, + byte[] publicKey = null, + [CallerMemberName] string assemblyName = "", + bool allowUnsafe = false) + { + CSharpCompilation compilation = CreateCSharpCompilationFromSyntax(syntax, assemblyName, enableNullable, publicKey, allowUnsafe); + + Assert.IsEmpty(compilation.GetDiagnostics()); + + return compilation.Assembly; + } + + public static IAssemblySymbol GetAssemblyFromSyntaxWithReferences(string syntax, + IEnumerable referencesSyntax, + bool enableNullable = false, + byte[] publicKey = null, + [CallerMemberName] string assemblyName = "", + bool allowUnsafe = false) + { + CSharpCompilation compilation = CreateCSharpCompilationFromSyntax(syntax, assemblyName, enableNullable, publicKey, allowUnsafe); + CSharpCompilation compilationWithReferences = CreateCSharpCompilationFromSyntax(referencesSyntax, $"{assemblyName}_reference", enableNullable, publicKey, allowUnsafe); + + compilation = compilation.AddReferences(compilationWithReferences.ToMetadataReference()); + + Assert.IsEmpty(compilation.GetDiagnostics()); + + return compilation.Assembly; + } + + private static CSharpCompilation CreateCSharpCompilationFromSyntax(string syntax, string name, bool enableNullable, byte[] publicKey, bool allowUnsafe, IEnumerable> diagnosticOptions = null) + { + CSharpCompilation compilation = CreateCSharpCompilation(name, enableNullable, publicKey, allowUnsafe, diagnosticOptions); + return compilation.AddSyntaxTrees(GetSyntaxTree(syntax)); + } + + private static CSharpCompilation CreateCSharpCompilationFromSyntax(IEnumerable syntax, string name, bool enableNullable, byte[] publicKey, bool allowUnsafe) + { + CSharpCompilation compilation = CreateCSharpCompilation(name, enableNullable, publicKey, allowUnsafe); + IEnumerable syntaxTrees = syntax.Select(s => GetSyntaxTree(s)); + return compilation.AddSyntaxTrees(syntaxTrees); + } + + private static SyntaxTree GetSyntaxTree(string syntax) => CSharpSyntaxTree.ParseText(syntax, ParseOptions); + + private static CSharpCompilation CreateCSharpCompilation(string name, bool enableNullable, byte[] publicKey, bool allowUnsafe, IEnumerable> diagnosticOptions = null) + { + bool publicSign = publicKey != null ? true : false; + var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, + publicSign: publicSign, + cryptoPublicKey: publicSign ? publicKey.ToImmutableArray() : default, + nullableContextOptions: enableNullable ? NullableContextOptions.Enable : NullableContextOptions.Disable, + allowUnsafe: allowUnsafe, + specificDiagnosticOptions: diagnosticOptions ?? DiagnosticOptions); + + return CSharpCompilation.Create(name, options: compilationOptions, references: DefaultReferences); + } + + private static CSharpParseOptions ParseOptions { get; } = new CSharpParseOptions(preprocessorSymbols: +#if NETFRAMEWORK + new string[] { "NETFRAMEWORK" } +#else + Array.Empty() +#endif + ); + + private static IEnumerable> DiagnosticOptions { get; } = new[] + { + // Suppress warning for unused events. + new KeyValuePair("CS0067", ReportDiagnostic.Suppress) + }; + + private static IEnumerable DefaultReferences { get; } = new[] + { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(typeof(DynamicAttribute).Assembly.Location), + }; + } +} diff --git a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/BodyBlockCSharpSyntaxRewriterTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/BodyBlockCSharpSyntaxRewriterTests.cs index 0b367620e62d..2a68d339ff70 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/BodyBlockCSharpSyntaxRewriterTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/BodyBlockCSharpSyntaxRewriterTests.cs @@ -1,13 +1,14 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.DotNet.GenAPI.SyntaxRewriter; namespace Microsoft.DotNet.GenAPI.Tests.SyntaxRewriter { + [TestClass] public class BodyBlockCSharpSyntaxRewriterTests : CSharpSyntaxRewriterTestBase { - [Fact] + [TestMethod] public void TestMethodDeclaration() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter(null), @@ -35,7 +36,7 @@ void M1() {} """); } - [Fact] + [TestMethod] public void TestMethodDeclarationWithExceptionMessage() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter("Not implemented"), @@ -63,7 +64,7 @@ void M1() {} """); } - [Fact] + [TestMethod] public void TestPropertyDeclaration() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter(null), @@ -91,7 +92,7 @@ int P3 { set { } } """); } - [Fact] + [TestMethod] public void TestPropertyDeclarationWithExceptionMessage() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter("Not implemented"), @@ -119,7 +120,7 @@ int P3 { set { } } """); } - [Fact] + [TestMethod] public void TestCustomOperatorDeclaration() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter(null), @@ -143,7 +144,7 @@ class B """); } - [Fact] + [TestMethod] public void TestCustomOperatorDeclarationWithExceptionMessage() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter("Not implemented"), @@ -167,7 +168,7 @@ class B """); } - [Fact] + [TestMethod] public void TestConstructorWithReferenceParameters() { CompareSyntaxTree(new BodyBlockCSharpSyntaxRewriter("Not implemented"), diff --git a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/CSharpSyntaxRewriterTestBase.cs b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/CSharpSyntaxRewriterTestBase.cs index 8bf24699fdc7..ce3f53cc36f8 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/CSharpSyntaxRewriterTestBase.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/CSharpSyntaxRewriterTestBase.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; @@ -18,7 +18,7 @@ protected static void Compare(CSharpSyntaxRewriter rewriter, string original, st StringBuilder stringBuilder = _stringWriter.GetStringBuilder(); string resulted = stringBuilder.ToString(); - Assert.True(resulted.Equals(expected), + Assert.IsTrue(resulted.Equals(expected), $"Expected:\n{expected}\nResulted:\n{resulted}"); } @@ -36,7 +36,7 @@ protected static void CompareSyntaxTree(CSharpSyntaxRewriter rewriter, string or SyntaxTree expectedSyntaxTree = CSharpSyntaxTree.ParseText(expected); // compare SyntaxTree and not string representation - Assert.True(resultedSyntaxTree.IsEquivalentTo(expectedSyntaxTree), + Assert.IsTrue(resultedSyntaxTree.IsEquivalentTo(expectedSyntaxTree), $"Expected:\n{expected}\nResulted:\n{resulted}"); } } diff --git a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/SingleLineStatementCSharpSyntaxRewriterTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/SingleLineStatementCSharpSyntaxRewriterTests.cs index 81d328f11992..af2a0f352630 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/SingleLineStatementCSharpSyntaxRewriterTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/SingleLineStatementCSharpSyntaxRewriterTests.cs @@ -1,13 +1,14 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.DotNet.GenAPI.SyntaxRewriter; namespace Microsoft.DotNet.GenAPI.Tests.SyntaxRewriter { + [TestClass] public class SingleLineStatementCSharpSyntaxRewriterTests : CSharpSyntaxRewriterTestBase { - [Fact] + [TestMethod] public void TestEmptyMethodBody() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -31,7 +32,7 @@ void Execute() { } """); } - [Fact] + [TestMethod] public void TestMethodBodyWithSingleStatement() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -57,7 +58,7 @@ class B """); } - [Fact] + [TestMethod] public void TestConstructorPostProcessing() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -81,7 +82,7 @@ public B() { } """); } - [Fact] + [TestMethod] public void TestMethodBodyWithSingleStatementInOneLine() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -105,7 +106,7 @@ class B """); } - [Fact] + [TestMethod] public void TestPropertyPostProcessing() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -135,7 +136,7 @@ int Property4 { get { } } """); } - [Fact] + [TestMethod] public void TestOperatorPostProcessing() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, @@ -161,7 +162,7 @@ class B """); } - [Fact] + [TestMethod] public void TestConversionOperatorPostProcessing() { Compare(SingleLineStatementCSharpSyntaxRewriter.Singleton, diff --git a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/TypeDeclarationCSharpSyntaxRewriterTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/TypeDeclarationCSharpSyntaxRewriterTests.cs index f33ea9ec90e4..0c2483cecbcf 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/TypeDeclarationCSharpSyntaxRewriterTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/SyntaxRewriter/TypeDeclarationCSharpSyntaxRewriterTests.cs @@ -1,13 +1,14 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.DotNet.GenAPI.SyntaxRewriter; namespace Microsoft.DotNet.GenAPI.Tests.SyntaxRewriter { + [TestClass] public class TypeDeclarationCSharpSyntaxRewriterTests : CSharpSyntaxRewriterTestBase { - [Fact] + [TestMethod] public void TestRemoveSystemObjectAsBaseClass() { CompareSyntaxTree(new TypeDeclarationCSharpSyntaxRewriter(addPartialModifier: true), @@ -29,7 +30,7 @@ partial class B """); } - [Fact] + [TestMethod] public void TestAddPartialKeyword() { CompareSyntaxTree(new TypeDeclarationCSharpSyntaxRewriter(addPartialModifier: true), @@ -51,7 +52,7 @@ partial interface D { } """); } - [Fact] + [TestMethod] public void TestPartialTypeDeclaration() { CompareSyntaxTree(new TypeDeclarationCSharpSyntaxRewriter(addPartialModifier: true), diff --git a/test/Microsoft.DotNet.GenAPI.Tests/TempDirectory.cs b/test/Microsoft.DotNet.GenAPI.Tests/TempDirectory.cs new file mode 100644 index 000000000000..0a614f69be67 --- /dev/null +++ b/test/Microsoft.DotNet.GenAPI.Tests/TempDirectory.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.DotNet.ApiSymbolExtensions.Tests +{ + public class TempDirectory : IDisposable + { + public const int MaxNameLength = 255; + + /// Gets the created directory's path. + public string DirPath { get; private set; } + + /// + /// Construct a random temp directory in the temp folder. + /// + public TempDirectory() + : this(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())) + { + } + + public TempDirectory(string path) + { + DirPath = path; + Directory.CreateDirectory(path); + } + + ~TempDirectory() { DeleteDirectory(); } + + public void Dispose() + { + GC.SuppressFinalize(this); + DeleteDirectory(); + } + + public string GenerateRandomFilePath() => Path.Combine(DirPath, Path.GetRandomFileName()); + + protected virtual void DeleteDirectory() + { + try { Directory.Delete(DirPath, recursive: true); } + catch { /* Ignore exceptions on disposal paths */ } + } + + /// + /// Generates a string with 255 random valid filename characters. + /// 255 is the max file/folder name length in NTFS and FAT32: + // https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison?redirectedfrom=MSDN#limits + /// + /// A 255 length string with random valid filename characters. + public static string GetMaxLengthRandomName() + { + string guid = Guid.NewGuid().ToString("N"); + return guid + new string('x', 255 - guid.Length); + } + } +} diff --git a/test/Microsoft.DotNet.HotReload.Client.Tests/Microsoft.DotNet.HotReload.Client.Tests.csproj b/test/Microsoft.DotNet.HotReload.Client.Tests/Microsoft.DotNet.HotReload.Client.Tests.csproj index 7500dad99340..ef519bdfcde4 100644 --- a/test/Microsoft.DotNet.HotReload.Client.Tests/Microsoft.DotNet.HotReload.Client.Tests.csproj +++ b/test/Microsoft.DotNet.HotReload.Client.Tests/Microsoft.DotNet.HotReload.Client.Tests.csproj @@ -17,6 +17,10 @@ + + + + diff --git a/test/Microsoft.DotNet.HotReload.Client.Tests/StaticWebAssetsManifestTests.cs b/test/Microsoft.DotNet.HotReload.Client.Tests/StaticWebAssetsManifestTests.cs index 87d3eadc3176..e82b59ba8884 100644 --- a/test/Microsoft.DotNet.HotReload.Client.Tests/StaticWebAssetsManifestTests.cs +++ b/test/Microsoft.DotNet.HotReload.Client.Tests/StaticWebAssetsManifestTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.DotNet.Watch.UnitTests; +using Microsoft.DotNet.Test.MSTest.Utilities; using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.DotNet.HotReload.UnitTests; diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs index b7d9c7f69059..c5b3e40cf567 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs +++ b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs @@ -1,145 +1,146 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch.UnitTests; +[TestClass] public class AspireHostLauncherCliTests { - [Fact] + [TestMethod] public void RequiredSdkOption() { // --sdk option is missing var args = new[] { "host", "--entrypoint", "proj", "a", "b" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void RequiredEntryPointOption() { // --entrypoint option is missing var args = new[] { "host", "--sdk", "sdk", "--verbose" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void ProjectAndSdkPaths() { var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "myproject.csproj" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("sdk", launcher.EnvironmentOptions.SdkDirectory); - Assert.True(launcher.EntryPoint.IsProjectFile); - Assert.Equal("myproject.csproj", launcher.EntryPoint.PhysicalPath); - Assert.Empty(launcher.ApplicationArguments); - Assert.Equal(LogLevel.Information, launcher.GlobalOptions.LogLevel); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("sdk", launcher.EnvironmentOptions.SdkDirectory); + Assert.IsTrue(launcher.EntryPoint.IsProjectFile); + Assert.AreEqual("myproject.csproj", launcher.EntryPoint.PhysicalPath); + Assert.IsEmpty(launcher.ApplicationArguments); + Assert.AreEqual(LogLevel.Information, launcher.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void FilePath() { var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "file.cs" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("sdk", launcher.EnvironmentOptions.SdkDirectory); - Assert.False(launcher.EntryPoint.IsProjectFile); - Assert.Equal("file.cs", launcher.EntryPoint.EntryPointFilePath); - Assert.Empty(launcher.ApplicationArguments); - Assert.Equal(LogLevel.Information, launcher.GlobalOptions.LogLevel); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("sdk", launcher.EnvironmentOptions.SdkDirectory); + Assert.IsFalse(launcher.EntryPoint.IsProjectFile); + Assert.AreEqual("file.cs", launcher.EntryPoint.EntryPointFilePath); + Assert.IsEmpty(launcher.ApplicationArguments); + Assert.AreEqual(LogLevel.Information, launcher.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void ApplicationArguments() { var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--verbose", "a", "b" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - AssertEx.SequenceEqual(["a", "b"], launcher.ApplicationArguments); - Assert.Equal(LogLevel.Debug, launcher.GlobalOptions.LogLevel); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreSequenceEqual(["a", "b"], launcher.ApplicationArguments); + Assert.AreEqual(LogLevel.Debug, launcher.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void VerboseOption() { // With verbose flag var argsVerbose = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--verbose" }; - var launcherVerbose = Assert.IsType(AspireLauncher.TryCreate(argsVerbose)); - Assert.Equal(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); + var launcherVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsVerbose)); + Assert.AreEqual(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); // Without verbose flag var argsNotVerbose = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj" }; - var launcherNotVerbose = Assert.IsType(AspireLauncher.TryCreate(argsNotVerbose)); - Assert.Equal(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); + var launcherNotVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotVerbose)); + Assert.AreEqual(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void QuietOption() { // With quiet flag var argsQuiet = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--quiet" }; - var launcherQuiet = Assert.IsType(AspireLauncher.TryCreate(argsQuiet)); - Assert.Equal(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); + var launcherQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsQuiet)); + Assert.AreEqual(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); // Without quiet flag var argsNotQuiet = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj" }; - var launcherNotQuiet = Assert.IsType(AspireLauncher.TryCreate(argsNotQuiet)); - Assert.Equal(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); + var launcherNotQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotQuiet)); + Assert.AreEqual(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void NoLaunchProfileOption() { // With no-launch-profile flag var argsNoProfile = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--no-launch-profile" }; - var launcherNoProfile = Assert.IsType(AspireLauncher.TryCreate(argsNoProfile)); - Assert.False(launcherNoProfile.LaunchProfileName.HasValue); + var launcherNoProfile = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNoProfile)); + Assert.IsFalse(launcherNoProfile.LaunchProfileName.HasValue); // Without no-launch-profile flag var argsDefault = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj" }; - var launcherDefault = Assert.IsType(AspireLauncher.TryCreate(argsDefault)); - Assert.True(launcherDefault.LaunchProfileName.HasValue); - Assert.Null(launcherDefault.LaunchProfileName.Value); + var launcherDefault = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsDefault)); + Assert.IsTrue(launcherDefault.LaunchProfileName.HasValue); + Assert.IsNull(launcherDefault.LaunchProfileName.Value); } - [Fact] + [TestMethod] public void LaunchProfileOption() { var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--launch-profile", "MyProfile" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.True(launcher.LaunchProfileName.HasValue); - Assert.Equal("MyProfile", launcher.LaunchProfileName.Value); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.IsTrue(launcher.LaunchProfileName.HasValue); + Assert.AreEqual("MyProfile", launcher.LaunchProfileName.Value); } - [Fact] + [TestMethod] public void ConflictingOptions() { // Cannot specify both --quiet and --verbose var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj", "--quiet", "--verbose" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void EntryPoint_MultipleValues() { // EntryPoint option should only accept one value; extra values become application arguments var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "proj1", "proj2" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("proj1", launcher.EntryPoint.ProjectOrEntryPointFilePath); - AssertEx.SequenceEqual(["proj2"], launcher.ApplicationArguments); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("proj1", launcher.EntryPoint.ProjectOrEntryPointFilePath); + Assert.AreSequenceEqual(["proj2"], launcher.ApplicationArguments); } - [Fact] + [TestMethod] public void AllOptionsSet() { var args = new[] { "host", "--sdk", "sdk", "--entrypoint", "myapp.csproj", "--verbose", "--no-launch-profile", "arg1", "arg2", "arg3" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - - Assert.True(launcher.EntryPoint.IsProjectFile); - Assert.Equal("myapp.csproj", launcher.EntryPoint.PhysicalPath); - Assert.Equal("sdk", launcher.EnvironmentOptions.SdkDirectory); - Assert.Equal(LogLevel.Debug, launcher.GlobalOptions.LogLevel); - Assert.False(launcher.LaunchProfileName.HasValue); - AssertEx.SequenceEqual(["arg1", "arg2", "arg3"], launcher.ApplicationArguments); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + + Assert.IsTrue(launcher.EntryPoint.IsProjectFile); + Assert.AreEqual("myapp.csproj", launcher.EntryPoint.PhysicalPath); + Assert.AreEqual("sdk", launcher.EnvironmentOptions.SdkDirectory); + Assert.AreEqual(LogLevel.Debug, launcher.GlobalOptions.LogLevel); + Assert.IsFalse(launcher.LaunchProfileName.HasValue); + Assert.AreSequenceEqual(["arg1", "arg2", "arg3"], launcher.ApplicationArguments); } -} +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs index 94abac0ac2ca..23ca92043e70 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs +++ b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; @@ -6,6 +6,7 @@ namespace Microsoft.DotNet.Watch.UnitTests; +[TestClass] public class AspireHostLauncherTests { private static AspireHostLauncher CreateLauncher( @@ -33,13 +34,13 @@ private static AspireHostLauncher CreateLauncher( private static void AssertCommonProperties(ProjectOptions options, AspireHostLauncher launcher) { - Assert.True(options.IsMainProject); - Assert.Equal("run", options.Command); - Assert.Equal(launcher.EntryPoint, options.Representation); - Assert.Empty(options.LaunchEnvironmentVariables); + Assert.IsTrue(options.IsMainProject); + Assert.AreEqual("run", options.Command); + Assert.AreEqual(launcher.EntryPoint, options.Representation); + Assert.IsEmpty(options.LaunchEnvironmentVariables); } - [Fact] + [TestMethod] public void GetProjectOptions_ProjectFile_UsesProjectFlag() { var launcher = CreateLauncher("myapp.csproj"); @@ -47,11 +48,11 @@ public void GetProjectOptions_ProjectFile_UsesProjectFlag() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.False(options.LaunchProfileName.HasValue); - AssertEx.SequenceEqual(["--project", "myapp.csproj", "--no-launch-profile"], options.CommandArguments); + Assert.IsFalse(options.LaunchProfileName.HasValue); + Assert.AreSequenceEqual(["--project", "myapp.csproj", "--no-launch-profile"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_EntryPointFile_UsesFileFlag() { var launcher = CreateLauncher("Program.cs"); @@ -59,11 +60,11 @@ public void GetProjectOptions_EntryPointFile_UsesFileFlag() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.False(options.LaunchProfileName.HasValue); - AssertEx.SequenceEqual(["--file", "Program.cs", "--no-launch-profile"], options.CommandArguments); + Assert.IsFalse(options.LaunchProfileName.HasValue); + Assert.AreSequenceEqual(["--file", "Program.cs", "--no-launch-profile"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_WithLaunchProfile_AddsLaunchProfileArguments() { var launcher = CreateLauncher("myapp.csproj", launchProfileName: "MyProfile"); @@ -71,12 +72,12 @@ public void GetProjectOptions_WithLaunchProfile_AddsLaunchProfileArguments() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.True(options.LaunchProfileName.HasValue); - Assert.Equal("MyProfile", options.LaunchProfileName.Value); - AssertEx.SequenceEqual(["--project", "myapp.csproj", "--launch-profile", "MyProfile"], options.CommandArguments); + Assert.IsTrue(options.LaunchProfileName.HasValue); + Assert.AreEqual("MyProfile", options.LaunchProfileName.Value); + Assert.AreSequenceEqual(["--project", "myapp.csproj", "--launch-profile", "MyProfile"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_NoLaunchProfile_AddsNoLaunchProfileFlag() { var launcher = CreateLauncher("myapp.csproj", launchProfileName: Optional.NoValue); @@ -84,11 +85,11 @@ public void GetProjectOptions_NoLaunchProfile_AddsNoLaunchProfileFlag() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.False(options.LaunchProfileName.HasValue); - AssertEx.SequenceEqual(["--project", "myapp.csproj", "--no-launch-profile"], options.CommandArguments); + Assert.IsFalse(options.LaunchProfileName.HasValue); + Assert.AreSequenceEqual(["--project", "myapp.csproj", "--no-launch-profile"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_NullLaunchProfile_UsesDefault() { // null value (HasValue=true) means use default launch profile - no --launch-profile or --no-launch-profile flag @@ -97,12 +98,12 @@ public void GetProjectOptions_NullLaunchProfile_UsesDefault() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.True(options.LaunchProfileName.HasValue); - Assert.Null(options.LaunchProfileName.Value); - AssertEx.SequenceEqual(["--project", "myapp.csproj"], options.CommandArguments); + Assert.IsTrue(options.LaunchProfileName.HasValue); + Assert.IsNull(options.LaunchProfileName.Value); + Assert.AreSequenceEqual(["--project", "myapp.csproj"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_WithApplicationArguments_AppendsArguments() { var launcher = CreateLauncher("myapp.csproj", launchProfileName: "Profile", applicationArguments: ["arg1", "arg2"]); @@ -110,12 +111,12 @@ public void GetProjectOptions_WithApplicationArguments_AppendsArguments() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.True(options.LaunchProfileName.HasValue); - Assert.Equal("Profile", options.LaunchProfileName.Value); - AssertEx.SequenceEqual(["--project", "myapp.csproj", "--launch-profile", "Profile", "arg1", "arg2"], options.CommandArguments); + Assert.IsTrue(options.LaunchProfileName.HasValue); + Assert.AreEqual("Profile", options.LaunchProfileName.Value); + Assert.AreSequenceEqual(["--project", "myapp.csproj", "--launch-profile", "Profile", "arg1", "arg2"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_SetsCustomWorkingDirectory() { var launcher = CreateLauncher("myapp.csproj", workingDirectory: "/custom/path"); @@ -123,10 +124,10 @@ public void GetProjectOptions_SetsCustomWorkingDirectory() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.Equal("/custom/path", options.WorkingDirectory); + Assert.AreEqual("/custom/path", options.WorkingDirectory); } - [Fact] + [TestMethod] public void GetProjectOptions_EntryPointFile_WithLaunchProfileAndArguments() { var launcher = CreateLauncher("Program.cs", launchProfileName: "Dev", applicationArguments: ["--port", "8080"]); @@ -134,12 +135,12 @@ public void GetProjectOptions_EntryPointFile_WithLaunchProfileAndArguments() var options = launcher.GetHostProjectOptions()!; AssertCommonProperties(options, launcher); - Assert.True(options.LaunchProfileName.HasValue); - Assert.Equal("Dev", options.LaunchProfileName.Value); - AssertEx.SequenceEqual(["--file", "Program.cs", "--launch-profile", "Dev", "--port", "8080"], options.CommandArguments); + Assert.IsTrue(options.LaunchProfileName.HasValue); + Assert.AreEqual("Dev", options.LaunchProfileName.Value); + Assert.AreSequenceEqual(["--file", "Program.cs", "--launch-profile", "Dev", "--port", "8080"], options.CommandArguments); } - [Fact] + [TestMethod] public void GetProjectOptions_NoLaunchProfile_WithApplicationArguments() { var launcher = CreateLauncher("myapp.csproj", launchProfileName: Optional.NoValue, applicationArguments: ["--urls", "http://localhost:5000"]); @@ -147,7 +148,7 @@ public void GetProjectOptions_NoLaunchProfile_WithApplicationArguments() var options = launcher.GetHostProjectOptions(); AssertCommonProperties(options, launcher); - Assert.False(options.LaunchProfileName.HasValue); - AssertEx.SequenceEqual(["--project", "myapp.csproj", "--no-launch-profile", "--urls", "http://localhost:5000"], options.CommandArguments); + Assert.IsFalse(options.LaunchProfileName.HasValue); + Assert.AreSequenceEqual(["--project", "myapp.csproj", "--no-launch-profile", "--urls", "http://localhost:5000"], options.CommandArguments); } -} +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs index d0151c2102fb..a4cb31a69526 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs +++ b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; @@ -6,175 +6,176 @@ namespace Microsoft.DotNet.Watch.UnitTests; +[TestClass] public class AspireResourceLauncherCliTests { - [Fact] + [TestMethod] public void RequiredServerOption() { // --server option is missing var args = new[] { "resource", "--entrypoint", "proj" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void RequiredEntryPointOption() { // --entrypoint option is missing var args = new[] { "resource", "--server", "pipe1" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void MinimalRequiredOptions() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj.csproj" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("pipe1", launcher.ServerPipeName); - Assert.Equal("proj.csproj", launcher.EntryPoint); - Assert.Empty(launcher.ApplicationArguments); - Assert.Empty(launcher.EnvironmentVariables); - Assert.True(launcher.LaunchProfileName.HasValue); - Assert.Null(launcher.LaunchProfileName.Value); - Assert.Equal(LogLevel.Information, launcher.GlobalOptions.LogLevel); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("pipe1", launcher.ServerPipeName); + Assert.AreEqual("proj.csproj", launcher.EntryPoint); + Assert.IsEmpty(launcher.ApplicationArguments); + Assert.IsEmpty(launcher.EnvironmentVariables); + Assert.IsTrue(launcher.LaunchProfileName.HasValue); + Assert.IsNull(launcher.LaunchProfileName.Value); + Assert.AreEqual(LogLevel.Information, launcher.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void ApplicationArguments() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "a", "b" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - AssertEx.SequenceEqual(["a", "b"], launcher.ApplicationArguments); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreSequenceEqual(["a", "b"], launcher.ApplicationArguments); } - [Fact] + [TestMethod] public void EnvironmentOption_SingleVariable() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-e", "KEY=value" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Single(launcher.EnvironmentVariables); - Assert.Equal("value", launcher.EnvironmentVariables["KEY"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.ContainsSingle(launcher.EnvironmentVariables); + Assert.AreEqual("value", launcher.EnvironmentVariables["KEY"]); } - [Fact] + [TestMethod] public void EnvironmentOption_MultipleVariables() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-e", "KEY1=val1", "-e", "KEY2=val2" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal(2, launcher.EnvironmentVariables.Count); - Assert.Equal("val1", launcher.EnvironmentVariables["KEY1"]); - Assert.Equal("val2", launcher.EnvironmentVariables["KEY2"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual(2, launcher.EnvironmentVariables.Count); + Assert.AreEqual("val1", launcher.EnvironmentVariables["KEY1"]); + Assert.AreEqual("val2", launcher.EnvironmentVariables["KEY2"]); } - [Fact] + [TestMethod] public void EnvironmentOption_ValueWithEquals() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-e", "CONN=Server=localhost;Port=5432" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("Server=localhost;Port=5432", launcher.EnvironmentVariables["CONN"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("Server=localhost;Port=5432", launcher.EnvironmentVariables["CONN"]); } - [Fact] + [TestMethod] public void EnvironmentOption_EmptyValue() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-e", "KEY=" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("", launcher.EnvironmentVariables["KEY"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("", launcher.EnvironmentVariables["KEY"]); } - [Fact] + [TestMethod] public void EnvironmentOption_NoEquals() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-e", "KEY" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("", launcher.EnvironmentVariables["KEY"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("", launcher.EnvironmentVariables["KEY"]); } - [Fact] + [TestMethod] public void NoLaunchProfileOption() { // With no-launch-profile flag var argsNoProfile = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "--no-launch-profile" }; - var launcherNoProfile = Assert.IsType(AspireLauncher.TryCreate(argsNoProfile)); - Assert.False(launcherNoProfile.LaunchProfileName.HasValue); + var launcherNoProfile = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNoProfile)); + Assert.IsFalse(launcherNoProfile.LaunchProfileName.HasValue); // Without no-launch-profile flag var argsDefault = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj" }; - var launcherDefault = Assert.IsType(AspireLauncher.TryCreate(argsDefault)); - Assert.True(launcherDefault.LaunchProfileName.HasValue); - Assert.Null(launcherDefault.LaunchProfileName.Value); + var launcherDefault = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsDefault)); + Assert.IsTrue(launcherDefault.LaunchProfileName.HasValue); + Assert.IsNull(launcherDefault.LaunchProfileName.Value); } - [Fact] + [TestMethod] public void LaunchProfileOption() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "--launch-profile", "MyProfile" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.True(launcher.LaunchProfileName.HasValue); - Assert.Equal("MyProfile", launcher.LaunchProfileName.Value); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.IsTrue(launcher.LaunchProfileName.HasValue); + Assert.AreEqual("MyProfile", launcher.LaunchProfileName.Value); } - [Fact] + [TestMethod] public void LaunchProfileOption_ShortForm() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "-lp", "MyProfile" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.True(launcher.LaunchProfileName.HasValue); - Assert.Equal("MyProfile", launcher.LaunchProfileName.Value); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.IsTrue(launcher.LaunchProfileName.HasValue); + Assert.AreEqual("MyProfile", launcher.LaunchProfileName.Value); } - [Fact] + [TestMethod] public void VerboseOption() { var argsVerbose = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "--verbose" }; - var launcherVerbose = Assert.IsType(AspireLauncher.TryCreate(argsVerbose)); - Assert.Equal(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); + var launcherVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsVerbose)); + Assert.AreEqual(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); var argsNotVerbose = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj" }; - var launcherNotVerbose = Assert.IsType(AspireLauncher.TryCreate(argsNotVerbose)); - Assert.Equal(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); + var launcherNotVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotVerbose)); + Assert.AreEqual(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void QuietOption() { var argsQuiet = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "--quiet" }; - var launcherQuiet = Assert.IsType(AspireLauncher.TryCreate(argsQuiet)); - Assert.Equal(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); + var launcherQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsQuiet)); + Assert.AreEqual(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); var argsNotQuiet = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj" }; - var launcherNotQuiet = Assert.IsType(AspireLauncher.TryCreate(argsNotQuiet)); - Assert.Equal(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); + var launcherNotQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotQuiet)); + Assert.AreEqual(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void ConflictingOptions() { // Cannot specify both --quiet and --verbose var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "proj", "--quiet", "--verbose" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void AllOptionsSet() { var args = new[] { "resource", "--server", "pipe1", "--entrypoint", "myapp.csproj", "-e", "K1=V1", "-e", "K2=V2", "--launch-profile", "Dev", "--verbose", "arg1", "arg2" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - - Assert.Equal("pipe1", launcher.ServerPipeName); - Assert.Equal("myapp.csproj", launcher.EntryPoint); - Assert.Equal(LogLevel.Debug, launcher.GlobalOptions.LogLevel); - Assert.True(launcher.LaunchProfileName.HasValue); - Assert.Equal("Dev", launcher.LaunchProfileName.Value); - AssertEx.SequenceEqual(["arg1", "arg2"], launcher.ApplicationArguments); - Assert.Equal(2, launcher.EnvironmentVariables.Count); - Assert.Equal("V1", launcher.EnvironmentVariables["K1"]); - Assert.Equal("V2", launcher.EnvironmentVariables["K2"]); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + + Assert.AreEqual("pipe1", launcher.ServerPipeName); + Assert.AreEqual("myapp.csproj", launcher.EntryPoint); + Assert.AreEqual(LogLevel.Debug, launcher.GlobalOptions.LogLevel); + Assert.IsTrue(launcher.LaunchProfileName.HasValue); + Assert.AreEqual("Dev", launcher.LaunchProfileName.Value); + Assert.AreSequenceEqual(["arg1", "arg2"], launcher.ApplicationArguments); + Assert.AreEqual(2, launcher.EnvironmentVariables.Count); + Assert.AreEqual("V1", launcher.EnvironmentVariables["K1"]); + Assert.AreEqual("V2", launcher.EnvironmentVariables["K2"]); } - [Fact] + [TestMethod] public void EnvironmentOption_Duplicates() { var command = new AspireResourceCommandDefinition(); @@ -187,7 +188,7 @@ public void EnvironmentOption_Duplicates() result.Errors.Should().BeEmpty(); } - [Fact] + [TestMethod] public void EnvironmentOption_Duplicates_CasingDifference() { var command = new AspireResourceCommandDefinition(); @@ -212,7 +213,7 @@ public void EnvironmentOption_Duplicates_CasingDifference() result.Errors.Should().BeEmpty(); } - [Fact] + [TestMethod] public void EnvironmentOption_MultiplePerToken() { var command = new AspireResourceCommandDefinition(); @@ -230,7 +231,7 @@ public void EnvironmentOption_MultiplePerToken() result.Errors.Should().BeEmpty(); } - [Fact] + [TestMethod] public void EnvironmentOption_NoValue() { var command = new AspireResourceCommandDefinition(); @@ -243,7 +244,7 @@ public void EnvironmentOption_NoValue() result.Errors.Should().BeEmpty(); } - [Fact] + [TestMethod] public void EnvironmentOption_WhitespaceTrimming() { var command = new AspireResourceCommandDefinition(); @@ -256,19 +257,19 @@ public void EnvironmentOption_WhitespaceTrimming() result.Errors.Should().BeEmpty(); } - [Theory] - [InlineData("")] - [InlineData("=")] - [InlineData("= X")] - [InlineData(" \u2002 = X")] + [TestMethod] + [DataRow("")] + [DataRow("=")] + [DataRow("= X")] + [DataRow(" \u2002 = X")] public void EnvironmentOption_Errors(string token) { var command = new AspireResourceCommandDefinition(); var result = command.Parse(["--server", "S", "--entrypoint", "E", "-e", token]); - AssertEx.SequenceEqual( + Assert.AreSequenceEqual( [ $"Incorrectly formatted environment variables '{token}'" ], result.Errors.Select(e => e.Message)); } -} +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs index 39ba1fdff22b..127b20e9ca0f 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs +++ b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs @@ -1,129 +1,130 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.Watch.UnitTests; +[TestClass] public class AspireServerLauncherCliTests { - [Fact] + [TestMethod] public void RequiredServerOption() { // --server option is missing var args = new[] { "server", "--sdk", "sdk" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void RequiredSdkOption() { // --sdk option is missing var args = new[] { "server", "--server", "pipe1" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void MinimalRequiredOptions() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("pipe1", launcher.ServerPipeName); - Assert.Equal(LogLevel.Information, launcher.GlobalOptions.LogLevel); - Assert.Empty(launcher.ResourcePaths); - Assert.Null(launcher.StatusPipeName); - Assert.Null(launcher.ControlPipeName); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("pipe1", launcher.ServerPipeName); + Assert.AreEqual(LogLevel.Information, launcher.GlobalOptions.LogLevel); + Assert.IsEmpty(launcher.ResourcePaths); + Assert.IsNull(launcher.StatusPipeName); + Assert.IsNull(launcher.ControlPipeName); } - [Fact] + [TestMethod] public void ResourceOption_SingleValue() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--resource", "proj1.csproj" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - AssertEx.SequenceEqual(["proj1.csproj"], launcher.ResourcePaths); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreSequenceEqual(["proj1.csproj"], launcher.ResourcePaths); } - [Fact] + [TestMethod] public void ResourceOption_MultipleValues() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--resource", "proj1.csproj", "proj2.csproj", "file.cs" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - AssertEx.SequenceEqual(["proj1.csproj", "proj2.csproj", "file.cs"], launcher.ResourcePaths); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreSequenceEqual(["proj1.csproj", "proj2.csproj", "file.cs"], launcher.ResourcePaths); } - [Fact] + [TestMethod] public void ResourceOption_MultipleFlags() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--resource", "proj1.csproj", "--resource", "proj2.csproj" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - AssertEx.SequenceEqual(["proj1.csproj", "proj2.csproj"], launcher.ResourcePaths); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreSequenceEqual(["proj1.csproj", "proj2.csproj"], launcher.ResourcePaths); } - [Fact] + [TestMethod] public void StatusPipeOption() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--status-pipe", "status1" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("status1", launcher.StatusPipeName); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("status1", launcher.StatusPipeName); } - [Fact] + [TestMethod] public void ControlPipeOption() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--control-pipe", "control1" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); - Assert.Equal("control1", launcher.ControlPipeName); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); + Assert.AreEqual("control1", launcher.ControlPipeName); } - [Fact] + [TestMethod] public void VerboseOption() { // With verbose flag var argsVerbose = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--verbose" }; - var launcherVerbose = Assert.IsType(AspireLauncher.TryCreate(argsVerbose)); - Assert.Equal(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); + var launcherVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsVerbose)); + Assert.AreEqual(LogLevel.Debug, launcherVerbose.GlobalOptions.LogLevel); // Without verbose flag var argsNotVerbose = new[] { "server", "--server", "pipe1", "--sdk", "sdk" }; - var launcherNotVerbose = Assert.IsType(AspireLauncher.TryCreate(argsNotVerbose)); - Assert.Equal(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); + var launcherNotVerbose = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotVerbose)); + Assert.AreEqual(LogLevel.Information, launcherNotVerbose.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void QuietOption() { // With quiet flag var argsQuiet = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--quiet" }; - var launcherQuiet = Assert.IsType(AspireLauncher.TryCreate(argsQuiet)); - Assert.Equal(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); + var launcherQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsQuiet)); + Assert.AreEqual(LogLevel.Warning, launcherQuiet.GlobalOptions.LogLevel); // Without quiet flag var argsNotQuiet = new[] { "server", "--server", "pipe1", "--sdk", "sdk" }; - var launcherNotQuiet = Assert.IsType(AspireLauncher.TryCreate(argsNotQuiet)); - Assert.Equal(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); + var launcherNotQuiet = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(argsNotQuiet)); + Assert.AreEqual(LogLevel.Information, launcherNotQuiet.GlobalOptions.LogLevel); } - [Fact] + [TestMethod] public void ConflictingOptions() { // Cannot specify both --quiet and --verbose var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--quiet", "--verbose" }; var launcher = AspireLauncher.TryCreate(args); - Assert.Null(launcher); + Assert.IsNull(launcher); } - [Fact] + [TestMethod] public void AllOptionsSet() { var args = new[] { "server", "--server", "pipe1", "--sdk", "sdk", "--resource", "proj1.csproj", "proj2.csproj", "--status-pipe", "status1", "--control-pipe", "control1", "--verbose" }; - var launcher = Assert.IsType(AspireLauncher.TryCreate(args)); + var launcher = Assert.IsExactInstanceOfType(AspireLauncher.TryCreate(args)); - Assert.Equal("pipe1", launcher.ServerPipeName); - Assert.Equal(LogLevel.Debug, launcher.GlobalOptions.LogLevel); - AssertEx.SequenceEqual(["proj1.csproj", "proj2.csproj"], launcher.ResourcePaths); - Assert.Equal("status1", launcher.StatusPipeName); - Assert.Equal("control1", launcher.ControlPipeName); + Assert.AreEqual("pipe1", launcher.ServerPipeName); + Assert.AreEqual(LogLevel.Debug, launcher.GlobalOptions.LogLevel); + Assert.AreSequenceEqual(["proj1.csproj", "proj2.csproj"], launcher.ResourcePaths); + Assert.AreEqual("status1", launcher.StatusPipeName); + Assert.AreEqual("control1", launcher.ControlPipeName); } -} +} \ No newline at end of file diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj index e65ce1a88a56..0aec8ad4a1ee 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj +++ b/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj @@ -1,19 +1,14 @@ - + + $(SdkTargetFramework) - Exe Microsoft.DotNet.Watch.Aspire.UnitTests MicrosoftAspNetCore - - - - - - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.Test.MSTest.Utilities/InMemoryLoggerProvider.cs b/test/Microsoft.DotNet.Test.MSTest.Utilities/InMemoryLoggerProvider.cs new file mode 100644 index 000000000000..3715dac3febe --- /dev/null +++ b/test/Microsoft.DotNet.Test.MSTest.Utilities/InMemoryLoggerProvider.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; + +namespace Microsoft.DotNet.Test.MSTest.Utilities; + +/// +/// An that appends every log entry to a caller-supplied list. +/// Useful for tests that need to assert on the exact sequence of log entries produced by a +/// component under test (without dragging in MSTest's TestContext sink). +/// +public sealed class InMemoryLoggerProvider(List<(LogLevel, string)> messagesCollection) : ILoggerProvider +{ + public ILogger CreateLogger(string categoryName) => new InMemoryLogger(messagesCollection); + + public void Dispose() + { + } + + private sealed class InMemoryLogger(List<(LogLevel, string)> messagesCollection) : ILogger + { + public IDisposable? BeginScope(TState state) where TState : notnull => NullScope.Instance; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + => messagesCollection.Add((logLevel, formatter(state, exception))); + } + + private sealed class NullScope : IDisposable + { + public static readonly NullScope Instance = new(); + + public void Dispose() + { + } + } +} diff --git a/test/Microsoft.DotNet.Test.MSTest.Utilities/Microsoft.DotNet.Test.MSTest.Utilities.csproj b/test/Microsoft.DotNet.Test.MSTest.Utilities/Microsoft.DotNet.Test.MSTest.Utilities.csproj new file mode 100644 index 000000000000..73adf7653621 --- /dev/null +++ b/test/Microsoft.DotNet.Test.MSTest.Utilities/Microsoft.DotNet.Test.MSTest.Utilities.csproj @@ -0,0 +1,42 @@ + + + + + + $(SdkTargetFramework);$(NetFrameworkToolCurrent) + Library + Microsoft.DotNet.Test.MSTest.Utilities + MicrosoftAspNetCore + false + + + + + + + + + + + + + + + + diff --git a/test/Microsoft.DotNet.HotReload.Client.Tests/Utilities/TestLogger.cs b/test/Microsoft.DotNet.Test.MSTest.Utilities/TestLogger.cs similarity index 70% rename from test/Microsoft.DotNet.HotReload.Client.Tests/Utilities/TestLogger.cs rename to test/Microsoft.DotNet.Test.MSTest.Utilities/TestLogger.cs index 6bb15080c57d..87c8c1248f62 100644 --- a/test/Microsoft.DotNet.HotReload.Client.Tests/Utilities/TestLogger.cs +++ b/test/Microsoft.DotNet.Test.MSTest.Utilities/TestLogger.cs @@ -1,12 +1,18 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Microsoft.DotNet.Watch.UnitTests; +namespace Microsoft.DotNet.Test.MSTest.Utilities; -internal class TestLogger(TestContext? output = null) : ILogger +/// +/// An that captures messages in memory and optionally echoes them to an +/// MSTest . Designed to be shared across MSTest.Sdk test projects so +/// the same pattern doesn't have to be duplicated per project. +/// +public class TestLogger(TestContext? testContext = null) : ILogger { public readonly object Guard = new(); private readonly List _messages = []; @@ -31,7 +37,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except HasWarning |= logLevel is LogLevel.Warning; _messages.Add(message); - output?.WriteLine(message); + testContext?.WriteLine(message); } } diff --git a/test/Microsoft.DotNet.Test.MSTest.Utilities/TestLoggerFactory.cs b/test/Microsoft.DotNet.Test.MSTest.Utilities/TestLoggerFactory.cs new file mode 100644 index 000000000000..15485a93f137 --- /dev/null +++ b/test/Microsoft.DotNet.Test.MSTest.Utilities/TestLoggerFactory.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.DotNet.Test.MSTest.Utilities; + +/// +/// An that writes log messages to an MSTest +/// (when provided) and a simple console sink. Useful for tests that +/// need a real (e.g. for components that take one in their ctor). +/// +public sealed class TestLoggerFactory : ILoggerFactory +{ + private readonly List _loggerProviders = new(); + private readonly List _factories = new(); + + public TestLoggerFactory(TestContext? testContext = null) + { + if (testContext is not null) + { + _loggerProviders.Add(new TestContextLoggerProvider(testContext)); + } + } + + public void Dispose() + { + while (_factories.Count > 0) + { + ILoggerFactory factory = _factories[0]; + _factories.RemoveAt(0); + factory.Dispose(); + } + } + + public ILogger CreateLogger(string categoryName) + { + ILoggerFactory loggerFactory = LoggerFactory.Create(builder => + { + builder.SetMinimumLevel(LogLevel.Trace); + + foreach (ILoggerProvider loggerProvider in _loggerProviders) + { + builder.AddProvider(loggerProvider); + } + + builder.AddSimpleConsole(options => + { + options.SingleLine = true; + options.TimestampFormat = "[yyyy-MM-dd HH:mm:ss.fff] "; + options.IncludeScopes = true; + }); + }); + + _factories.Add(loggerFactory); + return loggerFactory.CreateLogger(categoryName); + } + + public ILogger CreateLogger() => CreateLogger("Test Host"); + + public void AddProvider(ILoggerProvider provider) => _loggerProviders.Add(provider); + + private sealed class TestContextLoggerProvider(TestContext testContext) : ILoggerProvider + { + public ILogger CreateLogger(string categoryName) => new TestContextLogger(testContext, categoryName); + + public void Dispose() + { + } + } + + private sealed class TestContextLogger(TestContext testContext, string categoryName) : ILogger + { + public IDisposable? BeginScope(TState state) where TState : notnull => NullScope.Instance; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + testContext.WriteLine($"{logLevel}: {categoryName}: {formatter(state, exception)}"); + if (exception is not null) + { + testContext.WriteLine(exception.ToString()); + } + } + } + + private sealed class NullScope : IDisposable + { + public static readonly NullScope Instance = new(); + + public void Dispose() + { + } + } +} diff --git a/test/containerize.UnitTests/ParserTests.cs b/test/containerize.UnitTests/ParserTests.cs index 4240089eca13..d9273253b6ce 100644 --- a/test/containerize.UnitTests/ParserTests.cs +++ b/test/containerize.UnitTests/ParserTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; @@ -6,9 +6,10 @@ namespace containerize.UnitTests; +[TestClass] public class ParserTests { - [Fact] + [TestMethod] public void CanParseLabels() { ContainerizeCommand command = new(); @@ -41,17 +42,17 @@ public void CanParseLabels() Dictionary? labels = parseResult.GetValue(command.LabelsOption); - Assert.NotNull(labels); - Assert.Equal(6, labels.Count); - Assert.Empty(labels["NoValue"]); - Assert.Equal("Val2", labels["Valid2"]); - Assert.Equal("Val 3", labels["Valid3"]); - Assert.Equal("\"Val4\"", labels["Valid4"]); - Assert.Equal("\"Un1", labels["Unbalanced1"]); - Assert.Equal("Un2\"", labels["Unbalanced2"]); + Assert.IsNotNull(labels); + Assert.AreEqual(6, labels.Count); + Assert.IsEmpty(labels["NoValue"]); + Assert.AreEqual("Val2", labels["Valid2"]); + Assert.AreEqual("Val 3", labels["Valid3"]); + Assert.AreEqual("\"Val4\"", labels["Valid4"]); + Assert.AreEqual("\"Un1", labels["Unbalanced1"]); + Assert.AreEqual("Un2\"", labels["Unbalanced2"]); } - [Fact] + [TestMethod] public void CanParseLabels2() { ContainerizeCommand command = new(); @@ -79,15 +80,15 @@ public void CanParseLabels2() Dictionary? labels = parseResult.GetValue(command.LabelsOption); - Assert.NotNull(labels); - Assert.Equal(2, labels.Count); - Assert.Empty(labels["NoValue"]); - Assert.Equal("Val2", labels["Valid2"]); + Assert.IsNotNull(labels); + Assert.AreEqual(2, labels.Count); + Assert.IsEmpty(labels["NoValue"]); + Assert.AreEqual("Val2", labels["Valid2"]); } - [Theory] - [InlineData("not-a-label")] - [InlineData("not", "a", "label")] + [TestMethod] + [DataRow("not-a-label")] + [DataRow("not", "a", "label")] public void CanHandleInvalidLabels(params string[] labelStr) { ContainerizeCommand command = new(); @@ -114,12 +115,12 @@ public void CanHandleInvalidLabels(params string[] labelStr) } ParseResult parseResult = command.Parse(baseArgs.ToArray()); - Assert.Single(parseResult.Errors); + Assert.ContainsSingle(parseResult.Errors); - Assert.Equal($"Incorrectly formatted labels: {string.Join(";", labelStr)}", parseResult.Errors[0].Message); + Assert.AreEqual($"Incorrectly formatted labels: {string.Join(";", labelStr)}", parseResult.Errors[0].Message); } - [Fact] + [TestMethod] public void CanParseEnvironmentVariables() { ContainerizeCommand command = new(); @@ -149,21 +150,21 @@ public void CanParseEnvironmentVariables() ParseResult parseResult = command.Parse(baseArgs.ToArray()); - Assert.Empty(parseResult.Errors); + Assert.IsEmpty(parseResult.Errors); Dictionary? envVars = parseResult.GetValue(command.EnvVarsOption); - Assert.NotNull(envVars); - Assert.Equal(6, envVars.Count); - Assert.Empty(envVars["NoValue"]); - Assert.Equal("Val2", envVars["Valid2"]); - Assert.Equal("Val 3", envVars["Valid3"]); - Assert.Equal("\"Val4\"", envVars["Valid4"]); - Assert.Equal("\"Un1", envVars["Unbalanced1"]); - Assert.Equal("Un2\"", envVars["Unbalanced2"]); + Assert.IsNotNull(envVars); + Assert.AreEqual(6, envVars.Count); + Assert.IsEmpty(envVars["NoValue"]); + Assert.AreEqual("Val2", envVars["Valid2"]); + Assert.AreEqual("Val 3", envVars["Valid3"]); + Assert.AreEqual("\"Val4\"", envVars["Valid4"]); + Assert.AreEqual("\"Un1", envVars["Unbalanced1"]); + Assert.AreEqual("Un2\"", envVars["Unbalanced2"]); } - [Fact] + [TestMethod] public void CanParsePorts() { ContainerizeCommand command = new(); @@ -191,22 +192,22 @@ public void CanParsePorts() ParseResult parseResult = command.Parse(baseArgs.ToArray()); - Assert.Empty(parseResult.Errors); + Assert.IsEmpty(parseResult.Errors); Port[]? ports = parseResult.GetValue(command.PortsOption); - Assert.NotNull(ports); - Assert.Equal(4, ports.Length); + Assert.IsNotNull(ports); + Assert.AreEqual(4, ports.Length); Assert.Contains(new Port(1500, PortType.tcp), ports); Assert.Contains(new Port(1501, PortType.udp), ports); Assert.Contains(new Port(1501, PortType.tcp), ports); Assert.Contains(new Port(1502, PortType.tcp), ports); } - [Theory] - [InlineData("1501/smth", "(InvalidPortType)")] - [InlineData("1501\\tcp", "(InvalidPortNumber)")] - [InlineData("not-a-number", "(InvalidPortNumber)")] + [TestMethod] + [DataRow("1501/smth", "(InvalidPortType)")] + [DataRow("1501\\tcp", "(InvalidPortNumber)")] + [DataRow("not-a-number", "(InvalidPortNumber)")] public void CanHandleInvalidPorts(string portStr, string reason) { string errorMessage = $"Incorrectly formatted ports:{Environment.NewLine}\t{portStr}:\t{reason}{Environment.NewLine}"; @@ -232,9 +233,9 @@ public void CanHandleInvalidPorts(string portStr, string reason) baseArgs.Add(portStr); ParseResult parseResult = command.Parse(baseArgs.ToArray()); - Assert.Single(parseResult.Errors); + Assert.ContainsSingle(parseResult.Errors); - Assert.Equal(errorMessage, parseResult.Errors[0].Message); + Assert.AreEqual(errorMessage, parseResult.Errors[0].Message); } } diff --git a/test/containerize.UnitTests/containerize.UnitTests.csproj b/test/containerize.UnitTests/containerize.UnitTests.csproj index 215c72557027..3036a17b4558 100644 --- a/test/containerize.UnitTests/containerize.UnitTests.csproj +++ b/test/containerize.UnitTests/containerize.UnitTests.csproj @@ -1,17 +1,14 @@ - + $(SdkTargetFramework) enable - false true MicrosoftShared - Exe - - + \ No newline at end of file diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireLauncherTests.cs b/test/dotnet-watch.Tests/Aspire/AspireLauncherIntegrationTests.cs similarity index 98% rename from test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireLauncherTests.cs rename to test/dotnet-watch.Tests/Aspire/AspireLauncherIntegrationTests.cs index ceab4de2f838..2255ed3aa721 100644 --- a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireLauncherTests.cs +++ b/test/dotnet-watch.Tests/Aspire/AspireLauncherIntegrationTests.cs @@ -6,7 +6,7 @@ namespace Microsoft.DotNet.Watch.UnitTests; -public class AspireLauncherTests(ITestOutputHelper logger) : WatchSdkTest(logger) +public class AspireLauncherIntegrationTests(ITestOutputHelper logger) : WatchSdkTest(logger) { private WatchableApp CreateHostApp() => new( diff --git a/test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Utilities/PipeUtilities.cs b/test/dotnet-watch.Tests/Aspire/PipeUtilities.cs similarity index 100% rename from test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Utilities/PipeUtilities.cs rename to test/dotnet-watch.Tests/Aspire/PipeUtilities.cs diff --git a/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj b/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj index 72312ae26fb1..3b45b8eb3031 100644 --- a/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj +++ b/test/dotnet-watch.Tests/dotnet-watch.Tests.csproj @@ -1,4 +1,4 @@ - + Exe $(SdkTargetFramework) @@ -18,6 +18,8 @@ + +