Skip to content

Mocks & New IRoboCommand for non-windows platforms#217

Merged
PCAssistSoftware merged 41 commits intoPCAssistSoftware:devfrom
RFBomb:Extensions.Mocks
Apr 20, 2026
Merged

Mocks & New IRoboCommand for non-windows platforms#217
PCAssistSoftware merged 41 commits intoPCAssistSoftware:devfrom
RFBomb:Extensions.Mocks

Conversation

@RFBomb
Copy link
Copy Markdown
Contributor

@RFBomb RFBomb commented Mar 25, 2026

I required some mocks for my project, so I opted to add them into the Extensions package.
To make best use of the mocks, I'm also creating a new IRoboCommand to fully simulate the actions of RoboCopy via the IFileCopierFactory interfaces that were introduced a while back. This would allow full control of the copy and logging process by consumers that want it, and should also allow for cross-platform usage via custom IFileCopiers (like the StreamedFileCopier)

Overview

Base library changes:

  • Exposed some private methods from Authentication.cs
  • Added method RetryOptions.GetRetryWaitTime() to provide a TimeSpan based on the specified wait time
  • Improved documentation comments for SelectionOptions and CopyOptions
  • Added ProcessedDirectoryFlag.MisMatch
  • Added a storage int for the enum value for ProcessedFileInfo

Add RoboSharp.Extensions.RoboCommandPortable

  • This is a new IRoboCommand that is fully managed instead of starting a new process outside of the application's control.
  • This utilizes an IFileCopierFactory to allow consumers to create their own implementations, or use the baked in Windows.CopyFileEx or StreamedCopier factories.
  • The aim for this class is parity (as close to it) with RoboCopy, while also bringing support to cross platform targets.
  • Note : RoboCommand is still the suggested way to go due to speed and the backing of Microsoft, but this allows for more power over unit tests if (which was my requirement) and also it should work fine in a linux environment. I can't vouch for speed compared to other tools in that space though.

RoboSharp.Extensions.Mocks

  • This namespace has been introduced for various mocking for use with Dependency Injection unit testing where you may not want to actually perform copy operations during the test, but still need an IRoboCommand.

Unit Testing

  • Many unit tests have been refactored to make the tests more targeted and more consistent. No more sharing of destination directories between tests. What was being tested has not changed, but the structure of the tests have.
  • CommandTests has been introduced to learn how robocopy works and validate the tests against actual robocopy.
  • RoboMover and RoboCommandPortable tests are now derived from this test suite to ensure they perform identical to robocopy.

BackupApp

  • Removed Net48 target in favor of .Net10-windows and to allow testing of the additional command types provided by RoboSharp.Extensions
  • Now uses an IRoboCommandFactory to create the command of the specified type. Defaults to standard RoboCopy.
  • Added support for LoggingOptions logging paths

Build-And-Test Github Action

  • A github action has been introduced to build the solution, run all robosharp tests, then run all extensions tests, and finally grab various artifacts from the build.
  • The action will run on pushes to dev and pull requests to dev.

RFBomb added 2 commits March 25, 2026 17:04
- This new IRoboCommand utilizes the IFileCopierFactory to perform copy operations without creating a new RoboCopy process. This allows full control over the actual copy operation if desired, and allows for cross-platform targeting if needed.
- Added IAuthenticator to allow customization of the FactoryCommand's authentication prior to starting the command. By default simply verifies it can access source and destination.
- Adjusted helpers and extension methods as needed.
@PCAssistSoftware
Copy link
Copy Markdown
Owner

nice, I will keep following the progress of these changes. Thanks Robert

@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Mar 27, 2026

Just an update to this, I've added a github action to my repo. It does basically the same thing as AppVeyor integration, but I find it provides more useful and more controlled behavior.

I have it set up to build the solution, run the primary tests (against Robocommand), then run the extension tests. If all completes, it will package up the nuget packages and the compiled exe's (for backup app and console app) and upload as an artifact.

This can also be set up to deploy to nuget automatically on a successful push to main (dev) if you wanted to implement that.

I'm also reworking some unit tests to be more efficient, more isolated, and better for testing custom implementations (RoboMover and the new RoboCommandPortable which is a managed version of RoboCopy instead of calling a process).

Note i do not plan to implement some advanced functions (scheduling, useFAT times, etc), but core functionality should be 1:1.

@PCAssistSoftware
Copy link
Copy Markdown
Owner

Okay thanks for update.

