From 3365ba40e7f601ebbdb1cc4a7d085aea3c1545cd Mon Sep 17 00:00:00 2001 From: Benjamin Michaelis Date: Sat, 21 Oct 2023 10:12:06 +0100 Subject: [PATCH] feat: Update all references to other listings and update namespace (#89) --- .../ListingInformationTests.cs | 169 ++++++++++- ListingManager.Tests/ListingManagerTests.cs | 268 ++++++++++++++---- ListingManager.Tests/TempFileTestBase.cs | 2 +- ListingManager/ListingInformation.cs | 80 ++++-- ListingManager/ListingManager.cs | 94 +++--- ListingManager/Program.cs | 12 +- 6 files changed, 472 insertions(+), 153 deletions(-) diff --git a/ListingManager.Tests/ListingInformationTests.cs b/ListingManager.Tests/ListingInformationTests.cs index c959f5e..4b4485b 100644 --- a/ListingManager.Tests/ListingInformationTests.cs +++ b/ListingManager.Tests/ListingInformationTests.cs @@ -174,16 +174,15 @@ public void GetPaddedListingNumber_ListingNumber_ReturnCorrectPaddedListingNumbe } [Theory] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_01", "Listing01.01.cs", false, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_05", "Listing01.05.cs", false, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_04a", "Listing01.04a.cs", false, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_04a", "Listing01.04a.cs", true, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_06B", "Listing01.06B.cs", false, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_07C", "Listing01.07C.cs", true, false)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_07C.Tests", "Listing01.07C.Tests.cs", true, true)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_08.Tests", "Listing01.08.Tests.cs", true, true)] - [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_10.Tests", "Listing01.10.Tests.cs", true, true)] - public void GetNewNamespace_Namespace_ReturnCorrectNewNamespace(string expected, string listingPath, bool chapterOnly, bool isTest) + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_01", "Listing01.01.cs", false)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_05", "Listing01.05.cs", false)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_04a", "Listing01.04a.cs", false)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_06B", "Listing01.06B.cs", false)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_07C", "Listing01.07C.cs", false)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_07C.Tests", "Listing01.07C.Tests.cs", true)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_08.Tests", "Listing01.08.Tests.cs", true)] + [InlineData("AddisonWesley.Michaelis.EssentialCSharp.Chapter01.Listing01_10.Tests", "Listing01.10.Tests.cs", true)] + public void GetNewNamespace_Namespace_ReturnCorrectNewNamespace(string expected, string listingPath, bool isTest) { List filesToMake = new() { @@ -204,12 +203,12 @@ public void GetNewNamespace_Namespace_ReturnCorrectNewNamespace(string expected, var writtenFiles = WriteFiles(tempDir, filesToMake, toWrite); var writtenFile = Assert.Single(writtenFiles); - Assert.Equal(expected, new ListingInformation(writtenFile.FullName, isTest).GetNewNamespace(chapterOnly)); + Assert.Equal(expected, new ListingInformation(writtenFile.FullName, isTest).GetNewNamespace()); } [Theory] - [InlineData("Listing01.01.cs", "Listing01.01.cs", false, false)] - public void GetNewFileName_FileName_ReturnCorrectNewFileName(string expected, string listingPath, bool chapterOnly, bool isTest) + [InlineData("Listing01.01.cs", "Listing01.01.cs", false)] + public void GetNewFileName_FileName_ReturnCorrectNewFileName(string expected, string listingPath, bool isTest) { List filesToMake = new() { @@ -230,6 +229,148 @@ public void GetNewFileName_FileName_ReturnCorrectNewFileName(string expected, st var writtenFiles = WriteFiles(tempDir, filesToMake, toWrite); var writtenFile = Assert.Single(writtenFiles); - Assert.Equal(expected, new ListingInformation(writtenFile.FullName, isTest).GetNewFileName(chapterOnly)); + Assert.Equal(expected, new ListingInformation(writtenFile.FullName, isTest).GetNewFileName()); } + + #region ReferencesInFile + [Fact] + public void UpdateChapterListingNumbers_UsingStatement_ListingReferencesUpdated() + { + List filesToMake = new() + { + Path.Join("Chapter18","Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs"), + Path.Join("Chapter18","Listing18.04.UsingTypeofToCreateASystem.TypeInstance.cs"), + }; + ICollection expectedFiles = new List + { + Path.Join("Chapter18","Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs"), + Path.Join("Chapter18","Listing18.02.UsingTypeofToCreateASystem.TypeInstance.cs") + }; + + IEnumerable toWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_04", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + IEnumerable toWriteAlso = new List + { + "using Listing18_04;", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + IEnumerable expectedFileContents = new List + { + "using Listing18_02;", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + DirectoryInfo tempDir = CreateTempDirectory(); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter18"); + CreateTempDirectory(tempDir, name: "Chapter18.Tests"); + WriteFile(tempDir, filesToMake.Last(), toWrite.ToList()); + WriteFile(tempDir, filesToMake.First(), toWriteAlso.ToList()); + expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); + + ListingManager listingManager = new(tempDir.FullName, new OSStorageManager()); + listingManager.UpdateChapterListingNumbers(chapterDir.FullName, byFolder: true); + + List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) + .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); + + // Assert + Assert.Equal(2, files.Count); + Assert.Equivalent(expectedFiles, files); + + Assert.Equal(string.Join(Environment.NewLine, expectedFileContents) + Environment.NewLine, File.ReadAllText(expectedFiles.First())); + } + + [Fact] + public void UpdateChapterListingNumbers_StringLisingReference_ReferencesUpdated() + { + List filesToMake = new() + { + Path.Join("Chapter18","Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs"), + Path.Join("Chapter18","Listing18.04.UsingTypeofToCreateASystem.TypeInstance.cs"), + }; + ICollection expectedFiles = new List + { + Path.Join("Chapter18","Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs"), + Path.Join("Chapter18","Listing18.02.UsingTypeofToCreateASystem.TypeInstance.cs") + }; + + IEnumerable toWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_04", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + IEnumerable toWriteAlso = new List + { + "using Listing18_04;", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { " + + " static string Ps1Path { get; } =", + " Path.GetFullPath(", + " Path.Join(Ps1DirectoryPath, \"Listing18.04.HelloWorldInC#.ps1\"), \"Listing18.04.HelloWorldInC#.ps1\");", + " }", + "}" + }; + + IEnumerable expectedFileContents = new List + { + "using Listing18_02;", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { " + + " static string Ps1Path { get; } =", + " Path.GetFullPath(", + " Path.Join(Ps1DirectoryPath, \"Listing18.02.HelloWorldInC#.ps1\"), \"Listing18.02.HelloWorldInC#.ps1\");", + " }", + "}" + }; + + DirectoryInfo tempDir = CreateTempDirectory(); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter18"); + CreateTempDirectory(tempDir, name: "Chapter18.Tests"); + WriteFile(tempDir, filesToMake.Last(), toWrite.ToList()); + WriteFile(tempDir, filesToMake.First(), toWriteAlso.ToList()); + expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); + + ListingManager listingManager = new(tempDir.FullName, new OSStorageManager()); + listingManager.UpdateChapterListingNumbers(chapterDir.FullName, byFolder: true); + + List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) + .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); + + // Assert + Assert.Equal(2, files.Count); + Assert.Equivalent(expectedFiles, files); + + Assert.Equal(string.Join(Environment.NewLine, expectedFileContents) + Environment.NewLine, File.ReadAllText(expectedFiles.First())); + } + #endregion ReferencesInFile } \ No newline at end of file diff --git a/ListingManager.Tests/ListingManagerTests.cs b/ListingManager.Tests/ListingManagerTests.cs index 6ce4265..fe27128 100644 --- a/ListingManager.Tests/ListingManagerTests.cs +++ b/ListingManager.Tests/ListingManagerTests.cs @@ -61,6 +61,121 @@ public void GetAllExtraListings_ExtraListingsReturned() #region UpdateChapterListingNumbers #region GitStorageManager + [Fact] + public void UpdateChapterListingNumbers_GitStorageManagerByFolder_NamespacesUpdated() + { + ICollection filesToMake = new List + { + Path.Join("Chapter42","Listing18.06.cs"), + }; + + ICollection expectedFiles = new List + { + Path.Join("Chapter42","Listing42.01.cs") + }; + + IEnumerable toWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_06", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + IEnumerable expectedToWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter42.Listing42_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}", + }; + DirectoryInfo tempDir = CreateTempDirectory(); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter42"); + CreateTempDirectory(tempDir, name: "Chapter42.Tests"); + WriteFiles(tempDir, filesToMake, toWrite); + expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); + + Repository.Init(tempDir.FullName); + using var repo = new Repository(tempDir.FullName); + Commands.Stage(repo, "*"); + // Commit to the repository + repo.Commit("Here's a commit i made!", Author, Author); + + ListingManager listingManager = new(tempDir.FullName, new GitStorageManager(tempDir.FullName)); + + listingManager.UpdateChapterListingNumbers(chapterDir.FullName, byFolder: true); + + List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) + .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); + + // Assert + string expectedFile = Assert.Single(files); + Assert.Equivalent(expectedFiles, files); + + Assert.Equal(string.Join(Environment.NewLine, expectedToWrite) + Environment.NewLine, File.ReadAllText(expectedFile)); + } + + [Fact] + public void UpdateChapterListingNumbers_GitStorageManager_NamespacesUpdated() + { + ICollection filesToMake = new List + { + Path.Join("Chapter42","Listing42.06.cs"), + }; + + ICollection expectedFiles = new List + { + Path.Join("Chapter42","Listing42.01.cs") + }; + + IEnumerable toWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_06", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + IEnumerable expectedToWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter42.Listing42_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}", + }; + DirectoryInfo tempDir = CreateTempDirectory(); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter42"); + CreateTempDirectory(tempDir, name: "Chapter42.Tests"); + WriteFiles(tempDir, filesToMake, toWrite); + expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); + + Repository.Init(tempDir.FullName); + using var repo = new Repository(tempDir.FullName); + Commands.Stage(repo, "*"); + // Commit to the repository + repo.Commit("Here's a commit i made!", Author, Author); + + ListingManager listingManager = new(tempDir.FullName, new GitStorageManager(tempDir.FullName)); + listingManager.UpdateChapterListingNumbers(chapterDir.FullName); + + List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) + .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); + + // Assert + string expectedFile = Assert.Single(files); + Assert.Equivalent(expectedFiles, files); + + Assert.Equal(string.Join(Environment.NewLine, expectedToWrite) + Environment.NewLine, File.ReadAllText(expectedFile)); + } + [Fact] public void UpdateChapterListingNumbers_GitStorageManager_ListingsWithinListMissing_ListingsRenumbered() { @@ -93,7 +208,6 @@ public void UpdateChapterListingNumbers_GitStorageManager_ListingsWithinListMiss expectedFiles = ConvertFileNamesToFullPath(expectedFiles, null).ToList(); string rootedPath = Repository.Init(TempDirectory.FullName); - //Assert.Equal(rootedPath, TempDirectory.FullName); using var repo = new Repository(TempDirectory.FullName); Commands.Stage(repo, "*"); @@ -109,15 +223,15 @@ public void UpdateChapterListingNumbers_GitStorageManager_ListingsWithinListMiss Commands.Stage(repo, "*"); repo.RetrieveStatus(); - Assert.Equal(FileStatus.Unaltered, repo.RetrieveStatus(files[0])); - Assert.Equal(FileStatus.Unaltered, repo.RetrieveStatus(files[1])); + Assert.Equal(FileStatus.ModifiedInIndex, repo.RetrieveStatus(files[0])); + Assert.Equal(FileStatus.ModifiedInIndex, repo.RetrieveStatus(files[1])); //TODO: These ideally would be "FileStatus.RenamedInIndex" instead of //NewInIndex because this indicates the old file is just being removed //and the new one added instead of a true rename Assert.Equal(FileStatus.NewInIndex, repo.RetrieveStatus(files[2])); Assert.Equal(FileStatus.NewInIndex, repo.RetrieveStatus(files[3])); - } + } #endregion GitStorageManager #region UsingOSStorageManager [Fact] @@ -539,95 +653,136 @@ public void } [Fact] - public void - UpdateOnlyChapterNumberOfListingUsingChapterNumberFromFolder_UnitTestsAlsoUpdated_ListingsAndTestsUpdated() + public void RenumberAllFilesIncludingXML_DontChangeFiles_ListingsAndTestsUpdated() + { + // Make sure csproj file is created, but doesn't get renumbered (is ignored) + List filesToMake = new() + { + @"Chapter18.csproj", + @"Chapter18\Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs", + @"Chapter18\Listing18.02.UsingTypeofToCreateASystem.TypeInstance.cs", + @"Chapter18\Listing18.03.csproj.xml", + @"Chapter18\Listing18.04.DeclaringTheStackClass.cs", + @"Chapter18\Listing18.05.ReflectionWithGenerics.cs", + @"Chapter18.Tests\Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.Tests.cs", + @"Chapter18.Tests\Listing18.02.Tests.cs", + @"Chapter18.Tests\Listing18.05.ReflectionWithGenerics.Tests.cs", + }; + List expectedFiles = filesToMake.GetRange(1, filesToMake.Count - 1); + Assert.Equal(filesToMake.Count - 1, expectedFiles.Count); + + IEnumerable toWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}" + }; + + DirectoryInfo tempDir = CreateTempDirectory(); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter18"); + CreateTempDirectory(tempDir, name: "Chapter18.Tests"); + WriteFiles(tempDir, filesToMake, toWrite); + expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); + + ListingManager listingManager = new(TempDirectory.FullName, new OSStorageManager()); + listingManager.UpdateChapterListingNumbers(chapterDir.FullName); + + List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) + .Where(x => ListingInformation.ApprovedFileTypes.Contains(Path.GetExtension(x))).OrderBy(x => x).ToList(); + + // Assert + Assert.Equivalent(expectedFiles, files); + } + + [Fact] + public void UpdateChapterListingNumbers_OSStorageManagerByFolder_NamespacesUpdated() { ICollection filesToMake = new List { - "Chapter42/Listing01.01.cs", - "Chapter42/Listing01.01A.Some.cs", - "Chapter42/Listing01.01B.cs", - "Chapter42/Listing01.01C.cs", - "Chapter42/Listing01.05.cs", - "Chapter42.Tests/Listing01.01.Tests.cs", - "Chapter42.Tests/Listing01.01A.Some.Tests.cs", - "Chapter42.Tests/Listing01.01B.Tests.cs", - "Chapter42.Tests/Listing01.01C.Tests.cs", - "Chapter42.Tests/Listing01.05.Tests.cs" + Path.Join("Chapter42","Listing18.06.cs"), }; ICollection expectedFiles = new List { - @"Chapter42\Listing42.01.cs", - @"Chapter42\Listing42.01A.Some.cs", - @"Chapter42\Listing42.01B.cs", - @"Chapter42\Listing42.01C.cs", - @"Chapter42\Listing42.05.cs", - @"Chapter42.Tests\Listing42.01.Tests.cs", - @"Chapter42.Tests\Listing42.01A.Some.Tests.cs", - @"Chapter42.Tests\Listing42.01B.Tests.cs", - @"Chapter42.Tests\Listing42.01C.Tests.cs", - @"Chapter42.Tests\Listing42.05.Tests.cs" + Path.Join("Chapter42","Listing42.01.cs") }; IEnumerable toWrite = new List { - "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_06", "{", " using System;", " using System.Reflection;", " public class Program { }", "}" + }; + + IEnumerable expectedToWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter42.Listing42_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}", }; - DirectoryInfo tempDir = CreateTempDirectory(); DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter42"); CreateTempDirectory(tempDir, name: "Chapter42.Tests"); WriteFiles(tempDir, filesToMake, toWrite); expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); - ListingManager listingManager = new(TempDirectory.FullName, new OSStorageManager(), chapterOnly: true); + ListingManager listingManager = new(TempDirectory.FullName, new OSStorageManager()); listingManager.UpdateChapterListingNumbers(chapterDir.FullName, byFolder: true); List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); // Assert + string expectedFile = Assert.Single(files); Assert.Equivalent(expectedFiles, files); - } + Assert.Equal(string.Join(Environment.NewLine, expectedToWrite) + Environment.NewLine, File.ReadAllText(expectedFile)); + } + [Fact] - public void RenumberAllFilesIncludingXML_DontChangeFiles_ListingsAndTestsUpdated() - { - // Make sure csproj file is created, but doesn't get renumbered (is ignored) - List filesToMake = new() + public void UpdateChapterListingNumbers_OSStorageManager_NamespacesUpdated() + { + ICollection filesToMake = new List { - @"Chapter18.csproj", - @"Chapter18\Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.cs", - @"Chapter18\Listing18.02.UsingTypeofToCreateASystem.TypeInstance.cs", - @"Chapter18\Listing18.03.csproj.xml", - @"Chapter18\Listing18.04.DeclaringTheStackClass.cs", - @"Chapter18\Listing18.05.ReflectionWithGenerics.cs", - @"Chapter18.Tests\Listing18.01.UsingTypeGetPropertiesToObtainAnObjectsPublicProperties.Tests.cs", - @"Chapter18.Tests\Listing18.02.Tests.cs", - @"Chapter18.Tests\Listing18.05.ReflectionWithGenerics.Tests.cs", - }; - List expectedFiles = filesToMake.GetRange(1, filesToMake.Count - 1); - Assert.Equal(filesToMake.Count - 1, expectedFiles.Count); + Path.Join("Chapter42","Listing42.06.cs"), + }; + + ICollection expectedFiles = new List + { + Path.Join("Chapter42","Listing42.01.cs") + }; IEnumerable toWrite = new List { - "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_01", + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter18.Listing18_06", "{", " using System;", " using System.Reflection;", " public class Program { }", "}" + }; + + IEnumerable expectedToWrite = new List + { + "namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter42.Listing42_01", + "{", + " using System;", + " using System.Reflection;", + " public class Program { }", + "}", }; - DirectoryInfo tempDir = CreateTempDirectory(); - DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter18"); - CreateTempDirectory(tempDir, name: "Chapter18.Tests"); + DirectoryInfo chapterDir = CreateTempDirectory(tempDir, name: "Chapter42"); + CreateTempDirectory(tempDir, name: "Chapter42.Tests"); WriteFiles(tempDir, filesToMake, toWrite); expectedFiles = ConvertFileNamesToFullPath(expectedFiles, tempDir).ToList(); @@ -635,10 +790,13 @@ public void RenumberAllFilesIncludingXML_DontChangeFiles_ListingsAndTestsUpdated listingManager.UpdateChapterListingNumbers(chapterDir.FullName); List files = FileManager.GetAllFilesAtPath(tempDir.FullName, true) - .Where(x => ListingInformation.ApprovedFileTypes.Contains(Path.GetExtension(x))).OrderBy(x => x).ToList(); - - // Assert + .Where(x => Path.GetExtension(x) == ".cs").OrderBy(x => x).ToList(); + + // Assert + string expectedFile = Assert.Single(files); Assert.Equivalent(expectedFiles, files); + + Assert.Equal(string.Join(Environment.NewLine, expectedToWrite) + Environment.NewLine, File.ReadAllText(expectedFile)); } #endregion UsingOSStorageManager #endregion UpdateChapterListingNumbers @@ -809,8 +967,8 @@ public void PopulateListingDataFromPath_GivenSingleDirectoryOfListingsAndTests_A Assert.All(listingsWithTests, listing => Assert.Equal(listing.OriginalListingNumber, listing.AssociatedTest!.OriginalListingNumber)); Assert.All(listingsWithTests, listing => Assert.Equal(listing.OriginalListingNumberSuffix, listing.AssociatedTest!.OriginalListingNumberSuffix)); Assert.All(listingsWithTests, listing => Assert.Equal(listing.OriginalChapterNumber, listing.AssociatedTest!.OriginalChapterNumber)); - } - #endregion PopulateListingDataFromPath + } + #endregion PopulateListingDataFromPath [Theory] [InlineData("Chapter01", "Listing01.01A.cs")] diff --git a/ListingManager.Tests/TempFileTestBase.cs b/ListingManager.Tests/TempFileTestBase.cs index 2e04bfc..f8cc3a7 100644 --- a/ListingManager.Tests/TempFileTestBase.cs +++ b/ListingManager.Tests/TempFileTestBase.cs @@ -95,7 +95,7 @@ public IEnumerable ConvertFileNamesToFullPath(IEnumerable fileNa public FileInfo WriteFile(DirectoryInfo targetDirectory, string fileName, List toWrite) { - var ret = CreateTempFile(targetDirectory, name: fileName, contents: toWrite.ToString()); + var ret = CreateTempFile(targetDirectory, name: fileName, contents: string.Join(Environment.NewLine, toWrite)); return ret; } diff --git a/ListingManager/ListingInformation.cs b/ListingManager/ListingInformation.cs index f8bc221..9b54f1f 100644 --- a/ListingManager/ListingInformation.cs +++ b/ListingManager/ListingInformation.cs @@ -8,6 +8,7 @@ public partial class ListingInformation public const string TemporaryExtension = ".tmp"; public bool Changed { get; private set; } + public bool FileContentsChanged { get; private set; } public int OriginalChapterNumber { get; } private int _NewChapterNumber; @@ -67,20 +68,18 @@ public string NewListingNumberSuffix } public string Caption { get; set; } public string TemporaryPath => Path + TemporaryExtension; - public string Path { get; } + public string Path { get; set; } public string ParentDir { get; } public string NamespacePrefix => "AddisonWesley.Michaelis.EssentialCSharp"; public string ListingExtension { get; } - public string FileContents { get; set; } + public List FileContents { get; set; } public ListingInformation? AssociatedTest { get; set; } public bool IsTest { get; } private string FullCaption { get; } public ListingInformation(string listingPath, bool isTest = false) { - Regex regex = ExtractListingNameFromAnyApprovedFileTypes(); - - var matches = regex.Match(listingPath); + Match matches = ExtractListingNameFromAnyApprovedFileTypes().Match(listingPath); if (ApprovedFileTypes.Contains(matches.Groups[6].Value.ToLower()) is false) throw new ArgumentException("Listing path is not of an approved file type.", nameof(listingPath)); @@ -96,7 +95,7 @@ public ListingInformation(string listingPath, bool isTest = false) IsTest = isTest || (!string.IsNullOrWhiteSpace(FullCaption) ? FullCaption : string.Empty).EndsWith(".Tests"); Path = listingPath; ListingExtension = matches.Groups[6].Value; - FileContents = File.ReadAllText(listingPath); + FileContents = File.ReadAllLines(listingPath).ToList(); ParentDir = new FileInfo(listingPath).Directory?.FullName ?? throw new InvalidOperationException("Path is unexpectedly null"); } else @@ -104,28 +103,69 @@ public ListingInformation(string listingPath, bool isTest = false) throw new ArgumentException("Listing information not successfully able to be parsed from listing path.", nameof(listingPath)); } } - // Match any approved files regex: regexr.com/7lfi2 - [GeneratedRegex("Listing(\\d{2}).(\\d{2})([A-Za-z]*)(\\.{1}(.*))*(\\.(\\w+))$")] - private static partial Regex ExtractListingNameFromAnyApprovedFileTypes(); public string GetPaddedListingNumberWithSuffix(bool originalListingNumber = false) { if (!originalListingNumber) return NewListingNumber.ToString("D2") + NewListingNumberSuffix; else return (OriginalListingNumber.ToString("D2") + NewListingNumberSuffix); - } - public string GetNewNamespace(bool chapterOnly) + + public string GetNewNamespace() { string paddedChapterNumber = NewChapterNumber.ToString("D2"); - string paddedListingNumber = GetPaddedListingNumberWithSuffix(chapterOnly); + string paddedListingNumber = GetPaddedListingNumberWithSuffix(); return NamespacePrefix + $".Chapter{paddedChapterNumber}" + $".Listing{paddedChapterNumber}_" + paddedListingNumber + (IsTest ? ".Tests" : string.Empty); + } + + public bool UpdateNamespaceInFileContents() + { + return UpdateNamespaceInFileContents(GetNewNamespace()); } - public string GetNewFileName(bool chapterOnly) + public bool UpdateNamespaceInFileContents(string newNamespace) + { + bool updated = false; + for (int i = 0; i < FileContents.Count; i++) + { + if (FileContents[i].TrimStart().StartsWith("namespace")) + { + FileContents[i] = $"namespace {newNamespace}"; + updated = true; + FileContentsChanged = true; + } + } + return updated; + } + + public void UpdateReferencesInFile(List listingData) + { + for (int i = 0; i < FileContents.Count; i++) + { + if (ListingReference().IsMatch(FileContents[i])) + { + MatchCollection matches = ListingReference().Matches(FileContents[i]); + for (int j = 0; j < matches.Count; j++) + { + int chapterNumber = int.Parse(matches[j].Groups[1].Value); + string chapterListingDeliminator = matches[j].Groups[2].Value; + int listingNumber = int.Parse(matches[j].Groups[3].Value); + ListingInformation? referencedListingInformation = listingData.FirstOrDefault(item => item.OriginalChapterNumber == chapterNumber && item.OriginalListingNumber == listingNumber); + if (referencedListingInformation is not null) + { + string replacementListingReference = matches[j].Groups[0].Value.Replace($"{chapterNumber:D2}{matches[j].Groups[2].Value}{listingNumber:D2}", $"{referencedListingInformation.NewChapterNumber:D2}{matches[j].Groups[2].Value}{referencedListingInformation.NewListingNumber:D2}"); + FileContents[i] = FileContents[i].Replace(matches[j].Groups[0].Value, replacementListingReference); + } + } + FileContentsChanged = true; + } + } + } + + public string GetNewFileName() { string newFileNameTemplate = "Listing{0}.{1}{2}" + (IsTest && !FullCaption.EndsWith(".Tests") ? ".Tests" : string.Empty) + ListingExtension; string paddedChapterNumber = NewChapterNumber.ToString("00"); @@ -135,9 +175,13 @@ public string GetNewFileName(bool chapterOnly) paddedChapterNumber, paddedListingNumber, string.IsNullOrWhiteSpace(Caption) ? "" : $".{Caption}"); - } - + } + + // Match any approved files regex: regexr.com/7lfi2 + [GeneratedRegex("Listing(\\d{2}).(\\d{2})([A-Za-z]*)(\\.{1}(.*))*(\\.(\\w+))$")] + private static partial Regex ExtractListingNameFromAnyApprovedFileTypes(); [GeneratedRegex(@"\d{1}[A-Za-z]")] - private static partial Regex SingleDigitListingWithSuffix(); -} - + private static partial Regex SingleDigitListingWithSuffix(); + [GeneratedRegex("Listing(\\d{2})([_.])(\\d{2})")] + private static partial Regex ListingReference(); +} \ No newline at end of file diff --git a/ListingManager/ListingManager.cs b/ListingManager/ListingManager.cs index c34a0fc..cd9cb46 100644 --- a/ListingManager/ListingManager.cs +++ b/ListingManager/ListingManager.cs @@ -10,18 +10,15 @@ namespace EssentialCSharp.ListingManager; public partial class ListingManager { public IStorageManager StorageManager { get; } - public bool ChapterOnly { get; } - public ListingManager(string pathToChapter, bool chapterOnly = false) + public ListingManager(string pathToChapter) { StorageManager = Repository.IsValid(pathToChapter) ? new GitStorageManager(pathToChapter) : new OSStorageManager(); - ChapterOnly = chapterOnly; } - public ListingManager(string pathToChapter, IStorageManager storageManager, bool chapterOnly = false) + public ListingManager(string pathToChapter, IStorageManager storageManager) { StorageManager = storageManager; - ChapterOnly = chapterOnly; } public static IEnumerable GetAllExtraListings(string pathToStartFrom) @@ -74,25 +71,21 @@ public void UpdateChapterListingNumbers(string pathToChapter, List listingData = PopulateListingDataFromPath(pathToChapter, singleDir); for (int i = 0, listingNumber = 1; i < listingData.Count; i++, listingNumber++) { - ListingInformation curListingData = listingData[i] ?? throw new InvalidOperationException($"Listing data is null for an index of {i}"); - - if (!ChapterOnly) - { - curListingData.NewListingNumber = listingNumber; - curListingData.NewListingNumberSuffix = string.Empty; - } + ListingInformation curListingData = listingData[i] ?? throw new InvalidOperationException($"Listing data is null for an index of {i}"); + + curListingData.NewListingNumber = listingNumber; + curListingData.NewListingNumberSuffix = string.Empty; if (byFolder) { curListingData.NewChapterNumber = FileManager.GetFolderChapterNumber(pathToChapter); } - string newNamespace = curListingData.GetNewNamespace(ChapterOnly); - string newFileName = curListingData.GetNewFileName(ChapterOnly); + string newNamespace = curListingData.GetNewNamespace(); + string newFileName = curListingData.GetNewFileName(); Console.WriteLine($"Corrective action. {Path.GetFileName(curListingData.Path)} rename to {newFileName}"); - - if (!preview) UpdateNamespaceOfPath(curListingData.Path, newNamespace, newFileName); + curListingData.UpdateNamespaceInFileContents(); if (listingData.Where(item => item.AssociatedTest is not null).FirstOrDefault(x => x?.OriginalListingNumber == curListingData.OriginalListingNumber && x.OriginalListingNumberSuffix == curListingData.OriginalListingNumberSuffix) is ListingInformation curTestListingData) { @@ -106,17 +99,35 @@ public void UpdateChapterListingNumbers(string pathToChapter, if (!preview) { - UpdateNamespaceOfPath(curListingData.Path, newNamespace, newFileName); - if (curListingData.AssociatedTest is not null) - { - UpdateNamespaceOfPath(curListingData.AssociatedTest.Path, curListingData.AssociatedTest.GetNewNamespace(ChapterOnly), curListingData.AssociatedTest.GetNewFileName(ChapterOnly)); - } + curListingData.AssociatedTest?.UpdateNamespaceInFileContents(); } } } } + listingData.ForEach(item => item.UpdateReferencesInFile(listingData)); MoveListing(listingData); + UpdateFileContents(listingData); + } + + private void UpdateFileContents(List listingData) + { + foreach (ListingInformation listingInformation in listingData) + { + UpdateFileContents(listingInformation); + } + } + + private void UpdateFileContents(ListingInformation listingInformation) + { + if (listingInformation.FileContentsChanged) + { + File.WriteAllLines(Path.Combine(listingInformation.ParentDir, listingInformation.Path), listingInformation.FileContents); + if (listingInformation.AssociatedTest is ListingInformation listingTest && listingTest.Changed) + { + File.WriteAllLines(Path.Combine(listingInformation.ParentDir, listingTest.Path), listingTest.FileContents); + } + } } public void MoveListing(IEnumerable listingData) @@ -131,48 +142,19 @@ public void MoveListing(ListingInformation listingInformation) { if (listingInformation.Changed) { - StorageManager.Move(listingInformation.Path, Path.Combine(listingInformation.ParentDir, listingInformation.GetNewFileName(ChapterOnly))); + string listingInformationFileName = listingInformation.GetNewFileName(); + StorageManager.Move(listingInformation.Path, Path.Combine(listingInformation.ParentDir, listingInformationFileName)); + listingInformation.Path = listingInformationFileName; if (listingInformation.AssociatedTest is ListingInformation listingTest && listingTest.Changed) { if (listingTest.Changed) { - StorageManager.Move(listingTest.Path, Path.Combine(listingTest.ParentDir, listingTest.GetNewFileName(ChapterOnly))); + string listingTestInformationFileName = listingTest.GetNewFileName(); + StorageManager.Move(listingTest.Path, Path.Combine(listingTest.ParentDir, listingTestInformationFileName)); + listingTest.Path = listingTestInformationFileName; } } } - } - - private static void UpdateNamespaceOfPath(string path, string newNamespace, string newFileName = "") - { - if (Path.GetExtension(path) != ".tmp") - { - return; - } - - // read file into memory - string[] allLinesInFile = File.ReadAllLines(path); - - string targetPath = Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, newFileName) ?? path; - - using TextWriter textWriter = new StreamWriter(targetPath, true); - foreach (string line in allLinesInFile) - { - if (line.StartsWith("namespace")) - { - if (line.TrimEnd().EndsWith(";")) - { - textWriter.WriteLine("namespace " + newNamespace + ";"); - } - else - { - textWriter.WriteLine("namespace " + newNamespace); - } - } - else - { - textWriter.WriteLine(line); - } - } } public static bool GetPathToAccompanyingUnitTest(string listingPath, out string pathToTest) diff --git a/ListingManager/Program.cs b/ListingManager/Program.cs index dc9ed21..255ae4e 100644 --- a/ListingManager/Program.cs +++ b/ListingManager/Program.cs @@ -32,18 +32,12 @@ private static int Main(string[] args) name: "--byfolder", description: ""); - // TODO: Add better descriptions when their functionality becomes clearer - var chapterOnlyOption = new Option( - name: "--chapteronly", - description: ""); - var listingUpdating = new Command("update", "Updates namespaces and filenames for all lisitngs and accompanying tests within a chapter") { directoryIn, verboseOption, previewOption, byFolderOption, - chapterOnlyOption }; // Give better description when intent and functionality becomes more flushed out @@ -59,15 +53,15 @@ private static int Main(string[] args) scanForMismatchedListings }; - listingUpdating.SetHandler((directoryIn, verbose, preview, byFolder, chapterOnly) => + listingUpdating.SetHandler((directoryIn, verbose, preview, byFolder) => { Console.WriteLine(IntelliTect); Console.WriteLine($"Updating listing namespaces of: {directoryIn}"); // TODO: Add option for last parameter // TODO: Change parameter to take a DirectoryInfo instead of a string: https://github.com/IntelliTect/ListingManager/issues/26 - ListingManager listingManager = new(directoryIn!.FullName, chapterOnly: chapterOnly); + ListingManager listingManager = new(directoryIn!.FullName); listingManager.UpdateChapterListingNumbers(directoryIn.FullName, verbose, preview, byFolder, false); - }, directoryIn, verboseOption, previewOption, byFolderOption, chapterOnlyOption); + }, directoryIn, verboseOption, previewOption, byFolderOption); scanForMismatchedListings.SetHandler((directoryIn) => {