Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

62606 Return fully qualified path from FileSystemEventArgs #63051

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -340,15 +340,6 @@ private void OnFileSystemEntryChange(string fullPath)
{
try
{
// this can happen when the fullPath matches the root directory path
// but the root path is always created with a trailing slash
// this was masked by a side effect (bug) in RenamedEventArgs that was appending the trailing slash to fullPath value
// that behavior was changed with the fix for https://github.com/dotnet/runtime/issues/62606
if (fullPath.Length < _root.Length)
{
return;
}

var fileSystemInfo = new FileInfo(fullPath);
if (FileSystemInfoHelper.IsExcluded(fileSystemInfo, _filters))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
<Compile Include="System\IO\WaitForChangedResult.cs" />
<Compile Include="$(CommonPath)System\IO\PathInternal.CaseSensitivity.cs"
Link="Common\System\IO\PathInternal.CaseSensitivity.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
<Compile Include="$(CommonPath)System\IO\PathInternal.cs"
Link="Common\System\IO\PathInternal.cs" />
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.cs"
Link="Common\System\Text\ValueStringBuilder.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
<Compile Include="$(CommonPath)System\IO\PathInternal.Windows.cs"
Link="Common\System\IO\PathInternal.Windows.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public FileSystemEventArgs(WatcherChangeTypes changeType, string directory, stri
_changeType = changeType;
_name = name;
_fullPath = Path.Join(Path.GetFullPath(directory), name);

if (string.IsNullOrWhiteSpace(name))
{
_fullPath = PathInternal.EnsureTrailingSeparator(_fullPath);
}
}

/// <devdoc>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public RenamedEventArgs(WatcherChangeTypes changeType, string directory, string?
{
_oldName = oldName;
_oldFullPath = Path.Join(Path.GetFullPath(directory), oldName);

if (string.IsNullOrWhiteSpace(oldName))
{
_oldFullPath = PathInternal.EnsureTrailingSeparator(_oldFullPath);
}
}

/// <devdoc>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,86 +8,93 @@ namespace System.IO.Tests
public class FileSystemEventArgsTests
{
[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData(WatcherChangeTypes.Changed, "D:\\", "foo.txt", "D:\\foo.txt")]
[InlineData(WatcherChangeTypes.Changed, "E:\\bar", "foo.txt", "E:\\bar\\foo.txt")]
[InlineData(WatcherChangeTypes.All, "D:\\", "foo.txt", "D:\\foo.txt")]
[InlineData(WatcherChangeTypes.All, "E:\\bar", "foo.txt", "E:\\bar\\foo.txt")]
public static void FileSystemEventArgs_ctor_AbsolutePaths(WatcherChangeTypes changeType, string directory, string name, string expectedFullPath)
[InlineData(WatcherChangeTypes.Changed, "C:\\bar", "foo.txt")]
[InlineData(WatcherChangeTypes.All, "C:\\bar", "foo.txt")]
[InlineData((WatcherChangeTypes)0, "C:\\bar", "")]
[InlineData((WatcherChangeTypes)0, "C:\\bar", null)]
public static void FileSystemEventArgs_ctor_NonPathPropertiesAreSetCorrectly(WatcherChangeTypes changeType, string directory, string name)
{
FileSystemEventArgs args = new FileSystemEventArgs(changeType, directory, name);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(expectedFullPath, args.FullPath);
Assert.Equal(name, args.Name);
}

[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData(WatcherChangeTypes.Changed, "C:", "foo.txt")]
[InlineData(WatcherChangeTypes.All, "C:", "foo.txt")]
public static void FileSystemEventArgs_ctor_RelativePathFromCurrentDirectoryInGivenDrive(WatcherChangeTypes changeType, string directory, string name)
[InlineData("D:\\", "foo.txt", "D:\\foo.txt")]
[InlineData("E:\\bar", "foo.txt", "E:\\bar\\foo.txt")]
public static void FileSystemEventArgs_ctor_DirectoryIsAbsolutePath_Windows(string directory, string name, string expectedFullPath)
{
FileSystemEventArgs args = new FileSystemEventArgs(changeType, directory, name);
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + name, args.FullPath);
Assert.Equal(name, args.Name);
Assert.Equal(expectedFullPath, args.FullPath);
}

[Theory]
[InlineData(WatcherChangeTypes.Changed, "bar", "foo.txt")]
[InlineData(WatcherChangeTypes.Changed, "bar\\baz", "foo.txt")]
[InlineData(WatcherChangeTypes.All, "bar", "foo.txt")]
[InlineData(WatcherChangeTypes.All, "bar\\baz", "foo.txt")]
public static void FileSystemEventArgs_ctor_DirectoryIsRelativePath(WatcherChangeTypes changeType, string directory, string name)
[PlatformSpecific(TestPlatforms.AnyUnix)]
[InlineData("/", "foo.txt", "/foo.txt")]
[InlineData("/bar", "foo.txt", "/bar/foo.txt")]
public static void FileSystemEventArgs_ctor_DirectoryIsAbsolutePath_Unix(string directory, string name, string expectedFullPath)
{
FileSystemEventArgs args = new FileSystemEventArgs(changeType, directory, name);
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

directory = AppendDirectorySeparator(directory);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + directory + name, args.FullPath);
Assert.Equal(name, args.Name);
Assert.Equal(expectedFullPath, args.FullPath);
}