The idea of using github actions instead of appveyor is interesting and something I may consider at some point, but for now quite happy with appveyor and they have been very helpful recently in adding the VS 2026 and .NET 10 images for me to use for the most recent release.

@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Mar 27, 2026

I just wanted to inform you of the addition. Something I’ve noticed is that AppVeyor is passing while the GitHub action is (correctly) failing the unit tests.

@PCAssistSoftware
Copy link
Copy Markdown
Owner

I appreciate it, its certainly good to know of an alternative, as appveyor can sometimes be really problematic, and slow in supporting new .NET versions etc. So thank you

RFBomb added 3 commits March 29, 2026 20:40
- Provide a message to the log file if file logging is disabled via RoboSharpConfiguration
Rework CommandTests.cs since Claude.ai was not producing passing tests. Tests are passing locally using RoboCommand.
Trigger RoboCommandPortable to test against the RoboCommand test suite
@RFBomb RFBomb force-pushed the Extensions.Mocks branch from 6743a7a to a296860 Compare March 30, 2026 00:41
@PCAssistSoftware
Copy link
Copy Markdown
Owner

Okay, I will give it a try out when I get a moment and then get back to you. Please bear with me though as currently stacked with work before going away for a few days, so it maybe when I get back

@RFBomb RFBomb marked this pull request as ready for review April 1, 2026 20:44
@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Apr 1, 2026

No worries, I'm in absolutely no rush for this. I was more so finishing the original idea behind the extensions than anything, as well as implementing some nice-to-haves for unit testing that I found myself needing.

Copilot AI review requested due to automatic review settings April 15, 2026 13:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds cross-platform and test-friendly infrastructure to RoboSharp by introducing a fully managed IRoboCommand implementation (RoboCommandPortable), plus a set of mocks in RoboSharp.Extensions to support DI/unit-testing scenarios.

Changes:

  • Introduces RoboCommandPortable (managed Robocopy-like execution) plus supporting factories/authenticators and updated extensions helpers.
  • Adds RoboSharp.Extensions.Mocks (mock IRoboCommand, mock IFileCopier/pairs/factory) for unit tests and DI.
  • Refactors and modernizes unit tests (per-test temp destinations, async/timeout/cancellation), bumps MSTest, and adds a build-and-test GitHub Action.

Reviewed changes

Copilot reviewed 62 out of 62 changed files in this pull request and generated no comments.

