Skip to content

Commit 4ef5971

Browse files
committed
Merge pull request #80 from manne/full_path
modified Path.GetFullPath in TestingHelpers
2 parents 218c506 + 95e8c9f commit 4ef5971

2 files changed

Lines changed: 188 additions & 7 deletions

File tree

TestHelpers.Tests/MockPathTests.cs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,111 @@ public void GetFullPath_SendInPath_ReturnsFullPath()
102102
Assert.AreEqual(TestPath, result);
103103
}
104104

105+
[TestCase(@"c:\a", @"b", @"c:\a\b")]
106+
[TestCase(@"c:\a\b", @"c", @"c:\a\b\c")]
107+
[TestCase(@"c:\a\b", @"c\", @"c:\a\b\c\")]
108+
[TestCase(@"c:\a\b", @".\c\", @"c:\a\b\c\")]
109+
[TestCase(@"c:\a\b", @"..\c", @"c:\a\c")]
110+
[TestCase(@"c:\a\b\c", @"..\c\..\", @"c:\a\b\")]
111+
[TestCase(@"c:\a\b\c", @"..\..\..\..\..\d", @"c:\d")]
112+
[TestCase(@"c:\a\b\c\", @"..\..\..\..\..\d\", @"c:\d\")]
113+
public void GetFullPath_RelativePaths_ShouldReturnTheAbsolutePathWithCurrentDirectory(string currentDir, string relativePath, string expectedResult)
114+
{
115+
//Arrange
116+
var mockFileSystem = new MockFileSystem();
117+
mockFileSystem.Directory.SetCurrentDirectory(currentDir);
118+
var mockPath = new MockPath(mockFileSystem);
119+
120+
//Act
121+
var actualResult = mockPath.GetFullPath(relativePath);
122+
123+
//Assert
124+
Assert.AreEqual(expectedResult, actualResult);
125+
}
126+
127+
[TestCase(@"c:\a\b\..\c", @"c:\a\c")]
128+
[TestCase(@"c:\a\b\.\.\..\.\c", @"c:\a\c")]
129+
[TestCase(@"c:\a\b\.\c", @"c:\a\b\c")]
130+
[TestCase(@"c:\a\b\.\.\.\.\c", @"c:\a\b\c")]
131+
[TestCase(@"c:\a\..\..\c", @"c:\c")]
132+
public void GetFullPath_RootedPathWithRelativeSegments_ShouldReturnAnRootedAbsolutePath(string rootedPath, string expectedResult)
133+
{
134+
//Arrange
135+
var mockFileSystem = new MockFileSystem();
136+
var mockPath = new MockPath(mockFileSystem);
137+
138+
//Act
139+
var actualResult = mockPath.GetFullPath(rootedPath);
140+
141+
//Assert
142+
Assert.AreEqual(expectedResult, actualResult);
143+
}
144+
145+
[TestCase(@"c:\a", @"/b", @"c:\b")]
146+
[TestCase(@"c:\a", @"/b\", @"c:\b\")]
147+
[TestCase(@"c:\a", @"\b", @"c:\b")]
148+
[TestCase(@"c:\a", @"\b\..\c", @"c:\c")]
149+
[TestCase(@"z:\a", @"\b\..\c", @"z:\c")]
150+
[TestCase(@"z:\a", @"\b\..\c", @"z:\c")]
151+
[TestCase(@"z:\a", @"\\computer\share\c", @"\\computer\share\c")]
152+
[TestCase(@"z:\a", @"\\computer\share\c\..\d", @"\\computer\share\d")]
153+
[TestCase(@"z:\a", @"\\computer\share\c\..\..\d", @"\\computer\share\d")]
154+
public void GetFullPath_AbsolutePaths_ShouldReturnThePathWithTheRoot_Or_Unc(string currentDir, string absolutePath, string expectedResult)
155+
{
156+
//Arrange
157+
var mockFileSystem = new MockFileSystem();
158+
mockFileSystem.Directory.SetCurrentDirectory(currentDir);
159+
var mockPath = new MockPath(mockFileSystem);
160+
161+
//Act
162+
var actualResult = mockPath.GetFullPath(absolutePath);
163+
164+
//Assert
165+
Assert.AreEqual(expectedResult, actualResult);
166+
}
167+
168+
[Test]
169+
public void GetFullPath_InvalidUNCPaths_ShouldThrowArgumentException()
170+
{
171+
//Arrange
172+
var mockFileSystem = new MockFileSystem();
173+
var mockPath = new MockPath(mockFileSystem);
174+
175+
//Act
176+
TestDelegate action = () => mockPath.GetFullPath(@"\\shareZ");
177+
178+
//Assert
179+
Assert.Throws<ArgumentException>(action);
180+
}
181+
182+
[Test]
183+
public void GetFullPath_NullValue_ShouldThrowArgumentNullException()
184+
{
185+
//Arrange
186+
var mockFileSystem = new MockFileSystem();
187+
var mockPath = new MockPath(mockFileSystem);
188+
189+
//Act
190+
TestDelegate action = () => mockPath.GetFullPath(null);
191+
192+
//Assert
193+
Assert.Throws<ArgumentNullException>(action);
194+
}
195+
196+
[Test]
197+
public void GetFullPath_EmptyValue_ShouldThrowArgumentException()
198+
{
199+
//Arrange
200+
var mockFileSystem = new MockFileSystem();
201+
var mockPath = new MockPath(mockFileSystem);
202+
203+
//Act
204+
TestDelegate action = () => mockPath.GetFullPath(string.Empty);
205+
206+
//Assert
207+
Assert.Throws<ArgumentException>(action);
208+
}
209+
105210
[Test]
106211
public void GetInvalidFileNameChars_Called_ReturnsChars()
107212
{
@@ -151,7 +256,7 @@ public void GetRandomFileName_Called_ReturnsStringLengthGreaterThanZero()
151256
var result = mockPath.GetRandomFileName();
152257

153258
//Assert
154-
Assert.IsTrue(result.Length>0);
259+
Assert.IsTrue(result.Length > 0);
155260
}
156261

157262
[Test]

TestingHelpers/MockPath.cs

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
namespace System.IO.Abstractions.TestingHelpers
1+
using System.Collections.Generic;
2+
using System.Globalization;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace System.IO.Abstractions.TestingHelpers
27
{
38
/// <summary>
49
/// PathWrapper calls direct to Path but all this does is string manipulation so we can inherit directly from PathWrapper as no IO is done
@@ -15,17 +20,88 @@ public MockPath(IMockFileDataAccessor mockFileDataAccessor)
1520

1621
public override string GetFullPath(string path)
1722
{
23+
if (path == null)
24+
{
25+
throw new ArgumentNullException("path", "Value cannot be null.");
26+
}
27+
28+
if(path.Length == 0)
29+
{
30+
throw new ArgumentException("The path is not of a legal form.", "path");
31+
}
32+
1833
path = path.Replace(AltDirectorySeparatorChar, DirectorySeparatorChar);
1934

2035
string root = GetPathRoot(path);
2136

22-
if (root == "")
23-
path = Combine(mockFileDataAccessor.Directory.GetCurrentDirectory(), path);
37+
bool hasTrailingSlash = path[path.Length - 1] == DirectorySeparatorChar;
38+
string[] pathSegments;
39+
bool isUnc = false;
40+
41+
if (root.Length == 0)
42+
{
43+
// relative path on the current drive or volume
44+
path = mockFileDataAccessor.Directory.GetCurrentDirectory() + DirectorySeparatorChar + path;
45+
pathSegments = GetSegments(path);
46+
}
47+
else if (@"\".Equals(root, StringComparison.OrdinalIgnoreCase) || @"/".Equals(root, StringComparison.OrdinalIgnoreCase))
48+
{
49+
// absolute path on the current drive or volume
50+
pathSegments = GetSegments(GetPathRoot(mockFileDataAccessor.Directory.GetCurrentDirectory()), path);
51+
}
52+
else if (root.StartsWith(@"\\", StringComparison.OrdinalIgnoreCase))
53+
{
54+
// unc path
55+
pathSegments = GetSegments(path);
56+
if (pathSegments.Length < 2)
57+
{
58+
throw new ArgumentException(@"The UNC path should be of the form \\server\share.", "path");
59+
}
60+
61+
isUnc = true;
62+
}
63+
else
64+
{
65+
pathSegments = GetSegments(path);
66+
}
67+
68+
// unc paths need at least two segments, the others need one segment
69+
var minPathSegments = isUnc ? 2 : 1;
70+
var stack = new Stack<string>();
71+
foreach (var segment in pathSegments)
72+
{
73+
if ("..".Equals(segment, StringComparison.OrdinalIgnoreCase))
74+
{
75+
// only pop, if afterwards are at least the minimal amount of path segments
76+
if (stack.Count > minPathSegments)
77+
{
78+
stack.Pop();
79+
}
80+
}
81+
else if (".".Equals(segment, StringComparison.OrdinalIgnoreCase))
82+
{
83+
// ignore .
84+
}
85+
else
86+
{
87+
stack.Push(segment);
88+
}
89+
}
2490

25-
if (root == "/")
26-
path = Combine(GetPathRoot(mockFileDataAccessor.Directory.GetCurrentDirectory()), path);
91+
var fullPath = isUnc ? @"\\" : string.Empty;
92+
fullPath += string.Join(DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), stack.Reverse().ToArray());
2793

28-
return path;
94+
if (hasTrailingSlash)
95+
{
96+
fullPath += DirectorySeparatorChar;
97+
}
98+
99+
return fullPath;
100+
}
101+
102+
private string[] GetSegments(params string[] paths)
103+
{
104+
return paths.SelectMany(path => path.Split(new[] { DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)).ToArray();
29105
}
30106

31107
public override string GetTempFileName()

0 commit comments

Comments
 (0)