Skip to content

Commit

Permalink
Merge pull request #53 from d2dyno1/d2dyno/fx_fsw
Browse files Browse the repository at this point in the history
Update SystemFolderWatcher
  • Loading branch information
Arlodotexe authored May 18, 2024
2 parents 5ad8b97 + 88e1e99 commit c0aa68c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
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;
}
}

0 comments on commit c0aa68c

Please sign in to comment.