Skip to content

Conversation

T-rav
Copy link
Contributor

@T-rav T-rav commented May 29, 2025

Summary

This PR addresses several issues in the codebase and adds async versions of all synchronous methods.

Changes

  1. Bug Fixes:

    • Added proper error handling in MoveWithOverwrite and Rename methods with try-catch blocks
    • Added consistent null checking for all methods
    • Fixed the Append test that was incorrectly using Write method
    • Added directory existence check in ReadAllLines
  2. Improvements:

    • Updated stream disposal in Write_File_To_Path to use modern using declaration
    • Added validation for file names to ensure they don't contain path separators
    • Added comprehensive XML documentation comments to all public APIs
    • Added clear comments about encoding assumptions
  3. New Features:

    • Added asynchronous versions of all synchronous methods:
      • GetDocumentAsync
      • ListAsync
      • ExistsAsync
      • DeleteAsync
      • MoveAsync
      • MoveWithOverwriteAsync
      • RenameAsync
    • Added comprehensive tests for all new async methods

Testing

All 92 tests are passing, including the new tests for async methods. Each async method has a test to verify it behaves the same as its synchronous counterpart.

Future Work

Thread safety for static properties like NullDocument could be improved in a future PR.

Summary by CodeRabbit

  • New Features
    • Introduced asynchronous file system operations, including listing, checking existence, deleting, retrieving, moving, overwriting, and renaming files.
  • Bug Fixes
    • Improved input validation for file and directory names, handling invalid characters and empty paths.
    • Enhanced error handling to provide clearer feedback and prevent silent failures.
  • Documentation
    • Added comprehensive XML documentation to all public classes, interfaces, and methods for improved clarity.
  • Tests
    • Expanded test coverage to include asynchronous file system operations, ensuring consistent behavior with synchronous methods.

This commit:
1. Adds proper error handling in MoveWithOverwrite and Rename methods
2. Adds consistent null checking across all methods
3. Updates stream disposal to use modern C# syntax
4. Adds file name validation
5. Adds comprehensive XML documentation comments
6. Adds asynchronous versions of all synchronous methods
7. Fixes the Append test that was incorrectly using Write
8. Adds comprehensive tests for all new async methods
Copy link

coderabbitai bot commented May 29, 2025

Walkthrough

This update introduces asynchronous methods to the file system interface and its implementation, expanding support for async file operations such as listing, existence checks, deletion, document retrieval, moving, overwriting, and renaming. Corresponding async unit tests are added. All public methods now include comprehensive XML documentation, and input validation and error handling are improved throughout.

Changes

File(s) Change Summary
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs Added async method signatures for all main file operations; added XML documentation for all methods.
source/StoneAge.Data.FileSystem/FileSystem.cs Implemented async methods; improved validation and error handling; added XML documentation; updated sync methods for robustness.
source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs Added async test classes and methods for all new async operations, mirroring sync test coverage.
source/StoneAge.Data.FileSystem/Document.cs Added XML documentation comments to the Document class and its members.
source/StoneAge.Data.FileSystem/Domain/IDocument.cs Added XML documentation comments to the IDocument interface and its properties.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant IFileSystem
    participant FileSystem
    participant FileSystem_IO

    Test->>IFileSystem: Call Async Method (e.g., ListAsync)
    IFileSystem->>FileSystem: Forward Async Call
    FileSystem->>FileSystem_IO: Perform Async File Operation
    FileSystem_IO-->>FileSystem: Return Result
    FileSystem-->>IFileSystem: Return Task<Result>
    IFileSystem-->>Test: Await and Return Result
Loading

Possibly related PRs

  • Kode-Rex/DotnetCore-FileSystem#3: Adds null data handling inside Write_File_To_Path and a related test; both PRs expand file system test coverage and robustness, particularly for file writing scenarios.

Poem

In the warren, code hops anew,
Async and sync, now both in view!
With checks and docs, so neat and bright,
File bunnies test by day and night.
We hop through files, we leap through lines—
Robust and swift, our code now shines!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
source/StoneAge.Data.FileSystem/Domain/IDocument.cs (1)

