diff --git a/src/c#/DrivelutionTest/Core/DriverUpdaterFactoryTests.cs b/src/c#/DrivelutionTest/Core/DriverUpdaterFactoryTests.cs
new file mode 100644
index 00000000..75feab57
--- /dev/null
+++ b/src/c#/DrivelutionTest/Core/DriverUpdaterFactoryTests.cs
@@ -0,0 +1,212 @@
+using GeneralUpdate.Drivelution.Core;
+using GeneralUpdate.Drivelution.Abstractions;
+using GeneralUpdate.Drivelution.Abstractions.Configuration;
+using Serilog;
+using Serilog.Core;
+
+namespace DrivelutionTest.Core;
+
+///
+/// Tests for DriverUpdaterFactory class.
+/// Validates platform detection, factory creation, and platform-specific implementations.
+///
+public class DriverUpdaterFactoryTests
+{
+ ///
+ /// Tests that Create method returns a non-null instance.
+ ///
+ [Fact]
+ public void Create_WithoutParameters_ReturnsNonNullInstance()
+ {
+ // Arrange & Act
+ var updater = DriverUpdaterFactory.Create();
+
+ // Assert
+ Assert.NotNull(updater);
+ Assert.IsAssignableFrom(updater);
+ }
+
+ ///
+ /// Tests that Create method accepts custom logger.
+ ///
+ [Fact]
+ public void Create_WithCustomLogger_ReturnsInstance()
+ {
+ // Arrange
+ var logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
+
+ // Act
+ var updater = DriverUpdaterFactory.Create(logger);
+
+ // Assert
+ Assert.NotNull(updater);
+ Assert.IsAssignableFrom(updater);
+ }
+
+ ///
+ /// Tests that Create method accepts custom options.
+ ///
+ [Fact]
+ public void Create_WithCustomOptions_ReturnsInstance()
+ {
+ // Arrange
+ var options = new DriverUpdateOptions
+ {
+ LogLevel = "Debug",
+ LogFilePath = "./logs/test.log"
+ };
+
+ // Act
+ var updater = DriverUpdaterFactory.Create(null, options);
+
+ // Assert
+ Assert.NotNull(updater);
+ }
+
+ ///
+ /// Tests that GetCurrentPlatform returns a valid platform name.
+ ///
+ [Fact]
+ public void GetCurrentPlatform_ReturnsValidPlatformName()
+ {
+ // Act
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+
+ // Assert
+ Assert.NotNull(platform);
+ Assert.Contains(platform, new[] { "Windows", "Linux", "MacOS", "Unknown" });
+ }
+
+ ///
+ /// Tests that IsPlatformSupported returns a boolean value.
+ ///
+ [Fact]
+ public void IsPlatformSupported_ReturnsBooleanValue()
+ {
+ // Act
+ var isSupported = DriverUpdaterFactory.IsPlatformSupported();
+
+ // Assert
+ // Windows and Linux should be supported
+ Assert.True(isSupported || DriverUpdaterFactory.GetCurrentPlatform() == "MacOS" || DriverUpdaterFactory.GetCurrentPlatform() == "Unknown");
+ }
+
+ ///
+ /// Tests that CreateValidator returns a non-null instance.
+ ///
+ [Fact]
+ public void CreateValidator_WithoutLogger_ReturnsNonNullInstance()
+ {
+ // Skip on MacOS and Unknown platforms
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+ if (platform == "MacOS" || platform == "Unknown")
+ {
+ return;
+ }
+
+ // Act
+ var validator = DriverUpdaterFactory.CreateValidator();
+
+ // Assert
+ Assert.NotNull(validator);
+ Assert.IsAssignableFrom(validator);
+ }
+
+ ///
+ /// Tests that CreateBackup returns a non-null instance.
+ ///
+ [Fact]
+ public void CreateBackup_WithoutLogger_ReturnsNonNullInstance()
+ {
+ // Skip on MacOS and Unknown platforms
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+ if (platform == "MacOS" || platform == "Unknown")
+ {
+ return;
+ }
+
+ // Act
+ var backup = DriverUpdaterFactory.CreateBackup();
+
+ // Assert
+ Assert.NotNull(backup);
+ Assert.IsAssignableFrom(backup);
+ }
+
+ ///
+ /// Tests that CreateValidator with custom logger works correctly.
+ ///
+ [Fact]
+ public void CreateValidator_WithCustomLogger_ReturnsInstance()
+ {
+ // Skip on MacOS and Unknown platforms
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+ if (platform == "MacOS" || platform == "Unknown")
+ {
+ return;
+ }
+
+ // Arrange
+ var logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
+
+ // Act
+ var validator = DriverUpdaterFactory.CreateValidator(logger);
+
+ // Assert
+ Assert.NotNull(validator);
+ }
+
+ ///
+ /// Tests that CreateBackup with custom logger works correctly.
+ ///
+ [Fact]
+ public void CreateBackup_WithCustomLogger_ReturnsInstance()
+ {
+ // Skip on MacOS and Unknown platforms
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+ if (platform == "MacOS" || platform == "Unknown")
+ {
+ return;
+ }
+
+ // Arrange
+ var logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
+
+ // Act
+ var backup = DriverUpdaterFactory.CreateBackup(logger);
+
+ // Assert
+ Assert.NotNull(backup);
+ }
+
+ ///
+ /// Tests that Create throws PlatformNotSupportedException on unsupported platforms.
+ /// This test documents expected behavior but cannot be easily tested on supported platforms.
+ ///
+ [Fact]
+ public void Create_OnSupportedPlatform_DoesNotThrow()
+ {
+ // Skip on MacOS as it's not yet implemented
+ var platform = DriverUpdaterFactory.GetCurrentPlatform();
+
+ if (platform == "MacOS")
+ {
+ // MacOS should throw PlatformNotSupportedException
+ Assert.Throws(() => DriverUpdaterFactory.Create());
+ return;
+ }
+
+ // Act & Assert - should not throw on Windows/Linux
+ var exception = Record.Exception(() => DriverUpdaterFactory.Create());
+ Assert.Null(exception);
+ }
+}
diff --git a/src/c#/DrivelutionTest/DrivelutionTest.csproj b/src/c#/DrivelutionTest/DrivelutionTest.csproj
new file mode 100644
index 00000000..7c3fec32
--- /dev/null
+++ b/src/c#/DrivelutionTest/DrivelutionTest.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs b/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs
new file mode 100644
index 00000000..c7460e4f
--- /dev/null
+++ b/src/c#/DrivelutionTest/GeneralDrivelutionTests.cs
@@ -0,0 +1,330 @@
+using GeneralUpdate.Drivelution;
+using GeneralUpdate.Drivelution.Abstractions.Models;
+using GeneralUpdate.Drivelution.Abstractions.Configuration;
+using Serilog;
+
+namespace DrivelutionTest;
+
+///
+/// Tests for GeneralDrivelution static entry point class.
+/// Validates factory methods, quick update methods, and platform info retrieval.
+///
+public class GeneralDrivelutionTests
+{
+ ///
+ /// Tests that Create method returns a non-null instance.
+ ///
+ [Fact]
+ public void Create_WithoutParameters_ReturnsNonNullInstance()
+ {
+ // Act
+ var updater = GeneralDrivelution.Create();
+
+ // Assert
+ Assert.NotNull(updater);
+ }
+
+ ///
+ /// Tests that Create method with options returns a non-null instance.
+ ///
+ [Fact]
+ public void Create_WithOptions_ReturnsNonNullInstance()
+ {
+ // Arrange
+ var options = new DriverUpdateOptions
+ {
+ LogLevel = "Information",
+ LogFilePath = "./logs/test.log"
+ };
+
+ // Act
+ var updater = GeneralDrivelution.Create(options);
+
+ // Assert
+ Assert.NotNull(updater);
+ }
+
+ ///
+ /// Tests that Create method with custom logger returns a non-null instance.
+ ///
+ [Fact]
+ public void Create_WithCustomLogger_ReturnsNonNullInstance()
+ {
+ // Arrange
+ var logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
+
+ // Act
+ var updater = GeneralDrivelution.Create(logger);
+
+ // Assert
+ Assert.NotNull(updater);
+ }
+
+ ///
+ /// Tests that Create method with custom logger and options returns instance.
+ ///
+ [Fact]
+ public void Create_WithCustomLoggerAndOptions_ReturnsInstance()
+ {
+ // Arrange
+ var logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console()
+ .CreateLogger();
+ var options = new DriverUpdateOptions
+ {
+ LogLevel = "Debug"
+ };
+
+ // Act
+ var updater = GeneralDrivelution.Create(logger, options);
+
+ // Assert
+ Assert.NotNull(updater);
+ }
+
+ ///
+ /// Tests that GetPlatformInfo returns valid platform information.
+ ///
+ [Fact]
+ public void GetPlatformInfo_ReturnsValidPlatformInfo()
+ {
+ // Act
+ var platformInfo = GeneralDrivelution.GetPlatformInfo();
+
+ // Assert
+ Assert.NotNull(platformInfo);
+ Assert.NotNull(platformInfo.Platform);
+ Assert.NotEmpty(platformInfo.Platform);
+ Assert.NotNull(platformInfo.OperatingSystem);
+ Assert.NotEmpty(platformInfo.OperatingSystem);
+ Assert.NotNull(platformInfo.Architecture);
+ Assert.NotEmpty(platformInfo.Architecture);
+ Assert.NotNull(platformInfo.SystemVersion);
+ Assert.NotEmpty(platformInfo.SystemVersion);
+ }
+
+ ///
+ /// Tests that PlatformInfo ToString returns a valid string.
+ ///
+ [Fact]
+ public void PlatformInfo_ToString_ReturnsValidString()
+ {
+ // Arrange
+ var platformInfo = GeneralDrivelution.GetPlatformInfo();
+
+ // Act
+ var result = platformInfo.ToString();
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.NotEmpty(result);
+ Assert.Contains(platformInfo.Platform, result);
+ Assert.Contains(platformInfo.OperatingSystem, result);
+ }
+
+ ///
+ /// Tests that QuickUpdateAsync with minimal parameters works (or throws expected exceptions).
+ ///
+ [Fact]
+ public async Task QuickUpdateAsync_WithMinimalParameters_HandlesGracefully()
+ {
+ // Arrange
+ var testFilePath = Path.Combine(Path.GetTempPath(), $"test_driver_{Guid.NewGuid()}.txt");
+ File.WriteAllText(testFilePath, "Test driver content");
+
+ try
+ {
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ FilePath = testFilePath,
+ TargetOS = "",
+ Architecture = ""
+ };
+
+ // Act
+ var result = await GeneralDrivelution.QuickUpdateAsync(driverInfo);
+
+ // Assert
+ Assert.NotNull(result);
+ // The result might fail due to validation or permissions, but should not crash
+ // Verify that result status is one of the valid enum values
+ Assert.True(Enum.IsDefined(typeof(UpdateStatus), result.Status));
+ }
+ finally
+ {
+ if (File.Exists(testFilePath))
+ {
+ File.Delete(testFilePath);
+ }
+ }
+ }
+
+ ///
+ /// Tests that QuickUpdateAsync with custom strategy works.
+ ///
+ [Fact]
+ public async Task QuickUpdateAsync_WithCustomStrategy_HandlesGracefully()
+ {
+ // Arrange
+ var testFilePath = Path.Combine(Path.GetTempPath(), $"test_driver_{Guid.NewGuid()}.txt");
+ File.WriteAllText(testFilePath, "Test driver content");
+
+ try
+ {
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ FilePath = testFilePath,
+ TargetOS = "",
+ Architecture = ""
+ };
+
+ var strategy = new UpdateStrategy
+ {
+ RequireBackup = false,
+ RetryCount = 1,
+ RetryIntervalSeconds = 1
+ };
+
+ // Act
+ var result = await GeneralDrivelution.QuickUpdateAsync(driverInfo, strategy);
+
+ // Assert
+ Assert.NotNull(result);
+ // Verify that result status is one of the valid enum values
+ Assert.True(Enum.IsDefined(typeof(UpdateStatus), result.Status));
+ }
+ finally
+ {
+ if (File.Exists(testFilePath))
+ {
+ File.Delete(testFilePath);
+ }
+ }
+ }
+
+ ///
+ /// Tests that ValidateAsync with minimal driver info works.
+ ///
+ [Fact]
+ public async Task ValidateAsync_WithMinimalDriverInfo_ReturnsBooleanResult()
+ {
+ // Arrange
+ var testFilePath = Path.Combine(Path.GetTempPath(), $"test_driver_{Guid.NewGuid()}.txt");
+ File.WriteAllText(testFilePath, "Test driver content");
+
+ try
+ {
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ FilePath = testFilePath,
+ TargetOS = "",
+ Architecture = ""
+ };
+
+ // Act
+ var result = await GeneralDrivelution.ValidateAsync(driverInfo);
+
+ // Assert - Should return a boolean value without throwing
+ // No assertion needed - the test passes if no exception is thrown
+ }
+ finally
+ {
+ if (File.Exists(testFilePath))
+ {
+ File.Delete(testFilePath);
+ }
+ }
+ }
+
+ ///
+ /// Tests that ValidateAsync returns false for non-existent file.
+ ///
+ [Fact]
+ public async Task ValidateAsync_WithNonExistentFile_ReturnsFalse()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ FilePath = "/nonexistent/path/driver.sys",
+ TargetOS = "",
+ Architecture = ""
+ };
+
+ // Act
+ var result = await GeneralDrivelution.ValidateAsync(driverInfo);
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests that QuickUpdateAsync with cancellation token works.
+ ///
+ [Fact]
+ public async Task QuickUpdateAsync_WithCancellationToken_CanBeCancelled()
+ {
+ // Arrange
+ var testFilePath = Path.Combine(Path.GetTempPath(), $"test_driver_{Guid.NewGuid()}.txt");
+ File.WriteAllText(testFilePath, "Test driver content");
+
+ try
+ {
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ FilePath = testFilePath
+ };
+
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ // Act & Assert
+ // Should either complete quickly or throw cancellation exception
+ var exception = await Record.ExceptionAsync(
+ () => GeneralDrivelution.QuickUpdateAsync(driverInfo, cts.Token));
+
+ // Either succeeded, failed gracefully, or was cancelled
+ Assert.True(exception == null || exception is OperationCanceledException);
+ }
+ finally
+ {
+ if (File.Exists(testFilePath))
+ {
+ File.Delete(testFilePath);
+ }
+ }
+ }
+
+ ///
+ /// Tests that GetPlatformInfo reports correct support status.
+ ///
+ [Fact]
+ public void GetPlatformInfo_ReportsCorrectSupportStatus()
+ {
+ // Act
+ var platformInfo = GeneralDrivelution.GetPlatformInfo();
+
+ // Assert
+ if (platformInfo.Platform == "Windows" || platformInfo.Platform == "Linux")
+ {
+ Assert.True(platformInfo.IsSupported);
+ }
+ else if (platformInfo.Platform == "MacOS")
+ {
+ Assert.False(platformInfo.IsSupported); // MacOS not yet implemented
+ }
+ }
+}
diff --git a/src/c#/DrivelutionTest/Models/ModelTests.cs b/src/c#/DrivelutionTest/Models/ModelTests.cs
new file mode 100644
index 00000000..9e788f9e
--- /dev/null
+++ b/src/c#/DrivelutionTest/Models/ModelTests.cs
@@ -0,0 +1,383 @@
+using GeneralUpdate.Drivelution.Abstractions.Models;
+
+namespace DrivelutionTest.Models;
+
+///
+/// Tests for DriverInfo model class.
+/// Validates driver information structure and properties.
+///
+public class DriverInfoTests
+{
+ ///
+ /// Tests that DriverInfo can be instantiated with default values.
+ ///
+ [Fact]
+ public void Constructor_CreatesInstanceWithDefaultValues()
+ {
+ // Act
+ var driverInfo = new DriverInfo();
+
+ // Assert
+ Assert.NotNull(driverInfo);
+ Assert.Equal(string.Empty, driverInfo.Name);
+ Assert.Equal(string.Empty, driverInfo.Version);
+ Assert.Equal(string.Empty, driverInfo.FilePath);
+ Assert.Equal("SHA256", driverInfo.HashAlgorithm);
+ Assert.NotNull(driverInfo.TrustedPublishers);
+ Assert.Empty(driverInfo.TrustedPublishers);
+ Assert.NotNull(driverInfo.Metadata);
+ Assert.Empty(driverInfo.Metadata);
+ }
+
+ ///
+ /// Tests that DriverInfo properties can be set and retrieved.
+ ///
+ [Fact]
+ public void Properties_CanBeSetAndRetrieved()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.2.3",
+ FilePath = "/path/to/driver.sys",
+ TargetOS = "Windows",
+ Architecture = "X64",
+ HardwareId = "PCI\\VEN_1234&DEV_5678",
+ Hash = "abc123",
+ HashAlgorithm = "SHA256",
+ Description = "Test driver description",
+ ReleaseDate = new DateTime(2024, 1, 1)
+ };
+
+ // Act & Assert
+ Assert.Equal("Test Driver", driverInfo.Name);
+ Assert.Equal("1.2.3", driverInfo.Version);
+ Assert.Equal("/path/to/driver.sys", driverInfo.FilePath);
+ Assert.Equal("Windows", driverInfo.TargetOS);
+ Assert.Equal("X64", driverInfo.Architecture);
+ Assert.Equal("PCI\\VEN_1234&DEV_5678", driverInfo.HardwareId);
+ Assert.Equal("abc123", driverInfo.Hash);
+ Assert.Equal("SHA256", driverInfo.HashAlgorithm);
+ Assert.Equal("Test driver description", driverInfo.Description);
+ Assert.Equal(new DateTime(2024, 1, 1), driverInfo.ReleaseDate);
+ }
+
+ ///
+ /// Tests that TrustedPublishers list can be modified.
+ ///
+ [Fact]
+ public void TrustedPublishers_CanBeModified()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo();
+
+ // Act
+ driverInfo.TrustedPublishers.Add("Microsoft Corporation");
+ driverInfo.TrustedPublishers.Add("NVIDIA Corporation");
+
+ // Assert
+ Assert.Equal(2, driverInfo.TrustedPublishers.Count);
+ Assert.Contains("Microsoft Corporation", driverInfo.TrustedPublishers);
+ Assert.Contains("NVIDIA Corporation", driverInfo.TrustedPublishers);
+ }
+
+ ///
+ /// Tests that Metadata dictionary can be modified.
+ ///
+ [Fact]
+ public void Metadata_CanBeModified()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo();
+
+ // Act
+ driverInfo.Metadata["Author"] = "Test Author";
+ driverInfo.Metadata["License"] = "MIT";
+ driverInfo.Metadata["Website"] = "https://example.com";
+
+ // Assert
+ Assert.Equal(3, driverInfo.Metadata.Count);
+ Assert.Equal("Test Author", driverInfo.Metadata["Author"]);
+ Assert.Equal("MIT", driverInfo.Metadata["License"]);
+ Assert.Equal("https://example.com", driverInfo.Metadata["Website"]);
+ }
+
+ ///
+ /// Tests that HashAlgorithm defaults to SHA256.
+ ///
+ [Fact]
+ public void HashAlgorithm_DefaultsToSHA256()
+ {
+ // Arrange & Act
+ var driverInfo = new DriverInfo();
+
+ // Assert
+ Assert.Equal("SHA256", driverInfo.HashAlgorithm);
+ }
+}
+
+///
+/// Tests for UpdateStrategy model class.
+/// Validates update strategy configuration and properties.
+///
+public class UpdateStrategyTests
+{
+ ///
+ /// Tests that UpdateStrategy can be instantiated with default values.
+ ///
+ [Fact]
+ public void Constructor_CreatesInstanceWithDefaultValues()
+ {
+ // Act
+ var strategy = new UpdateStrategy();
+
+ // Assert
+ Assert.NotNull(strategy);
+ Assert.Equal(UpdateMode.Full, strategy.Mode);
+ Assert.False(strategy.ForceUpdate);
+ Assert.True(strategy.RequireBackup);
+ Assert.Equal(3, strategy.RetryCount);
+ Assert.Equal(5, strategy.RetryIntervalSeconds);
+ Assert.Equal(0, strategy.Priority);
+ Assert.Equal(RestartMode.Prompt, strategy.RestartMode);
+ Assert.False(strategy.SkipSignatureValidation);
+ Assert.False(strategy.SkipHashValidation);
+ Assert.Equal(300, strategy.TimeoutSeconds);
+ }
+
+ ///
+ /// Tests that UpdateStrategy properties can be set and retrieved.
+ ///
+ [Fact]
+ public void Properties_CanBeSetAndRetrieved()
+ {
+ // Arrange
+ var strategy = new UpdateStrategy
+ {
+ Mode = UpdateMode.Incremental,
+ ForceUpdate = true,
+ RequireBackup = false,
+ BackupPath = "/backup",
+ RetryCount = 5,
+ RetryIntervalSeconds = 10,
+ Priority = 1,
+ RestartMode = RestartMode.Immediate,
+ SkipSignatureValidation = true,
+ SkipHashValidation = true,
+ TimeoutSeconds = 600
+ };
+
+ // Act & Assert
+ Assert.Equal(UpdateMode.Incremental, strategy.Mode);
+ Assert.True(strategy.ForceUpdate);
+ Assert.False(strategy.RequireBackup);
+ Assert.Equal("/backup", strategy.BackupPath);
+ Assert.Equal(5, strategy.RetryCount);
+ Assert.Equal(10, strategy.RetryIntervalSeconds);
+ Assert.Equal(1, strategy.Priority);
+ Assert.Equal(RestartMode.Immediate, strategy.RestartMode);
+ Assert.True(strategy.SkipSignatureValidation);
+ Assert.True(strategy.SkipHashValidation);
+ Assert.Equal(600, strategy.TimeoutSeconds);
+ }
+
+ ///
+ /// Tests UpdateMode enum values.
+ ///
+ [Fact]
+ public void UpdateMode_HasExpectedValues()
+ {
+ // Assert
+ Assert.Equal(0, (int)UpdateMode.Full);
+ Assert.Equal(1, (int)UpdateMode.Incremental);
+ }
+
+ ///
+ /// Tests RestartMode enum values.
+ ///
+ [Fact]
+ public void RestartMode_HasExpectedValues()
+ {
+ // Assert
+ Assert.Equal(0, (int)RestartMode.None);
+ Assert.Equal(1, (int)RestartMode.Prompt);
+ Assert.Equal(2, (int)RestartMode.Delayed);
+ Assert.Equal(3, (int)RestartMode.Immediate);
+ }
+}
+
+///
+/// Tests for UpdateResult model class.
+/// Validates update result tracking and properties.
+///
+public class UpdateResultTests
+{
+ ///
+ /// Tests that UpdateResult can be instantiated.
+ ///
+ [Fact]
+ public void Constructor_CreatesInstance()
+ {
+ // Act
+ var result = new UpdateResult();
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.False(result.Success);
+ Assert.Equal(UpdateStatus.NotStarted, result.Status);
+ Assert.NotNull(result.StepLogs);
+ Assert.Empty(result.StepLogs);
+ Assert.Equal(string.Empty, result.Message);
+ }
+
+ ///
+ /// Tests that UpdateResult properties can be set and retrieved.
+ ///
+ [Fact]
+ public void Properties_CanBeSetAndRetrieved()
+ {
+ // Arrange
+ var startTime = DateTime.UtcNow;
+ var endTime = startTime.AddMinutes(5);
+ var error = new ErrorInfo
+ {
+ Code = "TEST_ERROR",
+ Message = "Test error message"
+ };
+
+ var result = new UpdateResult
+ {
+ Success = true,
+ Status = UpdateStatus.Succeeded,
+ Error = error,
+ StartTime = startTime,
+ EndTime = endTime,
+ BackupPath = "/backup/path",
+ RolledBack = false,
+ Message = "Update completed"
+ };
+
+ // Act & Assert
+ Assert.True(result.Success);
+ Assert.Equal(UpdateStatus.Succeeded, result.Status);
+ Assert.Equal(error, result.Error);
+ Assert.Equal(startTime, result.StartTime);
+ Assert.Equal(endTime, result.EndTime);
+ Assert.Equal("/backup/path", result.BackupPath);
+ Assert.False(result.RolledBack);
+ Assert.Equal("Update completed", result.Message);
+ }
+
+ ///
+ /// Tests that DurationMs is calculated correctly.
+ ///
+ [Fact]
+ public void DurationMs_CalculatesCorrectly()
+ {
+ // Arrange
+ var startTime = DateTime.UtcNow;
+ var endTime = startTime.AddSeconds(30);
+
+ var result = new UpdateResult
+ {
+ StartTime = startTime,
+ EndTime = endTime
+ };
+
+ // Act
+ var duration = result.DurationMs;
+
+ // Assert
+ Assert.InRange(duration, 29900, 30100); // Allow 100ms tolerance
+ }
+
+ ///
+ /// Tests that StepLogs can be modified.
+ ///
+ [Fact]
+ public void StepLogs_CanBeModified()
+ {
+ // Arrange
+ var result = new UpdateResult();
+
+ // Act
+ result.StepLogs.Add("Step 1: Started");
+ result.StepLogs.Add("Step 2: Validation");
+ result.StepLogs.Add("Step 3: Completed");
+
+ // Assert
+ Assert.Equal(3, result.StepLogs.Count);
+ Assert.Contains("Step 1: Started", result.StepLogs);
+ Assert.Contains("Step 2: Validation", result.StepLogs);
+ Assert.Contains("Step 3: Completed", result.StepLogs);
+ }
+
+ ///
+ /// Tests UpdateStatus enum values.
+ ///
+ [Fact]
+ public void UpdateStatus_HasExpectedValues()
+ {
+ // Assert
+ Assert.Equal(0, (int)UpdateStatus.NotStarted);
+ Assert.Equal(1, (int)UpdateStatus.Validating);
+ Assert.Equal(2, (int)UpdateStatus.BackingUp);
+ Assert.Equal(3, (int)UpdateStatus.Updating);
+ Assert.Equal(4, (int)UpdateStatus.Verifying);
+ Assert.Equal(5, (int)UpdateStatus.Succeeded);
+ Assert.Equal(6, (int)UpdateStatus.Failed);
+ Assert.Equal(7, (int)UpdateStatus.RolledBack);
+ }
+}
+
+///
+/// Tests for ErrorInfo model class.
+/// Validates error information structure.
+///
+public class ErrorInfoTests
+{
+ ///
+ /// Tests that ErrorInfo can be instantiated.
+ ///
+ [Fact]
+ public void Constructor_CreatesInstance()
+ {
+ // Act
+ var errorInfo = new ErrorInfo();
+
+ // Assert
+ Assert.NotNull(errorInfo);
+ }
+
+ ///
+ /// Tests that ErrorInfo properties can be set and retrieved.
+ ///
+ [Fact]
+ public void Properties_CanBeSetAndRetrieved()
+ {
+ // Arrange
+ var innerException = new InvalidOperationException("Inner exception");
+ var errorInfo = new ErrorInfo
+ {
+ Code = "ERR001",
+ Type = ErrorType.InstallationFailed,
+ Message = "Installation failed",
+ Details = "Detailed error information",
+ StackTrace = "Stack trace here",
+ InnerException = innerException,
+ CanRetry = true,
+ SuggestedResolution = "Try again"
+ };
+
+ // Act & Assert
+ Assert.Equal("ERR001", errorInfo.Code);
+ Assert.Equal(ErrorType.InstallationFailed, errorInfo.Type);
+ Assert.Equal("Installation failed", errorInfo.Message);
+ Assert.Equal("Detailed error information", errorInfo.Details);
+ Assert.Equal("Stack trace here", errorInfo.StackTrace);
+ Assert.Equal(innerException, errorInfo.InnerException);
+ Assert.True(errorInfo.CanRetry);
+ Assert.Equal("Try again", errorInfo.SuggestedResolution);
+ }
+}
diff --git a/src/c#/DrivelutionTest/Utilities/CompatibilityCheckerTests.cs b/src/c#/DrivelutionTest/Utilities/CompatibilityCheckerTests.cs
new file mode 100644
index 00000000..bfc10ab0
--- /dev/null
+++ b/src/c#/DrivelutionTest/Utilities/CompatibilityCheckerTests.cs
@@ -0,0 +1,335 @@
+using GeneralUpdate.Drivelution.Core.Utilities;
+using GeneralUpdate.Drivelution.Abstractions.Models;
+
+namespace DrivelutionTest.Utilities;
+
+///
+/// Tests for CompatibilityChecker utility class.
+/// Validates platform compatibility checking functionality.
+///
+public class CompatibilityCheckerTests
+{
+ ///
+ /// Tests that GetCurrentOS returns a valid operating system name.
+ ///
+ [Fact]
+ public void GetCurrentOS_ReturnsValidOSName()
+ {
+ // Act
+ var os = CompatibilityChecker.GetCurrentOS();
+
+ // Assert
+ Assert.NotNull(os);
+ Assert.Contains(os, new[] { "Windows", "Linux", "MacOS", "Unknown" });
+ }
+
+ ///
+ /// Tests that GetCurrentArchitecture returns a valid architecture.
+ ///
+ [Fact]
+ public void GetCurrentArchitecture_ReturnsValidArchitecture()
+ {
+ // Act
+ var arch = CompatibilityChecker.GetCurrentArchitecture();
+
+ // Assert
+ Assert.NotNull(arch);
+ Assert.NotEmpty(arch);
+ // Common architectures: X64, X86, Arm, Arm64
+ Assert.True(arch.Length > 0);
+ }
+
+ ///
+ /// Tests that GetSystemVersion returns a valid version string.
+ ///
+ [Fact]
+ public void GetSystemVersion_ReturnsValidVersionString()
+ {
+ // Act
+ var version = CompatibilityChecker.GetSystemVersion();
+
+ // Assert
+ Assert.NotNull(version);
+ Assert.NotEmpty(version);
+ }
+
+ ///
+ /// Tests that CheckCompatibility returns true for compatible driver.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithCompatibleDriver_ReturnsTrue()
+ {
+ // Arrange
+ var currentOS = CompatibilityChecker.GetCurrentOS();
+ var currentArch = CompatibilityChecker.GetCurrentArchitecture();
+
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = currentOS,
+ Architecture = currentArch,
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = CompatibilityChecker.CheckCompatibility(driverInfo);
+
+ // Assert
+ Assert.True(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibility returns false for incompatible OS.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithIncompatibleOS_ReturnsFalse()
+ {
+ // Arrange
+ var currentOS = CompatibilityChecker.GetCurrentOS();
+ var incompatibleOS = currentOS == "Windows" ? "Linux" : "Windows";
+
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = incompatibleOS,
+ Architecture = CompatibilityChecker.GetCurrentArchitecture(),
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = CompatibilityChecker.CheckCompatibility(driverInfo);
+
+ // Assert
+ Assert.False(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibility returns false for incompatible architecture.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithIncompatibleArchitecture_ReturnsFalse()
+ {
+ // Arrange
+ var currentArch = CompatibilityChecker.GetCurrentArchitecture();
+ var incompatibleArch = currentArch.Contains("64") ? "X86" : "X64";
+
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = CompatibilityChecker.GetCurrentOS(),
+ Architecture = incompatibleArch,
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = CompatibilityChecker.CheckCompatibility(driverInfo);
+
+ // Assert
+ Assert.False(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibility returns true when TargetOS is empty.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithEmptyTargetOS_ReturnsTrue()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = "",
+ Architecture = CompatibilityChecker.GetCurrentArchitecture(),
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = CompatibilityChecker.CheckCompatibility(driverInfo);
+
+ // Assert
+ Assert.True(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibility returns true when Architecture is empty.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithEmptyArchitecture_ReturnsTrue()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = CompatibilityChecker.GetCurrentOS(),
+ Architecture = "",
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = CompatibilityChecker.CheckCompatibility(driverInfo);
+
+ // Assert
+ Assert.True(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibility throws ArgumentNullException for null driver info.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithNullDriverInfo_ThrowsArgumentNullException()
+ {
+ // Act & Assert
+ Assert.Throws(() => CompatibilityChecker.CheckCompatibility(null!));
+ }
+
+ ///
+ /// Tests that CheckCompatibilityAsync works correctly.
+ ///
+ [Fact]
+ public async Task CheckCompatibilityAsync_WithCompatibleDriver_ReturnsTrue()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = CompatibilityChecker.GetCurrentOS(),
+ Architecture = CompatibilityChecker.GetCurrentArchitecture(),
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var isCompatible = await CompatibilityChecker.CheckCompatibilityAsync(driverInfo);
+
+ // Assert
+ Assert.True(isCompatible);
+ }
+
+ ///
+ /// Tests that CheckCompatibilityAsync can be cancelled.
+ ///
+ [Fact]
+ public async Task CheckCompatibilityAsync_WithCancellation_ThrowsOperationCanceledException()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = CompatibilityChecker.GetCurrentOS(),
+ Architecture = CompatibilityChecker.GetCurrentArchitecture(),
+ FilePath = "/test/driver.sys"
+ };
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ // Act & Assert
+ await Assert.ThrowsAnyAsync(
+ () => CompatibilityChecker.CheckCompatibilityAsync(driverInfo, cts.Token));
+ }
+
+ ///
+ /// Tests that GetCompatibilityReport returns a complete report.
+ ///
+ [Fact]
+ public void GetCompatibilityReport_ReturnsCompleteReport()
+ {
+ // Arrange
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = CompatibilityChecker.GetCurrentOS(),
+ Architecture = CompatibilityChecker.GetCurrentArchitecture(),
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var report = CompatibilityChecker.GetCompatibilityReport(driverInfo);
+
+ // Assert
+ Assert.NotNull(report);
+ Assert.NotNull(report.CurrentOS);
+ Assert.NotNull(report.CurrentArchitecture);
+ Assert.NotNull(report.SystemVersion);
+ Assert.True(report.OSCompatible);
+ Assert.True(report.ArchitectureCompatible);
+ Assert.True(report.OverallCompatible);
+ }
+
+ ///
+ /// Tests that GetCompatibilityReport shows incompatibility correctly.
+ ///
+ [Fact]
+ public void GetCompatibilityReport_WithIncompatibleDriver_ShowsIncompatibility()
+ {
+ // Arrange
+ var currentOS = CompatibilityChecker.GetCurrentOS();
+ var incompatibleOS = currentOS == "Windows" ? "Linux" : "Windows";
+
+ var driverInfo = new DriverInfo
+ {
+ Name = "Test Driver",
+ Version = "1.0.0",
+ TargetOS = incompatibleOS,
+ Architecture = "InvalidArchitecture",
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act
+ var report = CompatibilityChecker.GetCompatibilityReport(driverInfo);
+
+ // Assert
+ Assert.NotNull(report);
+ Assert.False(report.OSCompatible);
+ Assert.False(report.ArchitectureCompatible);
+ Assert.False(report.OverallCompatible);
+ }
+
+ ///
+ /// Tests that architecture normalization works correctly.
+ ///
+ [Fact]
+ public void CheckCompatibility_WithArchitectureAliases_RecognizesAliases()
+ {
+ // Arrange - Test common architecture aliases
+ var testCases = new[]
+ {
+ ("X64", "AMD64"),
+ ("X64", "x86_64"),
+ ("X86", "i386"),
+ ("ARM64", "AARCH64")
+ };
+
+ foreach (var (arch1, arch2) in testCases)
+ {
+ var driverInfo1 = new DriverInfo
+ {
+ Name = "Test Driver",
+ TargetOS = "",
+ Architecture = arch1,
+ FilePath = "/test/driver.sys"
+ };
+
+ var driverInfo2 = new DriverInfo
+ {
+ Name = "Test Driver",
+ TargetOS = "",
+ Architecture = arch2,
+ FilePath = "/test/driver.sys"
+ };
+
+ // Act - Both should be treated the same way
+ var result1 = CompatibilityChecker.CheckCompatibility(driverInfo1);
+ var result2 = CompatibilityChecker.CheckCompatibility(driverInfo2);
+
+ // Assert - Results should be consistent (both true or both false)
+ Assert.Equal(result1, result2);
+ }
+ }
+}
diff --git a/src/c#/DrivelutionTest/Utilities/HashValidatorTests.cs b/src/c#/DrivelutionTest/Utilities/HashValidatorTests.cs
new file mode 100644
index 00000000..ce7c6d40
--- /dev/null
+++ b/src/c#/DrivelutionTest/Utilities/HashValidatorTests.cs
@@ -0,0 +1,237 @@
+using GeneralUpdate.Drivelution.Core.Utilities;
+
+namespace DrivelutionTest.Utilities;
+
+///
+/// Tests for HashValidator utility class.
+/// Validates file hash computation and validation functionality.
+///
+public class HashValidatorTests : IDisposable
+{
+ private readonly string _testFilePath;
+ private readonly string _testContent = "Hello, World! This is test content for hash validation.";
+
+ public HashValidatorTests()
+ {
+ // Create a temporary test file
+ _testFilePath = Path.Combine(Path.GetTempPath(), $"test_{Guid.NewGuid()}.txt");
+ File.WriteAllText(_testFilePath, _testContent);
+ }
+
+ ///
+ /// Cleanup temporary test files.
+ ///
+ public void Dispose()
+ {
+ if (File.Exists(_testFilePath))
+ {
+ try
+ {
+ File.Delete(_testFilePath);
+ }
+ catch
+ {
+ // Ignore cleanup errors
+ }
+ }
+ }
+
+ ///
+ /// Tests that ComputeHashAsync returns a valid SHA256 hash.
+ ///
+ [Fact]
+ public async Task ComputeHashAsync_WithSHA256_ReturnsValidHash()
+ {
+ // Act
+ var hash = await HashValidator.ComputeHashAsync(_testFilePath, "SHA256");
+
+ // Assert
+ Assert.NotNull(hash);
+ Assert.NotEmpty(hash);
+ Assert.Equal(64, hash.Length); // SHA256 hash is 64 hex characters
+ Assert.Matches("^[a-f0-9]+$", hash); // Only lowercase hex characters
+ }
+
+ ///
+ /// Tests that ComputeHashAsync returns a valid MD5 hash.
+ ///
+ [Fact]
+ public async Task ComputeHashAsync_WithMD5_ReturnsValidHash()
+ {
+ // Act
+ var hash = await HashValidator.ComputeHashAsync(_testFilePath, "MD5");
+
+ // Assert
+ Assert.NotNull(hash);
+ Assert.NotEmpty(hash);
+ Assert.Equal(32, hash.Length); // MD5 hash is 32 hex characters
+ Assert.Matches("^[a-f0-9]+$", hash);
+ }
+
+ ///
+ /// Tests that ComputeHashAsync throws FileNotFoundException for non-existent file.
+ ///
+ [Fact]
+ public async Task ComputeHashAsync_WithNonExistentFile_ThrowsFileNotFoundException()
+ {
+ // Arrange
+ var nonExistentFile = Path.Combine(Path.GetTempPath(), $"nonexistent_{Guid.NewGuid()}.txt");
+
+ // Act & Assert
+ await Assert.ThrowsAsync(
+ () => HashValidator.ComputeHashAsync(nonExistentFile));
+ }
+
+ ///
+ /// Tests that ComputeHashAsync throws ArgumentException for unsupported algorithm.
+ ///
+ [Fact]
+ public async Task ComputeHashAsync_WithUnsupportedAlgorithm_ThrowsArgumentException()
+ {
+ // Act & Assert
+ await Assert.ThrowsAsync(
+ () => HashValidator.ComputeHashAsync(_testFilePath, "UNSUPPORTED"));
+ }
+
+ ///
+ /// Tests that ValidateHashAsync returns true for matching hash.
+ ///
+ [Fact]
+ public async Task ValidateHashAsync_WithMatchingHash_ReturnsTrue()
+ {
+ // Arrange
+ var expectedHash = await HashValidator.ComputeHashAsync(_testFilePath, "SHA256");
+
+ // Act
+ var isValid = await HashValidator.ValidateHashAsync(_testFilePath, expectedHash, "SHA256");
+
+ // Assert
+ Assert.True(isValid);
+ }
+
+ ///
+ /// Tests that ValidateHashAsync returns false for non-matching hash.
+ ///
+ [Fact]
+ public async Task ValidateHashAsync_WithNonMatchingHash_ReturnsFalse()
+ {
+ // Arrange
+ var wrongHash = "0000000000000000000000000000000000000000000000000000000000000000";
+
+ // Act
+ var isValid = await HashValidator.ValidateHashAsync(_testFilePath, wrongHash, "SHA256");
+
+ // Assert
+ Assert.False(isValid);
+ }
+
+ ///
+ /// Tests that ValidateHashAsync is case-insensitive.
+ ///
+ [Fact]
+ public async Task ValidateHashAsync_IsCaseInsensitive()
+ {
+ // Arrange
+ var expectedHash = await HashValidator.ComputeHashAsync(_testFilePath, "SHA256");
+ var upperCaseHash = expectedHash.ToUpperInvariant();
+
+ // Act
+ var isValid = await HashValidator.ValidateHashAsync(_testFilePath, upperCaseHash, "SHA256");
+
+ // Assert
+ Assert.True(isValid);
+ }
+
+ ///
+ /// Tests that ValidateHashAsync throws ArgumentException for null or empty hash.
+ ///
+ [Fact]
+ public async Task ValidateHashAsync_WithNullOrEmptyHash_ThrowsArgumentException()
+ {
+ // Act & Assert
+ await Assert.ThrowsAsync(
+ () => HashValidator.ValidateHashAsync(_testFilePath, "", "SHA256"));
+
+ await Assert.ThrowsAsync(
+ () => HashValidator.ValidateHashAsync(_testFilePath, null!, "SHA256"));
+ }
+
+ ///
+ /// Tests that ComputeStringHash returns a valid hash for string input.
+ ///
+ [Fact]
+ public void ComputeStringHash_WithValidString_ReturnsValidHash()
+ {
+ // Arrange
+ var input = "Test String";
+
+ // Act
+ var hash = HashValidator.ComputeStringHash(input, "SHA256");
+
+ // Assert
+ Assert.NotNull(hash);
+ Assert.NotEmpty(hash);
+ Assert.Equal(64, hash.Length);
+ }
+
+ ///
+ /// Tests that ComputeStringHash returns consistent results.
+ ///
+ [Fact]
+ public void ComputeStringHash_WithSameInput_ReturnsConsistentHash()
+ {
+ // Arrange
+ var input = "Consistent Test";
+
+ // Act
+ var hash1 = HashValidator.ComputeStringHash(input, "SHA256");
+ var hash2 = HashValidator.ComputeStringHash(input, "SHA256");
+
+ // Assert
+ Assert.Equal(hash1, hash2);
+ }
+
+ ///
+ /// Tests that ComputeStringHash returns different hashes for different inputs.
+ ///
+ [Fact]
+ public void ComputeStringHash_WithDifferentInputs_ReturnsDifferentHashes()
+ {
+ // Arrange
+ var input1 = "Test 1";
+ var input2 = "Test 2";
+
+ // Act
+ var hash1 = HashValidator.ComputeStringHash(input1, "SHA256");
+ var hash2 = HashValidator.ComputeStringHash(input2, "SHA256");
+
+ // Assert
+ Assert.NotEqual(hash1, hash2);
+ }
+
+ ///
+ /// Tests that ComputeStringHash throws ArgumentException for null or empty input.
+ ///
+ [Fact]
+ public void ComputeStringHash_WithNullOrEmptyInput_ThrowsArgumentException()
+ {
+ // Act & Assert
+ Assert.Throws(() => HashValidator.ComputeStringHash(""));
+ Assert.Throws(() => HashValidator.ComputeStringHash(null!));
+ }
+
+ ///
+ /// Tests that hash computation can be cancelled.
+ ///
+ [Fact]
+ public async Task ComputeHashAsync_WithCancellation_ThrowsOperationCanceledException()
+ {
+ // Arrange
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ // Act & Assert
+ await Assert.ThrowsAnyAsync(
+ () => HashValidator.ComputeHashAsync(_testFilePath, "SHA256", cts.Token));
+ }
+}
diff --git a/src/c#/DrivelutionTest/Utilities/VersionComparerAndRestartHelperTests.cs b/src/c#/DrivelutionTest/Utilities/VersionComparerAndRestartHelperTests.cs
new file mode 100644
index 00000000..04234777
--- /dev/null
+++ b/src/c#/DrivelutionTest/Utilities/VersionComparerAndRestartHelperTests.cs
@@ -0,0 +1,384 @@
+using GeneralUpdate.Drivelution.Core.Utilities;
+using GeneralUpdate.Drivelution.Abstractions.Models;
+
+namespace DrivelutionTest.Utilities;
+
+///
+/// Tests for VersionComparer utility class.
+/// Validates semantic versioning comparison functionality.
+///
+public class VersionComparerTests
+{
+ ///
+ /// Tests that Compare returns 0 for equal versions.
+ ///
+ [Fact]
+ public void Compare_WithEqualVersions_ReturnsZero()
+ {
+ // Act
+ var result = VersionComparer.Compare("1.0.0", "1.0.0");
+
+ // Assert
+ Assert.Equal(0, result);
+ }
+
+ ///
+ /// Tests that Compare returns 1 when first version is greater.
+ ///
+ [Fact]
+ public void Compare_WithGreaterFirstVersion_ReturnsOne()
+ {
+ // Act
+ var result = VersionComparer.Compare("2.0.0", "1.0.0");
+
+ // Assert
+ Assert.Equal(1, result);
+ }
+
+ ///
+ /// Tests that Compare returns -1 when first version is less.
+ ///
+ [Fact]
+ public void Compare_WithLesserFirstVersion_ReturnsNegativeOne()
+ {
+ // Act
+ var result = VersionComparer.Compare("1.0.0", "2.0.0");
+
+ // Assert
+ Assert.Equal(-1, result);
+ }
+
+ ///
+ /// Tests version comparison with minor version differences.
+ ///
+ [Fact]
+ public void Compare_WithMinorVersionDifference_ReturnsCorrectResult()
+ {
+ // Assert
+ Assert.True(VersionComparer.Compare("1.1.0", "1.0.0") > 0);
+ Assert.True(VersionComparer.Compare("1.0.0", "1.1.0") < 0);
+ }
+
+ ///
+ /// Tests version comparison with patch version differences.
+ ///
+ [Fact]
+ public void Compare_WithPatchVersionDifference_ReturnsCorrectResult()
+ {
+ // Assert
+ Assert.True(VersionComparer.Compare("1.0.1", "1.0.0") > 0);
+ Assert.True(VersionComparer.Compare("1.0.0", "1.0.1") < 0);
+ }
+
+ ///
+ /// Tests that version without prerelease is greater than version with prerelease.
+ ///
+ [Fact]
+ public void Compare_ReleaseVersionIsGreaterThanPrerelease()
+ {
+ // Act
+ var result = VersionComparer.Compare("1.0.0", "1.0.0-alpha");
+
+ // Assert
+ Assert.True(result > 0);
+ }
+
+ ///
+ /// Tests prerelease version comparison.
+ ///
+ [Fact]
+ public void Compare_WithPrereleaseVersions_ComparesCorrectly()
+ {
+ // Assert
+ Assert.True(VersionComparer.Compare("1.0.0-beta", "1.0.0-alpha") > 0);
+ Assert.True(VersionComparer.Compare("1.0.0-alpha.2", "1.0.0-alpha.1") > 0);
+ }
+
+ ///
+ /// Tests IsGreaterThan method.
+ ///
+ [Fact]
+ public void IsGreaterThan_WithGreaterVersion_ReturnsTrue()
+ {
+ // Act
+ var result = VersionComparer.IsGreaterThan("2.0.0", "1.0.0");
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests IsGreaterThan method with lesser version.
+ ///
+ [Fact]
+ public void IsGreaterThan_WithLesserVersion_ReturnsFalse()
+ {
+ // Act
+ var result = VersionComparer.IsGreaterThan("1.0.0", "2.0.0");
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests IsLessThan method.
+ ///
+ [Fact]
+ public void IsLessThan_WithLesserVersion_ReturnsTrue()
+ {
+ // Act
+ var result = VersionComparer.IsLessThan("1.0.0", "2.0.0");
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests IsLessThan method with greater version.
+ ///
+ [Fact]
+ public void IsLessThan_WithGreaterVersion_ReturnsFalse()
+ {
+ // Act
+ var result = VersionComparer.IsLessThan("2.0.0", "1.0.0");
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests IsEqual method.
+ ///
+ [Fact]
+ public void IsEqual_WithEqualVersions_ReturnsTrue()
+ {
+ // Act
+ var result = VersionComparer.IsEqual("1.0.0", "1.0.0");
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests IsEqual method with different versions.
+ ///
+ [Fact]
+ public void IsEqual_WithDifferentVersions_ReturnsFalse()
+ {
+ // Act
+ var result = VersionComparer.IsEqual("1.0.0", "1.0.1");
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests IsValidSemVer with valid versions.
+ ///
+ [Theory]
+ [InlineData("1.0.0")]
+ [InlineData("1.0.0-alpha")]
+ [InlineData("1.0.0-alpha.1")]
+ [InlineData("1.0.0+20130313144700")]
+ [InlineData("1.0.0-beta+exp.sha.5114f85")]
+ [InlineData("10.20.30")]
+ public void IsValidSemVer_WithValidVersions_ReturnsTrue(string version)
+ {
+ // Act
+ var result = VersionComparer.IsValidSemVer(version);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests IsValidSemVer with invalid versions.
+ ///
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("1")]
+ [InlineData("1.0")]
+ [InlineData("1.0.0.0")]
+ [InlineData("v1.0.0")]
+ [InlineData("01.0.0")]
+ public void IsValidSemVer_WithInvalidVersions_ReturnsFalse(string version)
+ {
+ // Act
+ var result = VersionComparer.IsValidSemVer(version);
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests Compare throws ArgumentException for null or empty versions.
+ ///
+ [Fact]
+ public void Compare_WithNullOrEmptyVersion_ThrowsArgumentException()
+ {
+ // Act & Assert
+ Assert.Throws(() => VersionComparer.Compare("", "1.0.0"));
+ Assert.Throws(() => VersionComparer.Compare("1.0.0", ""));
+ Assert.Throws(() => VersionComparer.Compare(null!, "1.0.0"));
+ }
+
+ ///
+ /// Tests Compare throws FormatException for invalid version format.
+ ///
+ [Fact]
+ public void Compare_WithInvalidFormat_ThrowsFormatException()
+ {
+ // Act & Assert
+ Assert.Throws(() => VersionComparer.Compare("invalid", "1.0.0"));
+ Assert.Throws(() => VersionComparer.Compare("1.0.0", "v1.0.0"));
+ }
+
+ ///
+ /// Tests complex prerelease version comparison scenarios.
+ ///
+ [Fact]
+ public void Compare_WithComplexPrereleaseVersions_ComparesCorrectly()
+ {
+ // Arrange & Act & Assert
+ Assert.True(VersionComparer.Compare("1.0.0-rc.1", "1.0.0-beta.11") > 0);
+ Assert.True(VersionComparer.Compare("1.0.0-rc.1", "1.0.0-rc.0") > 0);
+ Assert.True(VersionComparer.Compare("1.0.0-alpha.beta", "1.0.0-alpha.1") > 0); // alphanumeric > numeric
+ Assert.True(VersionComparer.Compare("1.0.0-alpha", "1.0.0-alpha.1") < 0); // shorter < longer
+ }
+
+ ///
+ /// Tests that build metadata is ignored in comparison.
+ ///
+ [Fact]
+ public void Compare_IgnoresBuildMetadata()
+ {
+ // Act
+ var result = VersionComparer.Compare("1.0.0+build1", "1.0.0+build2");
+
+ // Assert
+ Assert.Equal(0, result);
+ }
+
+ ///
+ /// Tests version comparison with various real-world scenarios.
+ ///
+ [Theory]
+ [InlineData("1.0.0", "1.0.0", 0)]
+ [InlineData("2.0.0", "1.9.9", 1)]
+ [InlineData("1.0.0", "1.0.1", -1)]
+ [InlineData("1.1.0", "1.0.9", 1)]
+ [InlineData("1.0.0", "1.0.0-rc.1", 1)]
+ [InlineData("1.0.0-rc.2", "1.0.0-rc.1", 1)]
+ public void Compare_RealWorldScenarios_ReturnsExpectedResult(string version1, string version2, int expected)
+ {
+ // Act
+ var result = VersionComparer.Compare(version1, version2);
+
+ // Assert
+ Assert.Equal(Math.Sign(expected), Math.Sign(result));
+ }
+}
+
+///
+/// Tests for RestartHelper utility class.
+/// Validates restart handling functionality.
+///
+public class RestartHelperTests
+{
+ ///
+ /// Tests that IsRestartRequired returns false for None mode.
+ ///
+ [Fact]
+ public void IsRestartRequired_WithNoneMode_ReturnsFalse()
+ {
+ // Act
+ var result = RestartHelper.IsRestartRequired(RestartMode.None);
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests that IsRestartRequired returns true for non-None modes.
+ ///
+ [Theory]
+ [InlineData(RestartMode.Prompt)]
+ [InlineData(RestartMode.Delayed)]
+ [InlineData(RestartMode.Immediate)]
+ public void IsRestartRequired_WithRestartModes_ReturnsTrue(RestartMode mode)
+ {
+ // Act
+ var result = RestartHelper.IsRestartRequired(mode);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests that HandleRestartAsync with None mode returns true.
+ ///
+ [Fact]
+ public async Task HandleRestartAsync_WithNoneMode_ReturnsTrue()
+ {
+ // Act
+ var result = await RestartHelper.HandleRestartAsync(RestartMode.None);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ ///
+ /// Tests that HandleRestartAsync with Prompt mode returns false (no user interaction in tests).
+ ///
+ [Fact]
+ public async Task HandleRestartAsync_WithPromptMode_ReturnsFalse()
+ {
+ // Act
+ var result = await RestartHelper.HandleRestartAsync(RestartMode.Prompt);
+
+ // Assert
+ Assert.False(result); // Prompt returns false as there's no user interaction
+ }
+
+ ///
+ /// Tests that PromptUserForRestart displays message and returns false.
+ ///
+ [Fact]
+ public void PromptUserForRestart_DisplaysMessage_ReturnsFalse()
+ {
+ // Act
+ var result = RestartHelper.PromptUserForRestart("Test message");
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests that PromptUserForRestart with empty message uses default message.
+ ///
+ [Fact]
+ public void PromptUserForRestart_WithEmptyMessage_UsesDefaultMessage()
+ {
+ // Act
+ var result = RestartHelper.PromptUserForRestart("");
+
+ // Assert
+ Assert.False(result);
+ }
+
+ ///
+ /// Tests that RestartHelper methods are callable without throwing exceptions
+ /// in non-privileged test environment (actual restart will fail due to permissions).
+ /// Note: We cannot actually restart the system during tests.
+ ///
+ [Fact]
+ public void RestartHelper_PublicMethods_AreCallable()
+ {
+ // This test documents that the RestartHelper class and its public methods exist
+ // and are callable. Actual restart functionality cannot be safely tested in unit tests.
+ // Act & Assert
+ Assert.True(RestartHelper.IsRestartRequired(RestartMode.None) == false);
+ Assert.True(RestartHelper.IsRestartRequired(RestartMode.Prompt) == true);
+ }
+}