chore: deprecate standalone SecureStoreManager utility

Move SecureStoreManager project and tests to Deprecated folder and remove
from solution. SecureStore functionality is now integrated into ConfigManager.
This commit is contained in:
Joseph Doherty
2026-01-27 07:26:40 -05:00
parent 937eb66ac8
commit 1e21e33ade
42 changed files with 0 additions and 2 deletions
@@ -0,0 +1,343 @@
using Shouldly;
using Xunit;
using JdeScoping.SecureStoreManager.ViewModels;
namespace JdeScoping.SecureStoreManager.Tests.ViewModels;
public class NewStoreDialogViewModelTests
{
[Fact]
public void IsValid_WhenStorePathEmpty_ReturnsFalse()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = string.Empty;
sut.KeyFilePath = "/path/to/key.key";
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void IsValid_WhenKeyFilePathEmpty_ReturnsFalse()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = "/path/to/store.json";
sut.KeyFilePath = string.Empty;
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void IsValid_WithValidConfiguration_ReturnsTrue()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = "/path/to/store.json";
sut.KeyFilePath = "/path/to/key.key";
// Act & Assert
sut.IsValid.ShouldBeTrue();
}
[Fact]
public void ValidationError_WhenStorePathEmpty_ReturnsAppropriateMessage()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = string.Empty;
// Act & Assert
sut.ValidationError.ShouldBe("Store path is required.");
}
[Fact]
public void ValidationError_WhenKeyFilePathEmpty_ReturnsAppropriateMessage()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = "/path/to/store.json";
sut.KeyFilePath = string.Empty;
// Act & Assert
sut.ValidationError.ShouldBe("Key file path is required.");
}
[Fact]
public void ValidationError_WhenValid_ReturnsNull()
{
// Arrange
var sut = new NewStoreDialogViewModel();
sut.StorePath = "/path/to/store.json";
sut.KeyFilePath = "/path/to/key.key";
// Act & Assert
sut.ValidationError.ShouldBeNull();
}
}
public class OpenStoreDialogViewModelTests
{
[Fact]
public void IsValid_WhenStorePathEmpty_ReturnsFalse()
{
// Arrange
var sut = new OpenStoreDialogViewModel();
sut.StorePath = string.Empty;
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void IsValid_WhenKeyFilePathEmpty_ReturnsFalse()
{
// Arrange
var sut = new OpenStoreDialogViewModel();
sut.StorePath = "/path/to/store.json";
sut.KeyFilePath = string.Empty;
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void ValidationError_WhenStorePathEmpty_ReturnsAppropriateMessage()
{
// Arrange
var sut = new OpenStoreDialogViewModel();
sut.StorePath = string.Empty;
// Act & Assert
sut.ValidationError.ShouldBe("Store path is required.");
}
[Fact]
public void ValidationError_WhenStoreFileDoesNotExist_ReturnsAppropriateMessage()
{
// Arrange
var sut = new OpenStoreDialogViewModel();
sut.StorePath = "/nonexistent/path/to/store.json";
// Act & Assert
sut.ValidationError.ShouldBe("Store file does not exist.");
}
[Fact]
public void ValidationError_WhenKeyFilePathEmpty_ReturnsAppropriateMessage()
{
// Arrange - Create temp store file so we get past that validation
var tempFile = Path.GetTempFileName();
try
{
var sut = new OpenStoreDialogViewModel();
sut.StorePath = tempFile;
sut.KeyFilePath = string.Empty;
// Act & Assert
sut.ValidationError.ShouldBe("Key file path is required.");
}
finally
{
File.Delete(tempFile);
}
}
[Fact]
public void ValidationError_WhenKeyFileDoesNotExist_ReturnsAppropriateMessage()
{
// Arrange - Create temp store file so we get past that validation
var tempFile = Path.GetTempFileName();
try
{
var sut = new OpenStoreDialogViewModel();
sut.StorePath = tempFile;
sut.KeyFilePath = "/nonexistent/key.key";
// Act & Assert
sut.ValidationError.ShouldBe("Key file does not exist.");
}
finally
{
File.Delete(tempFile);
}
}
}
public class SecretEditDialogViewModelTests
{
[Fact]
public void DefaultConstructor_SetsIsNewSecretToTrue()
{
// Arrange & Act
var sut = new SecretEditDialogViewModel();
// Assert
sut.IsNewSecret.ShouldBeTrue();
}
[Fact]
public void ParameterizedConstructor_SetsKey()
{
// Arrange & Act
var sut = new SecretEditDialogViewModel("testKey", "testValue");
// Assert
sut.Key.ShouldBe("testKey");
}
[Fact]
public void ParameterizedConstructor_SetsValue()
{
// Arrange & Act
var sut = new SecretEditDialogViewModel("testKey", "testValue");
// Assert
sut.Value.ShouldBe("testValue");
}
[Fact]
public void ParameterizedConstructor_SetsIsNewSecretToFalse()
{
// Arrange & Act
var sut = new SecretEditDialogViewModel("testKey", "testValue");
// Assert
sut.IsNewSecret.ShouldBeFalse();
}
[Fact]
public void IsKeyEditable_WhenIsNewSecret_ReturnsTrue()
{
// Arrange
var sut = new SecretEditDialogViewModel();
// Act & Assert
sut.IsKeyEditable.ShouldBeTrue();
}
[Fact]
public void IsKeyEditable_WhenEditingExisting_ReturnsFalse()
{
// Arrange
var sut = new SecretEditDialogViewModel("testKey", "testValue");
// Act & Assert
sut.IsKeyEditable.ShouldBeFalse();
}
[Fact]
public void DialogTitle_WhenIsNewSecret_ReturnsAddSecret()
{
// Arrange
var sut = new SecretEditDialogViewModel();
// Act & Assert
sut.DialogTitle.ShouldBe("Add Secret");
}
[Fact]
public void DialogTitle_WhenEditingExisting_ReturnsEditSecret()
{
// Arrange
var sut = new SecretEditDialogViewModel("testKey", "testValue");
// Act & Assert
sut.DialogTitle.ShouldBe("Edit Secret");
}
[Fact]
public void IsValid_WhenKeyEmpty_ReturnsFalse()
{
// Arrange
var sut = new SecretEditDialogViewModel();
sut.Key = string.Empty;
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void IsValid_WhenKeyWhitespace_ReturnsFalse()
{
// Arrange
var sut = new SecretEditDialogViewModel();
sut.Key = " ";
// Act & Assert
sut.IsValid.ShouldBeFalse();
}
[Fact]
public void IsValid_WhenKeyProvided_ReturnsTrue()
{
// Arrange
var sut = new SecretEditDialogViewModel();
sut.Key = "validKey";
// Act & Assert
sut.IsValid.ShouldBeTrue();
}
[Fact]
public void ValidationError_WhenKeyEmpty_ReturnsAppropriateMessage()
{
// Arrange
var sut = new SecretEditDialogViewModel();
sut.Key = string.Empty;
// Act & Assert
sut.ValidationError.ShouldBe("Key is required.");
}
[Fact]
public void ValidationError_WhenKeyProvided_ReturnsNull()
{
// Arrange
var sut = new SecretEditDialogViewModel();
sut.Key = "validKey";
// Act & Assert
sut.ValidationError.ShouldBeNull();
}
[Fact]
public void Key_SetterRaisesPropertyChanged()
{
// Arrange
var sut = new SecretEditDialogViewModel();
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(sut.Key))
propertyChangedRaised = true;
};
// Act
sut.Key = "newKey";
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void Value_SetterRaisesPropertyChanged()
{
// Arrange
var sut = new SecretEditDialogViewModel();
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(sut.Value))
propertyChangedRaised = true;
};
// Act
sut.Value = "newValue";
// Assert
propertyChangedRaised.ShouldBeTrue();
}
}
@@ -0,0 +1,262 @@
using NSubstitute;
using Shouldly;
using Xunit;
using JdeScoping.SecureStoreManager.Services;
using JdeScoping.SecureStoreManager.ViewModels;
namespace JdeScoping.SecureStoreManager.Tests.ViewModels;
public class MainWindowViewModelTests
{
private readonly ISecureStoreManager _mockStoreManager;
private readonly IDialogService _mockDialogService;
private readonly IClipboardService _mockClipboardService;
private readonly MainWindowViewModel _sut;
public MainWindowViewModelTests()
{
_mockStoreManager = Substitute.For<ISecureStoreManager>();
_mockDialogService = Substitute.For<IDialogService>();
_mockClipboardService = Substitute.For<IClipboardService>();
_sut = new MainWindowViewModel(_mockStoreManager, _mockDialogService, _mockClipboardService);
}
[Fact]
public void Constructor_InitializesEmptySecretsCollection()
{
_sut.Secrets.ShouldNotBeNull();
_sut.Secrets.Count.ShouldBe(0);
}
[Fact]
public void IsStoreOpen_DelegatesToStoreManager()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
// Act & Assert
_sut.IsStoreOpen.ShouldBeTrue();
}
[Fact]
public void HasUnsavedChanges_DelegatesToStoreManager()
{
// Arrange
_mockStoreManager.HasUnsavedChanges.Returns(true);
// Act & Assert
_sut.HasUnsavedChanges.ShouldBeTrue();
}
[Fact]
public void WindowTitle_WhenNoStoreOpen_ReturnsBasicTitle()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(false);
// Act & Assert
_sut.WindowTitle.ShouldBe("SecureStore Manager");
}
[Fact]
public void WindowTitle_WhenStoreOpen_IncludesPath()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.CurrentStorePath.Returns("/path/to/store.json");
_mockStoreManager.HasUnsavedChanges.Returns(false);
// Act & Assert
_sut.WindowTitle.ShouldBe("SecureStore Manager - /path/to/store.json");
}
[Fact]
public void WindowTitle_WhenUnsavedChanges_IncludesAsterisk()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.CurrentStorePath.Returns("/path/to/store.json");
_mockStoreManager.HasUnsavedChanges.Returns(true);
// Act & Assert
_sut.WindowTitle.ShouldBe("SecureStore Manager - /path/to/store.json *");
}
[Fact]
public void StatusMessage_DefaultsToReady()
{
_sut.StatusMessage.ShouldBe("Ready");
}
[Fact]
public async Task CreateNewStoreAsync_WithKeyFile_CallsStoreManagerCreateStore()
{
// Arrange
var storePath = "/path/to/store.json";
var keyPath = "/path/to/key.key";
_mockStoreManager.GetKeys().Returns(new List<string>().AsReadOnly());
// Act
await _sut.CreateNewStoreAsync(storePath, keyPath);
// Assert
_mockStoreManager.Received(1).CreateStore(storePath, keyPath);
}
[Fact]
public async Task OpenExistingStoreAsync_WithKeyFile_CallsStoreManagerOpenStore()
{
// Arrange
var storePath = "/path/to/store.json";
var keyPath = "/path/to/key.key";
_mockStoreManager.GetKeys().Returns(new List<string>().AsReadOnly());
// Act
await _sut.OpenExistingStoreAsync(storePath, keyPath);
// Assert
_mockStoreManager.Received(1).OpenStore(storePath, keyPath);
}
[Fact]
public async Task SaveSecretAsync_CallsStoreManagerSetSecret()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.GetKeys().Returns(new List<string> { "testKey" }.AsReadOnly());
_mockStoreManager.GetSecret("testKey").Returns("testValue");
// Act
await _sut.SaveSecretAsync("testKey", "testValue", isNew: true);
// Assert
_mockStoreManager.Received(1).SetSecret("testKey", "testValue");
}
[Fact]
public async Task SaveSecretAsync_RefreshesSecretsCollection()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.GetKeys().Returns(new List<string> { "key1", "key2" }.AsReadOnly());
_mockStoreManager.GetSecret("key1").Returns("value1");
_mockStoreManager.GetSecret("key2").Returns("value2");
// Act
await _sut.SaveSecretAsync("key1", "value1", isNew: true);
// Assert
_sut.Secrets.Count.ShouldBe(2);
}
[Fact]
public async Task PromptForUnsavedChangesAsync_WhenNoChanges_ReturnsTrue()
{
// Arrange
_mockStoreManager.HasUnsavedChanges.Returns(false);
// Act
var result = await _sut.PromptForUnsavedChangesAsync();
// Assert
result.ShouldBeTrue();
}
[Fact]
public void SaveCommand_CanExecute_WhenStoreOpenWithChanges()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.HasUnsavedChanges.Returns(true);
// Act
var canExecute = _sut.SaveCommand.CanExecute(null);
// Assert
canExecute.ShouldBeTrue();
}
[Fact]
public void SaveCommand_CannotExecute_WhenNoChanges()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
_mockStoreManager.HasUnsavedChanges.Returns(false);
// Act
var canExecute = _sut.SaveCommand.CanExecute(null);
// Assert
canExecute.ShouldBeFalse();
}
[Fact]
public void AddSecretCommand_CanExecute_WhenStoreOpen()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
// Act
var canExecute = _sut.AddSecretCommand.CanExecute(null);
// Assert
canExecute.ShouldBeTrue();
}
[Fact]
public void AddSecretCommand_CannotExecute_WhenStoreNotOpen()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(false);
// Act
var canExecute = _sut.AddSecretCommand.CanExecute(null);
// Assert
canExecute.ShouldBeFalse();
}
[Fact]
public void CloseStoreCommand_CanExecute_WhenStoreOpen()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(true);
// Act
var canExecute = _sut.CloseStoreCommand.CanExecute(null);
// Assert
canExecute.ShouldBeTrue();
}
[Fact]
public void CloseStoreCommand_CannotExecute_WhenStoreNotOpen()
{
// Arrange
_mockStoreManager.IsStoreOpen.Returns(false);
// Act
var canExecute = _sut.CloseStoreCommand.CanExecute(null);
// Assert
canExecute.ShouldBeFalse();
}
[Fact]
public void SelectedSecret_SetRaisesPropertyChanged()
{
// Arrange
var propertyChangedRaised = false;
_sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(_sut.SelectedSecret))
propertyChangedRaised = true;
};
// Act
_sut.SelectedSecret = new SecretItemViewModel("key", "value", _mockClipboardService);
// Assert
propertyChangedRaised.ShouldBeTrue();
}
}
@@ -0,0 +1,127 @@
using Shouldly;
using Xunit;
using JdeScoping.SecureStoreManager.ViewModels;
namespace JdeScoping.SecureStoreManager.Tests.ViewModels;
public class RelayCommandTests
{
[Fact]
public void Execute_CallsAction()
{
// Arrange
var wasCalled = false;
var sut = new RelayCommand(() => wasCalled = true);
// Act
sut.Execute(null);
// Assert
wasCalled.ShouldBeTrue();
}
[Fact]
public void Execute_PassesParameterToAction()
{
// Arrange
object? receivedParameter = null;
var sut = new RelayCommand(p => receivedParameter = p);
// Act
sut.Execute("testParam");
// Assert
receivedParameter.ShouldBe("testParam");
}
[Fact]
public void CanExecute_WhenNoPredicate_ReturnsTrue()
{
// Arrange
var sut = new RelayCommand(() => { });
// Act
var result = sut.CanExecute(null);
// Assert
result.ShouldBeTrue();
}
[Fact]
public void CanExecute_WhenPredicateReturnsTrue_ReturnsTrue()
{
// Arrange
var sut = new RelayCommand(() => { }, () => true);
// Act
var result = sut.CanExecute(null);
// Assert
result.ShouldBeTrue();
}
[Fact]
public void CanExecute_WhenPredicateReturnsFalse_ReturnsFalse()
{
// Arrange
var sut = new RelayCommand(() => { }, () => false);
// Act
var result = sut.CanExecute(null);
// Assert
result.ShouldBeFalse();
}
[Fact]
public void CanExecute_WithParameterPredicate_EvaluatesParameter()
{
// Arrange
var sut = new RelayCommand(_ => { }, p => p is string s && s == "valid");
// Act
var validResult = sut.CanExecute("valid");
var invalidResult = sut.CanExecute("invalid");
// Assert
validResult.ShouldBeTrue();
invalidResult.ShouldBeFalse();
}
[Fact]
public void RaiseCanExecuteChanged_FiresCanExecuteChangedEvent()
{
// Arrange
var sut = new RelayCommand(() => { });
var eventFired = false;
sut.CanExecuteChanged += (s, e) => eventFired = true;
// Act
sut.RaiseCanExecuteChanged();
// Assert
eventFired.ShouldBeTrue();
}
[Fact]
public void RaiseCanExecuteChanged_EventSenderIsSut()
{
// Arrange
var sut = new RelayCommand(() => { });
object? eventSender = null;
sut.CanExecuteChanged += (s, e) => eventSender = s;
// Act
sut.RaiseCanExecuteChanged();
// Assert
eventSender.ShouldBe(sut);
}
[Fact]
public void Constructor_WithNullExecute_ThrowsArgumentNullException()
{
// Arrange & Act & Assert
Should.Throw<ArgumentNullException>(() => new RelayCommand((Action<object?>)null!));
}
}
@@ -0,0 +1,170 @@
using NSubstitute;
using Shouldly;
using Xunit;
using JdeScoping.SecureStoreManager.Services;
using JdeScoping.SecureStoreManager.ViewModels;
namespace JdeScoping.SecureStoreManager.Tests.ViewModels;
public class SecretItemViewModelTests
{
private readonly IClipboardService _mockClipboardService;
public SecretItemViewModelTests()
{
_mockClipboardService = Substitute.For<IClipboardService>();
}
[Fact]
public void Constructor_InitializesKey()
{
// Arrange & Act
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
// Assert
sut.Key.ShouldBe("testKey");
}
[Fact]
public void Constructor_InitializesActualValue()
{
// Arrange & Act
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
// Assert
sut.ActualValue.ShouldBe("testValue");
}
[Fact]
public void Constructor_InitializesIsValueVisibleToFalse()
{
// Arrange & Act
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
// Assert
sut.IsValueVisible.ShouldBeFalse();
}
[Fact]
public void DisplayValue_WhenNotVisible_ReturnsMaskedValue()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
// Act & Assert
sut.DisplayValue.ShouldBe("********");
}
[Fact]
public void DisplayValue_WhenVisible_ReturnsActualValue()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
// Act
sut.IsValueVisible = true;
// Assert
sut.DisplayValue.ShouldBe("testValue");
}
[Fact]
public void ToggleVisibilityCommand_TogglesIsValueVisible()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
sut.IsValueVisible.ShouldBeFalse();
// Act
sut.ToggleVisibilityCommand.Execute(null);
// Assert
sut.IsValueVisible.ShouldBeTrue();
}
[Fact]
public void ToggleVisibilityCommand_TogglesBackToHidden()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
sut.IsValueVisible = true;
// Act
sut.ToggleVisibilityCommand.Execute(null);
// Assert
sut.IsValueVisible.ShouldBeFalse();
}
[Fact]
public async Task CopyToClipboardCommand_CallsClipboardService()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "secretPassword", _mockClipboardService);
// Act
sut.CopyToClipboardCommand.Execute(null);
// Assert - need to wait for async handler
// Give the async void handler time to complete
await Task.Delay(100);
await _mockClipboardService.Received(1).SetTextAsync("secretPassword");
}
[Fact]
public void IsValueVisible_SetterRaisesPropertyChangedForIsValueVisible()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(sut.IsValueVisible))
propertyChangedRaised = true;
};
// Act
sut.IsValueVisible = true;
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void IsValueVisible_SetterRaisesPropertyChangedForDisplayValue()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(sut.DisplayValue))
propertyChangedRaised = true;
};
// Act
sut.IsValueVisible = true;
// Assert
propertyChangedRaised.ShouldBeTrue();
}
[Fact]
public void IsValueVisible_SetToSameValue_DoesNotRaisePropertyChanged()
{
// Arrange
var sut = new SecretItemViewModel("testKey", "testValue", _mockClipboardService);
sut.IsValueVisible = false; // Already false, but explicitly set
var propertyChangedRaised = false;
sut.PropertyChanged += (s, e) =>
{
propertyChangedRaised = true;
};
// Act
sut.IsValueVisible = false;
// Assert
propertyChangedRaised.ShouldBeFalse();
}
}
@@ -0,0 +1,184 @@
using Shouldly;
using Xunit;
using JdeScoping.SecureStoreManager.ViewModels;
namespace JdeScoping.SecureStoreManager.Tests.ViewModels;
public class ViewModelBaseTests
{
/// <summary>
/// Test implementation of ViewModelBase for testing purposes.
/// </summary>
private class TestViewModel : ViewModelBase
{
private string _testProperty = string.Empty;
private int _testIntProperty;
public string TestProperty
{
get => _testProperty;
set => SetProperty(ref _testProperty, value);
}
public int TestIntProperty
{
get => _testIntProperty;
set => SetProperty(ref _testIntProperty, value);
}
public void RaisePropertyChangedForTest(string propertyName)
{
OnPropertyChanged(propertyName);
}
}
[Fact]
public void SetProperty_WhenValueUnchanged_ReturnsFalse()
{
// Arrange
var sut = new TestViewModel();
sut.TestProperty = "initialValue";
// Act
sut.TestProperty = "initialValue"; // Same value
// Assert - SetProperty should have returned false, but we can verify by checking no event was raised
// We test this indirectly through the property changed event not firing
}
[Fact]
public void SetProperty_WhenValueUnchanged_DoesNotRaisePropertyChanged()
{
// Arrange
var sut = new TestViewModel();
sut.TestProperty = "initialValue";
var eventRaised = false;
sut.PropertyChanged += (s, e) => eventRaised = true;
// Act
sut.TestProperty = "initialValue"; // Same value
// Assert
eventRaised.ShouldBeFalse();
}
[Fact]
public void SetProperty_WhenValueChanged_ReturnsTrue()
{
// Arrange
var sut = new TestViewModel();
// Act
sut.TestProperty = "newValue";
// Assert - SetProperty returned true (verified by property change being made)
sut.TestProperty.ShouldBe("newValue");
}
[Fact]
public void SetProperty_WhenValueChanged_RaisesPropertyChanged()
{
// Arrange
var sut = new TestViewModel();
var eventRaised = false;
sut.PropertyChanged += (s, e) => eventRaised = true;
// Act
sut.TestProperty = "newValue";
// Assert
eventRaised.ShouldBeTrue();
}
[Fact]
public void SetProperty_RaisesEventWithCorrectPropertyName()
{
// Arrange
var sut = new TestViewModel();
string? raisedPropertyName = null;
sut.PropertyChanged += (s, e) => raisedPropertyName = e.PropertyName;
// Act
sut.TestProperty = "newValue";
// Assert
raisedPropertyName.ShouldBe(nameof(TestViewModel.TestProperty));
}
[Fact]
public void SetProperty_RaisesEventWithSenderAsThis()
{
// Arrange
var sut = new TestViewModel();
object? eventSender = null;
sut.PropertyChanged += (s, e) => eventSender = s;
// Act
sut.TestProperty = "newValue";
// Assert
eventSender.ShouldBe(sut);
}
[Fact]
public void OnPropertyChanged_RaisesPropertyChangedEvent()
{
// Arrange
var sut = new TestViewModel();
var eventRaised = false;
sut.PropertyChanged += (s, e) => eventRaised = true;
// Act
sut.RaisePropertyChangedForTest("SomeProperty");
// Assert
eventRaised.ShouldBeTrue();
}
[Fact]
public void OnPropertyChanged_RaisesEventWithCorrectPropertyName()
{
// Arrange
var sut = new TestViewModel();
string? raisedPropertyName = null;
sut.PropertyChanged += (s, e) => raisedPropertyName = e.PropertyName;
// Act
sut.RaisePropertyChangedForTest("CustomProperty");
// Assert
raisedPropertyName.ShouldBe("CustomProperty");
}
[Fact]
public void SetProperty_WithValueType_WorksCorrectly()
{
// Arrange
var sut = new TestViewModel();
var eventRaised = false;
sut.PropertyChanged += (s, e) => eventRaised = true;
// Act
sut.TestIntProperty = 42;
// Assert
sut.TestIntProperty.ShouldBe(42);
eventRaised.ShouldBeTrue();
}
[Fact]
public void SetProperty_WithSameValueType_DoesNotRaiseEvent()
{
// Arrange
var sut = new TestViewModel();
sut.TestIntProperty = 42;
var eventRaised = false;
sut.PropertyChanged += (s, e) => eventRaised = true;
// Act
sut.TestIntProperty = 42; // Same value
// Assert
eventRaised.ShouldBeFalse();
}
}