AbsolutePath.IsPrefixOf and LocalPath.IsPrefixOf both <inheritdoc/> the same IPath{TPath}.IsPrefixOf contract, but they behave differently: the AbsolutePath one is a raw string prefix check, so a directory is reported as a prefix of a sibling whose name merely starts with the same characters.
Affects 1.12.0 (latest).
Reproduction
var dir = new AbsolutePath("/p/sub");
dir.IsPrefixOf(new AbsolutePath("/p/subx/a.txt")); // true <-- unexpected
new LocalPath("/p/sub").IsPrefixOf(new LocalPath("/p/subx/a.txt")); // false <-- expected
// the two agree for a genuine child:
dir.IsPrefixOf(new AbsolutePath("/p/sub/a.txt")); // true
Cause
LocalPath.IsPrefixOf checks that the match ends on a separator boundary, and AbsolutePath.IsPrefixOf does not:
// AbsolutePath.cs
public bool IsPrefixOf(AbsolutePath other) =>
Value.Length <= other.Value.Length && other.Value.StartsWith(Value);
// LocalPath.cs
public bool IsPrefixOf(LocalPath other)
{
if (!(Value.Length <= other.Value.Length && other.Value.StartsWith(Value))) return false;
return other.Value.Length == Value.Length || other.Value[Value.Length] == Separator;
}
Expected: AbsolutePath.IsPrefixOf applies the same separator-boundary check, so it agrees with LocalPath.IsPrefixOf on identical paths. (StartsWith is a plain string comparison in both types, which is consistent — only IsPrefixOf differs.)
AbsolutePath.IsPrefixOfandLocalPath.IsPrefixOfboth<inheritdoc/>the sameIPath{TPath}.IsPrefixOfcontract, but they behave differently: theAbsolutePathone is a raw string prefix check, so a directory is reported as a prefix of a sibling whose name merely starts with the same characters.Affects 1.12.0 (latest).
Reproduction
Cause
LocalPath.IsPrefixOfchecks that the match ends on a separator boundary, andAbsolutePath.IsPrefixOfdoes not:Expected:
AbsolutePath.IsPrefixOfapplies the same separator-boundary check, so it agrees withLocalPath.IsPrefixOfon identical paths. (StartsWithis a plain string comparison in both types, which is consistent — onlyIsPrefixOfdiffers.)