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

Update SystemFolderWatcher #53

Merged
merged 8 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/OwlCore.Storage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>

<Author>Arlo Godfrey</Author>
<Version>0.11.0</Version>
<Version>0.11.1</Version>
<Product>OwlCore</Product>
<Description>The most flexible file system abstraction, ever. Built in partnership with the UWP Community.

Expand All @@ -23,6 +23,10 @@
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageIcon>logo.png</PackageIcon>
<PackageReleaseNotes>
--- 0.11.1 ---
[Fixes]
Fixed an issue where SystemFolderWatcher would not capture any file system events.

--- 0.11.0 ---
[New]
Added new FileReadExtensions and FileWriteExtensions for reading and writing IFile as text content or byte arrays.
Expand Down Expand Up @@ -280,4 +284,4 @@ Initial release of OwlCore.Storage.
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>
</Project>
26 changes: 20 additions & 6 deletions src/System/IO/SystemFolderWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace OwlCore.Storage.System.IO
public class SystemFolderWatcher : IFolderWatcher
{
private readonly FileSystemWatcher _watcher;
private event NotifyCollectionChangedEventHandler? _collectionChanged;

/// <summary>
/// Creates a new instance of <see cref="SystemFolderWatcher"/>.
Expand Down Expand Up @@ -43,26 +44,38 @@ private void DetachEvents(FileSystemWatcher watcher)
private void OnCreated(object sender, FileSystemEventArgs e)
{
var newItem = CreateStorableFromPath(e.FullPath);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<IStorable> { newItem }));
_collectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<IStorable> { newItem }));
}

private void OnDeleted(object sender, FileSystemEventArgs e)
{
var oldItem = CreateStorableFromPath(e.FullPath, minimalImplementation: true);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List<IStorable> { oldItem }));
_collectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List<IStorable> { oldItem }));
}

private void OnRenamed(object sender, RenamedEventArgs e)
{
var newItem = CreateStorableFromPath(e.FullPath);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<IStorable> { newItem }));
_collectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<IStorable> { newItem }));

var oldItem = CreateStorableFromPath(e.OldFullPath, minimalImplementation: true);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List<IStorable> { oldItem }));
_collectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new List<IStorable> { oldItem }));
}

/// <inheritdoc />
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public event NotifyCollectionChangedEventHandler? CollectionChanged
{
add
{
_collectionChanged += value;
_watcher.EnableRaisingEvents = _collectionChanged is not null;
}
remove
{
_collectionChanged -= value;
_watcher.EnableRaisingEvents = _collectionChanged is not null;
}
}

/// <inheritdoc />
public IMutableFolder Folder { get; }
Expand Down Expand Up @@ -106,7 +119,8 @@ private static IStorable CreateStorableFromPath(string path, bool minimalImpleme
return new SystemFile(path);
}

throw new ArgumentException($"Could not determine if the path '{path}' is a file or folder.");
// The item is most likely deleted. Return all available information through SimpleStorableItem
return new SimpleStorableItem(id: path, name: Path.GetFileName(path));
}

private static bool IsFile(string path) => Path.GetFileName(path) is { } str && str != string.Empty && File.Exists(path);
Expand Down
49 changes: 48 additions & 1 deletion tests/OwlCore.Storage.Tests/SystemIO/IFolderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public override Task<IModifiableFolder> CreateModifiableFolderAsync()
public override Task<IModifiableFolder> CreateModifiableFolderWithItems(int fileCount, int folderCount)
{
var tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
var dir = Directory.CreateDirectory(tempFolder);
_ = Directory.CreateDirectory(tempFolder);

for (var i = 0; i < fileCount; i++)
{
Expand All @@ -33,4 +33,51 @@ public override Task<IModifiableFolder> CreateModifiableFolderWithItems(int file

return Task.FromResult<IModifiableFolder>(new SystemFolder(tempFolder));
}

// Folder Watcher tests
// TODO: Move these to CommonTests.

[TestMethod]
public async Task FolderWatcherOnFileCreate()
{
var folder = await CreateModifiableFolderAsync();

await using var watcher = await folder.GetFolderWatcherAsync();
var collectionChangedTaskCompletionSource = new TaskCompletionSource();
watcher.CollectionChanged += (sender, args) => collectionChangedTaskCompletionSource.SetResult();

await folder.CreateFileAsync(GetHashCode().ToString(), overwrite: true);

await collectionChangedTaskCompletionSource.Task;
}

[TestMethod]
[Timeout(2000)]
public async Task FolderWatcherOnFolderCreate()
{
var folder = await CreateModifiableFolderAsync();

await using var watcher = await folder.GetFolderWatcherAsync();
var collectionChangedTaskCompletionSource = new TaskCompletionSource();
watcher.CollectionChanged += (sender, args) => collectionChangedTaskCompletionSource.SetResult();

await folder.CreateFolderAsync(GetHashCode().ToString(), overwrite: true);

await collectionChangedTaskCompletionSource.Task;
}

[TestMethod]
public async Task FolderWatcherOnDelete()
{
var folder = await CreateModifiableFolderWithItems(1, 0);
var existingItem = await folder.GetItemsAsync(StorableType.File).FirstAsync();

await using var watcher = await folder.GetFolderWatcherAsync();
var collectionChangedTaskCompletionSource = new TaskCompletionSource();
watcher.CollectionChanged += (sender, args) => collectionChangedTaskCompletionSource.SetResult();

await folder.DeleteAsync(existingItem);

await collectionChangedTaskCompletionSource.Task;
}
}
Loading