Browse Source

Merge branch 'dev'

Piotr Czajkowski 2 days ago
parent
commit
9c691dd0b0

+ 23 - 17
ProcessFiles/ProcessFiles.cs

@@ -12,11 +12,11 @@ namespace ProcessFiles
         Failure
     }
 
-    public static class ProcessFiles
+    public class ProcessFiles
     {
-        private static List<string> errors = new();
+        private readonly List<string> errors = [];
 
-        private static Result WhatIsIt(string path)
+        private Result WhatIsIt(string path)
         {
             try
             {
@@ -25,12 +25,12 @@ namespace ProcessFiles
             }
             catch (Exception e)
             {
-                errors.Add(e.ToString());
+                errors.Add($"Problem getting attributes of {path}: {e.Message} ({e.Source})");
                 return Result.Failure;
             }
         }
 
-        private static string? GetExtension(string path)
+        private string? GetExtension(string path)
         {
             var extension = Path.GetExtension(path).TrimStart('.');
             if (!string.IsNullOrWhiteSpace(extension)) return extension;
@@ -39,12 +39,12 @@ namespace ProcessFiles
             return null;
         }
 
-        private static bool CheckExtension(string extension, string[] validExtensions)
+        private bool CheckExtension(string extension, string[] validExtensions)
         {
-            return validExtensions.Any(validExtension => extension.Equals(validExtension, StringComparison.InvariantCultureIgnoreCase));
+            return validExtensions.Any(validExtension => extension.Equals(validExtension, StringComparison.OrdinalIgnoreCase));
         }
 
-        private static bool IsValid(string path, string[] fileExtensions)
+        private bool IsValid(string path, string[] fileExtensions)
         {
             if (!File.Exists(path))
             {
@@ -63,7 +63,7 @@ namespace ProcessFiles
 
         }
 
-        private static void PerformAction(string path, Action<string> action)
+        private void PerformAction(string path, Action<string> action)
         {
             try
             {
@@ -71,11 +71,11 @@ namespace ProcessFiles
             }
             catch (Exception e)
             {
-                errors.Add($"{path}:\n{e}");
+                errors.Add($"Problem performing action on {path}: {e.Message} ({e.Source})");
             }
         }
 
-        private static void ProcessFile(string path, string[] fileExtensions, Action<string> action)
+        private void ProcessFile(string path, string[] fileExtensions, Action<string> action)
         {
             if (!IsValid(path, fileExtensions))
                 return;
@@ -83,7 +83,7 @@ namespace ProcessFiles
             PerformAction(path, action);
         }
 
-        private static void ProcessDir(string path, string[] fileExtensions, Action<string> action, bool recursive = false)
+        private void ProcessDir(string path, string[] fileExtensions, Action<string> action, bool recursive = false)
         {
             if (!Directory.Exists(path))
             {
@@ -100,7 +100,15 @@ namespace ProcessFiles
             List<string> files = [];
             foreach (var extension in fileExtensions)
             {
-                files.AddRange(Directory.GetFiles(path, $"*.{extension}", searchOption));
+                try
+                {
+                    var filesWithExtension = Directory.GetFiles(path, $"*.{extension}", searchOption);
+                    files.AddRange(filesWithExtension);
+                }
+                catch (Exception e)
+                {
+                    errors.Add($"Problem getting files: {e.Message} ({e.Source})");
+                }
             }
 
             if (files.Count == 0)
@@ -113,15 +121,13 @@ namespace ProcessFiles
                 ProcessFile(file, fileExtensions, action);
         }
 
-        public static IEnumerable<string> Process(IEnumerable<string> arguments, string fileExtension, Action<string> action, bool recursive = false)
+        public IEnumerable<string> Process(IEnumerable<string> arguments, string fileExtension, Action<string> action, bool recursive = false)
         {
             return Process(arguments, [fileExtension], action, recursive);
         }
 
-        public static IEnumerable<string> Process(IEnumerable<string> arguments, string[] fileExtensions, Action<string> action, bool recursive = false)
+        public IEnumerable<string> Process(IEnumerable<string> arguments, string[] fileExtensions, Action<string> action, bool recursive = false)
         {
-            errors = new List<string>();
-
             foreach (var argument in arguments)
             {
                 switch (WhatIsIt(argument))

+ 2 - 2
ProcessFiles/ProcessFiles.csproj

@@ -3,7 +3,7 @@
 	<PropertyGroup>
 		<Nullable>enable</Nullable>
 		<TargetFramework>net8.0</TargetFramework>
-		<Version>0.2.0</Version>
+		<Version>1.0.0</Version>
 		<Title>ProcessFiles</Title>
 		<Authors>Piotr Czajkowski</Authors>
 		<Description>Easily process files from command line arguments</Description>
@@ -13,7 +13,7 @@
 		<PackageReadmeFile>README.md</PackageReadmeFile>
 		<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
 		<RepositoryType>GitHub</RepositoryType>
-		<PackageReleaseNotes>Using .NET 8</PackageReleaseNotes>
+		<PackageReleaseNotes>Not static anymore</PackageReleaseNotes>
 	</PropertyGroup>
 
 	<ItemGroup>

+ 53 - 18
ProcessFilesTests/ProcessFilesTests.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using Xunit;
 
 namespace ProcessFilesTests
@@ -9,22 +10,19 @@ namespace ProcessFilesTests
         private readonly string testFolder = "./testFiles";
         private readonly string testFile = "./testFiles/test1.txt";
 
-        private readonly List<string> expectedInSubFolder = new()
-        {
+        private readonly List<string> expectedInSubFolder =
+        [
             "test2.txt",
             "test3.txt"
-        };
+        ];
 
-        private readonly List<string> expectedInSubFolderMultipleExtensions = new()
-        {
-            "test.json"
-        };
+        private readonly List<string> expectedInSubFolderMultipleExtensions = ["test.json"];
 
-        private readonly string expectedInFolder = "test1.txt";
+        private const string ExpectedInFolder = "test1.txt";
 
         public ProcessFilesTests()
         {
-            expectedInSubFolder.Add(expectedInFolder);
+            expectedInSubFolder.Add(ExpectedInFolder);
             expectedInSubFolderMultipleExtensions.AddRange(expectedInSubFolder);
         }
 
@@ -37,9 +35,10 @@ namespace ProcessFilesTests
                 result = Path.GetFileName(value);
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { testFolder }, "txt", TestAction);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process([testFolder], "txt", TestAction);
             Assert.Empty(errors);
-            Assert.Equal(expectedInFolder, result);
+            Assert.Equal(ExpectedInFolder, result);
         }
 
         private static bool CheckResult(List<string> result, List<string> expected)
@@ -65,7 +64,8 @@ namespace ProcessFilesTests
                 result.Add(Path.GetFileName(value));
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { testFolder }, "txt", TestAction, true);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process([testFolder], "txt", TestAction, true);
             Assert.Empty(errors);
             Assert.True(CheckResult(result, expectedInSubFolder));
         }
@@ -79,7 +79,8 @@ namespace ProcessFilesTests
                 result.Add(Path.GetFileName(value));
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { "./testFiles/subFolder", testFile }, "txt", TestAction);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process(["./testFiles/subFolder", testFile], "txt", TestAction);
             Assert.Empty(errors);
             Assert.True(CheckResult(result, expectedInSubFolder));
         }
