Index: Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj
===================================================================
diff -u -r8502d1a9cd739b227208f2f6ae6ea00fab758023 -r82b198560cfaa4d3e1d882dca9fd7859f169554e
--- Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 8502d1a9cd739b227208f2f6ae6ea00fab758023)
+++ Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -162,6 +162,7 @@
+
Index: Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs
===================================================================
diff -u -r71c4ff4caedb39679cd6642e2faf46ebd969dc9b -r82b198560cfaa4d3e1d882dca9fd7859f169554e
--- Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 71c4ff4caedb39679cd6642e2faf46ebd969dc9b)
+++ Core/Common/src/Core.Common.Gui/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -1427,6 +1427,51 @@
}
///
+ /// Looks up a localized string similar to Opgeslagen project initialiseren.
+ ///
+ public static string SaveProjectActivity_ProgressTextStepName_InitializeSavedProject {
+ get {
+ return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_InitializeSavedProject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Project opslaan.
+ ///
+ public static string SaveProjectActivity_ProgressTextStepName_SavingProject {
+ get {
+ return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_SavingProject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Voorbereiding opslaan.
+ ///
+ public static string SaveProjectActivity_ProgressTextStepName_StagingProject {
+ get {
+ return ResourceManager.GetString("SaveProjectActivity_ProgressTextStepName_StagingProject", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Opslaan van bestaand project.
+ ///
+ public static string SaveProjectActivity_Save_existing_project {
+ get {
+ return ResourceManager.GetString("SaveProjectActivity_Save_existing_project", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Opslaan van project.
+ ///
+ public static string SaveProjectActivity_Save_project {
+ get {
+ return ResourceManager.GetString("SaveProjectActivity_Save_project", resourceCulture);
+ }
+ }
+
+ ///
/// Looks up a localized string similar to Fout.
///
public static string SelectItemDialog_buttonOk_Click_Error {
Index: Core/Common/src/Core.Common.Gui/Properties/Resources.resx
===================================================================
diff -u -r71c4ff4caedb39679cd6642e2faf46ebd969dc9b -r82b198560cfaa4d3e1d882dca9fd7859f169554e
--- Core/Common/src/Core.Common.Gui/Properties/Resources.resx (.../Resources.resx) (revision 71c4ff4caedb39679cd6642e2faf46ebd969dc9b)
+++ Core/Common/src/Core.Common.Gui/Properties/Resources.resx (.../Resources.resx) (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -619,4 +619,19 @@
Stap {0} van {1} | {2}
+
+ Opslaan van bestaand project
+
+
+ Opslaan van project
+
+
+ Opgeslagen project initialiseren
+
+
+ Voorbereiding opslaan
+
+
+ Project opslaan
+
\ No newline at end of file
Index: Core/Common/src/Core.Common.Gui/SaveProjectActivity.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Gui/SaveProjectActivity.cs (revision 0)
+++ Core/Common/src/Core.Common.Gui/SaveProjectActivity.cs (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -0,0 +1,174 @@
+// Copyright (C) Stichting Deltares 2016. 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.IO;
+using Core.Common.Base.Data;
+using Core.Common.Base.Service;
+using Core.Common.Base.Storage;
+using Core.Common.Gui.Properties;
+using log4net;
+
+namespace Core.Common.Gui
+{
+ ///
+ /// Activity to save a .
+ ///
+ public class SaveProjectActivity : Activity
+ {
+ private readonly ILog log = LogManager.GetLogger(typeof(SaveProjectActivity));
+ private readonly bool savingExistingProject;
+ private readonly IProject project;
+ private readonly string filePath;
+ private readonly IStoreProject storeProject;
+ private readonly IProjectOwner projectOwner;
+ private int totalNumberOfSteps;
+
+ private bool cancel;
+
+ ///
+ /// Creates a new instance of .
+ ///
+ /// The project to be saved.
+ /// The location to save the project to.
+ /// When true it indicates that
+ /// is already located at . When false then
+ /// is not already located at .
+ /// The object responsible for saving .
+ /// The object responsible for hosting .
+ public SaveProjectActivity(IProject project, string filePath, bool savingExistingProject, IStoreProject storeProject, IProjectOwner projectOwner)
+ {
+ if (project == null)
+ {
+ throw new ArgumentNullException(nameof(project));
+ }
+ if (filePath == null)
+ {
+ throw new ArgumentNullException(nameof(filePath));
+ }
+ if (storeProject == null)
+ {
+ throw new ArgumentNullException(nameof(storeProject));
+ }
+ if (projectOwner == null)
+ {
+ throw new ArgumentNullException(nameof(projectOwner));
+ }
+
+ this.savingExistingProject = savingExistingProject;
+ this.project = project;
+ this.filePath = filePath;
+ this.storeProject = storeProject;
+ this.projectOwner = projectOwner;
+
+ Name = savingExistingProject ?
+ Resources.SaveProjectActivity_Save_existing_project :
+ Resources.SaveProjectActivity_Save_project;
+ }
+
+ protected override void OnRun()
+ {
+ cancel = false;
+ totalNumberOfSteps = savingExistingProject ? 1 : 2;
+ int currentStep = 1;
+
+ if (!storeProject.HasStagedProject)
+ {
+ totalNumberOfSteps++;
+ UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_StagingProject,
+ currentStep++,
+ totalNumberOfSteps);
+
+ storeProject.StageProject(project);
+ }
+
+ if (cancel)
+ {
+ return;
+ }
+
+ SaveProjectUncancellable(currentStep);
+ }
+
+ protected override void OnCancel()
+ {
+ cancel = true;
+ }
+
+ protected override void OnFinish()
+ {
+ if (State == ActivityState.Executed && !savingExistingProject)
+ {
+ InitializeProjectForNewLocation();
+ }
+ }
+
+ private void SaveProjectUncancellable(int currentStep)
+ {
+ try
+ {
+ UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_SavingProject,
+ currentStep,
+ totalNumberOfSteps);
+
+ storeProject.SaveProjectAs(filePath);
+ }
+ catch (StorageException e)
+ {
+ log.Error(e.Message, e.InnerException);
+ State = ActivityState.Failed;
+ return;
+ }
+ catch (ArgumentException e)
+ {
+ log.Error(e.Message, e);
+ State = ActivityState.Failed;
+ return;
+ }
+
+ // Override State (might be Cancelled) due to cancelling not possible
+ State = ActivityState.Executed;
+ }
+
+ private void InitializeProjectForNewLocation()
+ {
+ UpdateProgressText(Resources.SaveProjectActivity_ProgressTextStepName_InitializeSavedProject,
+ totalNumberOfSteps,
+ totalNumberOfSteps);
+
+ projectOwner.SetProject(project, filePath);
+ project.Name = Path.GetFileNameWithoutExtension(filePath);
+ project.NotifyObservers();
+ }
+
+ ///
+ /// Updates the progress text.
+ ///
+ /// A short description of the current step.
+ /// The number of the current step.
+ /// The total numbers of steps.
+ private void UpdateProgressText(string currentStepName, int currentStep, int totalSteps)
+ {
+ ProgressText = string.Format(Resources.Activity_UpdateProgressText_CurrentStepNumber_0_of_TotalStepsNumber_1_StepDescriptionName_2_,
+ currentStep, totalSteps, currentStepName);
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj
===================================================================
diff -u -r8502d1a9cd739b227208f2f6ae6ea00fab758023 -r82b198560cfaa4d3e1d882dca9fd7859f169554e
--- Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 8502d1a9cd739b227208f2f6ae6ea00fab758023)
+++ Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -138,6 +138,7 @@
+
Index: Core/Common/test/Core.Common.Gui.Test/SaveProjectActivityTest.cs
===================================================================
diff -u
--- Core/Common/test/Core.Common.Gui.Test/SaveProjectActivityTest.cs (revision 0)
+++ Core/Common/test/Core.Common.Gui.Test/SaveProjectActivityTest.cs (revision 82b198560cfaa4d3e1d882dca9fd7859f169554e)
@@ -0,0 +1,541 @@
+// Copyright (C) Stichting Deltares 2016. 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 System.ComponentModel;
+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);
+ CollectionAssert.IsEmpty(activity.LogMessages);
+ Assert.IsNull(activity.ProgressText);
+ Assert.AreEqual(ActivityState.None, activity.State);
+
+ string exitingPrefix = savingExistingProject ? "bestaand " : "";
+ string expectedName = $"Opslaan van {exitingPrefix}project";
+ Assert.AreEqual(expectedName, activity.Name);
+
+ 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_StageAndSaveProjectWithoutLogMessages(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
+ TestHelper.AssertLogMessagesCount(call, 0);
+ Assert.AreEqual(ActivityState.Executed, activity.State);
+ mocks.VerifyAll();
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void Run_AlreadyStagedProject_SaveProjectWithoutLogMessages(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
+ TestHelper.AssertLogMessagesCount(call, 0);
+ Assert.AreEqual(ActivityState.Executed, activity.State);
+ mocks.VerifyAll();
+ }
+
+ [Test]
+ [Combinatorial]
+ public void Run_SaveProjectAsThrowsException_FailedWithLogMessage(
+ [Values(true, false)] bool saveExistingProject,
+ [Values(SaveProjectAsExceptionType.StorageException,
+ SaveProjectAsExceptionType.CouldNotConnectException,
+ SaveProjectAsExceptionType.ArgumentException)] SaveProjectAsExceptionType exceptionType)
+ {
+ // Setup
+ const string filePath = "A";
+ const string message = "";
+
+ Exception exception = CreateException(exceptionType, message);
+
+ 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, saveExistingProject, storeProject, projectOwner);
+
+ // Call
+ Action call = () => activity.Run();
+
+ // Assert
+ TestHelper.AssertLogMessageWithLevelIsGenerated(call, Tuple.Create(message, LogLevelConstant.Error), 1);
+ 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} | Voorbereiding 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 Finish_SuccessfullySavedNewProject_UpdateProjectAndProjectOwnerWithMessage()
+ {
+ // Setup
+ 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);
+
+ // Call
+ Action call = () => activity.Finish();
+
+ // Assert
+ Tuple expectedMessage = Tuple.Create("Uitvoeren van '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 Finish_SuccessfullySavedExistingProject_DoNotUpdateProjectAndProjectOwnerWithMessage()
+ {
+ // Setup
+ 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);
+
+ // Call
+ Action call = () => activity.Finish();
+
+ // Assert
+ Tuple expectedMessage = Tuple.Create("Uitvoeren van '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} | Opgeslagen project initialiseren"
+ };
+ CollectionAssert.AreEqual(expectedProgressMessages, progressMessages);
+ mocks.VerifyAll();
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void GivenActivityStagingProject_WhenCancelling_ThenProjectNotSavedWithLogMessage(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.Finish();
+ };
+
+ // Then
+ string prefix = saveExistingProject ? "bestaand " : "";
+ TestHelper.AssertLogMessageWithLevelIsGenerated(call,
+ Tuple.Create($"Uitvoeren van 'Opslaan van {prefix}project' is geannuleerd.",
+ LogLevelConstant.Warn),
+ 1);
+
+ Assert.AreEqual(ActivityState.Canceled, activity.State);
+ mocks.VerifyAll();
+ }
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public void GivenActivitySavingStagedProject_WhenCancelling_ThenProjectSavedWithLogMessage(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();
+
+ bool 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.Finish();
+ };
+
+ // Then
+ string prefix = saveExistingProject ? "bestaand " : "";
+ TestHelper.AssertLogMessageWithLevelIsGenerated(call,
+ Tuple.Create($"Uitvoeren van 'Opslaan van {prefix}project' is gelukt.",
+ LogLevelConstant.Info),
+ 1);
+
+ Assert.AreEqual(ActivityState.Finished, activity.State);
+ mocks.VerifyAll();
+ }
+
+ private static Exception CreateException(SaveProjectAsExceptionType exceptionType, string message)
+ {
+ switch (exceptionType)
+ {
+ case SaveProjectAsExceptionType.ArgumentException:
+ return new ArgumentException(message);
+ case SaveProjectAsExceptionType.CouldNotConnectException:
+ return new CouldNotConnectException(message);
+ case SaveProjectAsExceptionType.StorageException:
+ return new StorageException(message);
+ default:
+ throw new InvalidEnumArgumentException();
+ }
+ }
+
+ public enum SaveProjectAsExceptionType
+ {
+ CouldNotConnectException,
+ StorageException,
+ ArgumentException
+ }
+ }
+}
\ No newline at end of file