From af28ae751a87a95c8f37abdebd5acf3d584983e3 Mon Sep 17 00:00:00 2001 From: Dmitriy Shepelev Date: Tue, 2 Sep 2025 16:45:26 -0700 Subject: [PATCH 1/2] Predict Fakes outputs --- .../Predictors/FakesOutputPathPredictor.cs | 27 ++++++ src/BuildPrediction/ProjectPredictors.cs | 2 + .../FakesOutputPathIntegrationTests.cs | 19 ++++ .../FakesOutputPathPredictorTests.cs | 96 +++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 src/BuildPrediction/Predictors/FakesOutputPathPredictor.cs create mode 100644 src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs create mode 100644 src/BuildPredictionTests/Predictors/FakesOutputPathPredictorTests.cs diff --git a/src/BuildPrediction/Predictors/FakesOutputPathPredictor.cs b/src/BuildPrediction/Predictors/FakesOutputPathPredictor.cs new file mode 100644 index 0000000..a5638ef --- /dev/null +++ b/src/BuildPrediction/Predictors/FakesOutputPathPredictor.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Execution; + +namespace Microsoft.Build.Prediction.Predictors +{ + /// + /// Predicts the output directory for Microsoft Fakes assemblies based on the FakesOutputPath property. + /// + public sealed class FakesOutputPathPredictor : IProjectPredictor + { + internal const string FakesOutputPathPropertyName = "FakesOutputPath"; + + /// + public void PredictInputsAndOutputs( + ProjectInstance projectInstance, + ProjectPredictionReporter predictionReporter) + { + string fakesOutputPath = projectInstance.GetPropertyValue(FakesOutputPathPropertyName); + if (!string.IsNullOrWhiteSpace(fakesOutputPath)) + { + predictionReporter.ReportOutputDirectory(fakesOutputPath); + } + } + } +} \ No newline at end of file diff --git a/src/BuildPrediction/ProjectPredictors.cs b/src/BuildPrediction/ProjectPredictors.cs index b4b91e5..83e846b 100644 --- a/src/BuildPrediction/ProjectPredictors.cs +++ b/src/BuildPrediction/ProjectPredictors.cs @@ -64,6 +64,7 @@ public static class ProjectPredictors /// /// /// + /// /// /// /// A collection of . @@ -114,6 +115,7 @@ public static class ProjectPredictors new GenerateBuildDependencyFilePredictor(), new GeneratePublishDependencyFilePredictor(), new GenerateRuntimeConfigurationFilesPredictor(), + new FakesOutputPathPredictor(), //// NOTE! When adding a new predictor here, be sure to update the doc comment above. }; diff --git a/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs b/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs new file mode 100644 index 0000000..87351bd --- /dev/null +++ b/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Prediction.Predictors; +using Xunit; + +namespace Microsoft.Build.Prediction.Tests.Predictors +{ + public class FakesOutputPathIntegrationTests + { + [Fact] + public void FakesOutputPathPredictorIncludedInAllPredictors() + { + // Verify that our new predictor is included in the AllProjectPredictors collection + var allPredictors = ProjectPredictors.AllProjectPredictors; + Assert.Contains(allPredictors, p => p is FakesOutputPathPredictor); + } + } +} \ No newline at end of file diff --git a/src/BuildPredictionTests/Predictors/FakesOutputPathPredictorTests.cs b/src/BuildPredictionTests/Predictors/FakesOutputPathPredictorTests.cs new file mode 100644 index 0000000..821c877 --- /dev/null +++ b/src/BuildPredictionTests/Predictors/FakesOutputPathPredictorTests.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Build.Construction; +using Microsoft.Build.Execution; +using Microsoft.Build.Prediction.Predictors; +using Xunit; + +namespace Microsoft.Build.Prediction.Tests.Predictors +{ + public class FakesOutputPathPredictorTests + { + [Fact] + public void FakesOutputPathFoundAsOutputDir() + { + const string FakesOutputPath = @"C:\repo\FakesAssemblies"; + ProjectInstance projectInstance = CreateTestProjectInstance(FakesOutputPath); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertPredictions( + projectInstance, + null, + null, + null, + new[] { new PredictedItem(FakesOutputPath, nameof(FakesOutputPathPredictor)) }); + } + + [Fact] + public void RelativeFakesOutputPathFoundAsOutputDir() + { + const string FakesOutputPath = @"bin\FakesAssemblies"; + ProjectInstance projectInstance = CreateTestProjectInstance(FakesOutputPath); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertPredictions( + projectInstance, + null, + null, + null, + new[] { new PredictedItem(FakesOutputPath, nameof(FakesOutputPathPredictor)) }); + } + + [Fact] + public void DefaultFakesAssembliesDirectoryFoundAsOutputDir() + { + const string FakesOutputPath = @"FakesAssemblies"; + ProjectInstance projectInstance = CreateTestProjectInstance(FakesOutputPath); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertPredictions( + projectInstance, + null, + null, + null, + new[] { new PredictedItem(FakesOutputPath, nameof(FakesOutputPathPredictor)) }); + } + + [Fact] + public void NoOutputsReportedIfNoFakesOutputPath() + { + ProjectInstance projectInstance = CreateTestProjectInstance(null); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertNoPredictions(); + } + + [Fact] + public void NoOutputsReportedIfEmptyFakesOutputPath() + { + ProjectInstance projectInstance = CreateTestProjectInstance(string.Empty); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertNoPredictions(); + } + + [Fact] + public void NoOutputsReportedIfWhitespaceFakesOutputPath() + { + ProjectInstance projectInstance = CreateTestProjectInstance(" "); + new FakesOutputPathPredictor() + .GetProjectPredictions(projectInstance) + .AssertNoPredictions(); + } + + private static ProjectInstance CreateTestProjectInstance(string fakesOutputPath) + { + ProjectRootElement projectRootElement = ProjectRootElement.Create(); + if (fakesOutputPath != null) + { + projectRootElement.AddProperty(FakesOutputPathPredictor.FakesOutputPathPropertyName, fakesOutputPath); + } + + return TestHelpers.CreateProjectInstanceFromRootElement(projectRootElement); + } + } +} \ No newline at end of file From ddd46d8e5f6406408e17d646ec19311bd206bb0f Mon Sep 17 00:00:00 2001 From: Dmitriy Shepelev Date: Tue, 2 Sep 2025 17:05:47 -0700 Subject: [PATCH 2/2] Delete src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs --- .../FakesOutputPathIntegrationTests.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs diff --git a/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs b/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs deleted file mode 100644 index 87351bd..0000000 --- a/src/BuildPredictionTests/Predictors/FakesOutputPathIntegrationTests.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Microsoft.Build.Prediction.Predictors; -using Xunit; - -namespace Microsoft.Build.Prediction.Tests.Predictors -{ - public class FakesOutputPathIntegrationTests - { - [Fact] - public void FakesOutputPathPredictorIncludedInAllPredictors() - { - // Verify that our new predictor is included in the AllProjectPredictors collection - var allPredictors = ProjectPredictors.AllProjectPredictors; - Assert.Contains(allPredictors, p => p is FakesOutputPathPredictor); - } - } -} \ No newline at end of file