diff --git a/dir.props b/dir.props
index 80aa264931dd..ecd04db42660 100644
--- a/dir.props
+++ b/dir.props
@@ -467,7 +467,7 @@
- netcoreapp1.1
+ netcoreapp1.1
netcoreapp1.0
netcoreapp1.1
diff --git a/dir.targets b/dir.targets
index 500ee75e3c18..4b3e69a0b71f 100644
--- a/dir.targets
+++ b/dir.targets
@@ -58,19 +58,6 @@
-
-
-
-
-
-
-
-
-
- netcoreapp1.1
-
-
-
diff --git a/src/Common/src/System/IO/PathInternal.Unix.cs b/src/Common/src/System/IO/PathInternal.Unix.cs
index d3e92a1e5c55..ccf1069a287c 100644
--- a/src/Common/src/System/IO/PathInternal.Unix.cs
+++ b/src/Common/src/System/IO/PathInternal.Unix.cs
@@ -16,6 +16,8 @@ internal static partial class PathInternal
internal static readonly int MaxComponentLength = Interop.Sys.MaxName;
+ internal const string ParentDirectoryPrefix = @"../";
+
/// Returns a value indicating if the given path contains invalid characters.
internal static bool HasIllegalCharacters(string path)
{
@@ -25,7 +27,6 @@ internal static bool HasIllegalCharacters(string path)
internal static int GetRootLength(string path)
{
- PathInternal.CheckInvalidPathChars(path);
return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0;
}
diff --git a/src/Common/src/System/IO/PathInternal.Windows.cs b/src/Common/src/System/IO/PathInternal.Windows.cs
index 8dd41bf354fd..079f1248ced1 100644
--- a/src/Common/src/System/IO/PathInternal.Windows.cs
+++ b/src/Common/src/System/IO/PathInternal.Windows.cs
@@ -45,6 +45,8 @@ internal static partial class PathInternal
internal const string UncExtendedPrefixToInsert = @"?\UNC\";
internal const string UncExtendedPathPrefix = @"\\?\UNC\";
internal const string DevicePathPrefix = @"\\.\";
+ internal const string ParentDirectoryPrefix = @"..\";
+
internal const int MaxShortPath = 260;
internal const int MaxShortDirectoryPath = 248;
internal const int MaxLongPath = short.MaxValue;
diff --git a/src/Common/src/System/IO/PathInternal.cs b/src/Common/src/System/IO/PathInternal.cs
index 67261060329e..ee68750224aa 100644
--- a/src/Common/src/System/IO/PathInternal.cs
+++ b/src/Common/src/System/IO/PathInternal.cs
@@ -21,7 +21,7 @@ internal static void CheckInvalidPathChars(string path)
if (path == null)
throw new ArgumentNullException(nameof(path));
- if (PathInternal.HasIllegalCharacters(path))
+ if (HasIllegalCharacters(path))
throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
}
@@ -98,16 +98,95 @@ internal static StringBuilder TrimEnd(this StringBuilder builder, params char[]
internal static int FindFileNameIndex(string path)
{
Debug.Assert(path != null);
- PathInternal.CheckInvalidPathChars(path);
-
+ CheckInvalidPathChars(path);
+
for (int i = path.Length - 1; i >= 0; i--)
{
char ch = path[i];
if (IsDirectoryOrVolumeSeparator(ch))
return i + 1;
}
-
+
return 0; // the whole path is the filename
}
+
+ ///
+ /// Returns true if the path ends in a directory separator.
+ ///
+ internal static bool EndsInDirectorySeparator(string path) =>
+ !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]);
+
+ ///
+ /// Get the common path length from the start of the string.
+ ///
+ internal static int GetCommonPathLength(string first, string second, bool ignoreCase)
+ {
+ int commonChars = EqualStartingCharacterCount(first, second, ignoreCase: ignoreCase);
+
+ // If nothing matches
+ if (commonChars == 0)
+ return commonChars;
+
+ // Or we're a full string and equal length or match to a separator
+ if (commonChars == first.Length
+ && (commonChars == second.Length || IsDirectorySeparator(second[commonChars])))
+ return commonChars;
+
+ if (commonChars == second.Length && IsDirectorySeparator(first[commonChars]))
+ return commonChars;
+
+ // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar.
+ while (commonChars > 0 && !IsDirectorySeparator(first[commonChars - 1]))
+ commonChars--;
+
+ return commonChars;
+ }
+
+ ///
+ /// Gets the count of common characters from the left optionally ignoring case
+ ///
+ unsafe internal static int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
+ {
+ if (string.IsNullOrEmpty(first) || string.IsNullOrEmpty(second)) return 0;
+
+ int commonChars = 0;
+
+ fixed (char* f = first)
+ fixed (char* s = second)
+ {
+ char* l = f;
+ char* r = s;
+ char* leftEnd = l + first.Length;
+ char* rightEnd = r + second.Length;
+
+ while (l != leftEnd && r != rightEnd
+ && (*l == *r || (ignoreCase && char.ToUpperInvariant((*l)) == char.ToUpperInvariant((*r)))))
+ {
+ commonChars++;
+ l++;
+ r++;
+ }
+ }
+
+ return commonChars;
+ }
+
+ ///
+ /// Returns true if the two paths have the same root
+ ///
+ internal static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
+ {
+ int firstRootLength = GetRootLength(first);
+ int secondRootLength = GetRootLength(second);
+
+ return firstRootLength == secondRootLength
+ && string.Compare(
+ strA: first,
+ indexA: 0,
+ strB: second,
+ indexB: 0,
+ length: firstRootLength,
+ comparisonType: comparisonType) == 0;
+ }
}
}
diff --git a/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
index 3411b75d5a53..0310cebdd89e 100644
--- a/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
+++ b/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
@@ -38,5 +38,62 @@ public void StartsWithOrdinal_PositiveCases(string source, string value, bool ex
Assert.Equal(expected, PathInternal.StartsWithOrdinal(source, value));
Assert.Equal(expected, PathInternal.StartsWithOrdinal(new StringBuilder(source), value));
}
+
+ [Theory,
+ InlineData("", "", true, 0)
+ InlineData("", "", false, 0)
+ InlineData("a", "", true, 0)
+ InlineData("a", "", false, 0)
+ InlineData("", "b", true, 0)
+ InlineData("", "b", false, 0)
+ InlineData("\0", "\0", true, 1)
+ InlineData("\0", "\0", false, 1)
+ InlineData("ABcd", "ABCD", true, 4)
+ InlineData("ABCD", "ABcd", true, 4)
+ InlineData("ABcd", "ABCD", false, 2)
+ InlineData("ABCD", "ABcd", false, 2)
+ InlineData("AB\0cd", "AB\0CD", true, 5)
+ InlineData("AB\0CD", "AB\0cd", true, 5)
+ InlineData("AB\0cd", "AB\0CD", false, 3)
+ InlineData("AB\0CD", "AB\0cd", false, 3)
+ InlineData("ABc\0", "ABC\0", true, 4)
+ InlineData("ABC\0", "ABc\0", true, 4)
+ InlineData("ABc\0", "ABC\0", false, 2)
+ InlineData("ABC\0", "ABc\0", false, 2)
+ InlineData("ABcdxyzl", "ABCDpdq", true, 4)
+ InlineData("ABCDxyz", "ABcdpdql", true, 4)
+ InlineData("ABcdxyz", "ABCDpdq", false, 2)
+ InlineData("ABCDxyzoo", "ABcdpdq", false, 2)
+ ]
+ public void EqualStartingCharacterCount(string first, string second, bool ignoreCase, int expected)
+ {
+ Assert.Equal(expected, PathInternal.EqualStartingCharacterCount(first, second, ignoreCase));
+ }
+
+
+ [Theory,
+ InlineData(@"", @"", true, 0)
+ InlineData(@"", @"", false, 0)
+ InlineData(@"a", @"A", true, 1)
+ InlineData(@"A", @"a", true, 1)
+ InlineData(@"a", @"A", false, 0)
+ InlineData(@"A", @"a", false, 0)
+ InlineData(@"foo", @"foobar", true, 0)
+ InlineData(@"foo", @"foobar", false, 0)
+ InlineData(@"foo", @"foo/bar", true, 3)
+ InlineData(@"foo", @"foo/bar", false, 3)
+ InlineData(@"foo/", @"foo/bar", true, 4)
+ InlineData(@"foo/", @"foo/bar", false, 4)
+ InlineData(@"foo/bar", @"foo/bar", true, 7)
+ InlineData(@"foo/bar", @"foo/bar", false, 7)
+ InlineData(@"foo/bar", @"foo/BAR", true, 7)
+ InlineData(@"foo/bar", @"foo/BAR", false, 4)
+ InlineData(@"foo/bar", @"foo/barb", true, 4)
+ InlineData(@"foo/bar", @"foo/barb", false, 4)
+ ]
+ public void GetCommonPathLength(string first, string second, bool ignoreCase, int expected)
+ {
+ Assert.Equal(expected, PathInternal.GetCommonPathLength(first, second, ignoreCase));
+ }
}
}
diff --git a/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
index 9e92dcff15bb..ce1f99c9a7ba 100644
--- a/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
+++ b/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
@@ -192,4 +192,19 @@ public void FindFileNameIndexTests(string path, int expected)
{
Assert.Equal(expected, PathInternal.FindFileNameIndex(path));
}
+
+ [Theory,
+ InlineData(@"", @"", StringComparison.OrdinalIgnoreCase, true)
+ InlineData(@"", @"", StringComparison.Ordinal, true)
+ InlineData(@"A", @"a", StringComparison.OrdinalIgnoreCase, true)
+ InlineData(@"A", @"a", StringComparison.Ordinal, true)
+ InlineData(@"C:\", @"c:\", StringComparison.OrdinalIgnoreCase, true)
+ InlineData(@"C:\", @"c:\", StringComparison.Ordinal, false)
+ ]
+ [PlatformSpecific(PlatformID.Windows)]
+ public void AreRootsEqual(string first, string second, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, PathInternal.AreRootsEqual(first, second, comparisonType));
+ }
+
}
diff --git a/src/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj b/src/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj
index 74b106b089d4..bd2a5c562d52 100644
--- a/src/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj
+++ b/src/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj
@@ -107,11 +107,5 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj b/src/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj
index 0b897dd0ef28..5e23c9680370 100644
--- a/src/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj
+++ b/src/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj
@@ -75,11 +75,5 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj b/src/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj
index db0aa0f87ba1..640e6cf37544 100644
--- a/src/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj
+++ b/src/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj
@@ -111,11 +111,5 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/System.Collections/tests/System.Collections.Tests.csproj b/src/System.Collections/tests/System.Collections.Tests.csproj
index 44b7d1d735be..f4261cbb9b7b 100644
--- a/src/System.Collections/tests/System.Collections.Tests.csproj
+++ b/src/System.Collections/tests/System.Collections.Tests.csproj
@@ -164,11 +164,5 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/System.Runtime.Extensions/System.Runtime.Extensions.sln b/src/System.Runtime.Extensions/System.Runtime.Extensions.sln
index 91e401abeba2..26b62e86eb52 100644
--- a/src/System.Runtime.Extensions/System.Runtime.Extensions.sln
+++ b/src/System.Runtime.Extensions/System.Runtime.Extensions.sln
@@ -139,5 +139,7 @@ Global
{845D2B72-D8A4-42E5-9BE9-17639EC4FC1A} = {1962877E-782F-499B-8468-F0F2A0692E96}
{E73B023E-609E-4281-866A-3AECB1AB5D48} = {8C66E70A-65C3-443E-A23A-18A1C12972B0}
{6C314C9B-3D28-4B05-9B4C-B57A00A9B3B9} = {4253F45C-FA2F-4743-9FC8-20666C416A68}
+ {373D255D-4749-4F26-A24A-A083E77B4471} = {4253F45C-FA2F-4743-9FC8-20666C416A68}
+ {9F312D76-9AF1-4E90-B3B0-815A1EC6C346} = {4253F45C-FA2F-4743-9FC8-20666C416A68}
EndGlobalSection
EndGlobal
diff --git a/src/System.Runtime.Extensions/pkg/System.Runtime.Extensions.pkgproj b/src/System.Runtime.Extensions/pkg/System.Runtime.Extensions.pkgproj
index b4546a50013b..5d2ee957e1b8 100644
--- a/src/System.Runtime.Extensions/pkg/System.Runtime.Extensions.pkgproj
+++ b/src/System.Runtime.Extensions/pkg/System.Runtime.Extensions.pkgproj
@@ -11,7 +11,7 @@
netcoreapp1.0;net462
-
+
netcoreapp1.1;net463;$(AllXamarinFrameworks)
diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.builds b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.builds
new file mode 100644
index 000000000000..89bc73da61ff
--- /dev/null
+++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.builds
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ netcoreapp1.1
+
+
+
+
\ No newline at end of file
diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
index 6b5bf347342c..6bd35d9b9a73 100644
--- a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
+++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
@@ -799,6 +799,9 @@ public static partial class Path
public static string GetTempPath() { return default(string); }
public static bool HasExtension(string path) { return default(bool); }
public static bool IsPathRooted(string path) { return default(bool); }
+#if netcoreapp11
+ public static string GetRelativePath(string relativeTo, string path) { return default(string); }
+#endif
}
}
namespace System.Net
diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.csproj b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.csproj
index e94f49d319b1..99ff56c0a3be 100644
--- a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.csproj
+++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.csproj
@@ -3,7 +3,8 @@
Library
- .NETStandard,Version=v1.7
+ .NETStandard,Version=v1.7
+ $(DefineConstants);netcoreapp11
diff --git a/src/System.Runtime.Extensions/ref/project.json b/src/System.Runtime.Extensions/ref/project.json
index f516fb8d41b1..c27a054d9a07 100644
--- a/src/System.Runtime.Extensions/ref/project.json
+++ b/src/System.Runtime.Extensions/ref/project.json
@@ -1,12 +1,9 @@
{
"dependencies": {
- "System.Runtime": "4.0.20"
+ "System.Runtime": "4.3.0-beta-24516-03"
},
"frameworks": {
- "netstandard1.7": {
- "imports": [
- "dotnet5.8"
- ]
- }
+ "netstandard1.7": { },
+ "netcoreapp1.1": { }
}
}
diff --git a/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj b/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
index cc7556ea2217..107d7812696f 100644
--- a/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
+++ b/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
@@ -186,7 +186,8 @@
Common\Interop\Windows\mincore\Interop.LookupAccountNameW.cs
-
+
+
Microsoft.Win32.Registry\src\Microsoft\Win32\Registry.cs
@@ -371,7 +372,8 @@
-
+
+
diff --git a/src/System.Runtime.Extensions/src/System/IO/Path.Unix.cs b/src/System.Runtime.Extensions/src/System/IO/Path.Unix.cs
index 48712719e0cd..ad6f9210b5a0 100644
--- a/src/System.Runtime.Extensions/src/System/IO/Path.Unix.cs
+++ b/src/System.Runtime.Extensions/src/System/IO/Path.Unix.cs
@@ -20,6 +20,8 @@ public static partial class Path
private static readonly int MaxPath = Interop.Sys.MaxPath;
private static readonly int MaxLongPath = MaxPath;
+ private static readonly bool s_isMac = Interop.Sys.GetUnixName() == "OSX";
+
// Expands the given path to a fully qualified path.
public static string GetFullPath(string path)
{
@@ -213,5 +215,8 @@ private static unsafe void GetCryptoRandomBytes(byte* bytes, int byteCount)
throw new InvalidOperationException(SR.InvalidOperation_Cryptography);
}
}
+
+ /// Gets whether the system is case-sensitive.
+ internal static bool IsCaseSensitive { get { return !s_isMac; } }
}
}
diff --git a/src/System.Runtime.Extensions/src/System/IO/Path.Windows.cs b/src/System.Runtime.Extensions/src/System/IO/Path.Windows.cs
index 81aa5d8237db..b597efc54ecf 100644
--- a/src/System.Runtime.Extensions/src/System/IO/Path.Windows.cs
+++ b/src/System.Runtime.Extensions/src/System/IO/Path.Windows.cs
@@ -146,5 +146,8 @@ public static string GetPathRoot(string path)
int pathRoot = PathInternal.GetRootLength(path);
return pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot);
}
+
+ /// Gets whether the system is case-sensitive.
+ internal static bool IsCaseSensitive { get { return false; } }
}
}
diff --git a/src/System.Runtime.Extensions/src/System/IO/Path.cs b/src/System.Runtime.Extensions/src/System/IO/Path.cs
index 8be636f4e8d2..d6daad0a9437 100644
--- a/src/System.Runtime.Extensions/src/System/IO/Path.cs
+++ b/src/System.Runtime.Extensions/src/System/IO/Path.cs
@@ -471,5 +471,105 @@ private static unsafe void Populate83FileNameFromRandomBytes(byte* bytes, int by
chars[10] = s_base32Char[(bytes[6] & 0x1F)];
chars[11] = s_base32Char[(bytes[7] & 0x1F)];
}
+
+ ///
+ /// Create a relative path from one path to another. Paths will be resolved before calculating the difference.
+ /// Default path comparison for the active platform will be used (OrdinalIgnoreCase for Windows or Mac, Ordinal for Unix).
+ ///
+ /// The source path the output should be relative to. This path is always considered to be a directory.
+ /// The destination path.
+ /// The relative path or if the paths don't share the same root.
+ /// Thrown if or is null or an empty string.
+ public static string GetRelativePath(string relativeTo, string path)
+ {
+ return GetRelativePath(relativeTo, path, StringComparison);
+ }
+
+ private static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType)
+ {
+ if (string.IsNullOrEmpty(relativeTo)) throw new ArgumentNullException(nameof(relativeTo));
+ if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
+ Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase);
+
+ relativeTo = GetFullPath(relativeTo);
+ path = GetFullPath(path);
+
+ // Need to check if the roots are different- if they are we need to return the "to" path.
+ if (!PathInternal.AreRootsEqual(relativeTo, path, comparisonType))
+ return path;
+
+ int commonLength = PathInternal.GetCommonPathLength(relativeTo, path, ignoreCase: comparisonType == StringComparison.OrdinalIgnoreCase);
+
+ // If there is nothing in common they can't share the same root, return the "to" path as is.
+ if (commonLength == 0)
+ return path;
+
+ // Trailing separators aren't significant for comparison
+ int relativeToLength = relativeTo.Length;
+ if (PathInternal.EndsInDirectorySeparator(relativeTo))
+ relativeToLength--;
+
+ bool pathEndsInSeparator = PathInternal.EndsInDirectorySeparator(path);
+ int pathLength = path.Length;
+ if (pathEndsInSeparator)
+ pathLength--;
+
+ // If we have effectively the same path, return "."
+ if (relativeToLength == pathLength && commonLength >= relativeToLength) return ".";
+
+ // We have the same root, we need to calculate the difference now using the
+ // common Length and Segment count past the length.
+ //
+ // Some examples:
+ //
+ // C:\Foo C:\Bar L3, S1 -> ..\Bar
+ // C:\Foo C:\Foo\Bar L6, S0 -> Bar
+ // C:\Foo\Bar C:\Bar\Bar L3, S2 -> ..\..\Bar\Bar
+ // C:\Foo\Foo C:\Foo\Bar L7, S1 -> ..\Bar
+
+ StringBuilder sb = StringBuilderCache.Acquire(Math.Max(relativeTo.Length, path.Length));
+
+ // Add parent segments for segments past the common on the "from" path
+ if (commonLength < relativeToLength)
+ {
+ sb.Append(PathInternal.ParentDirectoryPrefix);
+
+ for (int i = commonLength; i < relativeToLength; i++)
+ {
+ if (PathInternal.IsDirectorySeparator(relativeTo[i]))
+ {
+ sb.Append(PathInternal.ParentDirectoryPrefix);
+ }
+ }
+ }
+ else if (PathInternal.IsDirectorySeparator(path[commonLength]))
+ {
+ // No parent segments and we need to eat the initial separator
+ // (C:\Foo C:\Foo\Bar case)
+ commonLength++;
+ }
+
+ // Now add the rest of the "to" path, adding back the trailing separator
+ int count = pathLength - commonLength;
+ if (pathEndsInSeparator)
+ count++;
+
+ sb.Append(path, commonLength, count);
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+
+ // StringComparison and IsCaseSensitive are also available in PathInternal.CaseSensitivity but we are
+ // too low in System.Runtime.Extensions to use it (no FileStream, etc.)
+
+ /// Returns a comparison that can be used to compare file and directory names for equality.
+ internal static StringComparison StringComparison
+ {
+ get
+ {
+ return IsCaseSensitive ?
+ StringComparison.Ordinal :
+ StringComparison.OrdinalIgnoreCase;
+ }
+ }
}
}
diff --git a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.builds b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.builds
index 18aa54929d33..03957ab9b63e 100644
--- a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.builds
+++ b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.builds
@@ -9,6 +9,14 @@
netcoreapp1.0;net462
Windows_NT
+
+
+ netcoreapp1.1
+ netcoreapp1.1
+ Windows_NT
+
+
+ netcoreapp1.1
+ netcoreapp1.1
+ Unix
+
diff --git a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
index 0fc7286bc0fd..05a6b42cb48e 100644
--- a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
+++ b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
@@ -15,18 +15,34 @@
$(DefineConstants);netstandard17
.NETStandard,Version=v1.5
+
+
+
+ ns1.7-netcoreapp1.1
+
+
+
+
+ netcoreapp1.1
+
+
-
+
+
+
+
-
+
+
+
@@ -94,6 +110,7 @@
+
{1e689c1b-690c-4799-bde9-6e7990585894}
System.Runtime.Extensions.CoreCLR
diff --git a/src/System.Runtime.Extensions/tests/System/IO/Path.GetRelativePath.cs b/src/System.Runtime.Extensions/tests/System/IO/Path.GetRelativePath.cs
new file mode 100644
index 000000000000..747d7314b8b6
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/Path.GetRelativePath.cs
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public static class GetRelativePathTests
+ {
+ [Theory]
+ [InlineData(@"C:\", @"C:\", @".")]
+ [InlineData(@"C:\a", @"C:\a\", @".")]
+ [InlineData(@"C:\A", @"C:\a\", @".")]
+ [InlineData(@"C:\a\", @"C:\a", @".")]
+ [InlineData(@"C:\", @"C:\b", @"b")]
+ [InlineData(@"C:\a", @"C:\b", @"..\b")]
+ [InlineData(@"C:\a", @"C:\b\", @"..\b\")]
+ [InlineData(@"C:\a\", @"C:\b", @"..\b")]
+ [InlineData(@"C:\a", @"C:\a\b", @"b")]
+ [InlineData(@"C:\a", @"C:\A\b", @"b")]
+ [InlineData(@"C:\a", @"C:\b\c", @"..\b\c")]
+ [InlineData(@"C:\a\", @"C:\a\b", @"b")]
+ [InlineData(@"C:\", @"D:\b", @"D:\b")]
+ [InlineData(@"C:\a", @"D:\b", @"D:\b")]
+ [InlineData(@"C:\a\", @"D:\b", @"D:\b")]
+ [InlineData(@"C:\ab", @"C:\a", @"..\a")]
+ [InlineData(@"C:\a", @"C:\ab", @"..\ab")]
+ [InlineData(@"C:\", @"\\LOCALHOST\Share\b", @"\\LOCALHOST\Share\b")]
+ [InlineData(@"\\LOCALHOST\Share\a", @"\\LOCALHOST\Share\b", @"..\b")]
+ [PlatformSpecific(Xunit.PlatformID.Windows)]
+ public static void GetRelativePath_Windows(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar),
+ ignoreCase: true,
+ ignoreLineEndingDifferences: false,
+ ignoreWhiteSpaceDifferences: false);
+ }
+
+ [Theory]
+ [InlineData(@"/", @"/", @".")]
+ [InlineData(@"/a", @"/a/", @".")]
+ [InlineData(@"/a/", @"/a", @".")]
+ [InlineData(@"/", @"/b", @"b")]
+ [InlineData(@"/a", @"/b", @"../b")]
+ [InlineData(@"/a/", @"/b", @"../b")]
+ [InlineData(@"/a", @"/a/b", @"b")]
+ [InlineData(@"/a", @"/b/c", @"../b/c")]
+ [InlineData(@"/a/", @"/a/b", @"b")]
+ [InlineData(@"/ab", @"/a", @"../a")]
+ [InlineData(@"/a", @"/ab", @"../ab")]
+ [PlatformSpecific(Xunit.PlatformID.AnyUnix)]
+ public static void GetRelativePath_AnyUnix(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar));
+ }
+
+ [Theory]
+ [InlineData(@"/a", @"/A/", @"../A/")]
+ [InlineData(@"/a/", @"/A", @"../A")]
+ [InlineData(@"/a/", @"/A/b", @"../A/b")]
+ [PlatformSpecific(Xunit.PlatformID.Linux)]
+ public static void GetRelativePath_Linux(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar));
+ }
+
+ [Theory]
+ [InlineData(@"/a", @"/A/", @"../A/")]
+ [InlineData(@"/a/", @"/A", @"../A")]
+ [InlineData(@"/a/", @"/A/b", @"../A/b")]
+ [PlatformSpecific(Xunit.PlatformID.FreeBSD)]
+ public static void GetRelativePath_FreeBSD(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar));
+ }
+
+ [Theory]
+ [InlineData(@"/a", @"/A/", @"../A/")]
+ [InlineData(@"/a/", @"/A", @"../A")]
+ [InlineData(@"/a/", @"/A/b", @"../A/b")]
+ [PlatformSpecific(Xunit.PlatformID.NetBSD)]
+ public static void GetRelativePath_NetBSD(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar));
+ }
+
+ [Theory]
+ [InlineData(@"/a", @"/A/", @".")]
+ [InlineData(@"/a/", @"/A", @".")]
+ [InlineData(@"/a/", @"/A/b", @"b")]
+ [PlatformSpecific(Xunit.PlatformID.OSX)]
+ public static void GetRelativePath_Mac(string relativeTo, string path, string expected)
+ {
+ string result = Path.GetRelativePath(relativeTo, path);
+ Assert.Equal(expected, result);
+
+ // Check that we get the equivalent path when the result is combined with the sources
+ Assert.Equal(
+ Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar),
+ Path.GetFullPath(Path.Combine(Path.GetFullPath(relativeTo), result)).TrimEnd(Path.DirectorySeparatorChar),
+ ignoreCase: true,
+ ignoreLineEndingDifferences: false,
+ ignoreWhiteSpaceDifferences: false);
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/project.json b/src/System.Runtime.Extensions/tests/project.json
index b0d75a0fda64..d2db836c5108 100644
--- a/src/System.Runtime.Extensions/tests/project.json
+++ b/src/System.Runtime.Extensions/tests/project.json
@@ -32,7 +32,8 @@
},
"frameworks": {
"netstandard1.5": {},
- "netstandard1.7": {}
+ "netstandard1.7": {},
+ "netcoreapp1.1": {}
},
"supports": {
"coreFx.Test.netcoreapp1.0": {},
diff --git a/src/ref.builds b/src/ref.builds
index eebac73aaae8..4bf366da8cd2 100644
--- a/src/ref.builds
+++ b/src/ref.builds
@@ -2,7 +2,7 @@
-
+
OSGroup;TargetGroup