From 6e06b6c9d43abf88200fd0e5bccdf67b706ea564 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 04:45:31 +0000 Subject: [PATCH 1/2] Bump Moq.AutoMock from 3.6.1 to 4.0.1 --- updated-dependencies: - dependency-name: Moq.AutoMock dependency-version: 4.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 5faf22f3..49b280c4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -35,7 +35,7 @@ - + From 0482a91a972b411429808aba765a65e84389293a Mon Sep 17 00:00:00 2001 From: JLdgu Date: Wed, 25 Mar 2026 08:23:06 +0000 Subject: [PATCH 2/2] Correct validator and AutoMock update Make settings default view in Main Window --- .../Features/AddItem/AddItemValidatorTests.cs | 9 +- .../Features/AddItem/AddItemViewModelTests.cs | 228 ++++++++---------- .../MainWindow/MainWindowViewModelTests.cs | 7 +- .../Phones/PhonesMainViewModelTests.cs | 12 +- .../Features/Sims/SimValidatorTests.cs | 13 +- .../Features/Sims/SimsMainViewModelTests.cs | 82 +++---- .../MainWindow/MainWindowViewModel.cs | 9 +- .../Features/Users/UsersItemViewModel.cs | 7 +- .../Resources/TrackingNumber.png | Bin 0 -> 6769 bytes 9 files changed, 159 insertions(+), 208 deletions(-) create mode 100644 PhoneAssistant.WPF/Resources/TrackingNumber.png diff --git a/PhoneAssistant.Tests/Features/AddItem/AddItemValidatorTests.cs b/PhoneAssistant.Tests/Features/AddItem/AddItemValidatorTests.cs index a9de5d15..3d63e7df 100644 --- a/PhoneAssistant.Tests/Features/AddItem/AddItemValidatorTests.cs +++ b/PhoneAssistant.Tests/Features/AddItem/AddItemValidatorTests.cs @@ -1,4 +1,5 @@ -using FluentValidation.TestHelper; +using FluentValidation; +using FluentValidation.TestHelper; using Moq; using Moq.AutoMock; @@ -17,6 +18,12 @@ public sealed class AddItemValidatorTests public AddItemValidatorTests() { _mocker = new AutoMocker(); + Mock phones = _mocker.GetMock(); + var validator = new AddItemValidator(phones.Object); + var serviceProviderMock = _mocker.GetMock(); + serviceProviderMock + .Setup(sp => sp.GetService(typeof(IValidator))) + .Returns(validator); _validator = _mocker.CreateInstance(); _sut = _mocker.CreateInstance(); } diff --git a/PhoneAssistant.Tests/Features/AddItem/AddItemViewModelTests.cs b/PhoneAssistant.Tests/Features/AddItem/AddItemViewModelTests.cs index e18342b9..1dc8afee 100644 --- a/PhoneAssistant.Tests/Features/AddItem/AddItemViewModelTests.cs +++ b/PhoneAssistant.Tests/Features/AddItem/AddItemViewModelTests.cs @@ -1,52 +1,46 @@ -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - using CommunityToolkit.Mvvm.Messaging; - using FluentValidation; - using Moq; using Moq.AutoMock; - using PhoneAssistant.Model; using PhoneAssistant.Tests.Shared; using PhoneAssistant.WPF.Features.AddItem; +using System.ComponentModel; namespace PhoneAssistant.Tests.Features.AddItem; public partial class AddItemViewModelTests { private readonly AutoMocker _mocker = new(); - [Test] - public async Task AddItemViewModel_DefaultOEMAndModelAsync() + private Mock MockValidator() { - AddItemViewModel sut = _mocker.CreateInstance(); - - await Assert.That((Manufacturer)sut.OEM).IsEqualTo(Manufacturer.Apple); - await Assert.That(sut.Model).IsEqualTo("iPhone SE 2022"); + Mock phones = _mocker.GetMock(); + var validator = new AddItemValidator(phones.Object); + var serviceProviderMock = _mocker.GetMock(); + serviceProviderMock + .Setup(sp => sp.GetService(typeof(IValidator))) + .Returns(validator); + return phones; } [Test] - [Arguments(Manufacturer.Apple,"iPhone SE 2022")] - [Arguments(Manufacturer.Nokia, "110 4G")] - [Arguments(Manufacturer.Other, "")] - [Arguments(Manufacturer.Samsung, "A32")] - public async Task OnOEMChanged_ShouldChangeModelAsync(Manufacturer oem, string model) + public async Task AddItemViewModel_DefaultOEMAndModel() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); - sut.OEM = oem; - - await Assert.That(sut.Model).IsEqualTo(model); + await Assert.That((Manufacturer)sut.OEM).IsEqualTo(Manufacturer.Apple); + await Assert.That(sut.Model).IsEqualTo("iPhone SE 2022"); } [Test] - public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneHasSimAsync() + public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneHasSim() { Mock sims = _mocker.GetMock(); #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. sims.Setup(r => r.GetSimNumberAsync("07123456789")).ReturnsAsync((string)null); #pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.Condition = "condition"; @@ -63,13 +57,8 @@ public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneHasSimAsync [Test] public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneInStockAsync() { - Mock phones = _mocker.GetMock(); + var phones = MockValidator(); phones.Setup(r => r.AssetTagUniqueAsync("MP00001")).ReturnsAsync(true); - var validator = new AddItemValidator(phones.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); AddItemViewModel sut = _mocker.CreateInstance(); sut.AssetTag = "MP00001"; @@ -84,8 +73,9 @@ public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneInStockAsyn } [Test] - public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneOnlyAsync() + public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneOnly() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.Condition = "condition"; @@ -97,104 +87,82 @@ public async Task CanSavePhone_ShouldBeEnabled_WhenNoErrors_WithPhoneOnlyAsync() await Assert.That(sut.CanSavePhone()).IsTrue(); } - [Test] - [Arguments("12345")] - [Arguments("12345678")] - [Arguments("1A345")] - public async Task Ticket_should_have_Error_when_invalid_format(string ticket) - { - Mock phones = _mocker.GetMock(); - var validator = new AddItemValidator(phones.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - AddItemViewModel sut = _mocker.CreateInstance(); + //[Test] + //public async Task Imei_should_not_have_Error_when_present() + //{ + // AddItemViewModel sut = _mocker.CreateInstance(); - sut.Ticket = ticket; + // sut.Imei = "355808981147090"; - await Assert.That(sut.HasErrors).IsTrue(); - await Assert.That(sut.GetErrors(nameof(sut.Ticket))).IsNotEmpty(); - } + // await Assert.That(sut.GetErrors(nameof(sut.Imei))).IsEmpty(); + //} - [Test] - [Arguments(null)] - [Arguments("")] - public async Task Ticket_should_not_have_Error_when_Null_or_empty(string? actual) - { - Mock phones = _mocker.GetMock(); - var validator = new AddItemValidator(phones.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - AddItemViewModel sut = _mocker.CreateInstance(); + //[Test] + //[Arguments(null)] + //[Arguments("")] + //public async Task PhoneNumber_should_not_have_Error_when_Null_or_empty(string? actual) + //{ + // AddItemViewModel sut = _mocker.CreateInstance(); - sut.Ticket = actual; + // sut.PhoneNumber = actual; - await Assert.That(sut.GetErrors(nameof(sut.Ticket))).IsEmpty(); - } - - [Test] - public async Task Imei_should_not_have_Error_when_present() - { - AddItemViewModel sut = _mocker.CreateInstance(); + // await Assert.That(sut.GetErrors(nameof(sut.PhoneNumber))).IsEmpty(); + //} - sut.Imei = "355808981147090"; + //[Test] + //public async Task PhoneNumber_should_not_have_Error_when_present() + //{ + // AddItemViewModel sut = _mocker.CreateInstance(); - await Assert.That(sut.GetErrors(nameof(sut.Imei))).IsEmpty(); - } + // sut.PhoneNumber = "07123456789"; - [Test] - [Arguments(null)] - [Arguments("")] - public async Task PhoneNumber_should_not_have_Error_when_Null_or_empty(string? actual) - { - AddItemViewModel sut = _mocker.CreateInstance(); + // await Assert.That(sut.GetErrors(nameof(sut.PhoneNumber))).IsEmpty(); + //} - sut.PhoneNumber = actual; + //[Test] + //public async Task GetErrors_ShouldBeEmpty_WhenSimNumberNullAsync() + //{ + // AddItemViewModel sut = _mocker.CreateInstance(); - await Assert.That(sut.GetErrors(nameof(sut.PhoneNumber))).IsEmpty(); - } + // sut.SimNumber = null; - [Test] - public async Task PhoneNumber_should_not_have_Error_when_present() - { - AddItemViewModel sut = _mocker.CreateInstance(); - - sut.PhoneNumber = "07123456789"; + // await Assert.That(sut.GetErrors(nameof(sut.SimNumber))).IsEmpty(); + //} - await Assert.That(sut.GetErrors(nameof(sut.PhoneNumber))).IsEmpty(); - } - - [Test] - public async Task GetErrors_ShouldBeEmpty_WhenSimNumberNullAsync() - { - AddItemViewModel sut = _mocker.CreateInstance(); + //[Test] + //public async Task GetErrors_ShouldBeEmpty_WhenSimNumberSetAsync() + //{ + // AddItemViewModel sut = _mocker.CreateInstance(); - sut.SimNumber = null; + // sut.SimNumber = "8944122605566849402"; - await Assert.That(sut.GetErrors(nameof(sut.SimNumber))).IsEmpty(); - } + // await Assert.That(sut.GetErrors(nameof(sut.SimNumber))).IsEmpty(); + //} [Test] - public async Task GetErrors_ShouldBeEmpty_WhenSimNumberSetAsync() + public async Task LoadAsync_ShouldReturn_TaskCompleted() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); - sut.SimNumber = "8944122605566849402"; + Task result = sut.LoadAsync(); - await Assert.That(sut.GetErrors(nameof(sut.SimNumber))).IsEmpty(); + await Assert.That(result).IsCompleted(); } [Test] - public async Task LoadAsync_ShouldReturn_TaskCompleted() + [Arguments(Manufacturer.Apple, "iPhone SE 2022")] + [Arguments(Manufacturer.Nokia, "110 4G")] + [Arguments(Manufacturer.Other, "")] + [Arguments(Manufacturer.Samsung, "A32")] + public async Task OEM_should_change_Model(Manufacturer oem, string model) { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); - Task result = sut.LoadAsync(); + sut.OEM = oem; - await Assert.That(result).IsCompleted(); + await Assert.That(sut.Model).IsEqualTo(model); } [Test] @@ -202,6 +170,7 @@ public async Task OnPhoneNumberChanged_ShouldSetSimNumber_WhenSimExistsAsync() { Mock repository = _mocker.GetMock(); repository.Setup(r => r.GetSimNumberAsync("07123456789")).ReturnsAsync("sim number"); + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.PhoneNumber = "07123456789"; @@ -213,12 +182,7 @@ public async Task OnPhoneNumberChanged_ShouldSetSimNumber_WhenSimExistsAsync() [Test] public async Task PhoneClearCommand_ShouldDisablePhoneSaveAsync() { - Mock repository = _mocker.GetMock(); - var validator = new AddItemValidator(repository.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.PhoneClearCommand.Execute(null); @@ -229,6 +193,7 @@ public async Task PhoneClearCommand_ShouldDisablePhoneSaveAsync() [Test] public async Task PhoneClearCommand_ShouldResetAllPropertiesAsync() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); ArrangeSetAllPhoneProperties(sut); @@ -240,8 +205,9 @@ public async Task PhoneClearCommand_ShouldResetAllPropertiesAsync() [Test] [Description("Issue #65")] - public async Task PhoneSaveCommand_WithConditionN_ShouldLogNewAsync() + public async Task PhoneSaveCommand_should_Log_New_when_Condition_N() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.Condition = ApplicationConstants.Conditions[0][..1]; @@ -255,11 +221,12 @@ public async Task PhoneSaveCommand_WithConditionN_ShouldLogNewAsync() var actual = sut.LogItems.First(); await Assert.That(actual).Contains("New"); } - + [Test] [Description("Issue #65")] - public async Task PhoneSaveCommand_WithConditionR_ShouldLogRepurposedAsync() + public async Task PhoneSaveCommand_should_Log_Repurposed_when_Condition_R() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.Condition = ApplicationConstants.Conditions[1].Substring(0, 1); @@ -290,14 +257,9 @@ public async Task PhoneSaveCommand_WithPhoneAndSim_ShouldCallRepositoryAsync() OEM = Manufacturer.Apple, Status = "status" }; - Mock repository = _mocker.GetMock(); + var repository = MockValidator(); repository.Setup(r => r.AssetTagUniqueAsync("MP00001")).ReturnsAsync(true); repository.Setup(r => r.CreateAsync(It.IsAny())).Callback((p) => actual = p); - var validator = new AddItemValidator(repository.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); AddItemViewModel sut = _mocker.CreateInstance(); sut.AssetTag = expectedAssetTag; @@ -330,14 +292,9 @@ public async Task PhoneSaveCommand_WithPhoneOnly_ShouldCallRepositoryAsync() OEM = Manufacturer.Apple, Status = "status" }; - Mock repository = _mocker.GetMock(); + var repository = MockValidator(); repository.Setup(r => r.AssetTagUniqueAsync("MP00001")).ReturnsAsync(true); repository.Setup(r => r.CreateAsync(It.IsAny())).Callback((p) => actual = p); - var validator = new AddItemValidator(repository.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); AddItemViewModel sut = _mocker.CreateInstance(); sut.AssetTag = expectedAssetTag; @@ -355,15 +312,9 @@ public async Task PhoneSaveCommand_WithPhoneOnly_ShouldCallRepositoryAsync() } [Test] - public async Task PhoneSaveCommand_ShouldDisablePhoneSaveAsync() + public async Task PhoneSaveCommand_hould_disable_PhoneSaveCommand() { - Mock repository = _mocker.GetMock(); - var validator = new AddItemValidator(repository.Object); - var serviceProviderMock = _mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.PhoneSaveCommand.Execute(null); @@ -372,8 +323,9 @@ public async Task PhoneSaveCommand_ShouldDisablePhoneSaveAsync() } [Test] - public async Task PhoneSaveCommand_ShouldResetAllPhonePropertiesAsync() + public async Task PhoneSaveCommand_should_reset_all_Phone_properties() { + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); ArrangeSetAllPhoneProperties(sut); @@ -387,6 +339,7 @@ public void PhoneSaveCommand_ShouldSendPhoneMessage() { Mock message = _mocker.GetMock(); message.Setup(m => m.Send(It.IsAny(), It.IsAny())); + _ = MockValidator(); AddItemViewModel sut = _mocker.CreateInstance(); sut.AssetTag = "MP00001"; @@ -398,7 +351,20 @@ public void PhoneSaveCommand_ShouldSendPhoneMessage() message.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); } - private void ArrangeSetAllPhoneProperties(AddItemViewModel sut) + [Test] + [Arguments(null)] + [Arguments("")] + public async Task Ticket_should_not_have_Error_when_Null_or_empty(string? actual) + { + _ = MockValidator(); + AddItemViewModel sut = _mocker.CreateInstance(); + + sut.Ticket = actual; + + await Assert.That(sut.GetErrors(nameof(sut.Ticket))).IsEmpty(); + } + + private static void ArrangeSetAllPhoneProperties(AddItemViewModel sut) { sut.AssetTag = "MP00000"; sut.Condition = "condition"; @@ -411,7 +377,7 @@ private void ArrangeSetAllPhoneProperties(AddItemViewModel sut) sut.Ticket = 7654321.ToString(); } - private async Task AssertResetAllPhonePropertiesAsync(AddItemViewModel sut) + private static async Task AssertResetAllPhonePropertiesAsync(AddItemViewModel sut) { await Assert.That(sut.AssetTag).IsNull(); await Assert.That(sut.Condition).IsEqualTo(ApplicationConstants.Conditions[1].Substring(0, 1)); diff --git a/PhoneAssistant.Tests/Features/MainWindow/MainWindowViewModelTests.cs b/PhoneAssistant.Tests/Features/MainWindow/MainWindowViewModelTests.cs index 7f7b0c42..4b6ef168 100644 --- a/PhoneAssistant.Tests/Features/MainWindow/MainWindowViewModelTests.cs +++ b/PhoneAssistant.Tests/Features/MainWindow/MainWindowViewModelTests.cs @@ -59,10 +59,11 @@ public async Task UpdateViewAsync_WithValidViewModelType_CallUpdateAsync(ViewMod switch (viewModelType) { case ViewModelType.None: - dashboard.Verify(vm => vm.LoadAsync(), Times.Exactly(2)); + dashboard.Verify(vm => vm.LoadAsync(), Times.Never); + settings.Verify(vm => vm.LoadAsync(), Times.Exactly(2)); break; case ViewModelType.Dashboard: - dashboard.Verify(vm => vm.LoadAsync(), Times.Exactly(2)); + dashboard.Verify(vm => vm.LoadAsync(), Times.Once); break; case ViewModelType.Phones: phones.Verify(vm => vm.LoadAsync(), Times.Once); @@ -71,7 +72,7 @@ public async Task UpdateViewAsync_WithValidViewModelType_CallUpdateAsync(ViewMod sims.Verify(vm => vm.LoadAsync(), Times.Once); break; case ViewModelType.Settings: - settings.Verify(vm => vm.LoadAsync(), Times.Once); + settings.Verify(vm => vm.LoadAsync(), Times.Exactly(2)); break; case ViewModelType.Users: users.Verify(vm => vm.LoadAsync(), Times.Once); diff --git a/PhoneAssistant.Tests/Features/Phones/PhonesMainViewModelTests.cs b/PhoneAssistant.Tests/Features/Phones/PhonesMainViewModelTests.cs index 928ed714..60cb4b96 100644 --- a/PhoneAssistant.Tests/Features/Phones/PhonesMainViewModelTests.cs +++ b/PhoneAssistant.Tests/Features/Phones/PhonesMainViewModelTests.cs @@ -273,7 +273,6 @@ public async Task LoadAsync_should_call_GetActivePhones_when_IncludeDisposals_fa new Phone() { Imei = "2" , AssetTag = "Tag B2", Model = "", Condition = "", OEM = Manufacturer.Samsung, Status = "In Repair"}, new Phone() { Imei = "3" , AssetTag = "Tag C3", Model = "", Condition = "", OEM = Manufacturer.Nokia, Status = "Production"}, ]; - int index = 0; AutoMocker mocker = new(); Mock settings = mocker.GetMock(); settings.Setup(s => s.ApplicationSettings).Returns(new ApplicationSettings()); @@ -284,8 +283,7 @@ public async Task LoadAsync_should_call_GetActivePhones_when_IncludeDisposals_fa Mock messenger = mocker.GetMock(); Mock factory = mocker.GetMock(); factory.Setup(r => r.Create(It.IsAny())) - .Returns(() => new PhonesItemViewModel(settings.Object, baseReport.Object, repository.Object, messenger.Object, phones[index])) - .Callback(() => index++); + .Returns((Phone p) => new PhonesItemViewModel(settings.Object, baseReport.Object, repository.Object, messenger.Object, p)); PhonesMainViewModel vm = mocker.CreateInstance(); vm.IncludeDisposals = false; @@ -305,25 +303,23 @@ public async Task LoadAsync_should_call_GetAllPhones_when_IncludeDisposals_true( new Phone() { Imei = "4" , AssetTag = "Tag D4", Model = "", Condition = "", OEM = Manufacturer.Other, Status = "Decommissioned"}, new Phone() { Imei = "5" , AssetTag = "Tag E5", Model = "", Condition = "", OEM = Manufacturer.Apple, Status = "Disposed"}, ]; - int index = 0; AutoMocker mocker = new(); Mock settings = mocker.GetMock(); settings.Setup(s => s.ApplicationSettings).Returns(new ApplicationSettings()); Mock repository = mocker.GetMock(); repository.Setup(r => r.GetActivePhonesAsync()).ReturnsAsync(() => { return phones; }); repository.Setup(r => r.GetAllPhonesAsync()).ReturnsAsync(() => { return phones; }); - Mock sims = mocker.GetMock(); + Mock baseReport = mocker.GetMock(); Mock messenger = mocker.GetMock(); Mock factory = mocker.GetMock(); factory.Setup(r => r.Create(It.IsAny())) - .Returns(() => new PhonesItemViewModel(settings.Object, sims.Object, repository.Object, messenger.Object, phones[index])) - .Callback(() => index++); + .Returns((Phone p) => new PhonesItemViewModel(settings.Object, baseReport.Object, repository.Object, messenger.Object, p)); PhonesMainViewModel vm = mocker.CreateInstance(); vm.IncludeDisposals = true; await vm.LoadAsync(); - repository.Verify(r => r.GetAllPhonesAsync(), Times.Once()); + repository.Verify(r => r.GetAllPhonesAsync(), Times.Once); repository.Verify(r => r.GetActivePhonesAsync(), Times.Never()); } diff --git a/PhoneAssistant.Tests/Features/Sims/SimValidatorTests.cs b/PhoneAssistant.Tests/Features/Sims/SimValidatorTests.cs index 488ab829..68dc0815 100644 --- a/PhoneAssistant.Tests/Features/Sims/SimValidatorTests.cs +++ b/PhoneAssistant.Tests/Features/Sims/SimValidatorTests.cs @@ -1,5 +1,7 @@ -using FluentValidation.TestHelper; +using FluentValidation; +using FluentValidation.TestHelper; using Moq.AutoMock; +using PhoneAssistant.Model; using PhoneAssistant.WPF.Features.Sims; namespace PhoneAssistant.Tests.Features.Sims; @@ -13,9 +15,15 @@ internal sealed class SimValidatorTests public SimValidatorTests() { _mocker = new AutoMocker(); - _validator = _mocker.CreateInstance(); + var phones = _mocker.GetMock(); + _validator = new SimValidator(phones.Object); + _mocker.Use>(_validator); + var serviceProviderMock = _mocker.GetMock(); + serviceProviderMock + .Setup(sp => sp.GetService(typeof(IValidator))); _vm = _mocker.CreateInstance(); } + [Test] [Arguments(null)] [Arguments("")] @@ -41,6 +49,7 @@ public async Task NewUser_should_not_have_Error_when_Present() // Phone number validation is tested in ValidationRules_PhoneNumberTests // Sim number validation is tested in ValidationRules_SimNumberTests // Ticket validation is tested in ValidationRules_TicketTests - except for the case when ticket is required + [Test] [Arguments(null)] [Arguments("")] diff --git a/PhoneAssistant.Tests/Features/Sims/SimsMainViewModelTests.cs b/PhoneAssistant.Tests/Features/Sims/SimsMainViewModelTests.cs index 8e38b9e6..dd1b7bb4 100644 --- a/PhoneAssistant.Tests/Features/Sims/SimsMainViewModelTests.cs +++ b/PhoneAssistant.Tests/Features/Sims/SimsMainViewModelTests.cs @@ -14,18 +14,24 @@ namespace PhoneAssistant.Tests.Features.Sims; public sealed class SimsMainViewModelTests { - [Test] - public async Task HasErrors_should_be_false_when_required_fields_supplied() - { - AutoMocker mocker = new(); - var phonesRepository = mocker.GetMock(); + private readonly AutoMocker _mocker = new(); + + private void MockValidator() + { + var phonesRepository = _mocker.GetMock(); var validator = new SimValidator(phonesRepository.Object); - mocker.Use>(validator); - var serviceProviderMock = mocker.GetMock(); + _mocker.Use>(validator); + var serviceProviderMock = _mocker.GetMock(); serviceProviderMock .Setup(sp => sp.GetService(typeof(IValidator))) .Returns(validator); - var vm = mocker.CreateInstance(); + } + + [Test] + public async Task HasErrors_should_be_false_when_required_fields_supplied() + { + MockValidator(); + var vm = _mocker.CreateInstance(); vm.NewUser = "Rosie Lane"; vm.PhoneNumber = "07814209742"; @@ -37,16 +43,8 @@ public async Task HasErrors_should_be_false_when_required_fields_supplied() [Test] public async Task HasErrors_should_be_true_when_required_fields_missing() { - AutoMocker mocker = new(); - var phonesRepository = mocker.GetMock(); - var validator = new SimValidator(phonesRepository.Object); - mocker.Use>(validator); - var serviceProviderMock = mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - - var vm = mocker.CreateInstance(); + MockValidator(); + var vm = _mocker.CreateInstance(); await Assert.That(vm.HasErrors).IsTrue(); @@ -63,38 +61,24 @@ public async Task HasErrors_should_be_true_when_required_fields_missing() [Test] public async Task PhoneNumber_changed_should_set_SimNumber_when_SIM_exists() { - AutoMocker mocker = new(); - Mock baseRepository = mocker.GetMock(); + MockValidator(); + Mock baseRepository = _mocker.GetMock(); baseRepository.Setup(r => r.GetSimNumberAsync("01234567890")).ReturnsAsync("sim number"); - var phonesRepository = mocker.GetMock(); - var validator = new SimValidator(phonesRepository.Object); - var serviceProviderMock = mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); + var vm = _mocker.CreateInstance(); - var vm = mocker.CreateInstance(); vm.NewUser = "Alice"; vm.PhoneNumber = "01234567890"; vm.Ticket = "654321"; - mocker.VerifyAll(); + _mocker.VerifyAll(); await Assert.That(vm.SimNumber).IsEqualTo("sim number"); } [Test] public async Task PrintEnvelopeCommand_should_be_disabled_when_Errors() { - AutoMocker mocker = new(); - var phonesRepository = mocker.GetMock(); - var validator = new SimValidator(phonesRepository.Object); - mocker.Use>(validator); - var serviceProviderMock = mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - - var vm = mocker.CreateInstance(); + MockValidator(); + var vm = _mocker.CreateInstance(); await Assert.That(vm.HasErrors).IsTrue(); await Assert.That(vm.PrintEnvelopeCommand.CanExecute(null)).IsFalse(); @@ -103,14 +87,8 @@ public async Task PrintEnvelopeCommand_should_be_disabled_when_Errors() [Test] public async Task PrintEnvelopeCommand_should_be_enabled_when_all_properties_supplied() { - AutoMocker mocker = new(); - var phonesRepository = mocker.GetMock(); - var validator = new SimValidator(phonesRepository.Object); - var serviceProviderMock = mocker.GetMock(); - serviceProviderMock - .Setup(sp => sp.GetService(typeof(IValidator))) - .Returns(validator); - var vm = mocker.CreateInstance(); + MockValidator(); + var vm = _mocker.CreateInstance(); vm.NewUser = "Alice"; vm.PhoneNumber = "01234567890"; @@ -124,17 +102,17 @@ public async Task PrintEnvelopeCommand_should_be_enabled_when_all_properties_sup [Test] public async Task PrintEnvelopeCommand_should_call_PrintEnvelope_Execute_with_OrderDetails() { - AutoMocker mocker = new(); + MockValidator(); + var vm = _mocker.CreateInstance(); OrderDetails? actual = null; - var vm = mocker.CreateInstance(); + var printEnvelope = _mocker.GetMock(); + printEnvelope + .Setup(p => p.Execute(It.IsAny())) + .Callback(o => actual = o); vm.NewUser = "Rosie Lane"; vm.PhoneNumber = "07814209742"; vm.SimNumber = "8944122605563572205"; vm.Ticket = "262281"; - var printEnvelope = mocker.GetMock(); - printEnvelope - .Setup(p => p.Execute(It.IsAny())) - .Callback(o => actual = o); await vm.PrintEnvelopeCommand.ExecuteAsync(null); diff --git a/PhoneAssistant.WPF/Features/MainWindow/MainWindowViewModel.cs b/PhoneAssistant.WPF/Features/MainWindow/MainWindowViewModel.cs index af703fe6..ca7b1c5a 100644 --- a/PhoneAssistant.WPF/Features/MainWindow/MainWindowViewModel.cs +++ b/PhoneAssistant.WPF/Features/MainWindow/MainWindowViewModel.cs @@ -1,8 +1,6 @@ -using System.Windows; - + using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; - using PhoneAssistant.Model; using PhoneAssistant.WPF.Features.AddItem; using PhoneAssistant.WPF.Features.BaseReport; @@ -14,6 +12,7 @@ using PhoneAssistant.WPF.Features.Sims; using PhoneAssistant.WPF.Features.Users; using PhoneAssistant.WPF.Shared; +using System.Windows; namespace PhoneAssistant.WPF.Features.MainWindow; @@ -88,11 +87,9 @@ public MainWindowViewModel(IAddItemViewModel addItemViewModel, [RelayCommand] private async Task UpdateViewAsync(ViewModelType selectedViewModelType) { - ArgumentNullException.ThrowIfNull(selectedViewModelType); - SelectedViewModel = selectedViewModelType switch { - ViewModelType.None => _dashboardMainViewModel, + ViewModelType.None => _settingsMainViewModel, ViewModelType.AddItem => _addItemViewModel, ViewModelType.BaseReport => _baseReportMainViewModel, ViewModelType.Dashboard => _dashboardMainViewModel, diff --git a/PhoneAssistant.WPF/Features/Users/UsersItemViewModel.cs b/PhoneAssistant.WPF/Features/Users/UsersItemViewModel.cs index 6c61b665..55788d67 100644 --- a/PhoneAssistant.WPF/Features/Users/UsersItemViewModel.cs +++ b/PhoneAssistant.WPF/Features/Users/UsersItemViewModel.cs @@ -9,10 +9,7 @@ public sealed partial class UsersItemViewModel public UsersItemViewModel(User user) { - if (user is null) - { - throw new ArgumentNullException(nameof(user)); - } + ArgumentNullException.ThrowIfNull(user); User = user; } @@ -25,7 +22,7 @@ public void CopyNameToClipboard() [RelayCommand(CanExecute =nameof(CanCopyEmailToClipbaord))] public void CopyEmailToClipboard() { - Clipboard.SetText(User.Email); + Clipboard.SetText(User.Email!); } private bool CanCopyEmailToClipbaord() => !string.IsNullOrEmpty(User.Email); diff --git a/PhoneAssistant.WPF/Resources/TrackingNumber.png b/PhoneAssistant.WPF/Resources/TrackingNumber.png new file mode 100644 index 0000000000000000000000000000000000000000..f5c1940e10ff11cc3d4519e2671d8a851a2c728c GIT binary patch literal 6769 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