Skip to content

Commit 3229ce9

Browse files
feat: add testability for DriveInfo (#1094)
* feat: add testability for drives * review comments --------- Co-authored-by: Valentin Breuß <[email protected]>
1 parent d517e19 commit 3229ce9

File tree

9 files changed

+474
-196
lines changed

9 files changed

+474
-196
lines changed

src/TestableIO.System.IO.Abstractions.TestingHelpers/IMockFileDataAccessor.cs

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ public interface IMockFileDataAccessor : IFileSystem
2323
/// <returns>The file. <see langword="null"/> if the file does not exist.</returns>
2424
MockFileData GetFile(string path);
2525

26+
/// <summary>
27+
/// Gets a drive.
28+
/// </summary>
29+
/// <param name="name">The name of the drive to get.</param>
30+
/// <returns>The drive. <see langword="null"/> if the drive does not exist.</returns>
31+
MockDriveData GetDrive(string name);
32+
2633
/// <summary>
2734
/// </summary>
2835
void AddFile(string path, MockFileData mockFile);
@@ -31,6 +38,10 @@ public interface IMockFileDataAccessor : IFileSystem
3138
/// </summary>
3239
void AddDirectory(string path);
3340

41+
/// <summary>
42+
/// </summary>
43+
void AddDrive(string name, MockDriveData mockDrive);
44+
3445
/// <summary>
3546
/// </summary>
3647
void AddFileFromEmbeddedResource(string path, Assembly resourceAssembly, string embeddedResourcePath);
@@ -74,6 +85,11 @@ public interface IMockFileDataAccessor : IFileSystem
7485
/// </summary>
7586
IEnumerable<string> AllDirectories { get; }
7687

88+
/// <summary>
89+
/// Gets the names of all drives.
90+
/// </summary>
91+
IEnumerable<string> AllDrives { get; }
92+
7793
/// <summary>
7894
/// Gets a helper for string operations.
7995
/// </summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+

2+
namespace System.IO.Abstractions.TestingHelpers
3+
{
4+
/// <summary>
5+
/// The class represents the associated data of a drive.
6+
/// </summary>
7+
#if FEATURE_SERIALIZABLE
8+
[Serializable]
9+
#endif
10+
public class MockDriveData
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="MockDriveData"/> class.
14+
/// </summary>
15+
public MockDriveData()
16+
{
17+
IsReady = true;
18+
}
19+
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="MockDriveData"/> class by copying the given <see cref="MockDriveData"/>.
22+
/// </summary>
23+
/// <param name="template">The template instance.</param>
24+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="template"/> is <see langword="null"/>.</exception>
25+
public MockDriveData(MockDriveData template)
26+
{
27+
if (template == null)
28+
{
29+
throw new ArgumentNullException(nameof(template));
30+
}
31+
32+
AvailableFreeSpace = template.AvailableFreeSpace;
33+
DriveFormat = template.DriveFormat;
34+
DriveType = template.DriveType;
35+
IsReady = template.IsReady;
36+
TotalFreeSpace = template.TotalFreeSpace;
37+
TotalSize = template.TotalSize;
38+
VolumeLabel = template.VolumeLabel;
39+
}
40+
41+
/// <summary>
42+
/// Gets or sets the amount of available free space of the <see cref="MockDriveData"/>, in bytes.
43+
/// </summary>
44+
public long AvailableFreeSpace { get; set; }
45+
46+
/// <summary>
47+
/// Gets or sets the name of the file system of the <see cref="MockDriveData"/>, such as NTFS or FAT32.
48+
/// </summary>
49+
public string DriveFormat { get; set; }
50+
51+
/// <summary>
52+
/// Gets or sets the drive type of the <see cref="MockDriveData"/>, such as CD-ROM, removable, network, or fixed.
53+
/// </summary>
54+
public DriveType DriveType { get; set; }
55+
56+
/// <summary>
57+
/// Gets or sets the value that indicates whether the <see cref="MockDriveData"/> is ready.
58+
/// </summary>
59+
public bool IsReady { get; set; }
60+
61+
/// <summary>
62+
/// Gets or sets the total amount of free space available on the <see cref="MockDriveData"/>, in bytes.
63+
/// </summary>
64+
public long TotalFreeSpace { get; set; }
65+
66+
/// <summary>
67+
/// Gets or sets the total size of storage space on the <see cref="MockDriveData"/>, in bytes.
68+
/// </summary>
69+
public long TotalSize { get; set; }
70+
71+
/// <summary>
72+
/// Gets or sets the volume label of the <see cref="MockDriveData"/>.
73+
/// </summary>
74+
public string VolumeLabel { get; set; }
75+
}
76+
}

src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDriveInfo.cs

+76-33
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,60 @@
77
public class MockDriveInfo : DriveInfoBase
88
{
99
private readonly IMockFileDataAccessor mockFileDataAccessor;
10+
private readonly string name;
1011

1112
/// <inheritdoc />
1213
public MockDriveInfo(IMockFileDataAccessor mockFileDataAccessor, string name) : base(mockFileDataAccessor?.FileSystem)
1314
{
1415
this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor));
16+
this.name = mockFileDataAccessor.PathVerifier.NormalizeDriveName(name);
17+
}
1518

