// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections.Generic; using Core.Common.Base.Data; using Core.Common.Base.Service; using Core.Common.Base.Storage; using Core.Common.TestUtil; using NUnit.Framework; using Rhino.Mocks; namespace Core.Common.Gui.Test { [TestFixture] public class SaveProjectActivityTest { [Test] [TestCase(true)] [TestCase(false)] public void Constructor_ExpectedValues(bool savingExistingProject) { // Setup var mocks = new MockRepository(); var storeProject = mocks.Stub(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); mocks.ReplayAll(); // Call var activity = new SaveProjectActivity(project, "", savingExistingProject, storeProject, projectOwner); // Assert Assert.IsInstanceOf(activity); Assert.IsNull(activity.ProgressText); Assert.AreEqual(ActivityState.None, activity.State); string exitingPrefix = savingExistingProject ? "bestaand " : ""; string expectedName = $"Opslaan van {exitingPrefix}project"; Assert.AreEqual(expectedName, activity.Description); mocks.VerifyAll(); } [Test] public void Constructor_FilePathNull_ThrowsArgumentNullException() { // Setup var mocks = new MockRepository(); var storeProject = mocks.Stub(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); mocks.ReplayAll(); // Call TestDelegate call = () => new SaveProjectActivity(project, null, true, storeProject, projectOwner); // Assert string paramName = Assert.Throws(call).ParamName; Assert.AreEqual("filePath", paramName); mocks.VerifyAll(); } [Test] public void Constructor_ProjectNull_ThrowsArgumentNullException() { // Setup var mocks = new MockRepository(); var storeProject = mocks.Stub(); var projectOwner = mocks.Stub(); mocks.ReplayAll(); // Call TestDelegate call = () => new SaveProjectActivity(null, "", true, storeProject, projectOwner); // Assert string paramName = Assert.Throws(call).ParamName; Assert.AreEqual("project", paramName); mocks.VerifyAll(); } [Test] public void Constructor_StoreProjectNull_ThrowsArgumentNullException() { // Setup var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); mocks.ReplayAll(); // Call TestDelegate call = () => new SaveProjectActivity(project, "", true, null, projectOwner); // Assert string paramName = Assert.Throws(call).ParamName; Assert.AreEqual("storeProject", paramName); } [Test] public void Constructor_ProjectOwnerNull_ThrowsArgumentNullException() { // Setup var mocks = new MockRepository(); var project = mocks.Stub(); var storeProject = mocks.Stub(); mocks.ReplayAll(); // Call TestDelegate call = () => new SaveProjectActivity(project, "", true, storeProject, null); // Assert string paramName = Assert.Throws(call).ParamName; Assert.AreEqual("projectOwner", paramName); } [Test] [TestCase(true)] [TestCase(false)] public void Run_UnstagedProject_StageAndSaveProjectWithoutAdditionalLogMessages(bool saveExistingProject) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(false); using (mocks.Ordered()) { storeProject.Expect(sp => sp.StageProject(project)); storeProject.Expect(sp => sp.SaveProjectAs(filePath)); } mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); // Call Action call = () => activity.Run(); // Assert string prefix = saveExistingProject ? "bestaand " : ""; TestHelper.AssertLogMessageIsGenerated(call, $"Opslaan van {prefix}project is gestart.", 1); Assert.AreEqual(ActivityState.Executed, activity.State); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void Run_AlreadyStagedProject_SaveProjectWithoutAdditionalLogMessages(bool saveExistingProject) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(true); storeProject.Expect(sp => sp.SaveProjectAs(filePath)); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); // Call Action call = () => activity.Run(); // Assert string prefix = saveExistingProject ? "bestaand " : ""; TestHelper.AssertLogMessageIsGenerated(call, $"Opslaan van {prefix}project is gestart.", 1); Assert.AreEqual(ActivityState.Executed, activity.State); mocks.VerifyAll(); } [Test] [Combinatorial] public void Run_SaveProjectAsThrowsException_FailedWithAdditionalLogMessages(Exception exception, string errorMessage) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.Stub(); storeProject.Stub(sp => sp.HasStagedProject) .Return(true); storeProject.Stub(sp => sp.SaveProjectAs(filePath)) .Throw(exception); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); // Call Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessagesWithLevelAreGenerated(call, new[] { Tuple.Create($"Opslaan van project is gestart.", LogLevelConstant.Info), Tuple.Create(errorMessage, LogLevelConstant.Error) }, 2); Assert.AreEqual(ActivityState.Failed, activity.State); mocks.VerifyAll(); } [Test] [TestCaseSource(nameof(GetExceptions))] public void Run_SaveExistingProjectAsThrowsException_FailedWithAdditionalLogMessages(Exception exception, string errorMessage) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.Stub(); storeProject.Stub(sp => sp.HasStagedProject) .Return(true); storeProject.Stub(sp => sp.SaveProjectAs(filePath)) .Throw(exception); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, true, storeProject, projectOwner); // Call Action call = () => activity.Run(); // Assert TestHelper.AssertLogMessagesWithLevelAreGenerated(call, new[] { Tuple.Create($"Opslaan van bestaand project is gestart.", LogLevelConstant.Info), Tuple.Create(errorMessage, LogLevelConstant.Error) }, 2); Assert.AreEqual(ActivityState.Failed, activity.State); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void Run_UnstagedProject_ExpectedProgressMessages(bool saveExistingProject) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(false); using (mocks.Ordered()) { storeProject.Expect(sp => sp.StageProject(project)); storeProject.Expect(sp => sp.SaveProjectAs(filePath)); } mocks.ReplayAll(); var progressMessages = new List(); var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); activity.ProgressChanged += (sender, args) => { Assert.AreSame(activity, sender); Assert.AreEqual(EventArgs.Empty, args); progressMessages.Add(activity.ProgressText); }; // Call activity.Run(); // Assert int totalSteps = saveExistingProject ? 2 : 3; var expectedProgressMessages = new[] { $"Stap 1 van {totalSteps} | Voorbereidingen opslaan", $"Stap 2 van {totalSteps} | Project opslaan" }; CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void Run_AlreadyStagedProject_ExpectedProgressMessages(bool saveExistingProject) { // Setup const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(true); storeProject.Expect(sp => sp.SaveProjectAs(filePath)); mocks.ReplayAll(); var progressMessages = new List(); var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); activity.ProgressChanged += (sender, args) => { Assert.AreSame(activity, sender); Assert.AreEqual(EventArgs.Empty, args); progressMessages.Add(activity.ProgressText); }; // Call activity.Run(); // Assert int totalSteps = saveExistingProject ? 1 : 2; var expectedProgressMessages = new[] { $"Stap 1 van {totalSteps} | Project opslaan" }; CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); mocks.VerifyAll(); } [Test] public void GivenActivity_WhenSuccessfullySavedNewProject_ThenUpdateProjectAndProjectOwnerWithMessage() { // Given const string fileName = "A"; string filePath = $@"C:\\folder\{fileName}.rtd"; var mocks = new MockRepository(); var storeProject = mocks.Stub(); var project = mocks.Stub(); project.Expect(p => p.NotifyObservers()); var projectOwner = mocks.StrictMock(); projectOwner.Expect(po => po.SetProject(project, filePath)); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); activity.Run(); // Precondition Assert.AreEqual(ActivityState.Executed, activity.State); // When Action call = () => { activity.LogState(); activity.Finish(); }; // Then Tuple expectedMessage = Tuple.Create("Opslaan van project is gelukt.", LogLevelConstant.Info); TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); Assert.AreEqual(ActivityState.Finished, activity.State); Assert.AreEqual(fileName, project.Name); mocks.VerifyAll(); } [Test] public void GivenActivity_WhenSuccessfullySavedExistingProject_ThenDoNotUpdateProjectAndProjectOwnerWithMessage() { // Given const string fileName = "A"; string filePath = $@"C:\\folder\{fileName}.rtd"; var mocks = new MockRepository(); var storeProject = mocks.Stub(); var project = mocks.StrictMock(); var projectOwner = mocks.StrictMock(); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, true, storeProject, projectOwner); activity.Run(); // Precondition Assert.AreEqual(ActivityState.Executed, activity.State); // When Action call = () => { activity.LogState(); activity.Finish(); }; // Assert Tuple expectedMessage = Tuple.Create("Opslaan van bestaand project is gelukt.", LogLevelConstant.Info); TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); Assert.AreEqual(ActivityState.Finished, activity.State); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void Finish_SuccessfullySavedNewProject_ExpectedProgressMessages(bool hasStagedProject) { // Setup const string fileName = "A"; string filePath = $@"C:\\folder\{fileName}.rtd"; var mocks = new MockRepository(); var project = mocks.Stub(); var storeProject = mocks.Stub(); storeProject.Stub(sp => sp.HasStagedProject).Return(hasStagedProject); storeProject.Stub(sp => sp.StageProject(project)); storeProject.Stub(sp => sp.SaveProjectAs(filePath)); var projectOwner = mocks.Stub(); mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); activity.Run(); // Precondition Assert.AreEqual(ActivityState.Executed, activity.State); var progressMessages = new List(); activity.ProgressChanged += (sender, args) => { Assert.AreSame(activity, sender); Assert.AreEqual(EventArgs.Empty, args); progressMessages.Add(activity.ProgressText); }; // Call activity.Finish(); // Assert int totalSteps = hasStagedProject ? 2 : 3; var expectedProgressMessages = new[] { $"Stap {totalSteps} van {totalSteps} | Initialiseren van opgeslagen project" }; CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void GivenActivityStagingProject_WhenCancelling_ThenProjectNotSavedWithAdditionalLogMessages(bool saveExistingProject) { // Given const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.StrictMock(); var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(false); using (mocks.Ordered()) { storeProject.Expect(sp => sp.StageProject(project)); storeProject.Expect(sp => sp.SaveProjectAs(filePath)) .Repeat.Never(); } mocks.ReplayAll(); var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); activity.ProgressChanged += (sender, args) => activity.Cancel(); // When Action call = () => { activity.Run(); // Cancel called mid-progress activity.LogState(); activity.Finish(); }; // Then string prefix = saveExistingProject ? "bestaand " : ""; TestHelper.AssertLogMessagesWithLevelAreGenerated(call, new[] { Tuple.Create($"Opslaan van {prefix}project is gestart.", LogLevelConstant.Info), Tuple.Create($"Opslaan van {prefix}project is geannuleerd.", LogLevelConstant.Warn) }, 2); Assert.AreEqual(ActivityState.Canceled, activity.State); mocks.VerifyAll(); } [Test] [TestCase(true)] [TestCase(false)] public void GivenActivitySavingStagedProject_WhenCancelling_ThenProjectSavedWithAdditionalLogMessage(bool saveExistingProject) { // Given const string filePath = "A"; var mocks = new MockRepository(); var project = mocks.Stub(); var projectOwner = mocks.Stub(); if (!saveExistingProject) { projectOwner.Expect(po => po.SetProject(project, filePath)); } var storeProject = mocks.StrictMock(); storeProject.Stub(sp => sp.HasStagedProject) .Return(true); storeProject.Expect(sp => sp.SaveProjectAs(filePath)); mocks.ReplayAll(); var calledCancel = false; var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); activity.ProgressChanged += (sender, args) => { if (calledCancel) { activity.Cancel(); calledCancel = true; } }; // When Action call = () => { activity.Run(); // Cancel called mid-progress but beyond 'point of no return' activity.LogState(); activity.Finish(); }; // Then string prefix = saveExistingProject ? "bestaand " : ""; TestHelper.AssertLogMessagesWithLevelAreGenerated(call, new[] { Tuple.Create($"Opslaan van {prefix}project is gestart.", LogLevelConstant.Info), Tuple.Create($"Opslaan van {prefix}project is gelukt.", LogLevelConstant.Info) }, 2); Assert.AreEqual(ActivityState.Finished, activity.State); mocks.VerifyAll(); } private static IEnumerable GetExceptions() { const string exceptionMessage = "I am an error message"; yield return new TestCaseData(new ArgumentException(exceptionMessage), exceptionMessage) .SetName("ArgumentException"); yield return new TestCaseData(new CouldNotConnectException(exceptionMessage), exceptionMessage) .SetName("CouldNotConnectException"); yield return new TestCaseData(new StorageValidationException(exceptionMessage), exceptionMessage) .SetName("StorageValidationException"); } } }