using LibationFileManager; using LibationUiBase.Forms; using Newtonsoft.Json.Linq; [assembly: DoNotParallelize] namespace LibationUiBase.Tests; [TestClass] public class LibationFilesTest { //Mock MessageBox results in setup workflow private Queue MessageBoxResults { get; } = new(); private Task ShowMessageBox( object? owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool _) => Task.FromResult(MessageBoxResults.Dequeue()); public LibationFilesTest() { MessageBoxBase.ShowAsyncImpl = ShowMessageBox; } [TestMethod] public async Task Setup_NoSelection() { var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: false, selectedDirectory: null); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task Setup_NoSelection_SettingsExistInDefaultLocation() { var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: false, selectedDirectory: null); File.WriteAllText(Path.Combine(LibationFiles.DefaultLibationFilesDirectory, LibationFiles.SETTINGS_JSON), new JObject { { "Books", "SomePath" } }.ToString()); Assert.IsTrue(await setup.RunSetupIfNeededAsync()); Assert.IsTrue(libationFiles.SettingsAreValid); } [TestMethod] public async Task NewInstall_BadLibationFilesPath_ChooseDefault_Yes() { var libationFiles = new LibationFiles(CreateAppSettings(BadPath)); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); //Error Creating LibationFiles. Move to default directory? MessageBoxResults.Enqueue(DialogResult.Yes); Assert.IsTrue(await setup.RunSetupIfNeededAsync()); Assert.IsTrue(libationFiles.SettingsAreValid); } private static string BadPath => Configuration.IsWindows ? "NONEXISTANT:\\" : "/NONEXISTANT"; [TestMethod] public async Task NewInstall_BadLibationFilesPath_ChooseDefault_Yes_Fail() { var libationFiles = new LibationFiles(CreateAppSettings(BadPath)); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); LibationFiles.s_DefaultLibationFilesDirectory = Path.Combine(BadPath, "AlsoInvalid"); //Error Creating LibationFiles. Move to default directory? MessageBoxResults.Enqueue(DialogResult.Yes); MessageBoxResults.Enqueue(DialogResult.OK); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task NewInstall_BadLibationFilesPath_ChooseDefault_No() { var libationFiles = new LibationFiles(CreateAppSettings(BadPath)); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); //Error Creating LibationFiles. Move to default directory? MessageBoxResults.Enqueue(DialogResult.No); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task NewInstall_ReadonlyDir_DefaultDir() { var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); MakeUnixReadOnly(Directory.CreateDirectory(libationFiles.Location)); //Dismiss error creating settings file MBox MessageBoxResults.Enqueue(DialogResult.OK); //Prevent installer from being able to create settings file using var fs = Configuration.IsWindows ? File.Open(libationFiles.SettingsFilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read) : default(IDisposable); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task NewInstall_ReadonlyDir_CustomDir_RevertToDefault_No() { var customDir = Path.GetFullPath("CustomDir"); if (Directory.Exists(customDir)) Directory.Delete(customDir, recursive: true); MakeUnixReadOnly(Directory.CreateDirectory(customDir)); var libationFiles = new LibationFiles(CreateAppSettings(customDir)); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); //Error Creating Settings.json. Move to default directory? MessageBoxResults.Enqueue(DialogResult.No); //Prevent installer from being able to create settings file in customDir using var fs = Configuration.IsWindows ? File.Open(Path.Combine(customDir, LibationFiles.SETTINGS_JSON), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read) : default(IDisposable); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task NewInstall_ReadonlyDir_CustomDir_RevertToDefault_Yes() { var customDir = Path.GetFullPath("CustomDir"); if (Directory.Exists(customDir)) Directory.Delete(customDir, recursive: true); Directory.CreateDirectory(customDir); var libationFiles = new LibationFiles(CreateAppSettings(customDir)); var setup = CreateMockSetup(libationFiles, isNewUser: true, isReturningUser: false, selectedDirectory: null); //Error Creating Settings.json. Move to default directory? MessageBoxResults.Enqueue(DialogResult.Yes); //Prevent installer from being able to create settings file in customDir using var fs = File.Open(Path.Combine(customDir, LibationFiles.SETTINGS_JSON), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read); Assert.IsTrue(await setup.RunSetupIfNeededAsync()); Assert.IsTrue(libationFiles.SettingsAreValid); } [TestMethod] [DataRow(null)] [DataRow("")] [DataRow(" ")] public async Task Returning_BadSelectedDir(string? selectedDir) { var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: true, selectedDir); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); Assert.IsFalse(libationFiles.SettingsAreValid); } [TestMethod] public async Task Returning_SettingsFound() { var customDir = Path.GetFullPath("CustomDir"); if (Directory.Exists(customDir)) Directory.Delete(customDir, recursive: true); Directory.CreateDirectory(customDir); var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: true, selectedDirectory: customDir); File.WriteAllText(Path.Combine(customDir, LibationFiles.SETTINGS_JSON), new JObject { { "Books", "SomePath" } }.ToString()); Assert.IsTrue(await setup.RunSetupIfNeededAsync()); Assert.IsTrue(libationFiles.SettingsAreValid); } [TestMethod] public async Task Returning_SettingsNotFound_CreateAt_Yes() { var customDir = Path.GetFullPath("CustomDir"); if (Directory.Exists(customDir)) Directory.Delete(customDir, recursive: true); Directory.CreateDirectory(customDir); var libationFiles = new LibationFiles(CreateAppSettings()); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: true, selectedDirectory: customDir); //No valid settings were found. Create New Install? MessageBoxResults.Enqueue(DialogResult.Yes); Assert.IsTrue(await setup.RunSetupIfNeededAsync()); Assert.IsTrue(libationFiles.SettingsAreValid); } [TestMethod] public async Task Returning_SettingsNotFound_CreateAt_No() { var customDir = Path.GetFullPath("CustomDir"); if (Directory.Exists(customDir)) Directory.Delete(customDir, recursive: true); Directory.CreateDirectory(customDir); var appSettingsFile = CreateAppSettings(); var libationFiles = new LibationFiles(appSettingsFile); var setup = CreateMockSetup(libationFiles, isNewUser: false, isReturningUser: true, selectedDirectory: customDir); //No valid settings were found. Create New Install? MessageBoxResults.Enqueue(DialogResult.No); Assert.IsFalse(await setup.RunSetupIfNeededAsync()); } private LibationSetup CreateMockSetup(LibationFiles libationFiles, bool isNewUser, bool isReturningUser, string? selectedDirectory) { Assert.IsTrue(File.Exists(libationFiles.AppsettingsJsonFile)); Assert.IsFalse(libationFiles.SettingsAreValid); return new LibationSetup(libationFiles) { SetupPrompt = () => new MockLibationSetup { IsNewUser = isNewUser, IsReturningUser = isReturningUser }, SelectFolderPrompt = () => new MockLibationInstallLocation { SelectedDirectory = selectedDirectory} }; } private static void MakeUnixReadOnly(FileSystemInfo di) { #pragma warning disable CA1416 // Validate platform compatibility if (!Configuration.IsWindows) di.UnixFileMode &= ~(UnixFileMode.UserWrite | UnixFileMode.GroupWrite | UnixFileMode.OtherWrite); #pragma warning restore CA1416 } private class MockLibationSetup : ILibationSetup { public bool IsNewUser { get; set; } public bool IsReturningUser { get; set; } } private class MockLibationInstallLocation : ILibationInstallLocation { public string? SelectedDirectory { get; set; } } private static string CreateAppSettings(string? libationFiles = null) { var file = Path.GetFullPath($"appsettings.test.json"); var libationFilesDir = Path.Combine(Environment.CurrentDirectory, "LibationFilesTest"); if (Directory.Exists(libationFilesDir)) Directory.Delete(libationFilesDir, recursive: true); Directory.CreateDirectory(libationFilesDir); LibationFiles.s_DefaultLibationFilesDirectory = libationFilesDir; if (File.Exists(file)) File.Delete(file); File.WriteAllText(file, new JObject { { LibationFiles.LIBATION_FILES_KEY, libationFiles ?? libationFilesDir } }.ToString()); return file; } }