Repository navigation
Test Implementation for Path.GetRelativePath #773
Description
Activity
- addedstate: needs discussionIssues that need further discussionIssues that need further discussiontype: enhancementIssues that propose new functionalityIssues that propose new functionality
on Nov 29, 2021 After spending some more time debugging and looking into this issue, I realize now that what I am dealing with is probably a strange edge case, and not as pervasive as I previously thought, which is great! I'm still a bit confused by it, though. This example test always fails:
[Fact] public void Foo() { var fs = new MockFileSystem(); fs.AddDirectory("input"); fs.AddDirectory("output"); fs.AddFile("input/a.txt", "foo"); var result = fs.Path.GetRelativePath("/input", "a.txt"); Assert.Equal("a.txt", result); }But if you change "/input" to "input" in the
GetRelativePathcall, it all works as expected. In reality, in this example,/inputis what is created either way, but result will have the path to my test DLL when run.Thanks for reporting this and sharing some test cases!
Which OS are you running the test on?
/inputis something different thaninputso I'd not really expected these tests to succeed. Can you share the test results here so that its easier to understand what's going on?I am running this on Linux. So after digging around what I have realized is that if your path doesn't exist relative to the path provided, the API does strange things reaching out to the file system to figure out how to complete it. Or at least that's what it seems like. The two tests for this behavior are this:
public void Foo() { var fs = new MockFileSystem(); fs.AddDirectory("input"); fs.AddDirectory("output"); fs.AddFile("input/a.txt", "foo"); var result = fs.Path.GetRelativePath("/input", "a.txt"); Assert.Equal("a.txt", result); }and
public void Foo() { var fs = new MockFileSystem(); fs.AddDirectory("input"); fs.AddDirectory("output"); fs.AddFile("input/a.txt", "foo"); var result = fs.Path.GetRelativePath("input", "a.txt"); Assert.Equal("a.txt", result); }If you examine you will find that in both cases, the path
/input/a.txtexists, but in the first case, the relative path result will be a path to the executing DLL (in my case a test project DLL). It seems like the system path method that is being proxied through is doing more than just string manipulation. The documentation points out that it calls "Paths are resolved by calling the GetFullPath method..." which would suggest that it's reaching out to the underlying file system and not just doing string manipulation like the comments in the test project seem to suggest.I need to find some more time to test, to confirm or deny that theory.
Thanks for the detailed analysis! The .NET implementation seems to do quite a lot of stuff, it's totally possible that we need to override (certain parts of) it in our mock implementation.
- addedarea: testinghelpersIssues that address the testing helpersIssues that address the testing helpersstate: ready to pickIssues that are ready for being worked onIssues that are ready for being worked onand removedstate: needs discussionIssues that need further discussionIssues that need further discussion
on Dec 17, 2021 I just bumped into this as well. Debugging into the base implementation of
Path.GetRelativePath(), (and as @ZacheryPD mentioned) it callsGetFullPath(), which the mock can't intercept (note I'm currently on Windows, so it's possible the behavior on Linux is different).In my case I can get the
MockFileSystemto behave the same if I switch from thenew MockFileSystem()constructor to one like this:new MockFileSystem(files: null, Environment.CurrentDirectory)
Then, the MockFileSystem uses the same current directory when creating mock files as will be resolved by the Path class. I think it might make sense to update the default constructor of
MockFileSystemto do something similar.If you have any questions / concerns, please let me know! I can also provide a repo case if necessary.
- added a commit that references this issue
on Jul 24, 2023 - added a commit that references this issue
on Jul 31, 2023 Fixed with #1012
Is your feature request related to a problem? Please describe.
I am trying to implement a static site generator, and one of the tasks I need to do is adjust file paths handed to me to be relative to the root of the "static site" I am trying to create. This is something that Microsoft makes available via Path.GetRelativePath, and the normal implementation of it in System.IO.Abstractions seems to work great, but the Mock implementation is not being overwritten so the result is strange.
Describe the solution you'd like
I think it should be possible to write some kind of mock implementation that would use the mock file system as reference.
Describe alternatives you've considered
I could probably also implement this as a specific mock for my project, but wanted to see if this was something the community had an interest in.
Additional context
If desired, my plan is to start prototyping this out today, but I can't make any promises on how fast it'll go.
This is the example code that I need to "mock" the behavior of and this is a prototype test that currently behaves very strangely because of the GetRelativePath mock implementation.