16-
if (name == null)
19+
/// <inheritdoc />
20+
public override long AvailableFreeSpace
21+
{
22+
get
1723
{
18-
throw new ArgumentNullException(nameof(name));
24+
var mockDriveData = GetMockDriveData();
25+
return mockDriveData.AvailableFreeSpace;
1926
}
27+
}
2028

21-
const string DRIVE_SEPARATOR = @":\";
22-
23-
if (name.Length == 1
24-
|| (name.Length == 2 && name[1] == ':')
25-
|| (name.Length == 3 && mockFileDataAccessor.StringOperations.EndsWith(name, DRIVE_SEPARATOR)))
29+
/// <inheritdoc />
30+
public override string DriveFormat
31+
{
32+
get
2633
{
27-
name = name[0] + DRIVE_SEPARATOR;
34+
var mockDriveData = GetMockDriveData();
35+
return mockDriveData.DriveFormat;
2836
}
29-
else
30-
{
31-
mockFileDataAccessor.PathVerifier.CheckInvalidPathChars(name);
32-
name = mockFileDataAccessor.Path.GetPathRoot(name);
37+
}
3338

34-
if (string.IsNullOrEmpty(name) || mockFileDataAccessor.StringOperations.StartsWith(name, @"\\"))
35-
{
36-
throw new ArgumentException(
37-
@"Object must be a root directory (""C:\"") or a drive letter (""C"").");
38-
}
39+
/// <inheritdoc />
40+
public override DriveType DriveType
41+
{
42+
get
43+
{
44+
var mockDriveData = GetMockDriveData();
45+
return mockDriveData.DriveType;
3946
}
40-
41-
Name = name;
42-
IsReady = true;
4347
}
4448

4549
/// <inheritdoc />
46-
public new long AvailableFreeSpace { get; set; }
47-
/// <inheritdoc />
48-
public new string DriveFormat { get; set; }
49-
/// <inheritdoc />
50-
public new DriveType DriveType { get; set; }
51-
/// <inheritdoc />
52-
public new bool IsReady { get; protected set; }
50+
public override bool IsReady
51+
{
52+
get
53+
{
54+
var mockDriveData = GetMockDriveData();
55+
return mockDriveData.IsReady;
56+
}
57+
}
58+
5359
/// <inheritdoc />
54-
public override string Name { get; protected set; }
60+
public override string Name
61+
{
62+
get { return name; }
63+
}
5564

5665
/// <inheritdoc />
5766
public override IDirectoryInfo RootDirectory
@@ -63,16 +72,50 @@ public override IDirectoryInfo RootDirectory
6372
}
6473

6574
/// <inheritdoc />
66-
public override string ToString()
75+
public override long TotalFreeSpace
6776
{
68-
return Name;
77+
get
78+
{
79+
var mockDriveData = GetMockDriveData();
80+
return mockDriveData.TotalFreeSpace;
81+
}
6982
}
7083

7184
/// <inheritdoc />
72-
public new long TotalFreeSpace { get; protected set; }
85+
public override long TotalSize
86+
{
87+
get
88+
{
89+
var mockDriveData = GetMockDriveData();
90+
return mockDriveData.TotalSize;
91+
}
92+
}
93+
7394
/// <inheritdoc />
74-
public new long TotalSize { get; protected set; }
95+
public override string VolumeLabel
96+
{
97+
get
98+
{
99+
var mockDriveData = GetMockDriveData();
100+
return mockDriveData.VolumeLabel;
101+
}
102+
set
103+
{
104+
var mockDriveData = GetMockDriveData();
105+
mockDriveData.VolumeLabel = value;
106+
}
107+
}
108+
75109
/// <inheritdoc />
76-
public override string VolumeLabel { get; set; }
110+
public override string ToString()
111+
{
112+
return Name;
113+
}
114+
115+
private MockDriveData GetMockDriveData()
116+
{
117+
return mockFileDataAccessor.GetDrive(name)
118+
?? throw CommonExceptions.FileNotFound(name);
119+
}
77120
}
78121
}

src/TestableIO.System.IO.Abstractions.TestingHelpers/MockDriveInfoFactory.cs

+1-8
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,8 @@ public IFileSystem FileSystem
2323
/// <inheritdoc />
2424
public IDriveInfo[] GetDrives()
2525
{
26-
var driveLetters = new HashSet<string>(new DriveEqualityComparer(mockFileSystem));
27-
foreach (var path in mockFileSystem.AllPaths)
28-
{
29-
var pathRoot = mockFileSystem.Path.GetPathRoot(path);
30-
driveLetters.Add(pathRoot);
31-
}
32-
3326
var result = new List<DriveInfoBase>();
34-
foreach (string driveLetter in driveLetters)
27+
foreach (string driveLetter in mockFileSystem.AllDrives)
3528
{
3629
try
3730
{

0 commit comments

Comments
 (0)