[Fact]
public static void FileSystemEventArgs_ctor_Invalid_EmptyDirectory()
[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData("bar", "foo.txt")]
[InlineData("bar\\baz", "foo.txt")]
public static void FileSystemEventArgs_ctor_DirectoryIsRelativePath_Windows(string directory, string name)
{
Assert.Throws<ArgumentException>(() => new FileSystemEventArgs((WatcherChangeTypes)0, "", "foo.txt"));
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

directory = PathInternal.EnsureTrailingSeparator(directory);

Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory + name, args.FullPath);
}

[Fact]
public static void FileSystemEventArgs_ctor_Invalid_NullDirectory()
[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)]
[InlineData("bar", "foo.txt")]
[InlineData("bar/baz", "foo.txt")]
public static void FileSystemEventArgs_ctor_DirectoryIsRelativePath_Unix(string directory, string name)
{
Assert.Throws<ArgumentNullException>(() => new FileSystemEventArgs((WatcherChangeTypes)0, null, "foo.txt"));
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

directory = PathInternal.EnsureTrailingSeparator(directory);

Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory + name, args.FullPath);
}

[Theory]
[InlineData(WatcherChangeTypes.All, "bar", "")]
[InlineData(WatcherChangeTypes.All, "bar", null)]
[InlineData(WatcherChangeTypes.Changed, "bar", "")]
[InlineData(WatcherChangeTypes.Changed, "bar", null)]
public static void FileSystemEventArgs_ctor_When_EmptyFileName_Then_FullPathReturnsTheDirectoryFullPath(WatcherChangeTypes changeType, string directory, string name)
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData("C:", "foo.txt")]
public static void FileSystemEventArgs_ctor_RelativePathFromCurrentDirectoryInGivenDrive(string directory, string name)
{
FileSystemEventArgs args = new FileSystemEventArgs(changeType, directory, name);
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + directory, args.FullPath);
Assert.Equal(name, args.Name);
Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + name, args.FullPath);
}

#region Test Helpers

private static string AppendDirectorySeparator(string directory)
[Theory]
[InlineData("bar", "")]
[InlineData("bar", null)]
public static void FileSystemEventArgs_ctor_When_EmptyFileName_Then_FullPathReturnsTheDirectoryFullPath_WithTrailingSeparator(string directory, string name)
{
if (!directory.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
{
directory += Path.DirectorySeparatorChar;
}
return directory;
FileSystemEventArgs args = new FileSystemEventArgs(WatcherChangeTypes.All, directory, name);

directory = PathInternal.EnsureTrailingSeparator(directory);

Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory, args.FullPath);
}

