Skip to content

Commit ade59ac

Browse files
rkoeningerfgreinacher
authored andcommitted
Make paths case-sensitive on Unix (#418)
Fixes #321 Fixes #395 Fixes #405 * Added StringComparer to MockFileSystem, used in Mock* classes * Removed drive letter ToUpper in MockDriveInfo * Labelled tests as being Windows/Unix specific based on case sensitivity * Corrected UnixOnly test to check for null * Adjusted *Specifics wording * Fixed MockDirectory.GetParent to correctly identify and return '/' root * Fixed MockDirectory.GetFiles to handle un-normalized slashes * Made NormalizeSlashes handle UNC paths * Moved Exists check in MockDirectory.GetFiles into GetFilesInternal after path normalization * Made MockDirectory.GetLogicalDrives return drive letters in upper case instead of lower case * Fixed GetLogicalDrives test * De-triplicated check for Directory.Exists(DirName(FullPath(p))) * Added StringOperations, used throughout Mock* classes Cleaned up MockFileExistsTests, MockFileSystemTests * Removed WindowsSpecifics.EmptyInvalidPathChars Removed WindowsOnly label from the one that that used this reason * Made MockDirectory_GetParent_ShouldThr... WindowsOnly again because of Windows' stricter path rules * Combined private CheckDirectoryExists and VerifyDir... in MockFile * Cleanup, review change, in MockFileExistsTests
1 parent 47f8baa commit ade59ac

21 files changed

+413
-287
lines changed

System.IO.Abstractions.TestingHelpers.Tests/MockDirectoryTests.cs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,10 @@ public void MockDirectory_CreateDirectory_ShouldWorkWithUNCPath()
547547
var fileSystem = new MockFileSystem();
548548

549549
// Act
550-
fileSystem.Directory.CreateDirectory(XFS.Path(@"\\server\share\path\to\create", () => false));
550+
fileSystem.Directory.CreateDirectory(@"\\server\share\path\to\create");
551551

552552
// Assert
553-
Assert.IsTrue(fileSystem.Directory.Exists(XFS.Path(@"\\server\share\path\to\create\", () => false)));
553+
Assert.IsTrue(fileSystem.Directory.Exists(@"\\server\share\path\to\create\"));
554554
}
555555

556556
[Test]
@@ -561,7 +561,7 @@ public void MockDirectory_CreateDirectory_ShouldFailIfTryingToCreateUNCPathOnlyS
561561
var fileSystem = new MockFileSystem();
562562

563563
// Act
564-
var ex = Assert.Throws<ArgumentException>(() => fileSystem.Directory.CreateDirectory(XFS.Path(@"\\server", () => false)));
564+
var ex = Assert.Throws<ArgumentException>(() => fileSystem.Directory.CreateDirectory(@"\\server"));
565565

566566
// Assert
567567
StringAssert.StartsWith("The UNC path should be of the form \\\\server\\share.", ex.Message);
@@ -576,10 +576,10 @@ public void MockDirectory_CreateDirectory_ShouldSucceedIfTryingToCreateUNCPathSh
576576
var fileSystem = new MockFileSystem();
577577

578578
// Act
579-
fileSystem.Directory.CreateDirectory(XFS.Path(@"\\server\share", () => false));
579+
fileSystem.Directory.CreateDirectory(@"\\server\share");
580580

581581
// Assert
582-
Assert.IsTrue(fileSystem.Directory.Exists(XFS.Path(@"\\server\share\", () => false)));
582+
Assert.IsTrue(fileSystem.Directory.Exists(@"\\server\share\"));
583583
}
584584

585585
[Test]
@@ -599,6 +599,7 @@ public void MockDirectory_Delete_ShouldDeleteDirectory()
599599
}
600600

601601
[Test]
602+
[WindowsOnly(WindowsSpecifics.CaseInsensitivity)]
602603
public void MockDirectory_Delete_ShouldDeleteDirectoryCaseInsensitively()
603604
{
604605
// Arrange
@@ -614,6 +615,40 @@ public void MockDirectory_Delete_ShouldDeleteDirectoryCaseInsensitively()
614615
Assert.IsFalse(fileSystem.Directory.Exists(XFS.Path(@"c:\bar")));
615616
}
616617

618+
[Test]
619+
[UnixOnly(UnixSpecifics.CaseSensitivity)]
620+
public void MockDirectory_Delete_ShouldThrowDirectoryNotFoundException_WhenSpecifiedWithInDifferentCase()
621+
{
622+
// Arrange
623+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
624+
{
625+
{ "/bar/foo.txt", new MockFileData("Demo text content") }
626+
});
627+
628+
// Act
629+
TestDelegate action = () => fileSystem.Directory.Delete("/BAR", true);
630+
631+
// Assert
632+
Assert.Throws<DirectoryNotFoundException>(action);
633+
}
634+
635+
[Test]
636+
[UnixOnly(UnixSpecifics.CaseSensitivity)]
637+
public void MockDirectory_Delete_ShouldDeleteDirectoryCaseSensitively()
638+
{
639+
// Arrange
640+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
641+
{
642+
{ "/bar/foo.txt", new MockFileData("Demo text content") }
643+
});
644+
645+
// Act
646+
fileSystem.Directory.Delete("/bar", true);
647+
648+
// Assert
649+
Assert.IsFalse(fileSystem.Directory.Exists("/bar"));
650+
}
651+
617652
[Test]
618653
public void MockDirectory_Delete_ShouldThrowDirectoryNotFoundException()
619654
{
@@ -849,8 +884,8 @@ public void MockDirectory_GetLogicalDrives_Returns_LogicalDrives()
849884
else
850885
{
851886
Assert.AreEqual(2, drives.Length);
852-
Assert.IsTrue(drives.Contains("c:\\"));
853-
Assert.IsTrue(drives.Contains("d:\\"));
887+
Assert.IsTrue(drives.Contains(@"C:\"));
888+
Assert.IsTrue(drives.Contains(@"D:\"));
854889
}
855890
}
856891
#endif
@@ -1250,14 +1285,9 @@ public void MockDirectory_GetParent_ShouldReturnADirectoryInfoIfPathDoesNotExist
12501285
}
12511286

12521287
[Test]
1288+
[WindowsOnly(WindowsSpecifics.StrictPathRules)]
12531289
public void MockDirectory_GetParent_ShouldThrowArgumentExceptionIfPathHasIllegalCharacters()
12541290
{
1255-
if (XFS.IsUnixPlatform())
1256-
{
1257-
Assert.Pass("Path.GetInvalidChars() does not return anything on Mono");
1258-
return;
1259-
}
1260-
12611291
// Arrange
12621292
var fileSystem = new MockFileSystem();
12631293

@@ -1282,6 +1312,21 @@ public void MockDirectory_GetParent_ShouldReturnNullIfPathIsRoot()
12821312
Assert.IsNull(actualResult);
12831313
}
12841314

1315+
[Test]
1316+
[UnixOnly(UnixSpecifics.SlashRoot)]
1317+
public void MockDirectory_GetParent_ShouldReturnRootIfDirectoryIsInRoot()
1318+
{
1319+
// Arrange
1320+
var fileSystem = new MockFileSystem();
1321+
fileSystem.AddDirectory("/bar");
1322+
1323+
// Act
1324+
var parent = fileSystem.Directory.GetParent("/bar");
1325+
1326+
// Assert
1327+
Assert.AreEqual("/", parent.FullName);
1328+
}
1329+
12851330
public static IEnumerable<string[]> MockDirectory_GetParent_Cases
12861331
{
12871332
get

System.IO.Abstractions.TestingHelpers.Tests/MockFileExistsTests.cs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,70 @@ namespace System.IO.Abstractions.TestingHelpers.Tests
66

77
using XFS = MockUnixSupport;
88

9-
public class MockFileExistsTests {
9+
public class MockFileExistsTests
10+
{
1011
[Test]
1112
public void MockFile_Exists_ShouldReturnTrueForSamePath()
1213
{
1314
// Arrange
1415
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
1516
{
16-
{ XFS.Path(@"c:\something\demo.txt"), new MockFileData("Demo text content") },
17-
{ XFS.Path(@"c:\something\other.gif"), new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
17+
{ XFS.Path(@"C:\something\other.gif"), new MockFileData("gif content") }
1818
});
1919

20-
var file = new MockFile(fileSystem);
21-
2220
// Act
23-
var result = file.Exists(XFS.Path(@"c:\something\other.gif"));
21+
var result = fileSystem.File.Exists(XFS.Path(@"C:\something\other.gif"));
2422

2523
// Assert
2624
Assert.IsTrue(result);
2725
}
2826

2927
[Test]
28+
[WindowsOnly(WindowsSpecifics.CaseInsensitivity)]
3029
public void MockFile_Exists_ShouldReturnTrueForPathVaryingByCase()
3130
{
3231
// Arrange
3332
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
3433
{
35-
{ XFS.Path(@"c:\something\demo.txt"), new MockFileData("Demo text content") },
36-
{ XFS.Path(@"c:\something\other.gif"), new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
34+
{ @"C:\something\demo.txt", new MockFileData("Demo text content") }
3735
});
3836

39-
var file = new MockFile(fileSystem);
40-
4137
// Act
42-
var result = file.Exists(XFS.Path(@"c:\SomeThing\Other.gif"));
38+
var result = fileSystem.File.Exists(@"C:\SomeThing\DEMO.txt");
4339

4440
// Assert
4541
Assert.IsTrue(result);
4642
}
4743

4844
[Test]
49-
public void MockFile_Exists_ShouldReturnFalseForEntirelyDifferentPath()
45+
[UnixOnly(UnixSpecifics.CaseSensitivity)]
46+
public void MockFile_Exists_ShouldReturnFalseForPathVaryingByCase()
5047
{
5148
// Arrange
5249
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
5350
{
54-
{ XFS.Path(@"c:\something\demo.txt"), new MockFileData("Demo text content") },
55-
{ XFS.Path(@"c:\something\other.gif"), new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
51+
{ "/something/demo.txt", new MockFileData("Demo text content") }
5652
});
5753

58-
var file = new MockFile(fileSystem);
54+
// Act
55+
var result = fileSystem.File.Exists("/SomeThing/DEMO.txt");
56+
57+
// Assert
58+
Assert.IsFalse(result);
59+
}
60+
61+
[Test]
62+
public void MockFile_Exists_ShouldReturnFalseForEntirelyDifferentPath()
63+
{
64+
// Arrange
65+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
66+
{
67+
{ XFS.Path(@"C:\something\demo.txt"), new MockFileData("Demo text content") },
68+
{ XFS.Path(@"C:\something\other.gif"), new MockFileData("gif content") }
69+
});
5970

6071
// Act
61-
var result = file.Exists(XFS.Path(@"c:\SomeThing\DoesNotExist.gif"));
72+
var result = fileSystem.File.Exists(XFS.Path(@"C:\SomeThing\DoesNotExist.gif"));
6273

6374
// Assert
6475
Assert.IsFalse(result);
@@ -67,9 +78,14 @@ public void MockFile_Exists_ShouldReturnFalseForEntirelyDifferentPath()
6778
[Test]
6879
public void MockFile_Exists_ShouldReturnFalseForNullPath()
6980
{
70-
var file = new MockFile(new MockFileSystem());
81+
// Arrange
82+
var fileSystem = new MockFileSystem();
7183

72-
Assert.That(file.Exists(null), Is.False);
84+
// Act
85+
var result = fileSystem.File.Exists(null);
86+
87+
// Assert
88+
Assert.IsFalse(result);
7389
}
7490

7591
[Test]
@@ -78,14 +94,12 @@ public void MockFile_Exists_ShouldReturnFalseForDirectories()
7894
// Arrange
7995
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
8096
{
81-
{ XFS.Path(@"c:\something\demo.txt"), new MockFileData("Demo text content") },
82-
{ XFS.Path(@"c:\something\other.gif"), new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
97+
{ XFS.Path(@"C:\something\demo.txt"), new MockFileData("Demo text content") },
98+
{ XFS.Path(@"C:\something\other.gif"), new MockFileData("gif content") }
8399
});
84100

85-
var file = new MockFile(fileSystem);
86-
87101
// Act
88-
var result = file.Exists(XFS.Path(@"c:\SomeThing\"));
102+
var result = fileSystem.File.Exists(XFS.Path(@"C:\something\"));
89103

90104
// Assert
91105
Assert.IsFalse(result);

System.IO.Abstractions.TestingHelpers.Tests/MockFileSystemTests.cs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public void MockFileSystem_GetFile_ShouldReturnNullWhenFileIsNotRegistered()
1717
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
1818
{
1919
{ @"c:\something\demo.txt", new MockFileData("Demo\r\ntext\ncontent\rvalue") },
20-
{ @"c:\something\other.gif", new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
20+
{ @"c:\something\other.gif", new MockFileData("gif content") }
2121
});
2222

2323
var result = fileSystem.GetFile(@"c:\something\else.txt");
@@ -32,7 +32,7 @@ public void MockFileSystem_GetFile_ShouldReturnFileRegisteredInConstructor()
3232
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
3333
{
3434
{ @"c:\something\demo.txt", file1 },
35-
{ @"c:\something\other.gif", new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
35+
{ @"c:\something\other.gif", new MockFileData("gif content") }
3636
});
3737

3838
var result = fileSystem.GetFile(@"c:\something\demo.txt");
@@ -41,37 +41,70 @@ public void MockFileSystem_GetFile_ShouldReturnFileRegisteredInConstructor()
4141
}
4242

4343
[Test]
44+
[WindowsOnly(WindowsSpecifics.CaseInsensitivity)]
4445
public void MockFileSystem_GetFile_ShouldReturnFileRegisteredInConstructorWhenPathsDifferByCase()
4546
{
4647
var file1 = new MockFileData("Demo\r\ntext\ncontent\rvalue");
4748
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
4849
{
4950
{ @"c:\something\demo.txt", file1 },
50-
{ @"c:\something\other.gif", new MockFileData(new byte[] { 0x21, 0x58, 0x3f, 0xa9 }) }
51+
{ @"c:\something\other.gif", new MockFileData("gif content") }
5152
});
5253

5354
var result = fileSystem.GetFile(@"c:\SomeThing\DEMO.txt");
5455

5556
Assert.AreEqual(file1, result);
5657
}
5758

59+
[Test]
60+
[UnixOnly(UnixSpecifics.CaseSensitivity)]
61+
public void MockFileSystem_GetFile_ShouldNotReturnFileRegisteredInConstructorWhenPathsDifferByCase()
62+
{
63+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
64+
{
65+
{ "/something/demo.txt", new MockFileData("Demo\r\ntext\ncontent\rvalue") },
66+
{ "/something/other.gif", new MockFileData("gif content") }
67+
});
68+
69+
var result = fileSystem.GetFile("/SomeThing/DEMO.txt");
70+
71+
Assert.IsNull(result);
72+
}
73+
74+
[Test]
75+
public void MockFileSystem_AddFile_ShouldHandleUnnormalizedSlashes()
76+
{
77+
var path = XFS.Path(@"c:\d1\d2\file.txt");
78+
var alternatePath = XFS.Path("c:/d1/d2/file.txt");
79+
var alternateParentPath = XFS.Path("c://d1//d2/");
80+
var fs = new MockFileSystem();
81+
fs.AddFile(path, new MockFileData("Hello"));
82+
83+
var fileCount = fs.Directory.GetFiles(alternateParentPath).Length;
84+
var fileExists = fs.File.Exists(alternatePath);
85+
86+
Assert.AreEqual(1, fileCount);
87+
Assert.IsTrue(fileExists);
88+
}
89+
5890
[Test]
5991
public void MockFileSystem_AddFile_ShouldHandleNullFileDataAsEmpty()
6092
{
93+
var path = XFS.Path(@"c:\something\nullish.txt");
6194
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
6295
{
63-
{ @"c:\something\nullish.txt", null }
96+
{ path, null }
6497
});
6598

66-
var result = fileSystem.File.ReadAllText(@"c:\SomeThing\nullish.txt");
99+
var result = fileSystem.File.ReadAllText(path);
67100

68101
Assert.IsEmpty(result, "Null MockFileData should be allowed for and result in an empty file.");
69102
}
70103

71104
[Test]
72105
public void MockFileSystem_AddFile_ShouldRepaceExistingFile()
73106
{
74-
const string path = @"c:\some\file.txt";
107+
var path = XFS.Path(@"c:\some\file.txt");
75108
const string existingContent = "Existing content";
76109
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
77110
{
@@ -157,6 +190,7 @@ public void MockFileSystem_AddFile_ShouldMatchCapitalization_PerfectMatch()
157190
}
158191

159192
[Test]
193+
[WindowsOnly(WindowsSpecifics.CaseInsensitivity)]
160194
public void MockFileSystem_AddFile_ShouldMatchCapitalization_PartialMatch()
161195
{
162196
var fileSystem = new MockFileSystem();
@@ -175,6 +209,7 @@ public void MockFileSystem_AddFile_ShouldMatchCapitalization_PartialMatch()
175209
}
176210

177211
[Test]
212+
[WindowsOnly(WindowsSpecifics.CaseInsensitivity)]
178213
public void MockFileSystem_AddFile_ShouldMatchCapitalization_PartialMatch_FurtherLeft()
179214
{
180215
var fileSystem = new MockFileSystem();

System.IO.Abstractions.TestingHelpers.Tests/MockUnixSupportTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22

33
namespace System.IO.Abstractions.TestingHelpers.Tests
44
{
5+
using XFS = MockUnixSupport;
6+
57
[TestFixture]
68
public class MockUnixSupportTests
79
{
810
[Test]
11+
[UnixOnly(UnixSpecifics.SlashRoot)]
912
public void Should_Convert_Backslashes_To_Slashes_On_Unix()
1013
{
11-
Assert.AreEqual("/test/", MockUnixSupport.Path(@"\test\", () => true));
14+
Assert.AreEqual("/test/", XFS.Path(@"\test\"));
1215
}
1316

1417
[Test]
18+
[UnixOnly(UnixSpecifics.SlashRoot)]
1519
public void Should_Remove_Drive_Letter_On_Unix()
1620
{
17-
Assert.AreEqual("/test/", MockUnixSupport.Path(@"c:\test\", () => true));
21+
Assert.AreEqual("/test/", XFS.Path(@"c:\test\"));
1822
}
1923
}
2024
}

System.IO.Abstractions.TestingHelpers.Tests/UnixSpecifics.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
{
33
internal static class UnixSpecifics
44
{
5-
public const string SlashRoot = "Filesystem root is just '/' in Unix";
5+
public const string SlashRoot = "Filesystem root is just '/' on Unix";
6+
7+
public const string CaseSensitivity = "Paths are case-sensitive on Unix";
68
}
79
}

0 commit comments

Comments
 (0)