Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs =================================================================== diff -u -rd6e6eadf4a2521df75b6d371bacbb181a43058a3 -r8451668c9c13acb5ae08d4a8c25afa9667201278 --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision d6e6eadf4a2521df75b6d371bacbb181a43058a3) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision 8451668c9c13acb5ae08d4a8c25afa9667201278) @@ -181,34 +181,10 @@ [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - IPipingCalculationItem draggedItem = null; - object draggedItemContext = null; + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext); - #region Setup data objects related to dragged IPipingCalculationItem: - - switch (draggedItemType) - { - case PipingCalculationItemType.Calculation: - var calculation = new PipingCalculation(); - draggedItem = calculation; - draggedItemContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - break; - case PipingCalculationItemType.Group: - var group = new PipingCalculationGroup(); - draggedItem = group; - draggedItemContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - break; - default: - Assert.Fail(methodToTest + " not supported."); - break; - } - - #endregion - var targetGroup = new PipingCalculationGroup(); var targetGroupContext = new PipingCalculationGroupContext(targetGroup, Enumerable.Empty(), @@ -272,38 +248,13 @@ [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - IPipingCalculationItem draggedItem = null; - object draggedItemContext = null; + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext); - #region Setup data objects related to dragged IPipingCalculationItem: - - switch (draggedItemType) - { - case PipingCalculationItemType.Calculation: - var calculation = new PipingCalculation(); - draggedItem = calculation; - draggedItemContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - break; - case PipingCalculationItemType.Group: - var group = new PipingCalculationGroup(); - draggedItem = group; - draggedItemContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - break; - default: - Assert.Fail(methodToTest + " not supported."); - break; - } - - var sourceFailureMechanism = new PipingFailureMechanism(); sourceFailureMechanism.CalculationsGroup.Children.Add(draggedItem); - #endregion - var targetGroup = new PipingCalculationGroup(); var targetGroupContext = new PipingCalculationGroupContext(targetGroup, Enumerable.Empty(), @@ -376,29 +327,9 @@ [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - IPipingCalculationItem draggedItem = null; - object draggedItemContext = null; - - switch (draggedItemType) - { - case PipingCalculationItemType.Calculation: - var calculation = new PipingCalculation(); - draggedItem = calculation; - draggedItemContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - break; - case PipingCalculationItemType.Group: - var group = new PipingCalculationGroup(); - draggedItem = group; - draggedItemContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - break; - default: - Assert.Fail(); - break; - } + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext); var originalOwnerGroup = new PipingCalculationGroup(); originalOwnerGroup.Children.Add(draggedItem); @@ -419,8 +350,6 @@ newOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updatewasCalled = true); var newOwnerGroupContextNode = mockRepository.Stub(); - newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); - newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. var preUpdateDraggedItemContextNode = mockRepository.Stub(); preUpdateDraggedItemContextNode.Tag = draggedItemContext; @@ -434,6 +363,20 @@ postUpdateDraggedItemContextNode.Expect(n => n.Collapse()); postUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + newOwnerGroupContextNode.Tag = newOwnerGroupContext; + newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false).Repeat.Times(3); + newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. + newOwnerGroupContextNode.Expect(n => n.Nodes).WhenCalled(invocation => + { + if (updatewasCalled) + { + invocation.ReturnValue = new[] + { + postUpdateDraggedItemContextNode + }; + } + }).Return(new ITreeNode[0]).Repeat.Times(2); + var treeView = mockRepository.Stub(); treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { @@ -442,6 +385,7 @@ invocation.ReturnValue = postUpdateDraggedItemContextNode; } }).Return(preUpdateDraggedItemContextNode).Repeat.Twice(); + treeView.Expect(v => v.GetNodeByTag(newOwnerGroupContext)).Return(newOwnerGroupContextNode); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); @@ -481,31 +425,10 @@ { // Setup const string name = "Very cool name"; - IPipingCalculationItem draggedItem = null; - object draggedItemContext = null; + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, name); - - switch (draggedItemType) - { - case PipingCalculationItemType.Calculation: - var calculation = new PipingCalculation{ Name = name }; - draggedItem = calculation; - draggedItemContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - break; - case PipingCalculationItemType.Group: - var group = new PipingCalculationGroup{ Name = name }; - draggedItem = group; - draggedItemContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - break; - default: - Assert.Fail(); - break; - } - var existingItemStub = mockRepository.Stub(); existingItemStub.Stub(i => i.Name).Return(""); @@ -522,27 +445,45 @@ originalOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updatewasCalled = true).Repeat.Once(); var newOwnerGroupContextNode = mockRepository.Stub(); - newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(true); - var preUpdateDraggedItemContextNode = mockRepository.Stub(); - preUpdateDraggedItemContextNode.Tag = draggedItemContext; - preUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); - preUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + var preUpdateDraggedItemContextNode = CreateTreeNodeLeafForData(draggedItemContext); - var postUpdateDraggedItemContextNode = mockRepository.Stub(); - postUpdateDraggedItemContextNode.Tag = draggedItemContext; + var postUpdateDraggedItemContextNode = CreateTreeNodeLeafForData(draggedItemContext); postUpdateDraggedItemContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); - postUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); - postUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + var existingItemStub1 = CreateStubTreeNode(); + var existingItemStub2 = CreateStubTreeNode(); + + newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(true).Repeat.Times(3); + newOwnerGroupContextNode.Tag = originalOwnerGroupContext; + newOwnerGroupContextNode.Expect(n => n.Nodes).WhenCalled(invocation => + { + if (updatewasCalled) + { + invocation.ReturnValue = new[] + { + existingItemStub1, + postUpdateDraggedItemContextNode, + existingItemStub2 + }; + } + }).Return(new[] + { + existingItemStub1, + preUpdateDraggedItemContextNode, + existingItemStub2 + }).Repeat.Times(2); + + // Dragging within same group requires only recording state on that group. var treeView = mockRepository.Stub(); + treeView.Expect(v => v.GetNodeByTag(originalOwnerGroupContext)).Return(newOwnerGroupContextNode); treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { if (updatewasCalled) { invocation.ReturnValue = postUpdateDraggedItemContextNode; } - }).Return(preUpdateDraggedItemContextNode).Repeat.Twice(); + }).Return(null); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); @@ -563,6 +504,8 @@ // Assert CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + Assert.AreNotSame(draggedItem, originalOwnerGroup.Children[1], + "Should have removed 'draggedItem' from its original location in the collection."); Assert.AreSame(draggedItem, originalOwnerGroup.Children[newIndex], "Dragging node to specific location within owning PipingCalculationGroup should put the dragged data at that index."); Assert.AreEqual(name, draggedItem.Name, @@ -575,34 +518,14 @@ [Test] [Combinatorial] - public void OnDragDrop_DraggingPipingCalculationContextOntoGroupStartWithSameNamedItem_MoveCalculationInstanceToNewGroupAndRename( + public void OnDragDrop_DraggingPipingCalculationItemContextOntoGroupStartWithSameNamedItem_MoveCalculationItemInstanceToNewGroupAndRename( [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - IPipingCalculationItem draggedItem = null; - object draggedItemContext = null; + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext); - switch (draggedItemType) - { - case PipingCalculationItemType.Calculation: - var calculation = new PipingCalculation(); - draggedItem = calculation; - draggedItemContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - break; - case PipingCalculationItemType.Group: - var group = new PipingCalculationGroup(); - draggedItem = group; - draggedItemContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - break; - default: - Assert.Fail(); - break; - } - var originalOwnerGroup = new PipingCalculationGroup(); originalOwnerGroup.Children.Add(draggedItem); var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, @@ -625,9 +548,6 @@ newOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updateWasCalled = true); var newOwnerGroupContextNode = mockRepository.Stub(); - newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); - newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. - var preUpdateCalculationContextNode = mockRepository.Stub(); preUpdateCalculationContextNode.Tag = draggedItemContext; preUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(true); @@ -640,6 +560,20 @@ postUpdateCalculationContextNode.Expect(n => n.Expand()); postUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); + newOwnerGroupContextNode.Tag = originalOwnerGroupContext; + newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false).Repeat.Times(3); + newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. + newOwnerGroupContextNode.Expect(n => n.Nodes).WhenCalled(invocation => + { + if (updateWasCalled) + { + invocation.ReturnValue = new[] + { + postUpdateCalculationContextNode + }; + } + }).Return(new ITreeNode[0]).Repeat.Times(2); + var treeView = mockRepository.Stub(); treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { @@ -648,6 +582,7 @@ invocation.ReturnValue = postUpdateCalculationContextNode; } }).Return(preUpdateCalculationContextNode).Repeat.Twice(); + treeView.Expect(v => v.GetNodeByTag(newOwnerGroupContext)).Return(newOwnerGroupContextNode); treeView.Expect(v => v.StartLabelEdit()); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); @@ -692,8 +627,146 @@ mockRepository.VerifyAll(); } - + [Test] + [Combinatorial] + public void OnDragDrop_DraggingPipingCalculationItemContextOntoGroupWithOtherItems_ExpandedCollapsedStateOfOtherItemsRestored( + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) + { + // Setup + IPipingCalculationItem draggedItem; + object draggedItemContext; + CreatePipingCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext); + + var originalOwnerGroup = new PipingCalculationGroup(); + originalOwnerGroup.Children.Add(draggedItem); + var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, + Enumerable.Empty(), + Enumerable.Empty()); + + var newOwnerGroup = new PipingCalculationGroup(); + var newOwnerGroupContext = new PipingCalculationGroupContext(newOwnerGroup, + Enumerable.Empty(), + Enumerable.Empty()); + + var originalOwnerObserver = mockRepository.StrictMock(); + originalOwnerObserver.Expect(o => o.UpdateObserver()); + + var updatewasCalled = false; + var newOwnerObserver = mockRepository.StrictMock(); + newOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updatewasCalled = true); + + var nodeStub = CreateStubTreeNode(); + + var expandedNodeData = new object(); + var preUpdateExpandedNode = mockRepository.Stub(); + preUpdateExpandedNode.Tag = expandedNodeData; + preUpdateExpandedNode.Expect(n => n.IsExpanded).Return(true); + preUpdateExpandedNode.Stub(n => n.Nodes).Return(new[] + { + nodeStub + }); + + var postUpdateExpandedNode = mockRepository.Stub(); + postUpdateExpandedNode.Tag = expandedNodeData; + postUpdateExpandedNode.Expect(n => n.IsExpanded).Return(false); + postUpdateExpandedNode.Expect(n => n.Expand()); + postUpdateExpandedNode.Stub(n => n.Nodes).Return(new[] + { + nodeStub + }); + + var collapsedNodeData = new object(); + var preUpdateCollapsedNode = mockRepository.Stub(); + preUpdateCollapsedNode.Tag = collapsedNodeData; + preUpdateCollapsedNode.Expect(n => n.IsExpanded).Return(true); + preUpdateCollapsedNode.Stub(n => n.Nodes).Return(new[] + { + nodeStub + }); + + var postUpdateCollapsedNode = mockRepository.Stub(); + postUpdateCollapsedNode.Tag = collapsedNodeData; + postUpdateCollapsedNode.Expect(n => n.IsExpanded).Return(false); + postUpdateCollapsedNode.Expect(n => n.Expand()); + postUpdateCollapsedNode.Stub(n => n.Nodes).Return(new[] + { + nodeStub + }); + + var newOwnerGroupContextNode = mockRepository.Stub(); + newOwnerGroupContextNode.Tag = newOwnerGroupContext; + newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false).Repeat.Times(3); // 2x for recording and restoring state, 1x for expanding + newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. + newOwnerGroupContextNode.Stub(n => n.Nodes).WhenCalled(invocation => + { + if (updatewasCalled) + { + invocation.ReturnValue = new[] + { + postUpdateExpandedNode, + postUpdateCollapsedNode + }; + } + }).Return(new[] + { + preUpdateExpandedNode, + preUpdateCollapsedNode + }); + + var preUpdateDraggedItemContextNode = mockRepository.Stub(); + preUpdateDraggedItemContextNode.Tag = draggedItemContext; + preUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); + preUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + + var postUpdateDraggedItemContextNode = mockRepository.Stub(); + postUpdateDraggedItemContextNode.Tag = draggedItemContext; + postUpdateDraggedItemContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); + postUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(true); + postUpdateDraggedItemContextNode.Expect(n => n.Collapse()); + postUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + + var treeView = mockRepository.Stub(); + treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => + { + if (updatewasCalled) + { + invocation.ReturnValue = postUpdateDraggedItemContextNode; + } + }).Return(preUpdateDraggedItemContextNode).Repeat.Twice(); + treeView.Expect(v => v.GetNodeByTag(newOwnerGroupContext)).Return(newOwnerGroupContextNode); + + var contextMenuBuilderProviderMock = mockRepository.StrictMock(); + + mockRepository.ReplayAll(); + + originalOwnerGroup.Attach(originalOwnerObserver); + newOwnerGroup.Attach(newOwnerObserver); + + // Precondition: + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + CollectionAssert.DoesNotContain(newOwnerGroup.Children, draggedItem); + + var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock) + { + TreeView = treeView + }; + + // Call + nodePresenter.OnDragDrop(draggedItemContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, newOwnerGroup.Children.Count); + + // Assert + CollectionAssert.DoesNotContain(originalOwnerGroup.Children, draggedItem); + CollectionAssert.Contains(newOwnerGroup.Children, draggedItem); + Assert.AreSame(draggedItem, newOwnerGroup.Children.Last(), + "Dragging node at the end of the target PipingCalculationGroup should put the dragged data at the end of 'newOwnerGroup'."); + + Assert.AreSame(postUpdateDraggedItemContextNode, treeView.SelectedNode); + + mockRepository.VerifyAll(); + } + + [Test] public void CanRenameNode_ParentIsPipingFailureMechanismNode_ReturnFalse() { // Setup @@ -1338,6 +1411,66 @@ } /// + /// Creates an instance of and the corresponding context. + /// + /// Defines the implementation of to be constructed. + /// Output: The concrete create class based on . + /// Output: The corresponding with . + /// Optional: The name of . + /// + private static void CreatePipingCalculationItemAndContext(PipingCalculationItemType type, out IPipingCalculationItem data, out object dataContext, string initialName = null) + { + switch (type) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation(); + if (initialName != null) + { + calculation.Name = initialName; + } + data = calculation; + dataContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup(); + if (initialName != null) + { + group.Name = initialName; + } + data = group; + dataContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + throw new NotSupportedException(); + } + } + + /// + /// Use to creates a stub tree node as a simple node-tree leaf. + /// + private ITreeNode CreateStubTreeNode() + { + return CreateTreeNodeLeafForData(new object()); + } + + /// + /// Creates an stub that represents a tree-node leaf. + /// + /// The data associated with the node. + private ITreeNode CreateTreeNodeLeafForData(object nodeData) + { + var preUpdateDraggedItemContextNode = mockRepository.Stub(); + preUpdateDraggedItemContextNode.Tag = nodeData; + preUpdateDraggedItemContextNode.Stub(n => n.IsExpanded).Return(false); + preUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); + return preUpdateDraggedItemContextNode; + } + + /// /// Type indicator for testing methods on . /// public enum DragDropTestMethod