diff --git a/src/Tests/Microsoft.NET.Sdk.Razor.Tests/AspNetSdkBaselineTest.cs b/src/Tests/Microsoft.NET.Sdk.Razor.Tests/AspNetSdkBaselineTest.cs index a696cf003d17..24c661c81609 100644 --- a/src/Tests/Microsoft.NET.Sdk.Razor.Tests/AspNetSdkBaselineTest.cs +++ b/src/Tests/Microsoft.NET.Sdk.Razor.Tests/AspNetSdkBaselineTest.cs @@ -21,6 +21,18 @@ namespace Microsoft.NET.Sdk.Razor.Tests public class AspNetSdkBaselineTest : AspNetSdkTest { private static readonly JsonSerializerOptions BaselineSerializationOptions = new() { WriteIndented = true }; + private static readonly string BaselineGenerationInstructions = + @"If the difference in baselines is expected, please re-generate the baselines. +Note, baseline generation must be done on a Windows device. +Start by ensuring you're dogfooding the SDK from the current branch (dotnet --version should be '*.0.0-dev'). + If you're not on the dogfood sdk, from the root of the repository run: + 1. dotnet clean + 2. .\restore.cmd + 3. .\build.cmd + 4. .\eng\dogfood.cmd + +Then, using the dogfood SDK run the .\src\RazorSdk\update-test-baselines.ps1 script."; + protected static readonly string DotNetJSHashRegexPattern = "\\.[a-z0-9]{10}\\.js"; protected static readonly string DotNetJSHashTemplate = ".[[hash]].js"; @@ -352,8 +364,8 @@ internal void AssertManifest( manifest.BasePath.Should().Be(expected.BasePath); manifest.Mode.Should().Be(expected.Mode); manifest.ManifestType.Should().Be(expected.ManifestType); - - manifest.ReferencedProjectsConfiguration.Count().Should().Be(expected.ReferencedProjectsConfiguration.Count()); + + manifest.ReferencedProjectsConfiguration.Should().HaveSameCount(expected.ReferencedProjectsConfiguration); // Relax the check for project reference configuration items see // https://github.com/dotnet/sdk/pull/27381#issuecomment-1228764471 @@ -363,8 +375,139 @@ internal void AssertManifest( // .BeEquivalentTo(expected.ReferencedProjectsConfiguration.OrderBy(cm => cm.Identity)); manifest.DiscoveryPatterns.OrderBy(dp => dp.Name).Should().BeEquivalentTo(expected.DiscoveryPatterns.OrderBy(dp => dp.Name)); - manifest.Assets.OrderBy(a => a.BasePath).ThenBy(a => a.RelativePath).ThenBy(a => a.AssetKind) - .Should().BeEquivalentTo(expected.Assets.OrderBy(a => a.BasePath).ThenBy(a => a.RelativePath).ThenBy(a => a.AssetKind)); + + var manifestAssets = manifest.Assets.OrderBy(a => a.BasePath).ThenBy(a => a.RelativePath).ThenBy(a => a.AssetKind); + var expectedAssets = expected.Assets.OrderBy(a => a.BasePath).ThenBy(a => a.RelativePath).ThenBy(a => a.AssetKind); + + // If there's a mismatch in the number of assets, just print the strict difference in the asset `Identity` + if (manifestAssets.Count() != expectedAssets.Count()) + { + ThrowAssetCountMismatchError(manifestAssets, expectedAssets); + } + + // Otherwise, do a property level comparison of all assets + var manifestAssetsEnumerator = manifestAssets.GetEnumerator(); + var expectedAssetsEnumerator = expectedAssets.GetEnumerator(); + + var differences = new List(); + + do + { + var manifestAsset = manifestAssetsEnumerator.Current; + var expectedAsset = expectedAssetsEnumerator.Current; + + if (manifestAsset is null && expectedAsset is null) + { + continue; + } + + var assetDifferences = new List(); + + if (manifestAsset.Identity != expectedAsset.Identity) + { + assetDifferences.Add($"Expected manifest Identity of {expectedAsset.Identity} but found {manifestAsset.Identity}."); + } + if (manifestAsset.SourceType != expectedAsset.SourceType) + { + assetDifferences.Add($"Expected manifest SourceType of {expectedAsset.SourceType} but found {manifestAsset.SourceType}."); + } + if (manifestAsset.SourceId != expectedAsset.SourceId) + { + assetDifferences.Add($"Expected manifest SourceId of {expectedAsset.SourceId} but found {manifestAsset.SourceId}."); + } + if (manifestAsset.ContentRoot != expectedAsset.ContentRoot) + { + assetDifferences.Add($"Expected manifest ContentRoot of {expectedAsset.ContentRoot} but found {manifestAsset.ContentRoot}."); + } + if (manifestAsset.BasePath != expectedAsset.BasePath) + { + assetDifferences.Add($"Expected manifest BasePath of {expectedAsset.BasePath} but found {manifestAsset.BasePath}."); + } + if (manifestAsset.RelativePath != expectedAsset.RelativePath) + { + assetDifferences.Add($"Expected manifest RelativePath of {expectedAsset.RelativePath} but found {manifestAsset.RelativePath}."); + } + if (manifestAsset.AssetKind != expectedAsset.AssetKind) + { + assetDifferences.Add($"Expected manifest AssetKind of {expectedAsset.AssetKind} but found {manifestAsset.AssetKind}."); + } + if (manifestAsset.AssetMode != expectedAsset.AssetMode) + { + assetDifferences.Add($"Expected manifest AssetMode of {expectedAsset.AssetMode} but found {manifestAsset.AssetMode}."); + } + if (manifestAsset.AssetRole != expectedAsset.AssetRole) + { + assetDifferences.Add($"Expected manifest AssetRole of {expectedAsset.AssetRole} but found {manifestAsset.AssetRole}."); + } + if (manifestAsset.RelatedAsset != expectedAsset.RelatedAsset) + { + assetDifferences.Add($"Expected manifest RelatedAsset of {expectedAsset.RelatedAsset} but found {manifestAsset.RelatedAsset}."); + } + if (manifestAsset.AssetTraitName != expectedAsset.AssetTraitName) + { + assetDifferences.Add($"Expected manifest AssetTraitName of {expectedAsset.AssetTraitName} but found {manifestAsset.AssetTraitName}."); + } + if (manifestAsset.AssetTraitValue != expectedAsset.AssetTraitValue) + { + assetDifferences.Add($"Expected manifest AssetTraitValue of {expectedAsset.AssetTraitValue} but found {manifestAsset.AssetTraitValue}."); + } + if (manifestAsset.CopyToOutputDirectory != expectedAsset.CopyToOutputDirectory) + { + assetDifferences.Add($"Expected manifest CopyToOutputDirectory of {expectedAsset.CopyToOutputDirectory} but found {manifestAsset.CopyToOutputDirectory}."); + } + if (manifestAsset.CopyToPublishDirectory != expectedAsset.CopyToPublishDirectory) + { + assetDifferences.Add($"Expected manifest CopyToPublishDirectory of {expectedAsset.CopyToPublishDirectory} but found {manifestAsset.CopyToPublishDirectory}."); + } + if (manifestAsset.OriginalItemSpec != expectedAsset.OriginalItemSpec) + { + assetDifferences.Add($"Expected manifest OriginalItemSpec of {expectedAsset.OriginalItemSpec} but found {manifestAsset.OriginalItemSpec}."); + } + + if (assetDifferences.Any()) + { + differences.Add(@$" +================================================== + +For {expectedAsset.Identity}: + +{string.Join(Environment.NewLine, assetDifferences)} + +=================================================="); + } + + } while (manifestAssetsEnumerator.MoveNext() && expectedAssetsEnumerator.MoveNext()); + + differences.Should().BeEmpty( + @$" the generated manifest should match the expected baseline. + +{BaselineGenerationInstructions} + +"); + + static void ThrowAssetCountMismatchError(IEnumerable manifestAssets, IEnumerable expectedAssets) + { + var missingAssets = expectedAssets.Except(manifestAssets); + var unexpectedAssets = manifestAssets.Except(expectedAssets); + + var differences = new List(); + + if (missingAssets.Any()) + { + differences.Add($@"The following expected assets weren't found in the manifest: + {string.Join($"{Environment.NewLine}\t", missingAssets.Select(a => a.Identity))}"); + } + + if (unexpectedAssets.Any()) + { + differences.Add($@"The following additional unexpected assets were found in the manifest: + {string.Join($"{Environment.NewLine}\t", unexpectedAssets.Select(a => a.Identity))}"); + } + + throw new Exception($@"{string.Join(Environment.NewLine, differences)} + +{BaselineGenerationInstructions}"); + } } else { @@ -535,3 +678,4 @@ string TemplatizeRestorePath(string restorePath, string property) } } } +