using MaksIT.UScheduler.Shared; using MaksIT.UScheduler.Shared.Helpers; namespace MaksIT.UScheduler.Tests; public class ConfigurationFileServiceTests { [Fact] public void Default_path_is_shared_programdata() { var service = new ConfigurationFileService(); Assert.Equal(UserSettingsPath.GetShared(ConfigurationFileService.ProductFolder), service.FilePath); } [Fact] public void Save_to_new_file_writes_only_configuration() { var path = Path.Combine(Path.GetTempPath(), $"uscheduler-{Guid.NewGuid():N}.json"); try { var service = new ConfigurationFileService(path); service.Save(new Configuration { LogDir = @"C:\MaksIT\Logs", ScriptsDir = @"C:\MaksIT\Scripts" }); var json = File.ReadAllText(path); Assert.Contains("\"Configuration\"", json, StringComparison.Ordinal); Assert.DoesNotContain("\"Logging\"", json, StringComparison.Ordinal); Assert.Contains("C:\\\\MaksIT\\\\Logs", json, StringComparison.Ordinal); var reloaded = new ConfigurationFileService(path); Assert.Equal(@"C:\MaksIT\Logs", reloaded.Current.LogDir); Assert.Equal(@"C:\MaksIT\Scripts", reloaded.Current.ScriptsDir); } finally { if (File.Exists(path)) File.Delete(path); } } [Fact] public void Copies_seed_configuration_without_logging() { var dir = Path.Combine(Path.GetTempPath(), $"uscheduler-{Guid.NewGuid():N}"); Directory.CreateDirectory(dir); var seed = Path.Combine(dir, "appsettings.json"); var user = Path.Combine(dir, "settings.json"); File.WriteAllText(seed, """ { "Logging": { "LogLevel": { "Default": "Information" } }, "Configuration": { "LogDir": "C:\\MaksIT\\Logs", "ScriptsDir": "C:\\MaksIT\\Scripts", "Powershell": [ { "Path": "File-Sync\\file-sync.ps1", "Disabled": true } ] } } """); try { var service = new ConfigurationFileService(user, seed); Assert.True(File.Exists(user)); Assert.Equal(@"C:\MaksIT\Logs", service.Current.LogDir); Assert.Single(service.Current.Powershell); var json = File.ReadAllText(user); Assert.Contains("\"Configuration\"", json, StringComparison.Ordinal); Assert.DoesNotContain("\"Logging\"", json, StringComparison.Ordinal); } finally { Directory.Delete(dir, true); } } [Fact] public void Logging_only_seed_does_not_create_user_file() { var dir = Path.Combine(Path.GetTempPath(), $"uscheduler-{Guid.NewGuid():N}"); Directory.CreateDirectory(dir); var seed = Path.Combine(dir, "appsettings.json"); var user = Path.Combine(dir, "settings.json"); File.WriteAllText(seed, """ { "Logging": { "LogLevel": { "Default": "Information" } } } """); try { var service = new ConfigurationFileService(user, seed); Assert.False(File.Exists(user)); Assert.Equal(HostPaths.DefaultLogDirectory, service.Current.LogDir); } finally { Directory.Delete(dir, true); } } [Fact] public void Save_round_trips_powershell_entries() { var path = Path.Combine(Path.GetTempPath(), $"uscheduler-{Guid.NewGuid():N}.json"); try { var service = new ConfigurationFileService(path); service.Save(new Configuration { Powershell = [ new PowershellScript { Path = @"File-Sync\file-sync.ps1", Name = "File Sync", Disabled = true, IsSigned = false } ] }); var reloaded = new ConfigurationFileService(path); Assert.Single(reloaded.Current.Powershell); Assert.Equal(@"File-Sync\file-sync.ps1", reloaded.Current.Powershell[0].Path); Assert.True(reloaded.Current.Powershell[0].Disabled); Assert.False(reloaded.Current.Powershell[0].IsSigned); } finally { if (File.Exists(path)) File.Delete(path); } } } public class HostPathsTests { [Fact] public void Windows_defaults_use_maksit_data_root() { if (!OperatingSystem.IsWindows()) return; Assert.Equal(@"C:\MaksIT\Scripts", HostPaths.DefaultScriptsDirectory); Assert.Equal(@"C:\MaksIT\Logs", HostPaths.DefaultLogDirectory); Assert.Equal(@"C:\MaksIT", HostPaths.DefaultDataRoot); Assert.EndsWith( Path.Combine("MaksIT", "UScheduler"), HostPaths.DefaultInstallDirectory, StringComparison.OrdinalIgnoreCase); Assert.Equal( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "MaksIT", "UScheduler"), HostPaths.DefaultInstallDirectory); } [Fact] public void DetectServiceBinPath_finds_worker_next_to_ui() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-detect-{Guid.NewGuid():N}"); Directory.CreateDirectory(root); var exeName = HostServiceManager.GetExecutableFileName(); File.WriteAllBytes(Path.Combine(root, exeName), [0]); try { Assert.Equal(Path.GetFullPath(root), HostPaths.FindWorkerDirectory(root)); } finally { Directory.Delete(root, true); } } [Fact] public void Shared_settings_are_under_programdata() { if (!OperatingSystem.IsWindows()) return; var path = UserSettingsPath.GetShared("UScheduler"); Assert.Contains("MaksIT", path, StringComparison.OrdinalIgnoreCase); Assert.Contains("UScheduler", path, StringComparison.OrdinalIgnoreCase); Assert.EndsWith("settings.json", path, StringComparison.OrdinalIgnoreCase); Assert.Equal( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MaksIT", "UScheduler", "settings.json"), path); } [Fact] public void Per_user_settings_are_under_appdata() { var path = UserSettingsPath.Get("UScheduler"); Assert.Equal( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MaksIT", "UScheduler", "settings.json"), path); } [Fact] public void FindPortableRoot_returns_null_without_marker() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-no-portable-{Guid.NewGuid():N}"); Directory.CreateDirectory(root); try { Assert.Null(HostPaths.FindPortableRoot(root)); Assert.False(HostPaths.IsPortableLayout(root)); } finally { Directory.Delete(root, true); } } [Fact] public void FindPortableRoot_finds_marker_in_start_directory() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-portable-{Guid.NewGuid():N}"); Directory.CreateDirectory(root); File.WriteAllText(Path.Combine(root, HostPaths.PortableMarkerFileName), HostPaths.PortableMarkerContent); try { Assert.Equal(Path.GetFullPath(root), HostPaths.FindPortableRoot(root)); Assert.True(HostPaths.IsPortableLayout(root)); Assert.Equal( Path.GetFullPath(Path.Combine(root, "Data", "settings.json")), Path.GetFullPath(HostPaths.ResolveSharedSettingsFile(root))); Assert.Equal( Path.GetFullPath(Path.Combine(root, "Data", "ui-settings.json")), Path.GetFullPath(HostPaths.ResolveUiSettingsFile(root))); } finally { Directory.Delete(root, true); } } [Fact] public void FindPortableRoot_walks_up_to_parent_marker() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-portable-parent-{Guid.NewGuid():N}"); var worker = Path.Combine(root, "MaksIT.UScheduler"); Directory.CreateDirectory(worker); File.WriteAllText(Path.Combine(root, HostPaths.PortableMarkerFileName), HostPaths.PortableMarkerContent); try { Assert.Equal(Path.GetFullPath(root), HostPaths.FindPortableRoot(worker)); } finally { Directory.Delete(root, true); } } [Fact] public void ApplyPortableDefaults_replaces_machine_wide_paths() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-portable-defaults-{Guid.NewGuid():N}"); Directory.CreateDirectory(root); File.WriteAllText(Path.Combine(root, HostPaths.PortableMarkerFileName), HostPaths.PortableMarkerContent); try { var config = new Configuration { LogDir = HostPaths.DefaultLogDirectory, ScriptsDir = HostPaths.DefaultScriptsDirectory }; HostPaths.ApplyPortableDefaults(config, root); Assert.Equal(Path.GetFullPath(Path.Combine(root, "Logs")), Path.GetFullPath(config.LogDir)); Assert.Equal(Path.GetFullPath(Path.Combine(root, "Scripts")), Path.GetFullPath(config.ScriptsDir)); } finally { Directory.Delete(root, true); } } [Fact] public void Copies_seed_into_portable_data_folder_with_local_paths() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-portable-seed-{Guid.NewGuid():N}"); var data = Path.Combine(root, "Data"); Directory.CreateDirectory(data); File.WriteAllText(Path.Combine(root, HostPaths.PortableMarkerFileName), HostPaths.PortableMarkerContent); var seed = Path.Combine(root, "appsettings.json"); var user = Path.Combine(data, "settings.json"); var defaultLog = HostPaths.DefaultLogDirectory.Replace("\\", "\\\\", StringComparison.Ordinal); var defaultScripts = HostPaths.DefaultScriptsDirectory.Replace("\\", "\\\\", StringComparison.Ordinal); File.WriteAllText(seed, $$""" { "Logging": { "LogLevel": { "Default": "Information" } }, "Configuration": { "LogDir": "{{defaultLog}}", "ScriptsDir": "{{defaultScripts}}", "Powershell": [ { "Path": "File-Sync\\file-sync.ps1", "Disabled": true } ] } } """); try { var service = new ConfigurationFileService(user, seed); Assert.True(File.Exists(user)); Assert.Equal(Path.GetFullPath(Path.Combine(root, "Logs")), Path.GetFullPath(service.Current.LogDir)); Assert.Equal(Path.GetFullPath(Path.Combine(root, "Scripts")), Path.GetFullPath(service.Current.ScriptsDir)); Assert.Single(service.Current.Powershell); } finally { Directory.Delete(root, true); } } [Fact] public void FindBundledScriptsDirectory_finds_scripts_next_to_start() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-bundled-{Guid.NewGuid():N}"); var start = Path.Combine(root, "install"); var scripts = Path.Combine(start, "Scripts"); Directory.CreateDirectory(Path.Combine(scripts, "Native-Sync")); File.WriteAllText(Path.Combine(scripts, "Native-Sync", "native-sync.ps1"), "seed"); try { var found = HostPaths.FindBundledScriptsDirectory(start); Assert.Equal(Path.GetFullPath(scripts), found is null ? null : Path.GetFullPath(found)); } finally { Directory.Delete(root, true); } } [Fact] public void FindBundledScriptsDirectory_finds_sibling_scripts_folder() { var root = Path.Combine(Path.GetTempPath(), $"uscheduler-sibling-{Guid.NewGuid():N}"); var start = Path.Combine(root, "MaksIT.UScheduler"); var scripts = Path.Combine(root, "Scripts"); Directory.CreateDirectory(start); Directory.CreateDirectory(Path.Combine(scripts, "File-Sync")); try { var found = HostPaths.FindBundledScriptsDirectory(start); Assert.Equal(Path.GetFullPath(scripts), found is null ? null : Path.GetFullPath(found)); } finally { Directory.Delete(root, true); } } [Fact] public void ResolveScriptPath_uses_scripts_dir() { var dir = Path.Combine(Path.GetTempPath(), $"uscheduler-scripts-{Guid.NewGuid():N}"); Directory.CreateDirectory(dir); try { var config = new Configuration { ScriptsDir = dir }; var resolved = config.ResolveScriptPath(Path.Combine("File-Sync", "file-sync.ps1")); Assert.Equal(Path.GetFullPath(Path.Combine(dir, "File-Sync", "file-sync.ps1")), resolved); } finally { Directory.Delete(dir, true); } } }