New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PathVerifier should check specifically for invalid use of volume separator and tolerate alt dir separator #327
PathVerifier should check specifically for invalid use of volume separator and tolerate alt dir separator #327
Conversation
@@ -191,6 +197,64 @@ public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenTargetFileNameCont | |||
} | |||
} | |||
|
|||
[Test] | |||
[WindowsOnly(WindowsSpecifics.StrictPathRules + "; Mono does not raise this exception")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not WindowsSpecifics.Drives
? This way we wouldn't need the additional text. Same for the other new tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, used Drives
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this. I left a couple of comments.
var badDestinationPath = XFS.Path(@"^:\elsewhere\demo.txt"); | ||
var fileSystem = new MockFileSystem(); | ||
fileSystem.AddFile(sourcePath, new MockFileData("1")); | ||
fileSystem.AddDirectory(destinationFolder); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying the tests themselves are necessary? They're the only place the NotSupportedException
throws are tested, which is the impetus for the PR. There's a test for each potential issue with the volume separator (which would cause the NSE
), for each of sourcePath
and destinationPath
, for each of Move
and Copy
- that's the 8 tests.
Are these 5 particular ones redundant? I thought people would complain about a lack of coverage if I didn't add of these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant just the line above (and the variable), where you add some directory that doesn’t seem to be necessary for the test. Sorry for being unclear on this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, Ok. I re-visited all 8 of those tests and found that creating the source file and destination folder was not necessary to produce the error, so I removed those parts. They just create a file system and attempt the move/copy and assert the NotSupportedException
is raised.
[WindowsOnly(WindowsSpecifics.StrictPathRules + "; Mono does not raise this exception")] | ||
public void MockFile_Move_ShouldThrowNotSupportedExceptionWhenSourcePathContainsInvalidUseOfDriveSeparator() | ||
{ | ||
var sourcePath = XFS.Path(@"C:\something\demo.txt"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unnecessary.
[WindowsOnly(WindowsSpecifics.StrictPathRules + "; Mono does not raise this exception")] | ||
public void MockFile_Move_ShouldThrowNotSupportedExceptionWhenSourcePathContainsInvalidDriveLetter() | ||
{ | ||
var sourcePath = XFS.Path(@"C:\something\demo.txt"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unnecessary.
public void MockFile_Move_ShouldThrowNotSupportedExceptionWhenDestinationPathContainsInvalidUseOfDriveSeparator() | ||
{ | ||
var sourcePath = XFS.Path(@"C:\something\demo.txt"); | ||
var destinationFolder = XFS.Path(@"C:\elsewhere"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unnecessary.
public void MockFile_Move_ShouldThrowNotSupportedExceptionWhenDestinationPathContainsInvalidDriveLetter() | ||
{ | ||
var sourcePath = XFS.Path(@"C:\something\demo.txt"); | ||
var destinationFolder = XFS.Path(@"C:\elsewhere"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unnecessary.
TestingHelpers/PathVerifier.cs
Outdated
if (path.Length > 0 && path[0] == Path.VolumeSeparatorChar | ||
|| path.Length > 1 && path[1] == Path.VolumeSeparatorChar && !char.IsLetter(path[0]) | ||
|| path.LastIndexOf(Path.VolumeSeparatorChar) > 1) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole condition is a bit too dense for me. Maybe extract some intermediate variables or helper methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to private static
method and simplified expression. Almost added a comment, but I think the new code doesn't need it: lastVolSepIndex == -1 || lastVolSepIndex == 1 && char.IsLetter(path[0])
foreach (var invalidChar in fileSystem.Path.GetInvalidFileNameChars() | ||
.Where(x => x != fileSystem.Path.DirectorySeparatorChar | ||
&& x != fileSystem.Path.AltDirectorySeparatorChar | ||
&& x != fileSystem.Path.VolumeSeparatorChar)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment that explains why exclude some characters here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comments explaining why they're excluded and moved to local char[]
show I could just use .Except()
instead of length .Where()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also handled same case in Move tests
foreach (var invalidChar in fileSystem.Path.GetInvalidFileNameChars() | ||
.Where(x => x != fileSystem.Path.DirectorySeparatorChar | ||
&& x != fileSystem.Path.AltDirectorySeparatorChar | ||
&& x != fileSystem.Path.VolumeSeparatorChar)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did same here
@fgreinacher Applied suggested changes. Made code simpler and easier to understand. Thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -106,8 +106,19 @@ public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenSourceFileNameCont | |||
|
|||
var destFilePath = XFS.Path(@"c:\something\demo.txt"); | |||
var fileSystem = new MockFileSystem(); | |||
var excludeChars = new [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This list, comments and all, is introduced four times throughout the PR. I think there's value in pulling this out into a static constant helper file that we can just pull from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a class called Shared
to contain the building of the chars. There isn't a very good name for them though, as they're just chars that don't have ArgumentException
to be raised. So it's called SpecialInvalidPathChars
.
@@ -120,7 +131,7 @@ public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenSourceFileNameCont | |||
} | |||
|
|||
[Test] | |||
public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenSourcePathContainsInvalidChars_Message() | |||
public void MockFile_Copy_ShouldThrowArgumentExceptionWhenSourcePathContainsInvalidChars_Message() | |||
{ | |||
if (XFS.IsUnixPlatform()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not necessarily part of the PR, we're touching the line right above it. It'd be nice to push forward and get rid of these if() checks and use the attribute.
@@ -120,7 +131,7 @@ public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenSourceFileNameCont | |||
} | |||
|
|||
[Test] | |||
public void MockFile_Copy_ShouldThrowNotSupportedExceptionWhenSourcePathContainsInvalidChars_Message() | |||
public void MockFile_Copy_ShouldThrowArgumentExceptionWhenSourcePathContainsInvalidChars_Message() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not necessarily part of the PR, we're touching the line right above it. It'd be nice to push forward and get rid of these if() checks and use the attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done for this and 3 other similar tests.
} | ||
|
||
[Test] | ||
[WindowsOnly(WindowsSpecifics.Drives)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this necessarily be a Windows only feature? I may need to look into it more, but the C:\ path will just be converted to a unix path, along the lines of /tmp/some/dir, and I would think /elsewhere:/demo.txt would be a valid case and something to test against a Unix environment.
Tests verify behavior, skipping them on an environment doesn't prevent the behavioral changes from going through, they just make us blind to the side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the docs for Path.VolumeSeparatorChar:
The value of this field is a colon (:) on Windows and Macintosh, and a slash (/) on UNIX operating systems. This is most useful for parsing paths such as "c:\windows" or "MacVolume:System Folder".
So on Unix, the test would just be inserting a /
, which wouldn't cause any exception to be raised.
Drives
isn't exactly the reason why the test is Windows-only, but Unix doesn't have an analog to the :
on Windows, so there's no analog for this test on Unix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this approach is fine. @jpreese Any objections left?
|
||
fileSystem.AddFile(XFS.Path(@"C:\test.txt"), new MockFileData("content")); | ||
|
||
Assert.AreEqual("content", fileSystem.File.ReadAllText(XFS.Path("C:/test.txt"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the test is ReadAllBytes, but we're calling ReadAllText. It also looks like were hardcoding the forward slash. If AltDirectorySeparator were to change, this test might not make anymore sense. If you want to specifically test forward slash, I'd probably prefer calling out the way that were honestly just testing forwards and backwards slashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used byte array instead and built paths using fileSystem.Path.DirectorySeparatorChar
and .AltDirectorySeparatorChar
.
var destinationPath = XFS.Path(@"C:\elsewhere\demo.txt"); | ||
var fileSystem = new MockFileSystem(); | ||
|
||
Assert.Throws<NotSupportedException>(() => fileSystem.File.Copy(badSourcePath, destinationPath)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit, but it's generally preferred to split up the Act and Assert steps.
TestDelegate action = () => fileSystem.File.Copy(badSourcePath, destinationPath);
Assert.Throws<NotSupportedException>(action);
Makes the debugging and readability story a bit better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not my style, but sure, done.
Used [WindowsOnly] instead of if (IsUnix) Split delegates out of Assert.Throws onto separate line
...and no longer hard-codes forward slash
@jpreese Made suggested changes, except for the volume separator one, which I don't know what to do for. |
Merging this one. If we want to do something for the volume separator disuccuisb we can do that in a separate PR. |
Fixes #283
Fixes #320
^ Lots of information on the issue (#320) about how things are handled in Unix, Mono and the .NET Framework reference implementation of
File.Copy
/File.Move
.PathVerifier.IsLegalAbsoluteOrRelative
now throwsNotSupportedException
on Windows only when the path contains an invalid use of the drive separator char.ArgumentException
instead ofNotSupportedException
.