|
// 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 Microsoft.Build.Framework;
using Microsoft.Build.UnitTests;
using Microsoft.Build.Utilities;
using Shouldly;
using Xunit;
#nullable disable
namespace Microsoft.Build.Tasks.UnitTests
{
public class RARPrecomputedCache_Tests
{
[Fact]
public void TestPrecomputedCacheOutput()
{
using (TestEnvironment env = TestEnvironment.Create())
{
DateTime now = DateTime.Now;
TransientTestFile standardCache = env.CreateFile(".cache");
ResolveAssemblyReference t = new ResolveAssemblyReference()
{
_cache = new SystemState()
};
t._cache.instanceLocalFileStateCache = new Dictionary<string, SystemState.FileState>() {
{ Path.Combine(standardCache.Path, "assembly1"), new SystemState.FileState(now) },
{ Path.Combine(standardCache.Path, "assembly2"), new SystemState.FileState(now) { Assembly = new Shared.AssemblyNameExtension("hi") } } };
t._cache.SetGetLastWriteTime(_ => now);
_ = t._cache.GetFileState("assembly1");
_ = t._cache.GetFileState("assembly2");
t._cache.IsDirty = true;
t.StateFile = standardCache.Path;
t.WriteStateFile();
int standardLen = File.ReadAllText(standardCache.Path).Length;
File.Delete(standardCache.Path);
standardLen.ShouldBeGreaterThan(0);
string precomputedPath = standardCache.Path + ".cache";
t._cache.IsDirty = true;
t.AssemblyInformationCacheOutputPath = precomputedPath;
t.WriteStateFile();
File.Exists(standardCache.Path).ShouldBeFalse();
int preLen = File.ReadAllText(precomputedPath).Length;
preLen.ShouldBeGreaterThan(0);
preLen.ShouldNotBe(standardLen);
}
}
[Fact]
public void StandardCacheTakesPrecedence()
{
using (TestEnvironment env = TestEnvironment.Create())
{
DateTime now = DateTime.Now;
TransientTestFile standardCache = env.CreateFile(".cache");
ResolveAssemblyReference rarWriterTask = new ResolveAssemblyReference()
{
_cache = new SystemState()
};
rarWriterTask._cache.instanceLocalFileStateCache = new() {
{ "path1", new SystemState.FileState(now) },
};
rarWriterTask._cache.SetGetLastWriteTime(_ => now);
rarWriterTask.StateFile = standardCache.Path;
_ = rarWriterTask._cache.GetFileState("path1");
rarWriterTask._cache.IsDirty = true;
// Write standard cache
rarWriterTask.WriteStateFile();
string dllName = Path.Combine(Path.GetDirectoryName(standardCache.Path), "randomFolder", "dll.dll");
rarWriterTask._cache.instanceLocalFileStateCache.Add(dllName,
new SystemState.FileState(DateTime.Now)
{
Assembly = null,
RuntimeVersion = "v4.0.30319",
FrameworkNameAttribute = new System.Runtime.Versioning.FrameworkName(".NETFramework", Version.Parse("4.7.2"), "Profile"),
scatterFiles = new string[] { "first", "second" }
});
string precomputedCachePath = standardCache.Path + ".cache";
rarWriterTask.AssemblyInformationCacheOutputPath = precomputedCachePath;
rarWriterTask._cache.IsDirty = true;
// Write precomputed cache
rarWriterTask.WriteStateFile();
ResolveAssemblyReference rarReaderTask = new ResolveAssemblyReference();
rarReaderTask.StateFile = standardCache.Path;
rarReaderTask.AssemblyInformationCachePaths = new ITaskItem[]
{
new TaskItem(precomputedCachePath)
};
// At this point, we should have created two cache files: one "normal" one and one "precomputed" one.
// When we read the state file, it should read from the caches produced in a normal build. In this case,
// the normal cache does not have dll.dll, whereas the precomputed cache does, so it should not be
// present when we read it.
rarReaderTask.ReadStateFile(p => true);
rarReaderTask._cache.instanceLocalFileStateCache.ShouldNotContainKey(dllName);
}
}
[Fact]
public void TestPreComputedCacheInputMatchesOutput()
{
using (TestEnvironment env = TestEnvironment.Create())
{
TransientTestFile precomputedCache = env.CreateFile(".cache");
ResolveAssemblyReference rarWriterTask = new ResolveAssemblyReference()
{
_cache = new SystemState()
};
string dllName = Path.Combine(Path.GetDirectoryName(precomputedCache.Path), "randomFolder", "dll.dll");
rarWriterTask._cache.instanceLocalFileStateCache = new Dictionary<string, SystemState.FileState>() {
{ Path.Combine(precomputedCache.Path, "..", "assembly1", "assembly1"), new SystemState.FileState(DateTime.Now) },
{ Path.Combine(precomputedCache.Path, "assembly2"), new SystemState.FileState(DateTime.Now) { Assembly = new Shared.AssemblyNameExtension("hi") } },
{ dllName, new SystemState.FileState(DateTime.Now) {
Assembly = null,
RuntimeVersion = "v4.0.30319",
FrameworkNameAttribute = new System.Runtime.Versioning.FrameworkName(".NETFramework", Version.Parse("4.7.2"), "Profile"),
scatterFiles = new string[] { "first", "second" } } } };
rarWriterTask.AssemblyInformationCacheOutputPath = precomputedCache.Path;
rarWriterTask._cache.IsDirty = true;
// Throws an exception because precomputedCache.Path already exists.
Should.Throw<InvalidOperationException>(() => rarWriterTask.WriteStateFile());
File.Delete(precomputedCache.Path);
rarWriterTask.WriteStateFile();
ResolveAssemblyReference rarReaderTask = new ResolveAssemblyReference();
rarReaderTask.StateFile = precomputedCache.Path.Substring(0, precomputedCache.Path.Length - 6); // Not a real path; should not be used.
rarReaderTask.AssemblyInformationCachePaths = new ITaskItem[]
{
new TaskItem(precomputedCache.Path)
};
// At this point, the standard cache does not exist, so it defaults to reading the "precomputed" cache.
// Then we verify that the information contained in that cache matches what we'd expect.
rarReaderTask.ReadStateFile(p => true);
rarReaderTask._cache.instanceLocalFileStateCache.ShouldContainKey(dllName);
SystemState.FileState assembly3 = rarReaderTask._cache.instanceLocalFileStateCache[dllName];
assembly3.Assembly.ShouldBeNull();
assembly3.RuntimeVersion.ShouldBe("v4.0.30319");
assembly3.FrameworkNameAttribute.Version.ShouldBe(Version.Parse("4.7.2"));
assembly3.scatterFiles.Length.ShouldBe(2);
assembly3.scatterFiles[1].ShouldBe("second");
}
}
}
}
|