diff --git a/AppScaffolding/AppScaffolding.csproj b/AppScaffolding/AppScaffolding.csproj index cfabee5d..de7e2cc7 100644 --- a/AppScaffolding/AppScaffolding.csproj +++ b/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net5.0 - 6.3.4.19 + 6.4.0.1 diff --git a/FileLiberator/AudioFileStorageExt.cs b/FileLiberator/AudioFileStorageExt.cs index ed6b7d0f..a58bf648 100644 --- a/FileLiberator/AudioFileStorageExt.cs +++ b/FileLiberator/AudioFileStorageExt.cs @@ -11,42 +11,18 @@ namespace FileLiberator { public static class AudioFileStorageExt { - public class MultipartRenamer + private class MultipartRenamer { - private LibraryBookDto libraryBookDto { get; } + private LibraryBook libraryBook { get; } - public MultipartRenamer(LibraryBook libraryBook) : this(libraryBook.ToDto()) { } - public MultipartRenamer(LibraryBookDto libraryBookDto) => this.libraryBookDto = libraryBookDto; + internal MultipartRenamer(LibraryBook libraryBook) => this.libraryBook = libraryBook; internal string MultipartFilename(AaxDecrypter.MultiConvertFileProperties props) - => MultipartFilename(props, Configuration.Instance.ChapterFileTemplate, AudibleFileStorage.DecryptInProgressDirectory); - - public string MultipartFilename(AaxDecrypter.MultiConvertFileProperties props, string template, string fullDirPath) - { - var fileNamingTemplate = GetFileNamingTemplate(template, libraryBookDto, fullDirPath, Path.GetExtension(props.OutputFileName)); - - fileNamingTemplate.AddParameterReplacement(TemplateTags.ChCount, props.PartsTotal); - fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber, props.PartsPosition); - fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber0, FileUtility.GetSequenceFormatted(props.PartsPosition, props.PartsTotal)); - fileNamingTemplate.AddParameterReplacement(TemplateTags.ChTitle, props.Title ?? ""); - - return fileNamingTemplate.GetFilePath(); - } + => Templates.ChapterFile.GetFilename(libraryBook.ToDto(), props); } public static Func CreateMultipartRenamerFunc(this AudioFileStorage _, LibraryBook libraryBook) => new MultipartRenamer(libraryBook).MultipartFilename; - public static Func CreateMultipartRenamerFunc(this AudioFileStorage _, LibraryBookDto libraryBookDto) - => new MultipartRenamer(libraryBookDto).MultipartFilename; - - /// - /// DownloadDecryptBook: - /// Path: in progress directory. - /// File name: final file name. - /// - public static string GetInProgressFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension) - => GetFileNamingTemplate(Configuration.Instance.FileTemplate, libraryBook.ToDto(), AudibleFileStorage.DecryptInProgressDirectory, extension) - .GetFilePath(); /// /// DownloadDecryptBook: @@ -55,50 +31,26 @@ namespace FileLiberator /// File name: n/a /// public static string GetDestinationDirectory(this AudioFileStorage _, LibraryBook libraryBook) - => GetFileNamingTemplate(Configuration.Instance.FolderTemplate, libraryBook.ToDto(), AudibleFileStorage.BooksDirectory, null) - .GetFilePath(); + => Templates.Folder.GetFilename(libraryBook.ToDto()); + + /// + /// DownloadDecryptBook: + /// Path: in progress directory. + /// File name: final file name. + /// + public static string GetInProgressFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension) + => Templates.File.GetFilename(libraryBook.ToDto(), AudibleFileStorage.DecryptInProgressDirectory, extension); /// /// PDF: audio file does not exist /// public static string GetBooksDirectoryFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension) - => GetFileNamingTemplate(Configuration.Instance.FileTemplate, libraryBook.ToDto(), AudibleFileStorage.BooksDirectory, extension) - .GetFilePath(); + => Templates.File.GetFilename(libraryBook.ToDto(), AudibleFileStorage.BooksDirectory, extension); /// /// PDF: audio file already exists /// public static string GetCustomDirFilename(this AudioFileStorage _, LibraryBook libraryBook, string dirFullPath, string extension) - => GetFileNamingTemplate(Configuration.Instance.FileTemplate, libraryBook.ToDto(), dirFullPath, extension) - .GetFilePath(); - - public static FileNamingTemplate GetFileNamingTemplate(string template, LibraryBookDto libraryBookDto, string dirFullPath, string extension) - { - ArgumentValidator.EnsureNotNullOrWhiteSpace(template, nameof(template)); - ArgumentValidator.EnsureNotNull(libraryBookDto, nameof(libraryBookDto)); - - dirFullPath = dirFullPath?.Trim() ?? ""; - var t = template + FileUtility.GetStandardizedExtension(extension); - var fullfilename = dirFullPath == "" ? t : Path.Combine(dirFullPath, t); - - var fileNamingTemplate = new FileNamingTemplate(fullfilename) { IllegalCharacterReplacements = "_" }; - - var title = libraryBookDto.Title ?? ""; - var titleShort = title.IndexOf(':') < 1 ? title : title.Substring(0, title.IndexOf(':')); - - fileNamingTemplate.AddParameterReplacement(TemplateTags.Id, libraryBookDto.AudibleProductId); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Title, title); - fileNamingTemplate.AddParameterReplacement(TemplateTags.TitleShort, titleShort); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Author, libraryBookDto.AuthorNames); - fileNamingTemplate.AddParameterReplacement(TemplateTags.FirstAuthor, libraryBookDto.FirstAuthor); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Narrator, libraryBookDto.NarratorNames); - fileNamingTemplate.AddParameterReplacement(TemplateTags.FirstNarrator, libraryBookDto.FirstNarrator); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Series, libraryBookDto.SeriesName); - fileNamingTemplate.AddParameterReplacement(TemplateTags.SeriesNumber, libraryBookDto.SeriesNumber); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Account, libraryBookDto.Account); - fileNamingTemplate.AddParameterReplacement(TemplateTags.Locale, libraryBookDto.Locale); - - return fileNamingTemplate; - } + => Templates.File.GetFilename(libraryBook.ToDto(), dirFullPath, extension); } } diff --git a/LibationFileManager/LibationFileManager.csproj b/LibationFileManager/LibationFileManager.csproj index d6498bc0..96d707af 100644 --- a/LibationFileManager/LibationFileManager.csproj +++ b/LibationFileManager/LibationFileManager.csproj @@ -9,6 +9,7 @@ + diff --git a/LibationFileManager/TemplateTags.cs b/LibationFileManager/TemplateTags.cs index c9dfdda8..c3476fe7 100644 --- a/LibationFileManager/TemplateTags.cs +++ b/LibationFileManager/TemplateTags.cs @@ -18,7 +18,7 @@ namespace LibationFileManager IsChapterOnly = isChapterOnly; } - // putting these first is the incredibly lazy way to make them show up first in the settings dialog + // putting these first is the incredibly lazy way to make them show up first in the EditTemplateDialog public static TemplateTags ChCount { get; } = new TemplateTags("ch count", "Number of chapters", true); public static TemplateTags ChTitle { get; } = new TemplateTags("ch title", "Chapter title", true); public static TemplateTags ChNumber { get; } = new TemplateTags("ch#", "Chapter number", true); diff --git a/LibationFileManager/Templates.cs b/LibationFileManager/Templates.cs index ff3d2b61..7478c76e 100644 --- a/LibationFileManager/Templates.cs +++ b/LibationFileManager/Templates.cs @@ -1,4 +1,6 @@ -using System; +using Dinah.Core; +using FileManager; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -18,74 +20,30 @@ namespace LibationFileManager public const string WARNING_HAS_CHAPTER_TAGS = "Chapter tags should only be used in the template used for naming files which are split by chapter. Eg: "; public const string WARNING_NO_CHAPTER_NUMBER_TAG = "Should include chapter number tag in template used for naming files which are split by chapter. Ie: or "; - public static Templates Folder { get; } = new FolderTemplate(); - public static Templates File { get; } = new FileTemplate(); - public static Templates ChapterFile { get; } = new ChapterFileTemplate(); + public static FolderTemplate Folder { get; } = new FolderTemplate(); + public static FileTemplate File { get; } = new FileTemplate(); + public static ChapterFileTemplate ChapterFile { get; } = new ChapterFileTemplate(); public abstract string Name { get; } public abstract string Description { get; } public abstract string DefaultTemplate { get; } protected abstract bool IsChapterized { get; } - internal string GetValid(string configValue) + protected Templates() { } + + #region validation + internal string GetValid(string configValue) { var value = configValue?.Trim(); return IsValid(value) ? value : DefaultTemplate; } - public static string Sanitize(string template) - { - var value = template ?? ""; - - // don't use alt slash - value = value.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - - // don't allow double slashes - var sing = $"{Path.DirectorySeparatorChar}"; - var dbl = $"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}"; - while (value.Contains(dbl)) - value = value.Replace(dbl, sing); - - // trim. don't start or end with slash - while (true) - { - var start = value.Length; - value = value - .Trim() - .Trim(Path.DirectorySeparatorChar); - var end = value.Length; - if (start == end) - break; - } - - return value; - } - public abstract IEnumerable GetErrors(string template); public bool IsValid(string template) => !GetErrors(template).Any(); public abstract IEnumerable GetWarnings(string template); public bool HasWarnings(string template) => GetWarnings(template).Any(); - public IEnumerable GetTemplateTags() - => TemplateTags.GetAll() - // yeah, this line is a little funky but it works when you think through it. also: trust the unit tests - .Where(t => IsChapterized || !t.IsChapterOnly); - - public int TagCount(string template) - => GetTemplateTags() - // for == 1, use: - // .Count(t => template.Contains($"<{t.TagName}>")) - // .Sum() impl: == 2 - .Sum(t => template.Split($"<{t.TagName}>").Length - 1); - - public static bool ContainsChapterOnlyTags(string template) - => TemplateTags.GetAll() - .Where(t => t.IsChapterOnly) - .Any(t => ContainsTag(template, t.TagName)); - - public static bool ContainsTag(string template, string tag) => template.Contains($"<{tag}>"); - protected static string[] GetFileErrors(string template) { // File name only; not path. all other path chars are valid enough to pass this check and will be handled on final save. @@ -123,13 +81,102 @@ namespace LibationFileManager return warnings; } - private class FolderTemplate : Templates + internal int TagCount(string template) + => GetTemplateTags() + // for == 1, use: + // .Count(t => template.Contains($"<{t.TagName}>")) + // .Sum() impl: == 2 + .Sum(t => template.Split($"<{t.TagName}>").Length - 1); + + internal static bool ContainsChapterOnlyTags(string template) + => TemplateTags.GetAll() + .Where(t => t.IsChapterOnly) + .Any(t => ContainsTag(template, t.TagName)); + + internal static bool ContainsTag(string template, string tag) => template.Contains($"<{tag}>"); + #endregion + + #region to file name + /// + /// EditTemplateDialog: Get template generated filename for portion of path + /// + public string GetPortionFilename(LibraryBookDto libraryBookDto, string template) + => getFileNamingTemplate(libraryBookDto, template, null, null) + .GetFilePath(); + + internal static FileNamingTemplate getFileNamingTemplate(LibraryBookDto libraryBookDto, string template, string dirFullPath, string extension) + { + ArgumentValidator.EnsureNotNullOrWhiteSpace(template, nameof(template)); + ArgumentValidator.EnsureNotNull(libraryBookDto, nameof(libraryBookDto)); + + dirFullPath = dirFullPath?.Trim() ?? ""; + var t = template + FileUtility.GetStandardizedExtension(extension); + var fullfilename = dirFullPath == "" ? t : Path.Combine(dirFullPath, t); + + var fileNamingTemplate = new FileNamingTemplate(fullfilename) { IllegalCharacterReplacements = "_" }; + + var title = libraryBookDto.Title ?? ""; + var titleShort = title.IndexOf(':') < 1 ? title : title.Substring(0, title.IndexOf(':')); + + fileNamingTemplate.AddParameterReplacement(TemplateTags.Id, libraryBookDto.AudibleProductId); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Title, title); + fileNamingTemplate.AddParameterReplacement(TemplateTags.TitleShort, titleShort); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Author, libraryBookDto.AuthorNames); + fileNamingTemplate.AddParameterReplacement(TemplateTags.FirstAuthor, libraryBookDto.FirstAuthor); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Narrator, libraryBookDto.NarratorNames); + fileNamingTemplate.AddParameterReplacement(TemplateTags.FirstNarrator, libraryBookDto.FirstNarrator); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Series, libraryBookDto.SeriesName); + fileNamingTemplate.AddParameterReplacement(TemplateTags.SeriesNumber, libraryBookDto.SeriesNumber); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Account, libraryBookDto.Account); + fileNamingTemplate.AddParameterReplacement(TemplateTags.Locale, libraryBookDto.Locale); + + return fileNamingTemplate; + } + #endregion + + public IEnumerable GetTemplateTags() + => TemplateTags.GetAll() + // yeah, this line is a little funky but it works when you think through it. also: trust the unit tests + .Where(t => IsChapterized || !t.IsChapterOnly); + + public string Sanitize(string template) + { + var value = template ?? ""; + + // don't use alt slash + value = value.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + + // don't allow double slashes + var sing = $"{Path.DirectorySeparatorChar}"; + var dbl = $"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}"; + while (value.Contains(dbl)) + value = value.Replace(dbl, sing); + + // trim. don't start or end with slash + while (true) + { + var start = value.Length; + value = value + .Trim() + .Trim(Path.DirectorySeparatorChar); + var end = value.Length; + if (start == end) + break; + } + + return value; + } + + public class FolderTemplate : Templates { public override string Name => "Folder Template"; public override string Description => Configuration.GetDescription(nameof(Configuration.FolderTemplate)); public override string DefaultTemplate { get; } = " [<id>]"; protected override bool IsChapterized { get; } = false; + internal FolderTemplate() : base() { } + + #region validation public override IEnumerable<string> GetErrors(string template) { // null is invalid. whitespace is valid but not recommended @@ -144,27 +191,49 @@ namespace LibationFileManager } public override IEnumerable<string> GetWarnings(string template) => GetStandardWarnings(template); + #endregion + + #region to file name + /// <summary>USES LIVE CONFIGURATION VALUES</summary> + public string GetFilename(LibraryBookDto libraryBookDto) + => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FolderTemplate, AudibleFileStorage.BooksDirectory, null) + .GetFilePath(); + #endregion } - private class FileTemplate : Templates + public class FileTemplate : Templates { public override string Name => "File Template"; public override string Description => Configuration.GetDescription(nameof(Configuration.FileTemplate)); public override string DefaultTemplate { get; } = "<title> [<id>]"; protected override bool IsChapterized { get; } = false; + internal FileTemplate() : base() { } + + #region validation public override IEnumerable<string> GetErrors(string template) => GetFileErrors(template); public override IEnumerable<string> GetWarnings(string template) => GetStandardWarnings(template); + #endregion + + #region to file name + /// <summary>USES LIVE CONFIGURATION VALUES</summary> + public string GetFilename(LibraryBookDto libraryBookDto, string dirFullPath, string extension) + => getFileNamingTemplate(libraryBookDto, Configuration.Instance.FileTemplate, dirFullPath, extension) + .GetFilePath(); + #endregion } - private class ChapterFileTemplate : Templates + public class ChapterFileTemplate : Templates { public override string Name => "Chapter File Template"; public override string Description => Configuration.GetDescription(nameof(Configuration.ChapterFileTemplate)); public override string DefaultTemplate { get; } = "<title> [<id>] - <ch# 0> - <ch title>"; protected override bool IsChapterized { get; } = true; + internal ChapterFileTemplate() : base() { } + + #region validation public override IEnumerable<string> GetErrors(string template) => GetFileErrors(template); public override IEnumerable<string> GetWarnings(string template) @@ -178,7 +247,26 @@ namespace LibationFileManager warnings.Add(WARNING_NO_CHAPTER_NUMBER_TAG); return warnings; - } + } + #endregion + + #region to file name + /// <summary>USES LIVE CONFIGURATION VALUES</summary> + public string GetFilename(LibraryBookDto libraryBookDto, AaxDecrypter.MultiConvertFileProperties props) + => GetPortionFilename(libraryBookDto, Configuration.Instance.ChapterFileTemplate, props, AudibleFileStorage.DecryptInProgressDirectory); + + public string GetPortionFilename(LibraryBookDto libraryBookDto, string template, AaxDecrypter.MultiConvertFileProperties props, string fullDirPath) + { + var fileNamingTemplate = getFileNamingTemplate(libraryBookDto, template, fullDirPath, Path.GetExtension(props.OutputFileName)); + + fileNamingTemplate.AddParameterReplacement(TemplateTags.ChCount, props.PartsTotal); + fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber, props.PartsPosition); + fileNamingTemplate.AddParameterReplacement(TemplateTags.ChNumber0, FileUtility.GetSequenceFormatted(props.PartsPosition, props.PartsTotal)); + fileNamingTemplate.AddParameterReplacement(TemplateTags.ChTitle, props.Title ?? ""); + + return fileNamingTemplate.GetFilePath(); + } + #endregion } } } diff --git a/LibationWinForms/Dialogs/EditTemplateDialog.cs b/LibationWinForms/Dialogs/EditTemplateDialog.cs index b1e339ca..a14066ba 100644 --- a/LibationWinForms/Dialogs/EditTemplateDialog.cs +++ b/LibationWinForms/Dialogs/EditTemplateDialog.cs @@ -10,15 +10,15 @@ namespace LibationWinForms.Dialogs { public partial class EditTemplateDialog : Form { - // final valid value + // final value. post-validity check public string TemplateText { get; private set; } - // work-in-progress. not guaranteed to be valid + // hold the work-in-progress value. not guaranteed to be valid private string _workingTemplateText; private string workingTemplateText { get => _workingTemplateText; - set => _workingTemplateText = Templates.Sanitize(value); + set => _workingTemplateText = template.Sanitize(value); } private void resetTextBox(string value) => this.templateTb.Text = workingTemplateText = value; @@ -82,24 +82,19 @@ namespace LibationWinForms.Dialogs var chaptersTotal = 10; var books = config.Books; - var folder = FileLiberator.AudioFileStorageExt.GetFileNamingTemplate( - isFolder ? workingTemplateText : config.FolderTemplate, + var folder = Templates.Folder.GetPortionFilename( libraryBookDto, - null, - null) - .GetFilePath(); + isFolder ? workingTemplateText : config.FolderTemplate); var file - = (template == Templates.ChapterFile) - ? new FileLiberator.AudioFileStorageExt.MultipartRenamer(libraryBookDto).MultipartFilename( - new() { OutputFileName = "", PartsPosition = chapterNumber, PartsTotal = chaptersTotal, Title = chapterName }, - workingTemplateText, - "") - : FileLiberator.AudioFileStorageExt.GetFileNamingTemplate( - isFolder ? config.FileTemplate : workingTemplateText, + = template == Templates.ChapterFile + ? Templates.ChapterFile.GetPortionFilename( libraryBookDto, - null, - null) - .GetFilePath(); + workingTemplateText, + new() { OutputFileName = "", PartsPosition = chapterNumber, PartsTotal = chaptersTotal, Title = chapterName }, + "") + : Templates.File.GetPortionFilename( + libraryBookDto, + isFolder ? config.FileTemplate : workingTemplateText); var ext = config.DecryptToLossy ? "mp3" : "m4b"; const char ZERO_WIDTH_SPACE = '\u200B'; diff --git a/LibationWinForms/Dialogs/SettingsDialog.cs b/LibationWinForms/Dialogs/SettingsDialog.cs index 1774af5c..18d3ef52 100644 --- a/LibationWinForms/Dialogs/SettingsDialog.cs +++ b/LibationWinForms/Dialogs/SettingsDialog.cs @@ -108,19 +108,11 @@ namespace LibationWinForms.Dialogs private void chapterFileTemplateBtn_Click(object sender, EventArgs e) => editTemplate(Templates.ChapterFile, chapterFileTemplateTb); private static void editTemplate(Templates template, TextBox textBox) { -#if !DEBUG - TEMP_TEMP_TEMP(); - return; -#endif - var form = new EditTemplateDialog(template, textBox.Text); if (form.ShowDialog() == DialogResult.OK) textBox.Text = form.TemplateText; } - private static void TEMP_TEMP_TEMP() - => MessageBox.Show("Sorry, not yet. Coming soon :)"); - private void saveBtn_Click(object sender, EventArgs e) { var newBooks = booksSelectControl.SelectedDirectory; diff --git a/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs b/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs deleted file mode 100644 index 2d523606..00000000 --- a/_Tests/FileLiberator.Tests/AudioFileStorageExtTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Dinah.Core; -using FileLiberator; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using static AudioFileStorageExtTests.Shared; - -namespace AudioFileStorageExtTests -{ - public static class Shared - { - public static LibationFileManager.LibraryBookDto GetLibraryBook(string asin) - => new() - { - Account = "my account", - AudibleProductId = asin, - Title = "A Study in Scarlet: A Sherlock Holmes Novel", - Locale = "us", - Authors = new List<string> { "Arthur Conan Doyle", "Stephen Fry - introductions" }, - Narrators = new List<string> { "Stephen Fry" }, - SeriesName = "Sherlock Holmes", - SeriesNumber = "1" - }; - } - - [TestClass] - public class MultipartRenamer_MultipartFilename - { - [TestMethod] - [DataRow("asin", "[<id>] <ch# 0> of <ch count> - <ch title>", @"C:\foo\", "txt", 6, 10, "chap", @"C:\foo\[asin] 06 of 10 - chap.txt")] - [DataRow("asin", "<ch#>", @"C:\foo\", "txt", 6, 10, "chap", @"C:\foo\6.txt")] - public void Tests(string asin, string template, string dir, string ext, int pos, int total, string chapter, string expected) - => new AudioFileStorageExt.MultipartRenamer(GetLibraryBook(asin)) - .MultipartFilename(new() { OutputFileName = $"xyz.{ext}", PartsPosition = pos, PartsTotal = total, Title = chapter }, template, dir) - .Should().Be(expected); - } - - [TestClass] - public class GetFileNamingTemplate - { - [TestMethod] - [DataRow(null, "asin", @"C:\", "ext")] - [ExpectedException(typeof(ArgumentNullException))] - public void arg_null_exception(string template, string asin, string dirFullPath, string extension) - => AudioFileStorageExt.GetFileNamingTemplate(template, GetLibraryBook(asin), dirFullPath, extension); - - [TestMethod] - [DataRow("", "asin", @"C:\foo\bar", "ext")] - [DataRow(" ", "asin", @"C:\foo\bar", "ext")] - [ExpectedException(typeof(ArgumentException))] - public void arg_exception(string template, string asin, string dirFullPath, string extension) - => AudioFileStorageExt.GetFileNamingTemplate(template, GetLibraryBook(asin), dirFullPath, extension); - - [TestMethod] - public void null_extension() => Tests("f.txt", "asin", @"C:\foo\bar", null, @"C:\foo\bar\f.txt"); - - [TestMethod] - [DataRow("f.txt", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\f.txt.ext")] - [DataRow("f", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\f.ext")] - [DataRow("<id>", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\asin.ext")] - public void Tests(string template, string asin, string dirFullPath, string extension, string expected) - => AudioFileStorageExt.GetFileNamingTemplate(template, GetLibraryBook(asin), dirFullPath, extension) - .GetFilePath() - .Should().Be(expected); - } -} diff --git a/_Tests/LibationFileManager.Tests/TemplatesTests.cs b/_Tests/LibationFileManager.Tests/TemplatesTests.cs index 02c1b3ff..080cde1b 100644 --- a/_Tests/LibationFileManager.Tests/TemplatesTests.cs +++ b/_Tests/LibationFileManager.Tests/TemplatesTests.cs @@ -7,8 +7,26 @@ using FluentAssertions; using LibationFileManager; using Microsoft.VisualStudio.TestTools.UnitTesting; +using static TemplatesTests.Shared; + namespace TemplatesTests { + public static class Shared + { + public static LibraryBookDto GetLibraryBook(string asin) + => new() + { + Account = "my account", + AudibleProductId = asin, + Title = "A Study in Scarlet: A Sherlock Holmes Novel", + Locale = "us", + Authors = new List<string> { "Arthur Conan Doyle", "Stephen Fry - introductions" }, + Narrators = new List<string> { "Stephen Fry" }, + SeriesName = "Sherlock Holmes", + SeriesNumber = "1" + }; + } + [TestClass] public class ContainsChapterOnlyTags { @@ -29,6 +47,35 @@ namespace TemplatesTests [DataRow("<id><ch#>", "ch#", true)] public void Tests(string template, string tag, bool expected) => Templates.ContainsTag(template, tag).Should().Be(expected); } + + [TestClass] + public class getFileNamingTemplate + { + [TestMethod] + [DataRow(null, "asin", @"C:\", "ext")] + [ExpectedException(typeof(ArgumentNullException))] + public void arg_null_exception(string template, string asin, string dirFullPath, string extension) + => Templates.getFileNamingTemplate(GetLibraryBook(asin), template, dirFullPath, extension); + + [TestMethod] + [DataRow("", "asin", @"C:\foo\bar", "ext")] + [DataRow(" ", "asin", @"C:\foo\bar", "ext")] + [ExpectedException(typeof(ArgumentException))] + public void arg_exception(string template, string asin, string dirFullPath, string extension) + => Templates.getFileNamingTemplate(GetLibraryBook(asin), template, dirFullPath, extension); + + [TestMethod] + public void null_extension() => Tests("f.txt", "asin", @"C:\foo\bar", null, @"C:\foo\bar\f.txt"); + + [TestMethod] + [DataRow("f.txt", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\f.txt.ext")] + [DataRow("f", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\f.ext")] + [DataRow("<id>", "asin", @"C:\foo\bar", "ext", @"C:\foo\bar\asin.ext")] + public void Tests(string template, string asin, string dirFullPath, string extension, string expected) + => Templates.getFileNamingTemplate(GetLibraryBook(asin), template, dirFullPath, extension) + .GetFilePath() + .Should().Be(expected); + } } namespace Templates_Folder_Tests @@ -314,4 +361,15 @@ namespace Templates_ChapterFile_Tests [DataRow("<ID> case specific", 0)] public void Tests(string template, int expected) => Templates.ChapterFile.TagCount(template).Should().Be(expected); } + + [TestClass] + public class GetPortionFilename + { + [TestMethod] + [DataRow("asin", "[<id>] <ch# 0> of <ch count> - <ch title>", @"C:\foo\", "txt", 6, 10, "chap", @"C:\foo\[asin] 06 of 10 - chap.txt")] + [DataRow("asin", "<ch#>", @"C:\foo\", "txt", 6, 10, "chap", @"C:\foo\6.txt")] + public void Tests(string asin, string template, string dir, string ext, int pos, int total, string chapter, string expected) + => Templates.ChapterFile.GetPortionFilename(GetLibraryBook(asin), template, new() { OutputFileName = $"xyz.{ext}", PartsPosition = pos, PartsTotal = total, Title = chapter }, dir) + .Should().Be(expected); + } }