public void ReturnsError_WhenContentRootIsMissing()
        {
            // 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));

            var task = new GenerateStaticWebAssetsManifest
            {
                BuildEngine            = buildEngine.Object,
                ContentRootDefinitions = new TaskItem[]
                {
                    CreateItem(Path.Combine("wwwroot", "sample.js"), new Dictionary <string, string>
                    {
                        ["BasePath"] = "MyLibrary"
                    })
                }
            };

            // Act
            var result = task.Execute();

            // Assert
            result.Should().BeFalse();
            var expectedError = $"Missing required metadata 'ContentRoot' for '{Path.Combine("wwwroot", "sample.js")}'.";

            errorMessages.Should().ContainSingle(message => message == expectedError);
        }
        public void Generates_EmptyManifest_WhenNoItems_Passed()
        {
            // Arrange
            var file             = Path.GetTempFileName();
            var expectedDocument = @"<StaticWebAssets Version=""1.0"" />";

            try
            {
                var buildEngine = new Mock <IBuildEngine>();

                var task = new GenerateStaticWebAssetsManifest
                {
                    BuildEngine            = buildEngine.Object,
                    ContentRootDefinitions = new TaskItem[] { },
                    TargetManifestPath     = file
                };

                // Act
                var result = task.Execute();

                // Assert
                result.Should().BeTrue();
                var document = File.ReadAllText(file);
                document.Should().Contain(expectedDocument);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
        public void GeneratesManifestFailsWhenTwoAssetsEndUpOnTheSamePath(StaticWebAsset first, StaticWebAsset second)
        {
            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));

            // GetTempFilePath automatically creates the file, which interferes with the test.
            File.Delete(TempFilePath);
            var task = new GenerateStaticWebAssetsManifest
            {
                BuildEngine = buildEngine.Object,
                Assets      = new[]
                {
                    first.ToTaskItem(),
                second.ToTaskItem()
                },
                ReferencedProjectsConfigurations = Array.Empty <ITaskItem>(),
                DiscoveryPatterns = Array.Empty <ITaskItem>(),
                BasePath          = "/",
                Source            = "MyProject",
                ManifestType      = "Build",
                Mode         = "Default",
                ManifestPath = TempFilePath,
            };

            // Act
            var result = task.Execute();

            // Assert
            result.Should().Be(false);
        }
        public void GeneratesManifestFailsWhenInvalidAssetsAreProvided(Action <StaticWebAsset> change)
        {
            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));

            // GetTempFilePath automatically creates the file, which interferes with the test.
            File.Delete(TempFilePath);
            var asset = CreateAsset(Path.Combine("wwwroot", "candidate.js"), "MyProject", "Computed", "candidate.js", "All", "All");

            change(asset);
            var task = new GenerateStaticWebAssetsManifest
            {
                BuildEngine = buildEngine.Object,
                Assets      = new[]
                {
                    asset.ToTaskItem()
                },
                ReferencedProjectsConfigurations = Array.Empty <ITaskItem>(),
                DiscoveryPatterns = Array.Empty <ITaskItem>(),
                BasePath          = "/",
                Source            = "MyProject",
                ManifestType      = "Build",
                Mode         = "Default",
                ManifestPath = TempFilePath,
            };

            // Act
            var result = task.Execute();

            // Assert
            result.Should().Be(false);
        }
        public void SkipsAdditionalElements_WithSameBasePathAndSameContentRoot()
        {
            // Arrange
            var file             = Path.GetTempFileName();
            var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
  <ContentRoot BasePath=""Base/MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", $"razorContent{Path.DirectorySeparatorChar}")}"" />
</StaticWebAssets>";

            try
            {
                var buildEngine = new Mock <IBuildEngine>();

                var task = new GenerateStaticWebAssetsManifest
                {
                    BuildEngine            = buildEngine.Object,
                    ContentRootDefinitions = new TaskItem[]
                    {
                        CreateItem(Path.Combine("wwwroot", "sample.js"), new Dictionary <string, string>
                        {
                            // Base path needs to be normalized to '/' as it goes in the url
                            ["BasePath"]    = "Base\\MyLibrary",
                            ["SourceId"]    = "MyLibrary",
                            ["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent")
                        }),
                        // Comparisons are case insensitive
                        CreateItem(Path.Combine("wwwroot, site.css"), new Dictionary <string, string>
                        {
                            ["BasePath"]    = "Base\\MyLIBRARY",
                            ["SourceId"]    = "MyLibrary",
                            ["ContentRoot"] = Path.Combine(".", "nuget", "MyLIBRARY", "razorContent")
                        }),
                    },
                    TargetManifestPath = file
                };

                // Act
                var result = task.Execute();

                // Assert
                result.Should().BeTrue();
                var document = File.ReadAllText(file);
                document.Should().Contain(expectedDocument);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
        public void AllowsMultipleContentRootsWithSameBasePath_ForTheSameSourceId()
        {
            // Arrange
            var file             = Path.GetTempFileName();
            var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
  <ContentRoot BasePath=""Blazor.Client"" Path=""{Path.Combine(".", "nuget", "bin", "debug", $"netstandard2.1{Path.DirectorySeparatorChar}")}"" />
  <ContentRoot BasePath=""Blazor.Client"" Path=""{Path.Combine(".", "nuget", $"Blazor.Client{Path.DirectorySeparatorChar}")}"" />
</StaticWebAssets>";

            var buildEngine = new Mock <IBuildEngine>();

            var task = new GenerateStaticWebAssetsManifest
            {
                BuildEngine            = buildEngine.Object,
                ContentRootDefinitions = new TaskItem[]
                {
                    CreateItem(Path.Combine("wwwroot", "sample.js"), new Dictionary <string, string>
                    {
                        ["BasePath"]    = "Blazor.Client",
                        ["ContentRoot"] = Path.Combine(".", "nuget", "Blazor.Client"),
                        ["SourceId"]    = "Blazor.Client"
                    }),
                    CreateItem(Path.Combine("wwwroot", "otherLib.js"), new Dictionary <string, string>
                    {
                        ["BasePath"]    = "Blazor.Client",
                        ["ContentRoot"] = Path.Combine(".", "nuget", "bin", "debug", "netstandard2.1"),
                        ["SourceId"]    = "Blazor.Client"
                    })
                },
                TargetManifestPath = file
            };

            try
            {
                // Act
                var result = task.Execute();

                // Assert
                result.Should().BeTrue();
                var document = File.ReadAllText(file);
                document.Should().Contain(expectedDocument);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
        public void Generates_Manifest_WhenContentRootsAvailable()
        {
            // Arrange
            var file             = Path.GetTempFileName();
            var expectedDocument = $@"<StaticWebAssets Version=""1.0"">
  <ContentRoot BasePath=""MyLibrary"" Path=""{Path.Combine(".", "nuget", "MyLibrary", $"razorContent{Path.DirectorySeparatorChar}")}"" />
</StaticWebAssets>";

            try
            {
                var buildEngine = new Mock <IBuildEngine>();

                var task = new GenerateStaticWebAssetsManifest
                {
                    BuildEngine            = buildEngine.Object,
                    ContentRootDefinitions = new TaskItem[]
                    {
                        CreateItem(Path.Combine("wwwroot", "sample.js"), new Dictionary <string, string>
                        {
                            ["BasePath"]    = "MyLibrary",
                            ["ContentRoot"] = Path.Combine(".", "nuget", "MyLibrary", "razorContent"),
                            ["SourceId"]    = "MyLibrary"
                        }),
                    },
                    TargetManifestPath = file
                };

                // Act
                var result = task.Execute();

                // Assert
                result.Should().BeTrue();
                var document = File.ReadAllText(file);
                document.Should().Contain(expectedDocument);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
        public void CanGenerateEmptyManifest()
        {
            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));

            // GetTempFilePath automatically creates the file, which interferes with the test.
            File.Delete(TempFilePath);

            var task = new GenerateStaticWebAssetsManifest
            {
                BuildEngine = buildEngine.Object,
                Assets      = Array.Empty <ITaskItem>(),
                ReferencedProjectsConfigurations = Array.Empty <ITaskItem>(),
                DiscoveryPatterns = Array.Empty <ITaskItem>(),
                BasePath          = "/",
                Source            = "MyProject",
                ManifestType      = "Build",
                Mode         = "Default",
                ManifestPath = TempFilePath,
            };

            // Act
            var result = task.Execute();

            // Assert
            result.Should().Be(true);
            var manifest = StaticWebAssetsManifest.FromJsonString(File.ReadAllText(TempFilePath));

            manifest.Should().NotBeNull();
            manifest.Assets.Should().BeNullOrEmpty();
            manifest.DiscoveryPatterns.Should().BeNullOrEmpty();
            manifest.ReferencedProjectsConfiguration.Should().BeNullOrEmpty();
            manifest.Version.Should().Be(1);
            manifest.Hash.Should().NotBeNullOrWhiteSpace();
            manifest.Mode.Should().Be("Default");
            manifest.ManifestType.Should().Be("Build");
            manifest.BasePath.Should().Be("/");
            manifest.Source.Should().Be("MyProject");
        }
        public void GeneratesManifestWithAssets()
        {
            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));

            // GetTempFilePath automatically creates the file, which interferes with the test.
            File.Delete(TempFilePath);
            var asset = CreateAsset(Path.Combine("wwwroot", "candidate.js"), "MyProject", "Computed", "candidate.js", "All", "All");
            var task  = new GenerateStaticWebAssetsManifest
            {
                BuildEngine = buildEngine.Object,
                Assets      = new[]
                {
                    asset.ToTaskItem()
                },
                ReferencedProjectsConfigurations = Array.Empty <ITaskItem>(),
                DiscoveryPatterns = Array.Empty <ITaskItem>(),
                BasePath          = "/",
                Source            = "MyProject",
                ManifestType      = "Build",
                Mode         = "Default",
                ManifestPath = TempFilePath,
            };

            // Act
            var result = task.Execute();

            // Assert
            result.Should().Be(true);
            var manifest = StaticWebAssetsManifest.FromJsonString(File.ReadAllText(TempFilePath));

            manifest.Should().NotBeNull();
            manifest.Assets.Should().HaveCount(1);
            var newAsset = manifest.Assets[0];

            newAsset.Should().Be(asset);
        }