- Base64ToImageSourceConverter converts data URI strings to BitmapImage with null-safe error handling - Registered converter in App.xaml as Base64ToImageConverter global resource - Added 9 localization keys (EN+FR) for logo UI labels in Settings and Profile dialogs - Added ClientLogoPreview string property to ProfileManagementViewModel with FormatLogoPreview helper - Updated OnSelectedProfileChanged, BrowseClientLogoAsync, ClearClientLogoAsync, AutoPullClientLogoAsync - 17 tests pass (6 converter + 11 profile VM logo tests) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
186 lines
5.6 KiB
C#
186 lines
5.6 KiB
C#
using System.IO;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Moq;
|
|
using SharepointToolbox.Core.Models;
|
|
using SharepointToolbox.Infrastructure.Auth;
|
|
using SharepointToolbox.Infrastructure.Persistence;
|
|
using SharepointToolbox.Services;
|
|
using SharepointToolbox.ViewModels;
|
|
|
|
namespace SharepointToolbox.Tests.ViewModels;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public class ProfileManagementViewModelLogoTests : IDisposable
|
|
{
|
|
private readonly string _tempFile;
|
|
private readonly Mock<IBrandingService> _mockBranding;
|
|
private readonly GraphClientFactory _graphClientFactory;
|
|
private readonly ILogger<ProfileManagementViewModel> _logger;
|
|
|
|
public ProfileManagementViewModelLogoTests()
|
|
{
|
|
_tempFile = Path.GetTempFileName();
|
|
File.Delete(_tempFile);
|
|
_mockBranding = new Mock<IBrandingService>();
|
|
_graphClientFactory = new GraphClientFactory(new MsalClientFactory());
|
|
_logger = NullLogger<ProfileManagementViewModel>.Instance;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (File.Exists(_tempFile)) File.Delete(_tempFile);
|
|
if (File.Exists(_tempFile + ".tmp")) File.Delete(_tempFile + ".tmp");
|
|
}
|
|
|
|
private ProfileManagementViewModel CreateViewModel()
|
|
{
|
|
var profileService = new ProfileService(new ProfileRepository(_tempFile));
|
|
return new ProfileManagementViewModel(
|
|
profileService,
|
|
_mockBranding.Object,
|
|
_graphClientFactory,
|
|
_logger);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_BrowseClientLogoCommand_IsNotNull()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.NotNull(vm.BrowseClientLogoCommand);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_ClearClientLogoCommand_IsNotNull()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.NotNull(vm.ClearClientLogoCommand);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_AutoPullClientLogoCommand_IsNotNull()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.NotNull(vm.AutoPullClientLogoCommand);
|
|
}
|
|
|
|
[Fact]
|
|
public void BrowseClientLogoCommand_CannotExecute_WhenNoProfileSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.False(vm.BrowseClientLogoCommand.CanExecute(null));
|
|
}
|
|
|
|
[Fact]
|
|
public void ClearClientLogoCommand_CannotExecute_WhenNoProfileSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.False(vm.ClearClientLogoCommand.CanExecute(null));
|
|
}
|
|
|
|
[Fact]
|
|
public void AutoPullClientLogoCommand_CannotExecute_WhenNoProfileSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.False(vm.AutoPullClientLogoCommand.CanExecute(null));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ClearClientLogoCommand_ClearsClientLogo_AndPersists()
|
|
{
|
|
var profileService = new ProfileService(new ProfileRepository(_tempFile));
|
|
var profile = new TenantProfile
|
|
{
|
|
Name = "TestTenant",
|
|
TenantUrl = "https://test.sharepoint.com",
|
|
ClientId = "00000000-0000-0000-0000-000000000001",
|
|
ClientLogo = new LogoData { Base64 = "dGVzdA==", MimeType = "image/png" }
|
|
};
|
|
await profileService.AddProfileAsync(profile);
|
|
|
|
var vm = new ProfileManagementViewModel(
|
|
profileService,
|
|
_mockBranding.Object,
|
|
_graphClientFactory,
|
|
_logger);
|
|
|
|
vm.SelectedProfile = profile;
|
|
|
|
await vm.ClearClientLogoCommand.ExecuteAsync(null);
|
|
|
|
Assert.Null(profile.ClientLogo);
|
|
|
|
// Verify persisted
|
|
var profiles = await profileService.GetProfilesAsync();
|
|
var persisted = profiles.First(p => p.Name == "TestTenant");
|
|
Assert.Null(persisted.ClientLogo);
|
|
}
|
|
|
|
[Fact]
|
|
public void ClientLogoPreview_IsNull_WhenNoProfileSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
Assert.Null(vm.ClientLogoPreview);
|
|
}
|
|
|
|
[Fact]
|
|
public void ClientLogoPreview_UpdatesToDataUri_WhenProfileWithLogoSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
var profile = new TenantProfile
|
|
{
|
|
Name = "WithLogo",
|
|
TenantUrl = "https://test.sharepoint.com",
|
|
ClientId = "00000000-0000-0000-0000-000000000002",
|
|
ClientLogo = new LogoData { Base64 = "dGVzdA==", MimeType = "image/png" }
|
|
};
|
|
|
|
vm.SelectedProfile = profile;
|
|
|
|
Assert.Equal("data:image/png;base64,dGVzdA==", vm.ClientLogoPreview);
|
|
}
|
|
|
|
[Fact]
|
|
public void ClientLogoPreview_IsNull_WhenProfileWithoutLogoSelected()
|
|
{
|
|
var vm = CreateViewModel();
|
|
var profile = new TenantProfile
|
|
{
|
|
Name = "NoLogo",
|
|
TenantUrl = "https://test.sharepoint.com",
|
|
ClientId = "00000000-0000-0000-0000-000000000003"
|
|
};
|
|
|
|
vm.SelectedProfile = profile;
|
|
|
|
Assert.Null(vm.ClientLogoPreview);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ClearClientLogoCommand_SetsClientLogoPreviewToNull()
|
|
{
|
|
var profileService = new ProfileService(new ProfileRepository(_tempFile));
|
|
var profile = new TenantProfile
|
|
{
|
|
Name = "ClearTest",
|
|
TenantUrl = "https://test.sharepoint.com",
|
|
ClientId = "00000000-0000-0000-0000-000000000004",
|
|
ClientLogo = new LogoData { Base64 = "dGVzdA==", MimeType = "image/png" }
|
|
};
|
|
await profileService.AddProfileAsync(profile);
|
|
|
|
var vm = new ProfileManagementViewModel(
|
|
profileService,
|
|
_mockBranding.Object,
|
|
_graphClientFactory,
|
|
_logger);
|
|
|
|
vm.SelectedProfile = profile;
|
|
Assert.NotNull(vm.ClientLogoPreview);
|
|
|
|
await vm.ClearClientLogoCommand.ExecuteAsync(null);
|
|
|
|
Assert.Null(vm.ClientLogoPreview);
|
|
}
|
|
}
|