This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using YMhut.Box.Core.App;
|
||||
|
||||
namespace YMhut.Box.Tests;
|
||||
|
||||
[TestClass]
|
||||
[DoNotParallelize]
|
||||
public sealed class InstallLayoutPathsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ResolveInstallRootPrefersCurrentInstallRootEnvironment()
|
||||
{
|
||||
using var workspace = TestWorkspace.Create("ymhut-install-root-tests");
|
||||
var installRoot = workspace.CreateDirectory("install");
|
||||
var baseRoot = workspace.CreateDirectory("runtime");
|
||||
|
||||
using var environment = EnvironmentScope.Capture(
|
||||
InstallLayoutPaths.InstallRootEnvironmentVariable,
|
||||
InstallLayoutPaths.ArchivedLayoutEnvironmentVariable);
|
||||
environment.Set(InstallLayoutPaths.InstallRootEnvironmentVariable, installRoot);
|
||||
environment.Set(InstallLayoutPaths.ArchivedLayoutEnvironmentVariable, null);
|
||||
|
||||
Assert.AreEqual(installRoot, InstallLayoutPaths.ResolveInstallRoot(baseRoot));
|
||||
Assert.AreEqual(installRoot, InstallLayoutPaths.CandidateRoots(baseRoot).First());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ResolveInstallRootIgnoresLegacyArchivedLayoutForHealth()
|
||||
{
|
||||
using var workspace = TestWorkspace.Create("ymhut-archived-layout-tests");
|
||||
var archivedRoot = workspace.CreateDirectory("archived");
|
||||
var baseRoot = workspace.CreateDirectory("runtime");
|
||||
workspace.CreateFile(["runtime", "YMhutBox.exe"], string.Empty);
|
||||
|
||||
using var environment = EnvironmentScope.Capture(
|
||||
InstallLayoutPaths.InstallRootEnvironmentVariable,
|
||||
InstallLayoutPaths.ArchivedLayoutEnvironmentVariable);
|
||||
environment.Set(InstallLayoutPaths.InstallRootEnvironmentVariable, null);
|
||||
environment.Set(InstallLayoutPaths.ArchivedLayoutEnvironmentVariable, archivedRoot);
|
||||
|
||||
Assert.AreEqual(baseRoot, InstallLayoutPaths.ResolveInstallRoot(baseRoot));
|
||||
Assert.IsFalse(InstallLayoutPaths.CandidateRoots(baseRoot).Contains(archivedRoot));
|
||||
Assert.AreEqual(archivedRoot, InstallLayoutPaths.ResolveArchivedLayoutRoot());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ResolveAssetsRootAndExecutableUseInstallRoot()
|
||||
{
|
||||
using var workspace = TestWorkspace.Create("ymhut-install-assets-tests");
|
||||
var installRoot = workspace.CreateDirectory("install");
|
||||
var assetsRoot = workspace.CreateDirectory("install", "Assets");
|
||||
var executable = workspace.CreateFile(["install", "YMhutBox.exe"], string.Empty);
|
||||
var runtimeRoot = workspace.CreateDirectory("runtime");
|
||||
|
||||
using var environment = EnvironmentScope.Capture(
|
||||
InstallLayoutPaths.InstallRootEnvironmentVariable,
|
||||
InstallLayoutPaths.ArchivedLayoutEnvironmentVariable);
|
||||
environment.Set(InstallLayoutPaths.InstallRootEnvironmentVariable, installRoot);
|
||||
environment.Set(InstallLayoutPaths.ArchivedLayoutEnvironmentVariable, null);
|
||||
|
||||
Assert.AreEqual(assetsRoot, InstallLayoutPaths.ResolveAssetsRoot(runtimeRoot));
|
||||
Assert.AreEqual(executable, InstallLayoutPaths.ResolveInstalledExecutablePath(runtimeRoot));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RuntimeLayoutPolicySkipsLargeToolsAndUserDataRoots()
|
||||
{
|
||||
foreach (var relativePath in new[]
|
||||
{
|
||||
"Tools/vendor/tool.exe",
|
||||
"Metadata/tools.json",
|
||||
"data/settings.json",
|
||||
"FeedbackPackages/feedback.zip"
|
||||
})
|
||||
{
|
||||
Assert.IsTrue(RuntimeLayoutPolicy.ShouldSkipRelativePath(relativePath), relativePath);
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile(relativePath), relativePath);
|
||||
}
|
||||
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("unins000.exe"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("YMhutBox.exe"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("YMhutBox.dll"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("resources.pri"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("zh-CN/Microsoft.ui.xaml.dll.mui"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("lang/zh-CN/Microsoft.ui.xaml.dll.mui"));
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile("runtimes/win-x64/native/Microsoft.ui.xaml.dll"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InstallManifestParserReadsReleaseRequiredFilesAndPayloadFiles()
|
||||
{
|
||||
var manifest = InstallManifest.Parse(
|
||||
"""
|
||||
[Release]
|
||||
Version=2.0.6
|
||||
Build=2
|
||||
Channel=stable
|
||||
PackageVersion=2.0.6.2
|
||||
|
||||
[RequiredFiles]
|
||||
YMhutBox.exe
|
||||
YMhutBox.dll
|
||||
|
||||
[Files]
|
||||
YMhutBox.exe
|
||||
lang/zh-CN/Microsoft.ui.xaml.dll.mui
|
||||
Tools/SampleTool/tool.exe
|
||||
""");
|
||||
|
||||
Assert.IsNotNull(manifest.Release);
|
||||
Assert.AreEqual("2.0.6", manifest.Release.Version);
|
||||
Assert.AreEqual("2", manifest.Release.Build);
|
||||
Assert.AreEqual("stable", manifest.Release.Channel);
|
||||
Assert.AreEqual("2.0.6.2", manifest.Release.PackageVersion);
|
||||
Assert.IsTrue(manifest.RequiredFiles.SequenceEqual(["YMhutBox.exe", "YMhutBox.dll"]));
|
||||
Assert.IsTrue(manifest.ContainsFile(@"lang\zh-CN\Microsoft.ui.xaml.dll.mui"));
|
||||
Assert.IsTrue(manifest.ContainsFile("Tools/SampleTool/tool.exe"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RuntimeLayoutPolicySkipsRuntimePayloadRoots()
|
||||
{
|
||||
foreach (var relativePath in new[]
|
||||
{
|
||||
"lang/en-US/Microsoft.UI.Xaml.Phone.dll.mui",
|
||||
"Microsoft.UI.Xaml/Microsoft.UI.Xaml.dll",
|
||||
"runtimes/win-x64/native/WebView2Loader.dll",
|
||||
"worker/YMhut.Box.Worker.exe"
|
||||
})
|
||||
{
|
||||
Assert.IsFalse(RuntimeLayoutPolicy.ShouldCopyFile(relativePath), relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SourceFilesDoNotContainCommonMojibakeSequences()
|
||||
{
|
||||
var root = FindRepositoryRoot();
|
||||
var scanRoots = new[]
|
||||
{
|
||||
Path.Combine(root, "src", "YMhut.Box.Core"),
|
||||
Path.Combine(root, "src", "box-winUI"),
|
||||
Path.Combine(root, "installer")
|
||||
};
|
||||
var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".cs", ".xaml", ".iss" };
|
||||
var mojibakeMarkers = new[]
|
||||
{
|
||||
"Ã",
|
||||
"Â",
|
||||
"â",
|
||||
"鈥",
|
||||
"锛",
|
||||
"銆",
|
||||
"鐑",
|
||||
"澶",
|
||||
"璁",
|
||||
"鏍",
|
||||
"棰",
|
||||
"缃"
|
||||
};
|
||||
|
||||
var offenders = scanRoots
|
||||
.Where(Directory.Exists)
|
||||
.SelectMany(scanRoot => Directory.EnumerateFiles(scanRoot, "*.*", SearchOption.AllDirectories))
|
||||
.Where(path => extensions.Contains(Path.GetExtension(path)))
|
||||
.Where(path => !path.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase))
|
||||
.Where(path => !path.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(path => FindMojibakeMarkers(path, mojibakeMarkers))
|
||||
.Take(12)
|
||||
.ToArray();
|
||||
|
||||
Assert.IsEmpty(offenders, string.Join(Environment.NewLine, offenders));
|
||||
}
|
||||
|
||||
private static IEnumerable<string> FindMojibakeMarkers(string path, IReadOnlyList<string> markers)
|
||||
{
|
||||
var text = File.ReadAllText(path);
|
||||
foreach (var marker in markers)
|
||||
{
|
||||
if (text.Contains(marker, StringComparison.Ordinal))
|
||||
{
|
||||
yield return $"{Path.GetFileName(path)} contains '{marker}'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindRepositoryRoot()
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(directory.FullName, "src")) &&
|
||||
Directory.Exists(Path.Combine(directory.FullName, "installer")))
|
||||
{
|
||||
return directory.FullName;
|
||||
}
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
Assert.Fail("Repository root could not be found from test output directory.");
|
||||
return AppContext.BaseDirectory;
|
||||
}
|
||||
|
||||
private sealed class EnvironmentScope : IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string?> _snapshot;
|
||||
|
||||
private EnvironmentScope(IEnumerable<string> names)
|
||||
{
|
||||
_snapshot = names.ToDictionary(name => name, Environment.GetEnvironmentVariable, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
public static EnvironmentScope Capture(params string[] names) => new(names);
|
||||
|
||||
public void Set(string name, string? value) => Environment.SetEnvironmentVariable(name, value);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var item in _snapshot)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TestWorkspace : IDisposable
|
||||
{
|
||||
private TestWorkspace(string root)
|
||||
{
|
||||
Root = root;
|
||||
}
|
||||
|
||||
public string Root { get; }
|
||||
|
||||
public static TestWorkspace Create(string prefix)
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), prefix, Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(root);
|
||||
return new TestWorkspace(root);
|
||||
}
|
||||
|
||||
public string CreateDirectory(params string[] parts)
|
||||
{
|
||||
var directory = Path.Combine([Root, .. parts]);
|
||||
Directory.CreateDirectory(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
public string CreateFile(string[] parts, string contents)
|
||||
{
|
||||
var path = Path.Combine([Root, .. parts]);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||
File.WriteAllText(path, contents);
|
||||
return path;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(Root))
|
||||
{
|
||||
Directory.Delete(Root, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user