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

Enable item renaming and add tests for ApplicationDataStorageHelper #4173

Merged
merged 4 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public partial class ApplicationDataStorageHelper
/// <returns>Waiting task until completion with the object in the file.</returns>
public Task<T> ReadCacheFileAsync<T>(string filePath, T @default = default)
{
return ReadFileAsync<T>(CacheFolder, filePath, @default);
return ReadFileAsync<T>(this.CacheFolder, filePath, @default);
michael-hawker marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
Expand All @@ -39,7 +39,7 @@ public Task<T> ReadCacheFileAsync<T>(string filePath, T @default = default)
/// <returns>A list of file types and names in the target folder.</returns>
public Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadCacheFolderAsync(string folderPath)
{
return ReadFolderAsync(CacheFolder, folderPath);
return ReadFolderAsync(this.CacheFolder, folderPath);
}

/// <summary>
Expand All @@ -51,7 +51,7 @@ public Task<T> ReadCacheFileAsync<T>(string filePath, T @default = default)
/// <returns>Waiting task until completion.</returns>
public Task CreateCacheFileAsync<T>(string filePath, T value)
{
return SaveFileAsync<T>(CacheFolder, filePath, value);
return CreateFileAsync<T>(this.CacheFolder, filePath, value);
}

/// <summary>
Expand All @@ -61,17 +61,28 @@ public Task CreateCacheFileAsync<T>(string filePath, T value)
/// <returns>Waiting task until completion.</returns>
public Task CreateCacheFolderAsync(string folderPath)
{
return CreateFolderAsync(CacheFolder, folderPath);
return CreateFolderAsync(this.CacheFolder, folderPath);
}

/// <summary>
/// Deletes a file or folder item in the LocalCacheFolder.
/// </summary>
/// <param name="itemPath">The path to the item for deletion.</param>
/// <returns>Waiting task until completion.</returns>
public Task DeleteCacheItemAsync(string itemPath)
public Task<bool> TryDeleteCacheItemAsync(string itemPath)
{
return DeleteItemAsync(CacheFolder, itemPath);
return TryDeleteItemAsync(CacheFolder, itemPath);
}

/// <summary>
/// Rename an item in the LocalCacheFolder.
/// </summary>
/// <param name="itemPath">The path to the target item.</param>
/// <param name="newName">The new nam for the target item.</param>
/// <returns>Waiting task until completion.</returns>
public Task<bool> TryRenameCacheItemAsync(string itemPath, string newName)
{
return TryRenameItemAsync(this.CacheFolder, itemPath, newName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Toolkit.Helpers;
Expand Down Expand Up @@ -259,7 +260,7 @@ public bool TryDelete(string compositeKey, string key)
/// <inheritdoc />
public Task CreateFileAsync<T>(string filePath, T value)
{
return this.SaveFileAsync<T>(this.Folder, filePath, value);
return this.CreateFileAsync<T>(this.Folder, filePath, value);
}

/// <inheritdoc />
Expand All @@ -269,32 +270,26 @@ public Task CreateFolderAsync(string folderPath)
}

/// <inheritdoc />
public Task DeleteItemAsync(string itemPath)
public Task<bool> TryDeleteItemAsync(string itemPath)
{
return this.DeleteItemAsync(this.Folder, itemPath);
return TryDeleteItemAsync(this.Folder, itemPath);
}

/// <summary>
/// Saves an object inside a file.
/// </summary>
/// <typeparam name="T">Type of object saved.</typeparam>
/// <param name="filePath">Path to the file that will contain the object.</param>
/// <param name="value">Object to save.</param>
/// <returns>Waiting task until completion.</returns>
public Task<StorageFile> SaveFileAsync<T>(string filePath, T value)
/// <inheritdoc />
public Task<bool> TryRenameItemAsync(string itemPath, string newName)
{
return this.SaveFileAsync(this.Folder, filePath, value);
return TryRenameItemAsync(this.Folder, itemPath, newName);
}

private async Task<T?> ReadFileAsync<T>(StorageFolder folder, string filePath, T? @default = default)
{
string value = await StorageFileHelper.ReadTextFromFileAsync(folder, filePath);
string value = await StorageFileHelper.ReadTextFromFileAsync(folder, NormalizePath(filePath));
return (value != null) ? this.Serializer.Deserialize<T>(value) : @default;
}

private async Task<IEnumerable<(DirectoryItemType, string)>> ReadFolderAsync(StorageFolder folder, string folderPath)
{
var targetFolder = await folder.GetFolderAsync(folderPath);
var targetFolder = await folder.GetFolderAsync(NormalizePath(folderPath));
var items = await targetFolder.GetItemsAsync();

return items.Select((item) =>
Expand All @@ -307,20 +302,47 @@ public Task<StorageFile> SaveFileAsync<T>(string filePath, T value)
});
}

private Task<StorageFile> SaveFileAsync<T>(StorageFolder folder, string filePath, T value)
private async Task<StorageFile> CreateFileAsync<T>(StorageFolder folder, string filePath, T value)
{
return StorageFileHelper.WriteTextToFileAsync(folder, this.Serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting);
return await StorageFileHelper.WriteTextToFileAsync(folder, this.Serializer.Serialize(value)?.ToString(), NormalizePath(filePath), CreationCollisionOption.ReplaceExisting);
}

private async Task CreateFolderAsync(StorageFolder folder, string folderPath)
{
await folder.CreateFolderAsync(folderPath, CreationCollisionOption.OpenIfExists);
await folder.CreateFolderAsync(NormalizePath(folderPath), CreationCollisionOption.OpenIfExists);
}

private async Task<bool> TryDeleteItemAsync(StorageFolder folder, string itemPath)
{
try
{
var item = await folder.GetItemAsync(NormalizePath(itemPath));
await item.DeleteAsync();
return true;
}
catch
{
return false;
}
}

private async Task<bool> TryRenameItemAsync(StorageFolder folder, string itemPath, string newName)
{
try
{
var item = await folder.GetItemAsync(NormalizePath(itemPath));
await item.RenameAsync(newName, NameCollisionOption.FailIfExists);
return true;
}
catch
{
return false;
}
}

private async Task DeleteItemAsync(StorageFolder folder, string itemPath)
private string NormalizePath(string path)
{
var item = await folder.GetItemAsync(itemPath);
await item.DeleteAsync();
return Path.Combine(Path.GetDirectoryName(path), Path.GetFileName(path));
}
}
}
10 changes: 9 additions & 1 deletion Microsoft.Toolkit/Helpers/ObjectStorage/IFileStorageHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ public interface IFileStorageHelper
/// </summary>
/// <param name="itemPath">The path to the item for deletion.</param>
/// <returns>Waiting task until completion.</returns>
Task DeleteItemAsync(string itemPath);
Task<bool> TryDeleteItemAsync(string itemPath);

