94d5a864e0
Add SecureStore integration to ConfigManager for secure handling of connection strings and sensitive configuration values. Includes store/secret management UI, encrypted .store file support, and comprehensive test coverage.
400 lines
10 KiB
C#
400 lines
10 KiB
C#
using JdeScoping.ConfigManager.Constants;
|
|
using JdeScoping.ConfigManager.ViewModels.Dialogs;
|
|
|
|
namespace JdeScoping.ConfigManager.Tests.ViewModels.Dialogs;
|
|
|
|
public class NewStoreDialogViewModelTests
|
|
{
|
|
[Fact]
|
|
public void Constructor_DefaultsToUseKeyFile()
|
|
{
|
|
// Arrange & Act
|
|
var sut = new NewStoreDialogViewModel();
|
|
|
|
// Assert
|
|
sut.UseKeyFile.ShouldBeTrue();
|
|
sut.UsePassword.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenEmpty_IsValidReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "",
|
|
KeyFilePath = "/path/to/key.key"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenEmpty_ValidationErrorReturnsStorePathRequired()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "",
|
|
KeyFilePath = "/path/to/key.key"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.ValidationError.ShouldBe(SecureStoreStrings.StorePathRequired);
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenWhitespace_IsValidReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = " ",
|
|
KeyFilePath = "/path/to/key.key"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
sut.ValidationError.ShouldBe(SecureStoreStrings.StorePathRequired);
|
|
}
|
|
|
|
[Fact]
|
|
public void KeyFilePath_WhenRequiredAndEmpty_IsValidReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UseKeyFile = true,
|
|
KeyFilePath = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void KeyFilePath_WhenRequiredAndEmpty_ValidationErrorReturnsKeyFilePathRequired()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UseKeyFile = true,
|
|
KeyFilePath = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.ValidationError.ShouldBe(SecureStoreStrings.KeyFilePathRequired);
|
|
}
|
|
|
|
[Fact]
|
|
public void KeyFilePath_WhenRequiredAndProvided_IsValidReturnsTrue()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UseKeyFile = true,
|
|
KeyFilePath = "/path/to/key.key"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeTrue();
|
|
sut.ValidationError.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void Password_WhenRequiredAndEmpty_IsValidReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UsePassword = true,
|
|
Password = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void Password_WhenRequiredAndEmpty_ValidationErrorReturnsPasswordRequired()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UsePassword = true,
|
|
Password = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.ValidationError.ShouldBe(SecureStoreStrings.PasswordRequired);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConfirmPassword_WhenRequiredAndDoesNotMatch_IsValidReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UsePassword = true,
|
|
Password = "password123",
|
|
ConfirmPassword = "differentPassword"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void ConfirmPassword_WhenRequiredAndDoesNotMatch_ValidationErrorReturnsPasswordsDoNotMatch()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UsePassword = true,
|
|
Password = "password123",
|
|
ConfirmPassword = "differentPassword"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.ValidationError.ShouldBe(SecureStoreStrings.PasswordsDoNotMatch);
|
|
}
|
|
|
|
[Fact]
|
|
public void Password_WhenRequiredAndMatchesConfirmPassword_IsValidReturnsTrue()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure",
|
|
UsePassword = true,
|
|
Password = "password123",
|
|
ConfirmPassword = "password123"
|
|
};
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeTrue();
|
|
sut.ValidationError.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public void UseKeyFile_WhenSetToTrue_SetsUsePasswordToFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
UsePassword = true
|
|
};
|
|
|
|
// Act
|
|
sut.UseKeyFile = true;
|
|
|
|
// Assert
|
|
sut.UseKeyFile.ShouldBeTrue();
|
|
sut.UsePassword.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void UsePassword_WhenSetToTrue_SetsUseKeyFileToFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
UseKeyFile = true
|
|
};
|
|
|
|
// Act
|
|
sut.UsePassword = true;
|
|
|
|
// Assert
|
|
sut.UsePassword.ShouldBeTrue();
|
|
sut.UseKeyFile.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void IsValid_WhenNeitherKeyFileNorPasswordSelected_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel
|
|
{
|
|
StorePath = "/path/to/store.secure"
|
|
};
|
|
// Manually set both to false (shouldn't happen in UI, but test edge case)
|
|
sut.UseKeyFile = false;
|
|
|
|
// Act & Assert
|
|
sut.IsValid.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.StorePath))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.StorePath = "/new/path";
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenChanged_RaisesIsValidPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var isValidPropertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.IsValid))
|
|
isValidPropertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.StorePath = "/new/path";
|
|
|
|
// Assert
|
|
isValidPropertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void StorePath_WhenChanged_RaisesValidationErrorPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var validationErrorPropertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.ValidationError))
|
|
validationErrorPropertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.StorePath = "/new/path";
|
|
|
|
// Assert
|
|
validationErrorPropertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void KeyFilePath_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.KeyFilePath))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.KeyFilePath = "/new/key/path";
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Password_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.Password))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.Password = "newpassword";
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void ConfirmPassword_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.ConfirmPassword))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.ConfirmPassword = "newpassword";
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void UseKeyFile_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel { UseKeyFile = false };
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.UseKeyFile))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.UseKeyFile = true;
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void UsePassword_WhenChanged_RaisesPropertyChanged()
|
|
{
|
|
// Arrange
|
|
var sut = new NewStoreDialogViewModel();
|
|
var propertyChangedRaised = false;
|
|
sut.PropertyChanged += (s, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(NewStoreDialogViewModel.UsePassword))
|
|
propertyChangedRaised = true;
|
|
};
|
|
|
|
// Act
|
|
sut.UsePassword = true;
|
|
|
|
// Assert
|
|
propertyChangedRaised.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void Commands_AreInitialized()
|
|
{
|
|
// Arrange & Act
|
|
var sut = new NewStoreDialogViewModel();
|
|
|
|
// Assert
|
|
sut.BrowseStorePathCommand.ShouldNotBeNull();
|
|
sut.BrowseKeyFilePathCommand.ShouldNotBeNull();
|
|
sut.GenerateKeyFileCommand.ShouldNotBeNull();
|
|
}
|
|
}
|