Index: Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Plugin.Test/TreeNodeInfos/ClosingStructuresCalculationContextTreeNodeInfoTest.cs =================================================================== diff -u -rae95ee4069ad2b72db769ad325458379fa0d9646 -r543721804bf58d098ee833d1a023a6e0018f1452 --- Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Plugin.Test/TreeNodeInfos/ClosingStructuresCalculationContextTreeNodeInfoTest.cs (.../ClosingStructuresCalculationContextTreeNodeInfoTest.cs) (revision ae95ee4069ad2b72db769ad325458379fa0d9646) +++ Ringtoets/ClosingStructures/test/Ringtoets.ClosingStructures.Plugin.Test/TreeNodeInfos/ClosingStructuresCalculationContextTreeNodeInfoTest.cs (.../ClosingStructuresCalculationContextTreeNodeInfoTest.cs) (revision 543721804bf58d098ee833d1a023a6e0018f1452) @@ -25,6 +25,7 @@ using System.Linq; using System.Windows.Forms; using Core.Common.Base; +using Core.Common.Base.Data; using Core.Common.Base.Geometry; using Core.Common.Controls.TreeView; using Core.Common.Gui; @@ -44,6 +45,7 @@ using Ringtoets.Common.Data.Contribution; using Ringtoets.Common.Data.FailureMechanism; using Ringtoets.Common.Data.Hydraulics; +using Ringtoets.Common.Data.Probabilistics; using Ringtoets.Common.Data.Probability; using Ringtoets.Common.Data.Structures; using Ringtoets.Common.Data.TestUtil; @@ -285,6 +287,413 @@ } [Test] + public void ContextMenuStrip_CalculationWithoutStructure_ContextMenuItemUpdateStructureDisabled() + { + // Setup + var assessmentSection = mocks.Stub(); + + var calculation = new StructuresCalculation(); + var failureMechanism = new TestClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + var menuBuilder = new CustomItemsOnlyContextMenuBuilder(); + + using (var treeViewControl = new TreeViewControl()) + { + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(menuBuilder); + mocks.ReplayAll(); + + plugin.Gui = gui; + + // Call + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // Assert + TestHelper.AssertContextMenuStripContainsItem(menu, + contextMenuUpdateStructureIndex, + "&Bijwerken kunstwerk", + "Er moet een kunstwerk geselecteerd zijn.", + RingtoetsCommonFormsResources.UpdateItemIcon, + false); + } + } + } + + [Test] + public void ContextMenuStrip_CalculationWithStructure_ContextMenuItemUpdateStructureEnabled() + { + // Setup + var assessmentSection = mocks.Stub(); + + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = new TestClosingStructure() + } + }; + var failureMechanism = new TestClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + var menuBuilder = new CustomItemsOnlyContextMenuBuilder(); + + using (var treeViewControl = new TreeViewControl()) + { + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(menuBuilder); + mocks.ReplayAll(); + + plugin.Gui = gui; + + // Call + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // Assert + TestHelper.AssertContextMenuStripContainsItem(menu, + contextMenuUpdateStructureIndex, + "&Bijwerken kunstwerk", + "Berekening bijwerken met het kunstwerk.", + RingtoetsCommonFormsResources.UpdateItemIcon); + } + } + } + + [Test] + public void GivenCalculationWithStructureWithoutOutput_WhenStructureAndInputOutOfSyncAndUpdateClicked_ThenNoInquiryAndCalculationUpdatedAndInputObserverNotified() + { + // Given + var assessmentSection = mocks.Stub(); + var structure = new TestClosingStructure(); + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = structure + } + }; + var failureMechanism = new ClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + + var inputObserver = mocks.StrictMock(); + inputObserver.Expect(obs => obs.UpdateObserver()); + calculation.InputParameters.Attach(inputObserver); + + var calculationObserver = mocks.StrictMock(); + calculation.Attach(calculationObserver); + + using (var treeViewControl = new TreeViewControl()) + { + var mainWindow = mocks.Stub(); + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(new CustomItemsOnlyContextMenuBuilder()); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + plugin.Gui = gui; + + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // When + UpdateStructure(structure); + menu.Items[contextMenuUpdateStructureIndex].PerformClick(); + + // Then + Assert.IsFalse(calculation.HasOutput); + AssertClosingStructuresInput(structure, calculation.InputParameters); + + // Note: observer assertions are verified in the TearDown() + } + } + } + + [Test] + public void GivenCalculationWithStructureWithOutput_WhenStructureAndInputOutOfSyncAndUpdateClickedAndCancelled_ThenInquiryAndCalculationNotUpdatedAndObserversNotNotified() + { + // Given + var assessmentSection = mocks.Stub(); + var structure = new TestClosingStructure(); + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = structure + }, + Output = new TestStructuresOutput() + }; + + ClosingStructuresInput calculationInput = calculation.InputParameters; + RoundedDouble expectedStructureNormalOrientation = calculationInput.StructureNormalOrientation; + NormalDistribution expectedLevelCrestStructureNotClosing = calculationInput.LevelCrestStructureNotClosing; + LogNormalDistribution expectedFlowWidthAtBottomProtection = calculationInput.FlowWidthAtBottomProtection; + VariationCoefficientLogNormalDistribution expectedCriticalOvertoppingDischarge = calculationInput.CriticalOvertoppingDischarge; + NormalDistribution expectedWidthFlowApertures = calculationInput.WidthFlowApertures; + VariationCoefficientLogNormalDistribution expectedStorageStructureArea = calculationInput.StorageStructureArea; + LogNormalDistribution expectedAllowedLevelIncreaseStorage = calculationInput.AllowedLevelIncreaseStorage; + ClosingStructureInflowModelType expectedInflowModelType = calculationInput.InflowModelType; + LogNormalDistribution expectedAreaFlowApertures = calculationInput.AreaFlowApertures; + double expectedFailureProbabilityOpenStructure = calculationInput.FailureProbabilityOpenStructure; + double expectedFailureProbabilityReparation = calculationInput.FailureProbabilityReparation; + int expectedIdenticalApertures = calculationInput.IdenticalApertures; + NormalDistribution expectedInsideWaterLevel = calculationInput.InsideWaterLevel; + double expectedProbabilityOrFrequencyOpenStructureBeforeFlooding = calculationInput.ProbabilityOrFrequencyOpenStructureBeforeFlooding; + NormalDistribution expectedThresholdHeightOpenWeir = calculationInput.ThresholdHeightOpenWeir; + + var failureMechanism = new ClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + + var inputObserver = mocks.StrictMock(); + calculationInput.Attach(inputObserver); + + var calculationObserver = mocks.StrictMock(); + calculation.Attach(calculationObserver); + + string textBoxMessage = null; + DialogBoxHandler = (name, wnd) => + { + var helper = new MessageBoxTester(wnd); + textBoxMessage = helper.Text; + helper.ClickCancel(); + }; + + using (var treeViewControl = new TreeViewControl()) + { + var mainWindow = mocks.Stub(); + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(new CustomItemsOnlyContextMenuBuilder()); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + plugin.Gui = gui; + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // When + UpdateStructure(structure); + menu.Items[contextMenuUpdateStructureIndex].PerformClick(); + + // Then + Assert.IsTrue(calculation.HasOutput); + Assert.AreSame(structure, calculationInput.Structure); + Assert.AreEqual(expectedStructureNormalOrientation, calculationInput.StructureNormalOrientation); + Assert.AreEqual(expectedLevelCrestStructureNotClosing, calculationInput.LevelCrestStructureNotClosing); + Assert.AreEqual(expectedFlowWidthAtBottomProtection, calculationInput.FlowWidthAtBottomProtection); + Assert.AreEqual(expectedCriticalOvertoppingDischarge, calculationInput.CriticalOvertoppingDischarge); + Assert.AreEqual(expectedWidthFlowApertures, calculationInput.WidthFlowApertures); + Assert.AreEqual(expectedStorageStructureArea, calculationInput.StorageStructureArea); + Assert.AreEqual(expectedAllowedLevelIncreaseStorage, calculationInput.AllowedLevelIncreaseStorage); + Assert.AreEqual(expectedInflowModelType, calculationInput.InflowModelType); + Assert.AreEqual(expectedAreaFlowApertures, calculationInput.AreaFlowApertures); + Assert.AreEqual(expectedFailureProbabilityOpenStructure, calculationInput.FailureProbabilityOpenStructure); + Assert.AreEqual(expectedFailureProbabilityReparation, calculationInput.FailureProbabilityReparation); + Assert.AreEqual(expectedIdenticalApertures, calculationInput.IdenticalApertures); + Assert.AreEqual(expectedInsideWaterLevel, calculationInput.InsideWaterLevel); + Assert.AreEqual(expectedProbabilityOrFrequencyOpenStructureBeforeFlooding, calculationInput.ProbabilityOrFrequencyOpenStructureBeforeFlooding); + Assert.AreEqual(expectedThresholdHeightOpenWeir, calculationInput.ThresholdHeightOpenWeir); + + string expectedMessage = "Wanneer het kunstwerk wijzigt als gevolg van het bijwerken, " + + "zal het resultaat van deze berekening worden " + + $"verwijderd.{Environment.NewLine}{Environment.NewLine}Weet u zeker dat u wilt doorgaan?"; + Assert.AreEqual(expectedMessage, textBoxMessage); + + // Note: observer assertions are verified in the TearDown() + } + } + } + + [Test] + public void GivenCalculationWithStructureWithOutput_WhenStructureAndInputOutOfSyncAndUpdateClickedAndContinued_ThenInquiryAndUpdatesCalculationAndObserversNotified() + { + // Given + var assessmentSection = mocks.Stub(); + var structure = new TestClosingStructure(); + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = structure + }, + Output = new TestStructuresOutput() + }; + var failureMechanism = new ClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + + var inputObserver = mocks.StrictMock(); + inputObserver.Expect(obs => obs.UpdateObserver()); + calculation.InputParameters.Attach(inputObserver); + + var calculationObserver = mocks.StrictMock(); + calculationObserver.Expect(obs => obs.UpdateObserver()); + calculation.Attach(calculationObserver); + + string textBoxMessage = null; + DialogBoxHandler = (name, wnd) => + { + var helper = new MessageBoxTester(wnd); + textBoxMessage = helper.Text; + helper.ClickOk(); + }; + + using (var treeViewControl = new TreeViewControl()) + { + var mainWindow = mocks.Stub(); + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(new CustomItemsOnlyContextMenuBuilder()); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + plugin.Gui = gui; + + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // When + UpdateStructure(structure); + menu.Items[contextMenuUpdateStructureIndex].PerformClick(); + + // Then + Assert.IsFalse(calculation.HasOutput); + AssertClosingStructuresInput(structure, calculation.InputParameters); + + string expectedMessage = "Wanneer het kunstwerk wijzigt als gevolg van het bijwerken, " + + "zal het resultaat van deze berekening worden " + + $"verwijderd.{Environment.NewLine}{Environment.NewLine}Weet u zeker dat u wilt doorgaan?"; + Assert.AreEqual(expectedMessage, textBoxMessage); + + // Note: observer assertions are verified in the TearDown() + } + } + } + + [Test] + public void GivenCalculationWithStructureWithOutput_WhenStructureAndInputInSyncAndUpdateClickedAndContinued_ThenInquiryAndCalculationNotUpdatedAndObserversNotNotified() + { + // Given + var assessmentSection = mocks.Stub(); + + var structure = new TestClosingStructure(); + UpdateStructure(structure); + + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = structure + }, + Output = new TestStructuresOutput() + }; + + var inputObserver = mocks.StrictMock(); + calculation.InputParameters.Attach(inputObserver); + + var calculationObserver = mocks.StrictMock(); + calculation.Attach(calculationObserver); + + var failureMechanism = new ClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + + string textBoxMessage = null; + DialogBoxHandler = (name, wnd) => + { + var helper = new MessageBoxTester(wnd); + textBoxMessage = helper.Text; + helper.ClickOk(); + }; + + using (var treeViewControl = new TreeViewControl()) + { + var mainWindow = mocks.Stub(); + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(new CustomItemsOnlyContextMenuBuilder()); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + plugin.Gui = gui; + + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // When + menu.Items[contextMenuUpdateStructureIndex].PerformClick(); + + // Then + Assert.IsTrue(calculation.HasOutput); + AssertClosingStructuresInput(structure, calculation.InputParameters); + + string expectedMessage = "Wanneer het kunstwerk wijzigt als gevolg van het bijwerken, " + + "zal het resultaat van deze berekening worden " + + $"verwijderd.{Environment.NewLine}{Environment.NewLine}Weet u zeker dat u wilt doorgaan?"; + Assert.AreEqual(expectedMessage, textBoxMessage); + + // Note: observer assertions are verified in the TearDown() + } + } + } + + [Test] + public void GivenCalculationWithStructureWithOutput_WhenStructureAndInputPartiallyOutOfSyncAndUpdateClicked_ThenInquiryAndUpdatesCalculationAndNotifiesObserver() + { + // Given + var assessmentSection = mocks.Stub(); + + var structure = new TestClosingStructure(); + UpdateStructure(structure); + + var calculation = new StructuresCalculation + { + InputParameters = + { + Structure = structure + }, + Output = new TestStructuresOutput() + }; + + var inputObserver = mocks.StrictMock(); + inputObserver.Expect(obs => obs.UpdateObserver()); + calculation.InputParameters.Attach(inputObserver); + + var calculationObserver = mocks.StrictMock(); + calculationObserver.Expect(obs => obs.UpdateObserver()); + calculation.Attach(calculationObserver); + + var failureMechanism = new ClosingStructuresFailureMechanism(); + var nodeData = new ClosingStructuresCalculationContext(calculation, failureMechanism, assessmentSection); + + string textBoxMessage = null; + DialogBoxHandler = (name, wnd) => + { + var helper = new MessageBoxTester(wnd); + textBoxMessage = helper.Text; + helper.ClickOk(); + }; + + using (var treeViewControl = new TreeViewControl()) + { + var mainWindow = mocks.Stub(); + var gui = mocks.Stub(); + gui.Stub(cmp => cmp.Get(nodeData, treeViewControl)).Return(new CustomItemsOnlyContextMenuBuilder()); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + plugin.Gui = gui; + + using (ContextMenuStrip menu = info.ContextMenuStrip(nodeData, assessmentSection, treeViewControl)) + { + // When + ClosingStructuresInput inputParameters = calculation.InputParameters; + inputParameters.StructureNormalOrientation = (RoundedDouble) 1.1; + menu.Items[contextMenuUpdateStructureIndex].PerformClick(); + + // Then + Assert.IsFalse(calculation.HasOutput); + AssertClosingStructuresInput(structure, calculation.InputParameters); + + string expectedMessage = "Wanneer het kunstwerk wijzigt als gevolg van het bijwerken, " + + "zal het resultaat van deze berekening worden " + + $"verwijderd.{Environment.NewLine}{Environment.NewLine}Weet u zeker dat u wilt doorgaan?"; + Assert.AreEqual(expectedMessage, textBoxMessage); + + // Note: observer assertions are verified in the TearDown() + } + } + } + + [Test] public void ContextMenuStrip_NoHydraulicBoundaryDatabase_ContextMenuItemPerformCalculationAndValidationDisabledAndTooltipSet() { // Setup @@ -652,5 +1061,89 @@ // Assert Assert.IsNull(result.Calculation); } + + private static void UpdateStructure(ClosingStructure structure) + { + var structureToUpdateFrom = new ClosingStructure( + new ClosingStructure.ConstructionProperties + { + Id = structure.Id, + Name = structure.Name, + Location = structure.Location, + StructureNormalOrientation = (RoundedDouble) 1.0, + LevelCrestStructureNotClosing = + { + Mean = (RoundedDouble) 2.0, + StandardDeviation = (RoundedDouble) 3.0 + }, + FlowWidthAtBottomProtection = + { + Mean = (RoundedDouble) 4.0, + StandardDeviation = (RoundedDouble) 5.0 + }, + CriticalOvertoppingDischarge = + { + Mean = (RoundedDouble) 6.0, + CoefficientOfVariation = (RoundedDouble) 7.0 + }, + WidthFlowApertures = + { + Mean = (RoundedDouble) 8.0, + StandardDeviation = (RoundedDouble) 9.0 + }, + StorageStructureArea = + { + Mean = (RoundedDouble) 10.0, + CoefficientOfVariation = (RoundedDouble) 11.0 + }, + AllowedLevelIncreaseStorage = + { + Mean = (RoundedDouble) 12.0, + StandardDeviation = (RoundedDouble) 13.0 + }, + InflowModelType = ClosingStructureInflowModelType.FloodedCulvert, + AreaFlowApertures = + { + Mean = (RoundedDouble) 14.0, + StandardDeviation = (RoundedDouble) 15.0 + }, + FailureProbabilityOpenStructure = 0.16, + FailureProbabilityReparation = 0.17, + IdenticalApertures = 18, + InsideWaterLevel = + { + Mean = (RoundedDouble) 19.0, + StandardDeviation = (RoundedDouble) 20.0 + }, + ProbabilityOrFrequencyOpenStructureBeforeFlooding = 0.21, + ThresholdHeightOpenWeir = + { + Mean = (RoundedDouble) 22.0, + StandardDeviation = (RoundedDouble) 23.0 + } + }); + + structure.CopyProperties(structureToUpdateFrom); + } + + private static void AssertClosingStructuresInput(TestClosingStructure structure, ClosingStructuresInput inputParameters) + { + Assert.AreSame(structure, inputParameters.Structure); + Assert.AreEqual(structure.StructureNormalOrientation, inputParameters.StructureNormalOrientation); + Assert.AreEqual(structure.LevelCrestStructureNotClosing, inputParameters.LevelCrestStructureNotClosing); + Assert.AreEqual(structure.FlowWidthAtBottomProtection, inputParameters.FlowWidthAtBottomProtection); + Assert.AreEqual(structure.CriticalOvertoppingDischarge, inputParameters.CriticalOvertoppingDischarge); + Assert.AreEqual(structure.WidthFlowApertures, inputParameters.WidthFlowApertures); + Assert.AreEqual(structure.StorageStructureArea, inputParameters.StorageStructureArea); + Assert.AreEqual(structure.AllowedLevelIncreaseStorage, inputParameters.AllowedLevelIncreaseStorage); + Assert.AreEqual(structure.InflowModelType, inputParameters.InflowModelType); + Assert.AreEqual(structure.AreaFlowApertures, inputParameters.AreaFlowApertures); + Assert.AreEqual(structure.FailureProbabilityOpenStructure, inputParameters.FailureProbabilityOpenStructure); + Assert.AreEqual(structure.FailureProbabilityReparation, inputParameters.FailureProbabilityReparation); + Assert.AreEqual(structure.IdenticalApertures, inputParameters.IdenticalApertures); + Assert.AreEqual(structure.InsideWaterLevel, inputParameters.InsideWaterLevel); + Assert.AreEqual(structure.ProbabilityOrFrequencyOpenStructureBeforeFlooding, inputParameters.ProbabilityOrFrequencyOpenStructureBeforeFlooding); + Assert.AreEqual(structure.ThresholdHeightOpenWeir, inputParameters.ThresholdHeightOpenWeir); + } } } \ No newline at end of file Index: Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Plugin.Test/TreeNodeInfos/HeightStructuresCalculationContextTreeNodeInfoTest.cs =================================================================== diff -u -r028a46631860bbbf730867f1068b422d2683e074 -r543721804bf58d098ee833d1a023a6e0018f1452 --- Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Plugin.Test/TreeNodeInfos/HeightStructuresCalculationContextTreeNodeInfoTest.cs (.../HeightStructuresCalculationContextTreeNodeInfoTest.cs) (revision 028a46631860bbbf730867f1068b422d2683e074) +++ Ringtoets/HeightStructures/test/Ringtoets.HeightStructures.Plugin.Test/TreeNodeInfos/HeightStructuresCalculationContextTreeNodeInfoTest.cs (.../HeightStructuresCalculationContextTreeNodeInfoTest.cs) (revision 543721804bf58d098ee833d1a023a6e0018f1452) @@ -410,7 +410,6 @@ }; HeightStructuresInput calculationInput = calculation.InputParameters; - RoundedDouble expectedStructureNormalOrientation = calculationInput.StructureNormalOrientation; NormalDistribution expectedLevelCrestStructure = calculationInput.LevelCrestStructure; LogNormalDistribution expectedFlowWidthAtBottomProtection = calculationInput.FlowWidthAtBottomProtection; @@ -454,9 +453,7 @@ // Then Assert.IsTrue(calculation.HasOutput); - Assert.AreSame(structure, calculationInput.Structure); - Assert.AreEqual(expectedStructureNormalOrientation, calculationInput.StructureNormalOrientation); Assert.AreEqual(expectedLevelCrestStructure, calculationInput.LevelCrestStructure); Assert.AreEqual(expectedFlowWidthAtBottomProtection, calculationInput.FlowWidthAtBottomProtection);