/// <summary>
/// Rename an item.
/// </summary>
/// <param name="itemPath">The path to the target item.</param>
/// <param name="newName">The new nam for the target item.</param>
/// <returns>Waiting task until completion.</returns>
Task<bool> TryRenameItemAsync(string itemPath, string newName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,95 @@ public void Test_StorageHelper_NewPersonTest()
Assert.AreEqual(input.Age, output.Age);
}

[TestCategory("Helpers")]
[TestMethod]
public async Task Test_StorageHelper_FileCRUDTest()
{
var fileName = "TestFile.txt";
var fileName2 = "TestFile2.txt";
var fileContents = "this is a test";
var fileContents2 = "this is also a test";
var storageHelper = ApplicationDataStorageHelper.GetCurrent();

// Create a file
await storageHelper.CreateFileAsync(fileName, fileContents);

// Read a file
var readContents = await storageHelper.ReadFileAsync<string>(fileName);
Assert.AreEqual(fileContents, readContents);

// Update a file
await storageHelper.CreateFileAsync(fileName, fileContents2);
var readContents2 = await storageHelper.ReadFileAsync<string>(fileName);
Assert.AreEqual(fileContents2, readContents2);

// Rename a file
var itemRenamed = await storageHelper.TryRenameItemAsync(fileName, fileName2);
Assert.IsTrue(itemRenamed);

// Delete a file
var itemDeleted = await storageHelper.TryDeleteItemAsync(fileName2);
Assert.IsTrue(itemDeleted);
}

[TestCategory("Helpers")]
[TestMethod]
public async Task Test_StorageHelper_SubFolderCRUDTest()
{
var folderName = "TestFolder1";
var subFolderName = "TestSubFolder";
var subFolderName2 = "TestSubFolder2";
var subFolderPath = $"{folderName}/{subFolderName}";
var subFolderPath2 = $"{folderName}/{subFolderName2}";
var fileName = "TestFile.txt";
var fileName2 = "TestFile2.txt";
var filePath = $"{subFolderPath}/{fileName}";
var filePath2 = $"{subFolderPath2}/{fileName2}";
var fileContents = "this is a test";

var storageHelper = ApplicationDataStorageHelper.GetCurrent();

// Attempt to delete the folder to clean up from any previously failed test runs.
await storageHelper.TryDeleteItemAsync(folderName);

// Create a subfolder
await storageHelper.CreateFolderAsync(subFolderPath);

// Create a file in the subfolder
await storageHelper.CreateFileAsync(filePath, fileContents);

// Read a file from the subfolder
var readContents = await storageHelper.ReadFileAsync<string>(filePath);
Assert.AreEqual(fileContents, readContents);

// List subfolder contents
var folderItems = await storageHelper.ReadFolderAsync(subFolderPath);
var folderItemsList = folderItems.ToList();
Assert.AreEqual(1, folderItemsList.Count());
Assert.AreEqual(fileName, folderItemsList[0].Name);
Assert.AreEqual(Microsoft.Toolkit.Helpers.DirectoryItemType.File, folderItemsList[0].ItemType);

// Rename a file in a subfolder
var itemRenamed = await storageHelper.TryRenameItemAsync(filePath, fileName2);
Assert.IsTrue(itemRenamed);

// Rename a subfolder
var folderRenamed = await storageHelper.TryRenameItemAsync(subFolderPath, subFolderName2);
Assert.IsTrue(folderRenamed);

// Delete a file in a subfolder
var fileDeleted = await storageHelper.TryDeleteItemAsync(filePath2);
Assert.IsTrue(fileDeleted);

// Delete a subfolder
var subFolderDeleted = await storageHelper.TryDeleteItemAsync(subFolderPath2);
Assert.IsTrue(subFolderDeleted);

// Delete the folder to clean up.
var folderDeleted = await storageHelper.TryDeleteItemAsync(folderName);
Assert.IsTrue(folderDeleted);
}

public class Person
{
public string Name { get; set; }
Expand Down