1-1: Remove unused using statement.

The using System.Text; directive is not used in this file and should be removed to keep the code clean.

-using System.Text;
source/StoneAge.Data.FileSystem/FileSystem.cs (5)

15-19: Consider thread safety for the static NullDocument field.

As mentioned in the PR objectives, the static NullDocument field may need thread safety improvements in the future. While the field reference is readonly, the Document object's properties could potentially be modified if accessed concurrently.


76-86: Improve file size formatting for better readability.

The current implementation converts the file size to a string without formatting, which may result in many decimal places. Consider formatting the output for better readability.

- Size = Convert_Bytes_To_Megabytes(info.Length).ToString()
+ Size = $"{Convert_Bytes_To_Megabytes(info.Length):F2} MB"

Additionally, consider extracting the conversion function as a private method for potential reuse across the class.


96-99: Consider using ConfigureAwait(false) for library code.

For better performance in library code, consider using ConfigureAwait(false) on the async operations to avoid capturing the synchronization context unnecessarily.

Example for ListAsync:

- return await Task.Run(() => List(directory));
+ return await Task.Run(() => List(directory)).ConfigureAwait(false);

Apply similar changes to other async wrapper methods: ExistsAsync, DeleteAsync, GetDocumentAsync, MoveAsync, MoveWithOverwriteAsync, and RenameAsync.

Also applies to: 121-124, 154-157, 196-199, 231-234, 271-274, 315-318


369-371: Update documentation to specify UTF-8 encoding.

The XML documentation mentions "default encoding for the system," but File.ReadAllLinesAsync specifically uses UTF-8 encoding by default.

- /// This method assumes the file is encoded in the default encoding for the system.
+ /// This method assumes the file is encoded in UTF-8.

436-436: Fix typo in error message.

- result.ErrorMessages.Add($"An error occured creating directory structure [{e.Message}]");
+ result.ErrorMessages.Add($"An error occurred creating directory structure [{e.Message}]");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3a6c8f and 4345679.

📒 Files selected for processing (5)
  • source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (1 hunks)
  • source/StoneAge.Data.FileSystem/Document.cs (1 hunks)
  • source/StoneAge.Data.FileSystem/Domain/IDocument.cs (1 hunks)
  • source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (1 hunks)
  • source/StoneAge.Data.FileSystem/FileSystem.cs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
source/StoneAge.Data.FileSystem/Domain/IDocument.cs (4)
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (2)
  • IDocument (73-73)
  • IDocument (80-80)
source/StoneAge.Data.FileSystem/DocumentBuilder.cs (1)
  • IDocument (48-56)
source/StoneAge.Data.FileSystem/FileSystem.cs (2)
  • IDocument (164-167)
  • IDocument (177-189)
source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (1)
  • IDocument (1170-1177)
source/StoneAge.Data.FileSystem/Document.cs (5)
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (2)
  • IDocument (73-73)
  • IDocument (80-80)
source/StoneAge.Data.FileSystem/DocumentBuilder.cs (1)
  • IDocument (48-56)
source/StoneAge.Data.FileSystem/Domain/IDocumentBuilderGeneration.cs (1)
  • IDocument (5-5)
source/StoneAge.Data.FileSystem/FileSystem.cs (2)
  • IDocument (164-167)
  • IDocument (177-189)
source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (1)
  • IDocument (1170-1177)
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (6)
source/StoneAge.Data.FileSystem/Domain/WriteFileResult.cs (2)
  • WriteFileResult (5-16)
  • WriteFileResult (12-15)
source/StoneAge.Data.FileSystem/FileSystem.cs (10)
  • WriteFileResult (394-418)
  • WriteFileResult (425-442)
  • IDocument (164-167)
  • IDocument (177-189)
  • IEnumerable (69-89)
  • Exists (106-114)
  • Delete (130-147)
  • Move (207-223)
  • MoveWithOverwrite (242-263)
  • Rename (282-307)
