File: StaticWebAssets\UpdateExternallyDefinedStaticWebAssetsTest.cs
Web Access
Project: ..\..\..\test\Microsoft.NET.Sdk.StaticWebAssets.Tests\Microsoft.NET.Sdk.StaticWebAssets.Tests.csproj (Microsoft.NET.Sdk.StaticWebAssets.Tests)
// 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 Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Moq;
 
namespace Microsoft.AspNetCore.StaticWebAssets.Tasks;
 
public class UpdateExternallyDefinedStaticWebAssetsTest
{
    [Fact]
    public void Execute_UpdatesAssetsWithoutFingerprint()
    {
        // Arrange
        var errorMessages = new List<string>();
        var buildEngine = new Mock<IBuildEngine>();
        buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
            .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
 
        Directory.CreateDirectory(Path.Combine(AppContext.BaseDirectory, "dist", "assets"));
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"), "body { color: red; }");
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "index.html"), "<html><body></body></html>");
        var assets = new ITaskItem [] {
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, @"dist\assets\index-C5tBAdQX.css"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "assets/index-C5tBAdQX.css",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, @"dist\assets\index-C5tBAdQX.css"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                }),
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, @"dist\index.html"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "index.html",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, @"dist\index.html"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                })
        };
 
        var task = new UpdateExternallyDefinedStaticWebAssets
        {
            Assets = assets,
            Endpoints = [],
            BuildEngine = buildEngine.Object
        };
 
        // Act
        var result = task.Execute();
 
        // Assert
        result.Should().BeTrue();
 
        task.UpdatedAssets.Should().HaveCount(2);
        task.AssetsWithoutEndpoints.Should().HaveCount(2);
        task.UpdatedAssets[0].GetMetadata("Fingerprint").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[1].GetMetadata("Fingerprint").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[0].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[1].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
    }
 
    [Fact]
    public void Execute_DoesNotAddAssets_WithEndpointsTo_AssetsWithoutEndpoints()
    {
        // Arrange
        var errorMessages = new List<string>();
        var buildEngine = new Mock<IBuildEngine>();
        buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
            .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
 
        Directory.CreateDirectory(Path.Combine(AppContext.BaseDirectory, "dist", "assets"));
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"), "body { color: red; }");
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "index.html"), "<html><body></body></html>");
        var assets = new ITaskItem[] {
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "assets/index-C5tBAdQX.css",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                }),
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, "dist", "index.html"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "index.html",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, "dist", "index.html"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                })
        };
 
        var task = new UpdateExternallyDefinedStaticWebAssets
        {
            Assets = assets,
            Endpoints = [
                new TaskItem(
                    "index.html",
                    new Dictionary<string, string>
                    {
                        ["Route"] = "/index.html",
                        ["AssetFile"] = Path.Combine(AppContext.BaseDirectory, "dist", "index.html"),
                        ["Selectors"] = "[]",
                        ["ResponseHeaders"] = "[]",
                        ["EndpointProperties"] = "[]"
                    })
                ],
            BuildEngine = buildEngine.Object
        };
 
        // Act
        var result = task.Execute();
 
        // Assert
        result.Should().BeTrue();
 
        task.UpdatedAssets.Should().HaveCount(2);
        task.AssetsWithoutEndpoints.Should().HaveCount(1);
        task.AssetsWithoutEndpoints[0].ItemSpec.Should().Be(Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"));
        task.UpdatedAssets[0].GetMetadata("Fingerprint").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[1].GetMetadata("Fingerprint").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[0].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[1].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
    }
 
    [Fact]
    public void Execute_InfersFingerprint_ForMatchingAssets()
    {
        // Arrange
        var errorMessages = new List<string>();
        var buildEngine = new Mock<IBuildEngine>();
        buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
            .Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
 
        Directory.CreateDirectory(Path.Combine(AppContext.BaseDirectory, "dist", "assets"));
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"), "body { color: red; }");
        File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "dist", "index.html"), "<html><body></body></html>");
        var assets = new ITaskItem[] {
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "assets/index-C5tBAdQX.css",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, "dist", "assets", "index-C5tBAdQX.css"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                }),
            new TaskItem(
                Path.Combine(AppContext.BaseDirectory, "dist", "index.html"),
                new Dictionary<string, string>
                {
                    ["RelativePath"] = "index.html",
                    ["BasePath"] = "",
                    ["AssetMode"] = "All",
                    ["AssetKind"] = "Publish",
                    ["SourceId"] = "MyProject",
                    ["CopyToOutputDirectory"] = "PreserveNewest",
                    ["RelatedAsset"] = "",
                    ["ContentRoot"] = Path.Combine(AppContext.BaseDirectory, "dist"),
                    ["SourceType"] = "Discovered",
                    ["AssetRole"] = "Primary",
                    ["AssetTraitValue"] = "",
                    ["AssetTraitName"] = "",
                    ["OriginalItemSpec"] = Path.Combine(AppContext.BaseDirectory, "dist", "index.html"),
                    ["CopyToPublishDirectory"] = "PreserveNewest"
                })
        };
 
        var fingerprintExpressions = new TaskItem[]
        {
            new TaskItem(
                "React",
                new Dictionary<string, string>
                {
                    ["Pattern"] = "assets/.*-(?<fingerprint>.+)\\..*",
                })
        };
 
        var task = new UpdateExternallyDefinedStaticWebAssets
        {
            FingerprintInferenceExpressions = fingerprintExpressions,
            Assets = assets,
            Endpoints = [],
            BuildEngine = buildEngine.Object
        };
 
        // Act
        var result = task.Execute();
 
        // Assert
        result.Should().BeTrue();
        task.UpdatedAssets.Should().HaveCount(2);
        task.UpdatedAssets[0].GetMetadata("Fingerprint").Should().Be("C5tBAdQX");
        task.UpdatedAssets[0].GetMetadata("RelativePath").Should().Be("assets/index-#[{fingerprint}].css");
        task.UpdatedAssets[1].GetMetadata("Fingerprint").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[0].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
        task.UpdatedAssets[1].GetMetadata("Integrity").Should().NotBeNullOrEmpty();
    }
}