|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Shouldly;
using Xunit;
#nullable disable
namespace Microsoft.Build.UnitTests.Evaluation
{
/// <summary>
/// Tests mainly for project evaluation logging
/// </summary>
public class EvaluationLogging_Tests : IDisposable
{
/// <summary>
/// Cleanup
/// </summary>
public EvaluationLogging_Tests()
{
ProjectCollection.GlobalProjectCollection.UnloadAllProjects();
GC.Collect();
}
/// <summary>
/// Cleanup
/// </summary>
public void Dispose()
{
ProjectCollection.GlobalProjectCollection.UnloadAllProjects();
GC.Collect();
}
private static void AssertLoggingEvents(
Action<Project, MockLogger> loggingTest = null,
MockLogger firstEvaluationLogger = null,
Func<Project, MockLogger> reevaluationLoggerFactory = null)
{
var projectImportContents =
@"<Project>
<Target Name=`Foo`
AfterTargets=`X`
BeforeTargets=`Y`
>
</Target>
<PropertyGroup>
<P>Bar</P>
<P2>$(NonExisting)</P2>
</PropertyGroup>
</Project>".Cleanup();
var projectContents =
@"<Project>
<Target Name=`Foo`>
</Target>
<PropertyGroup>
<P>Foo</P>
</PropertyGroup>
<Import Project=`{0}`/>
<Import Project=`{0}`/>
</Project>".Cleanup();
using (var env = TestEnvironment.Create())
{
var collection = env.CreateProjectCollection().Collection;
var importFile = env.CreateFile().Path;
File.WriteAllText(importFile, projectImportContents);
projectContents = string.Format(projectContents, importFile);
var projectFile = env.CreateFile().Path;
File.WriteAllText(projectFile, projectContents);
firstEvaluationLogger ??= new MockLogger();
collection.RegisterLogger(firstEvaluationLogger);
var project = new Project(projectFile, null, null, collection);
firstEvaluationLogger.AllBuildEvents.ShouldNotBeEmpty();
if (reevaluationLoggerFactory != null)
{
var reevaluationLogger = reevaluationLoggerFactory.Invoke(project);
collection.RegisterLogger(reevaluationLogger);
project.SetProperty("aProperty", "Value");
project.ReevaluateIfNecessary();
reevaluationLogger.AllBuildEvents.ShouldNotBeEmpty();
}
loggingTest?.Invoke(project, firstEvaluationLogger);
}
}
[Fact]
public void AllEvaluationEventsShouldHaveAnEvaluationId()
{
AssertLoggingEvents(
(project, firstEvaluationLogger) =>
{
var evaluationId = project.LastEvaluationId;
evaluationId.ShouldNotBe(BuildEventContext.InvalidEvaluationId);
foreach (var buildEvent in firstEvaluationLogger.AllBuildEvents)
{
buildEvent.BuildEventContext.EvaluationId.ShouldBe(evaluationId);
}
});
}
[Fact]
public void GivenOneProjectThereShouldBeOneStartedAndOneEndedEvent()
{
AssertLoggingEvents(
(project, firstEvaluationLogger) =>
{
var allBuildEvents = firstEvaluationLogger.AllBuildEvents.Where(be => be is ProjectEvaluationStartedEventArgs || be is ProjectEvaluationFinishedEventArgs).ToList();
allBuildEvents.Count.ShouldBe(2);
allBuildEvents[0].GetType().ShouldBe(typeof(ProjectEvaluationStartedEventArgs));
allBuildEvents[1].GetType().ShouldBe(typeof(ProjectEvaluationFinishedEventArgs));
});
}
[Fact]
public void ProjectShouldHaveValidEvaluationIdDuringEvaluation()
{
AssertLoggingEvents(
null,
null,
project => new MockLogger
{
AdditionalHandlers = new List<Action<object, BuildEventArgs>>
{
(sender, args) =>
{
var eventEvaluationId = args.BuildEventContext.EvaluationId;
eventEvaluationId.ShouldNotBe(BuildEventContext.InvalidEvaluationId);
project.LastEvaluationId.Should().Be(eventEvaluationId);
}
}
});
}
[Fact]
public void TurnOnProfileEvaluationFromLogger()
{
AssertLoggingEvents(
(project, logger) =>
{
foreach (var e in logger.AllBuildEvents.OfType<ProjectEvaluationFinishedEventArgs>())
{
e.ProfilerResult.ShouldNotBeNull();
}
},
new MockLogger(null, true));
}
}
}
|