Show a summary per file
File Description
RoboSharpUnitTesting/Test_Setup.cs Refactors unit test setup to use per-test destinations + cancellation support.
RoboSharpUnitTesting/SerializationTests.cs Uses per-test temp destination + cleanup.
RoboSharpUnitTesting/SelectionOptionsTests.cs Updates assertion API usage for newer MSTest.
RoboSharpUnitTesting/RoboSharpUnitTesting.csproj Bumps MSTest, sets LangVersion, ensures test file copy to output.
RoboSharpUnitTesting/RoboQueueEventTests.cs Makes tests async and isolates destinations per test.
RoboSharpUnitTesting/RoboCommandParserTests.cs Updates assertion API usage for newer MSTest.
RoboSharpUnitTesting/RoboCommandEventTests.cs Makes tests async and isolates destinations per test.
RoboSharpUnitTesting/ProgressEstimatorTests.cs Adds cancellation/timeout usage and per-test destinations; updates expected counts.
RoboSharpUnitTesting/LoggingOptionsTests.cs Makes tests async and isolates destinations per test.
RoboSharpUnitTesting/JobOptionsTests.cs Makes tests async and isolates destinations per test.
RoboSharp/VersionManager.cs Adds platform guard annotation for Windows detection.
RoboSharp/SelectionOptions.cs Improves XML documentation for selection flags.
RoboSharp/RoboSharpConfiguration.cs Adjusts directory-class token defaults and adds directory mismatch mapping.
RoboSharp/RoboSharp.csproj Bumps package version to 1.6.3.
RoboSharp/RoboCommand.cs Ensures parsed ProcessedFileInfo attempts to set enum classification.
RoboSharp/RetryOptions.cs Adds GetRetryWaitTime() helper.
RoboSharp/Results/ResultsBuilder.cs Emits a log message when file logging is disabled after header parsing.
RoboSharp/Results/ProgressEstimator.cs Adds directory mismatch handling and a new AddDirExtra pathway.
RoboSharp/ProcessedFileInfo.cs Adds stored enum int + mapping helpers to translate log class strings to enums.
RoboSharp/ProcessedDirectoryFlag.cs Adds MisMatch directory flag.
RoboSharp/DefaultConfigurations/RoboSharpConfig_EN.cs Updates default existing-dir token.
RoboSharp/CopyOptions.cs Improves XML documentation for /COPY: flags.
RoboSharp/Authentication.cs Exposes internal directory check methods publicly.
RoboSharp.sln Updates VS metadata and adds workflow file to solution items.
RoboSharp.Extensions/Windows/CopyFileExFactory.cs Adds Windows-only guard in factory ctor.
RoboSharp.Extensions/Windows/CopyFileEx.cs Adjusts overwrite behavior for hidden destination files.
RoboSharp.Extensions/StreamedCopier.cs Adjusts attribute handling and hidden-file overwrite behavior.
RoboSharp.Extensions/RoboSharp.Extensions.csproj Bumps package version and updates package documentation text.
RoboSharp.Extensions/RoboMover.cs Ensures results header is created for mover runs.
RoboSharp.Extensions/RoboCommandPortableFactory.cs Adds factory for creating RoboCommandPortable commands.
RoboSharp.Extensions/RoboCommandPortable.cs Adds managed, cross-platform IRoboCommand implementation using IFileCopierFactory.
RoboSharp.Extensions/Options/SelectionExtensions.cs Tightens newer-file exclusion checks to require destination existence.
RoboSharp.Extensions/Options/CopyExtensions.cs Adds empty-directory evaluation + redefines purging logic on IRoboCommand.
RoboSharp.Extensions/Mocks/MockRoboCommandFactory.cs Adds mock command factory for DI/testing.
RoboSharp.Extensions/Mocks/MockRoboCommand.cs Adds mock IRoboCommand implementation returning completed tasks.
RoboSharp.Extensions/Mocks/MockProcessedFilePair.cs Adds mutable processed file pair for tests/mocking.
RoboSharp.Extensions/Mocks/MockProcessedDirectoryPair.cs Adds mutable processed directory pair for tests/mocking.
RoboSharp.Extensions/Mocks/MockIFileCopier.cs Adds mock IFileCopier with delay/return customization.
RoboSharp.Extensions/Mocks/MockFileCopierFactory.cs Adds mock copier factory that produces mock copiers.
RoboSharp.Extensions/IFilePairExtensions.cs Moves/expands evaluation logic for file pairs + UTC timestamp compare.
RoboSharp.Extensions/IDirectoryPairExtensions.cs Moves/expands evaluation logic for directory pairs + mismatch detection helper.
RoboSharp.Extensions/IAuthenticator.cs Adds authenticator abstraction and default implementations for portable command.
RoboSharp.Extensions/Helpers/ResultsBuilder.cs Adjusts logging behavior for extras/skipped + adds mismatch reporting and header suppression.
RoboSharp.Extensions/DirectoryPair.cs Adds helper methods to create child pairs (NET6+).
RoboSharp.Extensions.UnitTests/Windows/SymbolicLinkTests.cs Windows-gates symlink tests and adds admin-check behavior.
RoboSharp.Extensions.UnitTests/Windows/CopyFileExTests.cs Major refactor of CopyFileEx tests to use shared copier test base + richer cases.
RoboSharp.Extensions.UnitTests/RoboSharp.Extensions.UnitTests.csproj Adds targets and bumps MSTest package version.
RoboSharp.Extensions.UnitTests/RoboMoverTests.cs Refactors tests onto shared CommandTests<T> suite + async flow.
RoboSharp.Extensions.UnitTests/RoboCommandPortableTests.cs Adds full CommandTests<T> suite against RoboCommandPortable implementations.
RoboSharp.Extensions.UnitTests/Options/CopyExtensionsTests.cs Updates asserts and messages for clearer failures.
RoboSharp.Extensions.UnitTests/IFileCopierTests.cs Reworks copier tests into generic base + adds StreamedCopier test type.
RoboSharp.Extensions.UnitTests/Helpers/ResultsBuilderTests.cs Updates builder setup + adjusts skipped logging expectations.
RoboSharp.Extensions.UnitTests/DirectoryPairTests.cs Uses per-test temp destination + adds mismatch test coverage.
RoboSharp.Extensions.UnitTests/BatchCommandTests.cs Uses per-test temp destination + cancellation token plumbing + timeouts.
RoboSharp.BackupApp/ViewModels/MainWindowViewModel.cs Wires UI command generator to a selectable command factory.
RoboSharp.BackupApp/ViewModels/CommandGeneratorViewModel.cs Switches to factory-created commands; copies option objects into created commands.
RoboSharp.BackupApp/RoboSharp.BackupApp.csproj Drops net48 target, keeps Windows targets.
RoboSharp.BackupApp/MainWindow.xaml Adds UI selector for command type (RoboCommand/Portable/Mover).
.github/workflows/build-and-test.yml Adds CI workflow to restore/build/test/pack/publish artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@PCAssistSoftware
Copy link
Copy Markdown
Owner