#endregion
[Fact]
public static void FileSystemEventArgs_ctor_Invalid()
{
Assert.Throws<ArgumentNullException>(() => new FileSystemEventArgs((WatcherChangeTypes)0, null, "foo.txt"));
Assert.Throws<ArgumentException>(() => new FileSystemEventArgs((WatcherChangeTypes)0, "", "foo.txt"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class RenamedEventArgsTests
public static void RenamedEventArgs_ctor_NonPathPropertiesAreSetCorrectly(WatcherChangeTypes changeType, string directory, string name, string oldName)
{
RenamedEventArgs args = new RenamedEventArgs(changeType, directory, name, oldName);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(name, args.Name);
Assert.Equal(oldName, args.OldName);
Expand All @@ -23,89 +24,80 @@ public static void RenamedEventArgs_ctor_NonPathPropertiesAreSetCorrectly(Watche

[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData(WatcherChangeTypes.Changed, "D:\\", "foo.txt", "bar.txt", "D:\\bar.txt")]
[InlineData(WatcherChangeTypes.Changed, "E:\\bar", "foo.txt", "bar.txt", "E:\\bar\\bar.txt")]
[InlineData(WatcherChangeTypes.All, "D:\\", "foo.txt", "bar.txt", "D:\\bar.txt")]
[InlineData(WatcherChangeTypes.All, "E:\\bar", "foo.txt", "bar.txt", "E:\\bar\\bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsAnAbsolutePath(WatcherChangeTypes changeType, string directory, string name, string oldName, string expectedOldFullPath)
[InlineData("D:\\", "foo.txt", "bar.txt", "D:\\bar.txt")]
[InlineData("E:\\bar", "foo.txt", "bar.txt", "E:\\bar\\bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsAnAbsolutePath_Windows(string directory, string name, string oldName, string expectedOldFullPath)
{
RenamedEventArgs args = new RenamedEventArgs(changeType, directory, name, oldName);
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(expectedOldFullPath, args.OldFullPath);
Assert.Equal(name, args.Name);
Assert.Equal(oldName, args.OldName);
}

[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData(WatcherChangeTypes.Changed, "C:", "foo.txt", "bar.txt")]
[InlineData(WatcherChangeTypes.All, "C:", "foo.txt", "bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsRelativePathFromCurrentDirectoryInGivenDrive(WatcherChangeTypes changeType, string directory, string name, string oldName)
[PlatformSpecific(TestPlatforms.AnyUnix)]
[InlineData("/", "foo.txt", "bar.txt", "/bar.txt")]
[InlineData("/bar", "foo.txt", "bar.txt", "/bar/bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsAnAbsolutePath_Unix(string directory, string name, string oldName, string expectedOldFullPath)
{
RenamedEventArgs args = new RenamedEventArgs(changeType, directory, name, oldName);
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + oldName, args.OldFullPath);
Assert.Equal(name, args.Name);
Assert.Equal(expectedOldFullPath, args.OldFullPath);
}

[Theory]
[InlineData(WatcherChangeTypes.Changed, "bar", "foo.txt", "bar.txt")]
[InlineData(WatcherChangeTypes.Changed, "bar\\baz", "foo.txt", "bar.txt")]
[InlineData(WatcherChangeTypes.All, "bar", "foo.txt", "bar.txt")]
[InlineData(WatcherChangeTypes.All, "bar\\baz", "foo.txt", "bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsRelativePath(WatcherChangeTypes changeType, string directory, string name, string oldName)
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData("bar", "foo.txt", "bar.txt")]
[InlineData("bar\\baz", "foo.txt", "bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsRelativePath_Windows(string directory, string name, string oldName)
{
RenamedEventArgs args = new RenamedEventArgs(changeType, directory, name, oldName);
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

directory = AppendDirectorySeparator(directory);
directory = PathInternal.EnsureTrailingSeparator(directory);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + directory + oldName, args.OldFullPath);
Assert.Equal(name, args.Name);
Assert.Equal(oldName, args.OldName);
Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory + oldName, args.OldFullPath);
}

[Fact]
public static void RenamedEventArgs_ctor_Invalid_EmptyDirectory()
[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)]
[InlineData("bar", "foo.txt", "bar.txt")]
[InlineData("bar/baz", "foo.txt", "bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsRelativePath_Unix(string directory, string name, string oldName)
{
Assert.Throws<ArgumentException>(() => new RenamedEventArgs((WatcherChangeTypes)0, "", "foo.txt", "bar.txt"));
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

directory = PathInternal.EnsureTrailingSeparator(directory);

Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory + oldName, args.OldFullPath);
}

[Fact]
public static void RenamedEventArgs_ctor_Invalid_NullDirectory()
[Theory]
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData("C:", "foo.txt", "bar.txt")]
public static void RenamedEventArgs_ctor_OldFullPath_DirectoryIsRelativePathFromCurrentDirectoryInGivenDrive(string directory, string name, string oldName)
{
Assert.Throws<ArgumentNullException>(() => new RenamedEventArgs((WatcherChangeTypes)0, null, "foo.txt", "bar.txt"));
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + oldName, args.OldFullPath);
}

[Theory]
[InlineData(WatcherChangeTypes.All, "bar", "", "")]
[InlineData(WatcherChangeTypes.All, "bar", null, null)]
[InlineData(WatcherChangeTypes.Changed, "bar", "", "")]
[InlineData(WatcherChangeTypes.Changed, "bar", null, null)]
[InlineData(WatcherChangeTypes.All, "bar", "foo.txt", "")]
[InlineData(WatcherChangeTypes.Changed, "bar", "foo.txt", null)]
public static void RenamedEventArgs_ctor_When_EmptyOldFileName_Then_OldFullPathReturnsTheDirectoryFullPath(WatcherChangeTypes changeType, string directory, string name, string oldName)
[InlineData( "bar", "", "")]
[InlineData( "bar", null, null)]
[InlineData( "bar", "foo.txt", null)]
public static void RenamedEventArgs_ctor_When_EmptyOldFileName_Then_OldFullPathReturnsTheDirectoryFullPath_WithTrailingSeparator(string directory, string name, string oldName)
{
RenamedEventArgs args = new RenamedEventArgs(changeType, directory, name, oldName);
RenamedEventArgs args = new RenamedEventArgs(WatcherChangeTypes.All, directory, name, oldName);

Assert.Equal(changeType, args.ChangeType);
Assert.Equal(AppendDirectorySeparator(Directory.GetCurrentDirectory()) + directory, args.OldFullPath);
Assert.Equal(name, args.Name);
}
directory = PathInternal.EnsureTrailingSeparator(directory);

#region Test Helpers
Assert.Equal(PathInternal.EnsureTrailingSeparator(Directory.GetCurrentDirectory()) + directory, args.OldFullPath);
}

private static string AppendDirectorySeparator(string directory)
[Fact]
public static void RenamedEventArgs_ctor_Invalid()
{
if (!directory.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
{
directory += Path.DirectorySeparatorChar;
}
return directory;
Assert.Throws<ArgumentException>(() => new RenamedEventArgs((WatcherChangeTypes)0, "", "foo.txt", "bar.txt"));
Assert.Throws<ArgumentNullException>(() => new RenamedEventArgs((WatcherChangeTypes)0, null, "foo.txt", "bar.txt"));
}

#endregion
}
}
Loading