using Cleanuparr.Persistence.Models.Configuration.DownloadCleaner; using Shouldly; using Xunit; using ValidationException = Cleanuparr.Domain.Exceptions.ValidationException; namespace Cleanuparr.Persistence.Tests.Models.Configuration.DownloadCleaner; public sealed class UnlinkedConfigTests { [Fact] public void Defaults_EnabledIsFalse() { var config = new UnlinkedConfig(); config.Enabled.ShouldBeFalse(); } [Fact] public void Defaults_TargetCategoryIsSet() { var config = new UnlinkedConfig(); config.TargetCategory.ShouldBe("cleanuparr-unlinked"); } [Fact] public void Defaults_CategoriesIsEmpty() { var config = new UnlinkedConfig(); config.Categories.ShouldBeEmpty(); } [Fact] public void Validate_WhenDisabled_DoesNotThrow() { var config = new UnlinkedConfig { Enabled = false, TargetCategory = "", Categories = [] }; Should.NotThrow(() => config.Validate()); } [Fact] public void Validate_WhenEnabled_WithValidConfig_DoesNotThrow() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies", "tv"] }; Should.NotThrow(() => config.Validate()); } [Fact] public void Validate_WhenEnabled_WithEmptyTargetCategory_ThrowsValidationException() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "", Categories = ["movies"] }; var exception = Should.Throw(() => config.Validate()); exception.Message.ShouldBe("Unlinked target category is required"); } [Fact] public void Validate_WhenEnabled_WithEmptyCategories_ThrowsValidationException() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = [] }; var exception = Should.Throw(() => config.Validate()); exception.Message.ShouldBe("No unlinked categories configured"); } [Fact] public void Validate_WhenEnabled_WithTargetCategoryInCategories_ThrowsValidationException() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies", "cleanuparr-unlinked"] }; var exception = Should.Throw(() => config.Validate()); exception.Message.ShouldBe("The unlinked target category should not be present in unlinked categories"); } [Fact] public void Validate_WhenEnabled_WithEmptyCategoryEntry_ThrowsValidationException() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies", ""] }; var exception = Should.Throw(() => config.Validate()); exception.Message.ShouldBe("Empty unlinked category filter found"); } [Fact] public void Validate_WhenEnabled_WithNonExistentIgnoredRootDir_ThrowsValidationException() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies"], IgnoredRootDirs = ["/non/existent/path/that/should/not/exist"] }; var exception = Should.Throw(() => config.Validate()); exception.Message.ShouldContain("root directory does not exist"); } [Fact] public void Validate_WhenEnabled_WithEmptyIgnoredRootDirs_DoesNotThrow() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies"], IgnoredRootDirs = [] }; Should.NotThrow(() => config.Validate()); } [Fact] public void Validate_WhenEnabled_SkipsEmptyStringInIgnoredRootDirs() { var config = new UnlinkedConfig { Enabled = true, TargetCategory = "cleanuparr-unlinked", Categories = ["movies"], IgnoredRootDirs = [""] }; Should.NotThrow(() => config.Validate()); } }