@@ -93,9 +94,10 @@ namespace ProcessFilesTests
                 result = Path.GetFileName(value);
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { testFile }, "txt", TestAction);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process([testFile], "txt", TestAction);
             Assert.Empty(errors);
-            Assert.Equal(expectedInFolder, result);
+            Assert.Equal(ExpectedInFolder, result);
         }
 
         [Fact]
@@ -107,7 +109,8 @@ namespace ProcessFilesTests
                 result = value;
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { "./testFiles/test.txt" }, "txt", TestAction);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process(["./testFiles/test.txt"], "txt", TestAction);
             Assert.NotEmpty(errors);
             Assert.Empty(result);
         }
@@ -121,7 +124,8 @@ namespace ProcessFilesTests
                 result = value;
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { testFile }, "abc", TestAction);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process([testFile], "abc", TestAction);
             Assert.NotEmpty(errors);
             Assert.Empty(result);
         }
@@ -135,9 +139,40 @@ namespace ProcessFilesTests
                 result.Add(Path.GetFileName(value));
             }
 
-            var errors = ProcessFiles.ProcessFiles.Process(new[] { testFolder }, new[] { "txt", "json" }, TestAction, true);
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process([testFolder], ["txt", "json"], TestAction, true);
             Assert.Empty(errors);
             Assert.True(CheckResult(result, expectedInSubFolderMultipleExtensions));
         }
+        
+        [Fact]
+        public void ProcessWhenActionInvokesProcessShouldPreserveOuterErrors()
+        {
+            var missingPath = Path.Combine(testFolder, "missing.txt");
+            var nestedMissingPath = Path.Combine(testFolder, "nested-missing.txt");
+
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process(
+                [missingPath, testFile],
+                "txt",
+                _ => test.Process([nestedMissingPath], "txt", _ => { })).ToList();
+
+            Assert.True(errors.Exists(x => x.StartsWith($"Problem getting attributes of {missingPath}")));
+            Assert.True(errors.Exists(x => x.StartsWith($"Problem getting attributes of {nestedMissingPath}")));
+        }
+
+        [Fact]
+        public void ProcessDirectoryEnumerationFailureShouldBeReportedAsError()
+        {
+            var test = new ProcessFiles.ProcessFiles();
+            var errors = test.Process(
+                [testFolder],
+                ["txt["], // invalid search pattern forces Directory.GetFiles to throw
+                _ => { }).ToList();
+
+            Assert.Single(errors);
+            Assert.Contains(testFolder, errors[0]);
+            Assert.Contains("txt[", errors[0]);
+        }
     }
 }

+ 2 - 2
ProcessFilesTests/ProcessFilesTests.csproj

@@ -23,9 +23,9 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
     <PackageReference Include="xunit" Version="2.9.3" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
+    <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>