Skip to content

Commit ea4a6ce

Browse files
authored
Small enhancements for IO file sys operations (#67)
* Add support for directory and file path validation utilities and register file system services - Introduced `DirectoryExtensions` with methods for ensuring directory existence. - Added `IOServiceCollectionExtensions` to enable dependency injection for file system abstractions. * Add unit tests for `DirectoryExtensions` to validate directory creation logic - Introduced comprehensive tests for `EnsureDirectoryExists` and `EnsureDirectoryForFileNameExists`. - Covered edge cases for null, empty, and whitespace paths. * Suppress nullable warnings in `EnumerableStringExtensions` and adjust null-forgiving operator usage in `ToDictionary` method
1 parent d96f12e commit ea4a6ce

4 files changed

Lines changed: 161 additions & 1 deletion

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.IO.Abstractions;
2+
3+
#nullable enable
4+
5+
namespace CreativeCoders.Core.IO;
6+
7+
public static class DirectoryExtensions
8+
{
9+
public static void EnsureDirectoryExists(this IDirectory directory, string? directoryPath)
10+
{
11+
if (string.IsNullOrWhiteSpace(directoryPath))
12+
{
13+
return;
14+
}
15+
16+
directory.CreateDirectory(directoryPath);
17+
}
18+
19+
public static void EnsureDirectoryForFileNameExists(this IDirectory directory, string? filePath)
20+
{
21+
if (string.IsNullOrWhiteSpace(filePath))
22+
{
23+
return;
24+
}
25+
26+
var directoryPath = directory.FileSystem.Path.GetDirectoryName(filePath);
27+
if (string.IsNullOrWhiteSpace(directoryPath))
28+
{
29+
return;
30+
}
31+
32+
directory.CreateDirectory(directoryPath);
33+
}
34+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.IO.Abstractions;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.DependencyInjection.Extensions;
5+
6+
namespace CreativeCoders.Core.IO;
7+
8+
[ExcludeFromCodeCoverage]
9+
public static class IOServiceCollectionExtensions
10+
{
11+
public static IServiceCollection AddFileSystem(this IServiceCollection services)
12+
{
13+
services.TryAddSingleton<IFileSystem, FileSystemEx>();
14+
services.TryAddSingleton<IFileSystemEx, FileSystemEx>();
15+
16+
return services;
17+
}
18+
}

source/Core/CreativeCoders.Core/Text/EnumerableStringExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace CreativeCoders.Core.Text;
1010

1111
public static class EnumerableStringExtensions
1212
{
13+
[SuppressMessage("ReSharper", "NullableWarningSuppressionIsUsed")]
1314
public static Dictionary<string, string> ToDictionary(this IEnumerable<string> items, string separator,
1415
bool ignoreInvalidEntries = true)
1516
{
@@ -27,7 +28,7 @@ public static Dictionary<string, string> ToDictionary(this IEnumerable<string> i
2728

2829
return x != null;
2930
})
30-
.ToDictionary(x => x.Key, x => x.Value);
31+
.ToDictionary(x => x!.Key, x => x!.Value);
3132
}
3233

3334
[ExcludeFromCodeCoverage]
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System.IO.Abstractions;
2+
using CreativeCoders.Core.IO;
3+
using FakeItEasy;
4+
using AwesomeAssertions;
5+
using Xunit;
6+
7+
#nullable enable
8+
namespace CreativeCoders.Core.UnitTests.IO;
9+
10+
public class DirectoryExtensionsTests
11+
{
12+
[Fact]
13+
public void EnsureDirectoryExists_ValidPath_CreatesDirectory()
14+
{
15+
// Arrange
16+
var directory = A.Fake<IDirectory>();
17+
const string path = "/test/path";
18+
19+
// Act
20+
directory.EnsureDirectoryExists(path);
21+
22+
// Assert
23+
A.CallTo(() => directory.CreateDirectory(path))
24+
.MustHaveHappenedOnceExactly();
25+
}
26+
27+
[Theory]
28+
[InlineData(null)]
29+
[InlineData("")]
30+
[InlineData(" ")]
31+
public void EnsureDirectoryExists_NullOrEmptyPath_DoesNotCreateDirectory(string? path)
32+
{
33+
// Arrange
34+
var directory = A.Fake<IDirectory>();
35+
36+
// Act
37+
directory.EnsureDirectoryExists(path);
38+
39+
// Assert
40+
A.CallTo(() => directory.CreateDirectory(A<string>._))
41+
.MustNotHaveHappened();
42+
}
43+
44+
[Fact]
45+
public void EnsureDirectoryForFileNameExists_ValidFilePath_CreatesDirectory()
46+
{
47+
// Arrange
48+
var directory = A.Fake<IDirectory>();
49+
var fileSystem = A.Fake<IFileSystem>();
50+
var pathMock = A.Fake<IPath>();
51+
52+
A.CallTo(() => directory.FileSystem).Returns(fileSystem);
53+
A.CallTo(() => fileSystem.Path).Returns(pathMock);
54+
55+
const string filePath = "/test/path/file.txt";
56+
const string directoryPath = "/test/path";
57+
58+
A.CallTo(() => pathMock.GetDirectoryName(filePath)).Returns(directoryPath);
59+
60+
// Act
61+
directory.EnsureDirectoryForFileNameExists(filePath);
62+
63+
// Assert
64+
A.CallTo(() => directory.CreateDirectory(directoryPath))
65+
.MustHaveHappenedOnceExactly();
66+
}
67+
68+
[Theory]
69+
[InlineData(null)]
70+
[InlineData("")]
71+
[InlineData(" ")]
72+
public void EnsureDirectoryForFileNameExists_NullOrEmptyFilePath_DoesNotCreateDirectory(string? filePath)
73+
{
74+
// Arrange
75+
var directory = A.Fake<IDirectory>();
76+
77+
// Act
78+
directory.EnsureDirectoryForFileNameExists(filePath);
79+
80+
// Assert
81+
A.CallTo(() => directory.CreateDirectory(A<string>._))
82+
.MustNotHaveHappened();
83+
}
84+
85+
[Fact]
86+
public void EnsureDirectoryForFileNameExists_GetDirectoryNameReturnsNull_DoesNotCreateDirectory()
87+
{
88+
// Arrange
89+
var directory = A.Fake<IDirectory>();
90+
var fileSystem = A.Fake<IFileSystem>();
91+
var pathMock = A.Fake<IPath>();
92+
93+
A.CallTo(() => directory.FileSystem).Returns(fileSystem);
94+
A.CallTo(() => fileSystem.Path).Returns(pathMock);
95+
96+
const string filePath = "file.txt";
97+
98+
A.CallTo(() => pathMock.GetDirectoryName(filePath)).Returns(null);
99+
100+
// Act
101+
directory.EnsureDirectoryForFileNameExists(filePath);
102+
103+
// Assert
104+
A.CallTo(() => directory.CreateDirectory(A<string>._))
105+
.MustNotHaveHappened();
106+
}
107+
}

0 commit comments

Comments
 (0)