source/StoneAge.Data.FileSystem/DocumentBuilder.cs (1)
  • IDocument (48-56)
source/StoneAge.Data.FileSystem/Domain/IDocumentBuilderGeneration.cs (1)
  • IDocument (5-5)
source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (1)
  • IDocument (1170-1177)
source/StoneAge.Data.FileSystem/Domain/FileInformation.cs (1)
  • FileInformation (3-7)
source/StoneAge.Data.FileSystem/FileSystem.cs (6)
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (18)
  • IDocument (73-73)
  • IDocument (80-80)
  • Task (17-17)
  • Task (25-25)
  • Task (39-39)
  • Task (53-53)
  • Task (66-66)
  • Task (87-87)
  • Task (94-94)
  • Task (110-110)
  • Task (126-126)
  • Task (142-142)
  • IEnumerable (32-32)
  • Exists (46-46)
  • Delete (59-59)
  • Move (102-102)
  • MoveWithOverwrite (118-118)
  • Rename (134-134)
source/StoneAge.Data.FileSystem/DocumentBuilder.cs (2)
  • IDocument (48-56)
  • DocumentBuilder (8-67)
source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (1)
  • IDocument (1170-1177)
source/StoneAge.Data.FileSystem/Document.cs (2)
  • Document (10-37)
  • ToString (33-36)
source/StoneAge.Data.FileSystem/Domain/WriteFileResult.cs (2)
  • WriteFileResult (5-16)
  • WriteFileResult (12-15)
source/StoneAge.Data.FileSystem/Domain/FileInformation.cs (1)
  • FileInformation (3-7)
🔇 Additional comments (11)
source/StoneAge.Data.FileSystem/Domain/IFileSystem.cs (1)

1-144: Excellent async interface design with comprehensive documentation!

The addition of asynchronous counterparts to all file system operations follows .NET async patterns perfectly. The XML documentation is thorough and consistent across all methods. The interface maintains backward compatibility while expanding functionality.

source/StoneAge.Data.FileSystem/Domain/IDocument.cs (1)

5-19: Well-documented interface with clear property descriptions.

The XML documentation clearly explains the purpose of each property and the interface itself. This will greatly improve API usability.

source/StoneAge.Data.FileSystem/Document.cs (1)

6-37: Excellent documentation with important encoding clarifications.

The XML documentation is comprehensive and particularly valuable for the ToString() method, which clearly explains the UTF-8 encoding assumption and potential issues with other encodings. This will help prevent encoding-related bugs in consumer code.

source/StoneAge.Data.FileSystem.Tests/FileSystemTests.cs (8)

268-323: Comprehensive async test coverage with good consistency validation.

The ListAsync test class properly mirrors the synchronous tests and includes a valuable consistency test to ensure both versions behave identically. This pattern helps maintain behavioral parity between sync and async implementations.


381-453: Well-structured async existence checks with comprehensive edge case testing.

The ExistsAsync tests cover all the important scenarios including null/whitespace inputs, existing/non-existing files, and directory existence. The consistency test at the end is particularly valuable for ensuring sync/async parity.


516-593: Thorough async deletion test coverage.

The DeleteAsync test class properly validates all deletion scenarios and includes good consistency testing between sync and async versions. The tests appropriately handle edge cases like null paths and non-existent files.


639-697: Complete async document retrieval testing.

The GetDocumentAsync tests comprehensively cover document retrieval scenarios and include proper validation that both sync and async versions return equivalent results (comparing both Name and Data properties).


853-940: Robust async file move operation testing.

The MoveAsync test class covers all the critical move scenarios including success cases, failures due to missing source files, and conflicts with existing destination files. The consistency test properly validates that both file operations complete successfully.


965-1024: Comprehensive async move-with-overwrite testing.

The MoveWithOverwriteAsync tests properly validate the overwrite functionality and include good consistency testing. The test setup with different content for source and destination files ensures proper validation of the move operation.


1069-1133: Complete async rename operation testing.

