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(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 FindMojibakeMarkers(string path, IReadOnlyList 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 _snapshot; private EnvironmentScope(IEnumerable 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); } } } }