Hi

Finally found some time to take a look at this.

First question, why the change below as this breaks existing functionality in my apps?

RoboSharp/DefaultConfigurations/RoboSharpConfig_EN.cs line 36

        LogParsing_ExistingDir = "Existing Dir";

changed to

        LogParsing_ExistingDir = ""; 

And also related area to this e.g.

RoboSharp/RoboSharpConfiguration.cs line 329

       get { return existingDirToken ?? GetDefaultConfiguration().existingDirToken ?? "Existing Dir"; }

changed to

        get { return existingDirToken ?? GetDefaultConfiguration().existingDirToken ?? ""; }

@PCAssistSoftware
Copy link
Copy Markdown
Owner

any other breaking changes I need to be aware of?

@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Apr 18, 2026

Good catch, I'll re-review. That should be the only one, but I agree with you and I'll revert it since its been there a long time.

Robocopy doesn't emit a token there for existing dirs, so it was breaking my unit tests, if i recall correctly. But thats easy enough to handle with a custom configuration, so that is what I'll implement for the unit tests.

RFBomb added 3 commits April 20, 2026 11:00
Add support for Logging paths to the MainWindow
- RoboSharpConfig_EN had the 'Existing Directory' overridden, and some consumers rely on that functionality. Reverted back to previous value.
- Added unit tests for to ensure this does not occur in future.
   - This required isolating and exposing the function that transforms a log line into a ProcessedFileInfo for a directory or file. `RoboCommand.ParseFileorDirectory`
Transformed GetDefaultConfiguration() to use [GeneratedRegex]
Comment thread RoboSharp/RoboCommand.cs Outdated
Comment thread RoboSharp/RoboSharpConfiguration.cs Outdated
Copy link
Copy Markdown
Owner

@PCAssistSoftware PCAssistSoftware left a comment

Choose a reason for hiding this comment

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

couple of comments left in the code, will test fully later

N.B. First time using submit review, so hopefully this works!

RFBomb and others added 3 commits April 20, 2026 12:02
- Symbolic Link testing requires Admin privileges.
- Instead of declaring the test passed, it will not properly communicate that the test has been ignored if run without admin privileges.
@RFBomb RFBomb requested a review from PCAssistSoftware April 20, 2026 16:54
Copy link
Copy Markdown
Owner

@PCAssistSoftware PCAssistSoftware left a comment

Choose a reason for hiding this comment

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

All looking good, the initial problem I encountered is now resolved. Will run some more thorough tests later today or tomorrow and then get back to you, but unless I find any issues with existing apps this should be good to merge

@PCAssistSoftware PCAssistSoftware dismissed their stale review April 20, 2026 17:02

changes made and checked

Normalize nuget package versions to 1.6.3.0
@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Apr 20, 2026

OK cool, I'm just did one last commit to normalize the version numbers, since I noticed I bumped extensions greater than robosharp. Both will be v1.6.3 (nuget is currently 1.6.2).

(Extensions had been bumped more due to my messing around with an local nuget repository, but once its published I'll defer my stuff back to standard nuget)

@PCAssistSoftware
Copy link
Copy Markdown
Owner

Okay, have now tested this release with all my apps and is working fine, also ran all the tests and had a look and test of new functionality via backup app and all looks good, so if nothing more you want to amend then I am more than happy to merge. Thanks again for all you do.

@RFBomb
Copy link
Copy Markdown
Contributor Author

RFBomb commented Apr 20, 2026

I'm happy that its all working. As part of this commit I had buffed up some of the unit tests as well to be better testing of some things and allow easier testing of others. Part of that was isolating each test to a randomly generated folder instead of always using same source and destination, which previously (rare occasion) had some issues polluting between tests.

Suffice to say, merge away!

@PCAssistSoftware PCAssistSoftware merged commit ad0efe8 into PCAssistSoftware:dev Apr 20, 2026
1 check passed
@RFBomb RFBomb deleted the Extensions.Mocks branch April 20, 2026 19:49
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.

3 participants