The RenameAsync test class provides thorough coverage of rename scenarios and includes proper consistency validation between sync and async versions. The tests appropriately use unique file names to avoid conflicts.


1-1181: Outstanding comprehensive test suite for async file operations.

This test file demonstrates excellent testing practices:

  • Complete coverage of all new async methods
  • Proper mirroring of existing sync test patterns
  • Valuable consistency tests ensuring sync/async behavioral parity
  • Good edge case coverage (null inputs, missing files, etc.)
  • Clean test organization with nested test fixtures

The 92 passing tests mentioned in the PR objectives indicate robust validation of the new async functionality.

Comment on lines +394 to +418
private WriteFileResult Write_File_To_Path(IDocument file, string filePath, FileMode fileMode)
{
var result = new WriteFileResult();

if (file.Data == null)
{
result.ErrorMessages.Add("No file data provided; cannot write file.");
return result;
}

try
{
// Modern using declaration (C# 8.0+)
using var stream = new FileStream(filePath, fileMode);
stream.Write(file.Data);

result.FullFilePath = filePath;
}
catch (Exception e)
{
result.ErrorMessages.Add($"An error occured writing the file [{e.Message}]");
}

return result;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use async I/O operations and fix typo.

This method is called from async methods but uses synchronous I/O. Also, there's a typo in the error message.

- private WriteFileResult Write_File_To_Path(IDocument file, string filePath, FileMode fileMode)
+ private async Task<WriteFileResult> Write_File_To_PathAsync(IDocument file, string filePath, FileMode fileMode)
{
    var result = new WriteFileResult();

    if (file.Data == null)
    {
        result.ErrorMessages.Add("No file data provided; cannot write file.");
        return result;
    }

    try
    {
        // Modern using declaration (C# 8.0+)
        using var stream = new FileStream(filePath, fileMode);
-       stream.Write(file.Data);
+       await stream.WriteAsync(file.Data).ConfigureAwait(false);

        result.FullFilePath = filePath;
    }
    catch (Exception e)
    {
-       result.ErrorMessages.Add($"An error occured writing the file [{e.Message}]");
+       result.ErrorMessages.Add($"An error occurred writing the file [{e.Message}]");
    }

    return result;
}

Also update the callers in Write (line 58) and Append (line 358) methods to use await.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private WriteFileResult Write_File_To_Path(IDocument file, string filePath, FileMode fileMode)
{
var result = new WriteFileResult();
if (file.Data == null)
{
result.ErrorMessages.Add("No file data provided; cannot write file.");
return result;
}
try
{
// Modern using declaration (C# 8.0+)
using var stream = new FileStream(filePath, fileMode);
stream.Write(file.Data);
result.FullFilePath = filePath;
}
catch (Exception e)
{
result.ErrorMessages.Add($"An error occured writing the file [{e.Message}]");
}
return result;
}
private async Task<WriteFileResult> Write_File_To_PathAsync(IDocument file, string filePath, FileMode fileMode)
{
var result = new WriteFileResult();
if (file.Data == null)
{
result.ErrorMessages.Add("No file data provided; cannot write file.");
return result;
}
try
{
// Modern using declaration (C# 8.0+)
using var stream = new FileStream(filePath, fileMode);
await stream.WriteAsync(file.Data).ConfigureAwait(false);
result.FullFilePath = filePath;
}
catch (Exception e)
{
result.ErrorMessages.Add($"An error occurred writing the file [{e.Message}]");
}
return result;
}
🤖 Prompt for AI Agents
In source/StoneAge.Data.FileSystem/FileSystem.cs from lines 394 to 418, the
Write_File_To_Path method uses synchronous file I/O and contains a typo in the
error message ("occured" should be "occurred"). Refactor this method to use
async file I/O operations such as FileStream.WriteAsync and mark the method as
async returning Task<WriteFileResult>. Correct the typo in the error message
string. Additionally, update the callers of this method in the Write method
around line 58 and the Append method around line 358 to use await when calling
the updated async Write_File_To_Path method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant