refactor: address code review findings across all projects
Apply comprehensive fixes from code reviews including: - Extract shared utilities (SqlFormatHelper, CellValueConverter, DbDestinationBase) - Add interface abstractions (IAuthenticationService, IDatabaseMigrator, IMisQueryBuilder) - Implement SecureStore for encrypted secrets storage - Fix error handling with proper HTTP status codes and logging - Optimize double enumeration in DevEtlRegistry - Add DataSync.Dev README for developer onboarding - Extract filter panel base classes to reduce duplication - Update code review docs to mark all issues as fixed
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||
<PackageReference Include="Shouldly" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Utils\JdeScoping.SecureStoreManager\JdeScoping.SecureStoreManager.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,340 @@
|
||||
using System.IO;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using JdeScoping.SecureStoreManager.Services;
|
||||
|
||||
namespace JdeScoping.SecureStoreManager.Tests.Services;
|
||||
|
||||
public class SecureStoreManagerTests : IDisposable
|
||||
{
|
||||
private readonly string _testDirectory;
|
||||
private readonly SecureStoreManager.Services.SecureStoreManager _sut;
|
||||
|
||||
public SecureStoreManagerTests()
|
||||
{
|
||||
_testDirectory = Path.Combine(Path.GetTempPath(), $"SecureStoreTests_{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(_testDirectory);
|
||||
_sut = new SecureStoreManager.Services.SecureStoreManager();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut.Dispose();
|
||||
if (Directory.Exists(_testDirectory))
|
||||
{
|
||||
Directory.Delete(_testDirectory, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsStoreOpen_WhenNoStoreOpen_ReturnsFalse()
|
||||
{
|
||||
_sut.IsStoreOpen.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CurrentStorePath_WhenNoStoreOpen_ReturnsNull()
|
||||
{
|
||||
_sut.CurrentStorePath.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasUnsavedChanges_WhenNoStoreOpen_ReturnsFalse()
|
||||
{
|
||||
_sut.HasUnsavedChanges.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateStore_WithKeyFile_CreatesStoreAndKeyFile()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
|
||||
// Act
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
|
||||
// Assert
|
||||
_sut.IsStoreOpen.ShouldBeTrue();
|
||||
_sut.CurrentStorePath.ShouldBe(storePath);
|
||||
File.Exists(storePath).ShouldBeTrue();
|
||||
File.Exists(keyPath).ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateStoreWithPassword_CreatesStore()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
|
||||
// Act
|
||||
_sut.CreateStoreWithPassword(storePath, "testpassword123");
|
||||
|
||||
// Assert
|
||||
_sut.IsStoreOpen.ShouldBeTrue();
|
||||
_sut.CurrentStorePath.ShouldBe(storePath);
|
||||
File.Exists(storePath).ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateStoreWithPassword_WithEmptyPassword_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<ArgumentException>(() => _sut.CreateStoreWithPassword(storePath, ""));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenStore_WithValidKeyFile_OpensStore()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.CloseStore();
|
||||
|
||||
// Act
|
||||
_sut.OpenStore(storePath, keyPath);
|
||||
|
||||
// Assert
|
||||
_sut.IsStoreOpen.ShouldBeTrue();
|
||||
_sut.CurrentStorePath.ShouldBe(storePath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenStore_WithNonExistentStore_ThrowsFileNotFoundException()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "nonexistent.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<FileNotFoundException>(() => _sut.OpenStore(storePath, keyPath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenStoreWithPassword_OpensStore()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var password = "testpassword123";
|
||||
_sut.CreateStoreWithPassword(storePath, password);
|
||||
_sut.CloseStore();
|
||||
|
||||
// Act
|
||||
_sut.OpenStoreWithPassword(storePath, password);
|
||||
|
||||
// Assert
|
||||
_sut.IsStoreOpen.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloseStore_ClosesOpenStore()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
|
||||
// Act
|
||||
_sut.CloseStore();
|
||||
|
||||
// Assert
|
||||
_sut.IsStoreOpen.ShouldBeFalse();
|
||||
_sut.CurrentStorePath.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetSecret_AddsSecretAndMarksUnsaved()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.Save(); // Save to clear unsaved flag
|
||||
|
||||
// Act
|
||||
_sut.SetSecret("testKey", "testValue");
|
||||
|
||||
// Assert
|
||||
_sut.HasUnsavedChanges.ShouldBeTrue();
|
||||
_sut.GetKeys().ShouldContain("testKey");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSecret_ReturnsCorrectValue()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.SetSecret("testKey", "testValue");
|
||||
|
||||
// Act
|
||||
var value = _sut.GetSecret("testKey");
|
||||
|
||||
// Assert
|
||||
value.ShouldBe("testValue");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSecret_WhenKeyNotFound_ThrowsKeyNotFoundException()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<KeyNotFoundException>(() => _sut.GetSecret("nonexistent"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveSecret_RemovesSecretAndMarksUnsaved()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.SetSecret("testKey", "testValue");
|
||||
_sut.Save();
|
||||
|
||||
// Act
|
||||
_sut.RemoveSecret("testKey");
|
||||
|
||||
// Assert
|
||||
_sut.HasUnsavedChanges.ShouldBeTrue();
|
||||
_sut.GetKeys().ShouldNotContain("testKey");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveSecret_WhenKeyNotFound_ThrowsKeyNotFoundException()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<KeyNotFoundException>(() => _sut.RemoveSecret("nonexistent"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_PersistsSecretsToStore()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.SetSecret("testKey", "testValue");
|
||||
|
||||
// Act
|
||||
_sut.Save();
|
||||
_sut.CloseStore();
|
||||
_sut.OpenStore(storePath, keyPath);
|
||||
|
||||
// Assert
|
||||
_sut.GetKeys().ShouldContain("testKey");
|
||||
_sut.GetSecret("testKey").ShouldBe("testValue");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_ClearsUnsavedChangesFlag()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.SetSecret("testKey", "testValue");
|
||||
_sut.HasUnsavedChanges.ShouldBeTrue();
|
||||
|
||||
// Act
|
||||
_sut.Save();
|
||||
|
||||
// Assert
|
||||
_sut.HasUnsavedChanges.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetKeys_ReturnsAllSecretKeys()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
_sut.SetSecret("key1", "value1");
|
||||
_sut.SetSecret("key2", "value2");
|
||||
_sut.SetSecret("key3", "value3");
|
||||
|
||||
// Act
|
||||
var keys = _sut.GetKeys();
|
||||
|
||||
// Assert
|
||||
keys.Count.ShouldBe(3);
|
||||
keys.ShouldContain("key1");
|
||||
keys.ShouldContain("key2");
|
||||
keys.ShouldContain("key3");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateKeyFile_CreatesNewKeyFile()
|
||||
{
|
||||
// Arrange
|
||||
var keyPath = Path.Combine(_testDirectory, "generated.key");
|
||||
|
||||
// Act
|
||||
_sut.GenerateKeyFile(keyPath);
|
||||
|
||||
// Assert
|
||||
File.Exists(keyPath).ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExportKey_WhenNoStoreOpen_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var keyPath = Path.Combine(_testDirectory, "export.key");
|
||||
|
||||
// Act & Assert
|
||||
Should.Throw<InvalidOperationException>(() => _sut.ExportKey(keyPath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExportKey_WhenStoreOpen_ExportsKey()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = Path.Combine(_testDirectory, "test.json");
|
||||
var keyPath = Path.Combine(_testDirectory, "test.key");
|
||||
var exportPath = Path.Combine(_testDirectory, "export.key");
|
||||
_sut.CreateStore(storePath, keyPath);
|
||||
|
||||
// Act
|
||||
_sut.ExportKey(exportPath);
|
||||
|
||||
// Assert
|
||||
File.Exists(exportPath).ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetKeys_WhenNoStoreOpen_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Act & Assert
|
||||
Should.Throw<InvalidOperationException>(() => _sut.GetKeys());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetSecret_WhenNoStoreOpen_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Act & Assert
|
||||
Should.Throw<InvalidOperationException>(() => _sut.SetSecret("key", "value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSecret_WhenNoStoreOpen_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Act & Assert
|
||||
Should.Throw<InvalidOperationException>(() => _sut.GetSecret("key"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
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 MainWindowViewModel _sut;
|
||||
|
||||
public MainWindowViewModelTests()
|
||||
{
|
||||
_mockStoreManager = Substitute.For<ISecureStoreManager>();
|
||||
_sut = new MainWindowViewModel(_mockStoreManager);
|
||||
}
|
||||
|
||||
[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, null);
|
||||
|
||||
// Assert
|
||||
_mockStoreManager.Received(1).CreateStore(storePath, keyPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateNewStoreAsync_WithPassword_CallsStoreManagerCreateStoreWithPassword()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = "/path/to/store.json";
|
||||
var password = "password123";
|
||||
_mockStoreManager.GetKeys().Returns(new List<string>().AsReadOnly());
|
||||
|
||||
// Act
|
||||
await _sut.CreateNewStoreAsync(storePath, null, password);
|
||||
|
||||
// Assert
|
||||
_mockStoreManager.Received(1).CreateStoreWithPassword(storePath, password);
|
||||
}
|
||||
|
||||
[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, null);
|
||||
|
||||
// Assert
|
||||
_mockStoreManager.Received(1).OpenStore(storePath, keyPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OpenExistingStoreAsync_WithPassword_CallsStoreManagerOpenStoreWithPassword()
|
||||
{
|
||||
// Arrange
|
||||
var storePath = "/path/to/store.json";
|
||||
var password = "password123";
|
||||
_mockStoreManager.GetKeys().Returns(new List<string>().AsReadOnly());
|
||||
|
||||
// Act
|
||||
await _sut.OpenExistingStoreAsync(storePath, null, password);
|
||||
|
||||
// Assert
|
||||
_mockStoreManager.Received(1).OpenStoreWithPassword(storePath, password);
|
||||
}
|
||||
|
||||
[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");
|
||||
|
||||
// Assert
|
||||
propertyChangedRaised.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user