Test(subPath: "c:/foo/bar", basePath: "c:/foo");
Test(subPath: "c:/foo/bar/qux", basePath: "c:/foo");
Test(subPath: "c:/foo", basePath: "c:/foo/bar");
Test(subPath: "c:/FOO/bar", basePath: "C:/foo");
Test(subPath: @"c:\foo\bar", basePath: @"c:\foo");
Test(subPath: "c:/foo", basePath: "c:");
Test(subPath: "c:/foo/bar", basePath: "c:/foo/");
Test(subPath: "c:/foo/bar/", basePath: "c:/foo");
Test(subPath: "c:/foo/bar", basePath: "c:/foo/bar");
Test(subPath: "d:/foo/bar", basePath: "c:/foo");
Test(subPath: "c:/foo/.bar", basePath: "c:/foo");
Test(subPath: "c:/foo/../foo/bar", basePath: "c:/foo");
void Test(string subPath, string basePath) {
var isSubPath = subPath.IsSubPathOf(basePath);
var infix = isSubPath ? " " : " NOT ";
Console.WriteLine($"'{subPath}'\tis{infix}a sub path of\t'{basePath}'");
public static class Ext {
public static bool IsSubPathOf(this string subPath, string basePath) {
var rel = Path.GetRelativePath(basePath.Replace('\\', '/'), subPath.Replace('\\', '/'));
&& !rel.StartsWith("../")
&& !Path.IsPathRooted(rel);