using System.IO; 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 ProfileManagementViewModelRegistrationTests : IDisposable { private readonly string _tempFile; private readonly Mock _mockBranding; private readonly Mock _mockAppReg; private readonly GraphClientFactory _graphClientFactory; public ProfileManagementViewModelRegistrationTests() { _tempFile = Path.GetTempFileName(); File.Delete(_tempFile); _mockBranding = new Mock(); _mockAppReg = new Mock(); _graphClientFactory = new GraphClientFactory(new MsalClientFactory()); } 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, NullLogger.Instance, _mockAppReg.Object); } private static TenantProfile MakeProfile(string? appId = null) => new TenantProfile { Name = "TestTenant", TenantUrl = "https://test.sharepoint.com", ClientId = "00000000-0000-0000-0000-000000000001", AppId = appId }; [Fact] public void RegisterAppCommand_CanExecute_WhenProfileSelected_AndNoAppId() { var vm = CreateViewModel(); vm.SelectedProfile = MakeProfile(appId: null); Assert.True(vm.RegisterAppCommand.CanExecute(null)); } [Fact] public void RegisterAppCommand_CannotExecute_WhenNoProfile() { var vm = CreateViewModel(); Assert.False(vm.RegisterAppCommand.CanExecute(null)); } [Fact] public void RemoveAppCommand_CanExecute_WhenProfileHasAppId() { var vm = CreateViewModel(); vm.SelectedProfile = MakeProfile(appId: "some-app-id"); Assert.True(vm.RemoveAppCommand.CanExecute(null)); } [Fact] public void RemoveAppCommand_CannotExecute_WhenNoAppId() { var vm = CreateViewModel(); vm.SelectedProfile = MakeProfile(appId: null); Assert.False(vm.RemoveAppCommand.CanExecute(null)); } [Fact] public async Task RegisterApp_ShowsFallback_WhenNotAdmin() { _mockAppReg .Setup(s => s.IsGlobalAdminAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(false); var vm = CreateViewModel(); vm.SelectedProfile = MakeProfile(appId: null); await vm.RegisterAppCommand.ExecuteAsync(null); Assert.True(vm.ShowFallbackInstructions); } [Fact] public async Task RegisterApp_SetsAppId_OnSuccess() { _mockAppReg .Setup(s => s.IsGlobalAdminAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(true); _mockAppReg .Setup(s => s.RegisterAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(AppRegistrationResult.Success("new-app-id-123")); var profileService = new ProfileService(new ProfileRepository(_tempFile)); var profile = MakeProfile(appId: null); await profileService.AddProfileAsync(profile); var vm = new ProfileManagementViewModel( profileService, _mockBranding.Object, _graphClientFactory, NullLogger.Instance, _mockAppReg.Object); vm.SelectedProfile = profile; await vm.RegisterAppCommand.ExecuteAsync(null); Assert.Equal("new-app-id-123", profile.AppId); } [Fact] public async Task RemoveApp_ClearsAppId() { _mockAppReg .Setup(s => s.RemoveAsync(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); _mockAppReg .Setup(s => s.ClearMsalSessionAsync(It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); var profileService = new ProfileService(new ProfileRepository(_tempFile)); var profile = MakeProfile(appId: "existing-app-id"); await profileService.AddProfileAsync(profile); var vm = new ProfileManagementViewModel( profileService, _mockBranding.Object, _graphClientFactory, NullLogger.Instance, _mockAppReg.Object); vm.SelectedProfile = profile; await vm.RemoveAppCommand.ExecuteAsync(null); Assert.Null(profile.AppId); } }