Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-2286: fix for crash upon unresolved node undo #10315

Merged
merged 3 commits into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions src/DynamoCore/Graph/Nodes/DummyNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;

namespace Dynamo.Graph.Nodes
Expand Down Expand Up @@ -250,11 +251,10 @@ private void LoadNode(XmlNode nodeElement)
OutputCount = Int32.Parse(outputCount.Value);
LegacyNodeName = legacyName.Value;

if (nodeElement.ChildNodes != null)
foreach (XmlNode childNode in nodeElement.ChildNodes)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if childNodes is null - this will throw an exception - I think you should keep the if

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resharper tells me that expression will always be true.

{
foreach (XmlNode childNode in nodeElement.ChildNodes)
if (childNode.Name.Equals("OriginalNodeContent"))
OriginalNodeContent = (XmlElement)nodeElement.FirstChild.FirstChild;
if (childNode.Name.Equals("OriginalNodeContent"))
OriginalNodeContent = (XmlElement) nodeElement.FirstChild.FirstChild;
}

if (originalElement != null)
Expand Down Expand Up @@ -292,18 +292,30 @@ private void LoadNode(XmlNode nodeElement)

private void UpdatePorts()
{
var guids = InPorts.Select(x => x.GUID).ToArray();
InPorts.Clear();
for (int input = 0; input < InputCount; input++)
{
var name = string.Format("Port {0}", input + 1);
InPorts.Add(new PortModel(PortType.Input, this, new PortData(name, "")));
var name = $"Port {input + 1}";
var pm = new PortModel(PortType.Input, this, new PortData(name, ""));
InPorts.Add(pm);
if (guids.Length == InputCount)
{
pm.GUID = guids[input];
}
}

guids = OutPorts.Select(x => x.GUID).ToArray();
OutPorts.Clear();
for (int output = 0; output < OutputCount; output++)
{
var name = string.Format("Port {0}", output + 1);
OutPorts.Add(new PortModel(PortType.Output, this, new PortData(name, "")));
var name = $"Port {output + 1}";
var pm = new PortModel(PortType.Output, this, new PortData(name, ""));
OutPorts.Add(pm);
if (guids.Length == OutputCount)
{
pm.GUID = guids[output];
}
}

RegisterAllPorts();
Expand Down
19 changes: 18 additions & 1 deletion src/DynamoCore/Graph/Nodes/PortModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum PortType { Input, Output };
/// <summary>
/// PortModel represents Dynamo ports.
/// </summary>
public class PortModel : ModelBase
public class PortModel : ModelBase, IEquatable<PortModel>
{
#region private fields
ObservableCollection<ConnectorModel> connectors = new ObservableCollection<ConnectorModel>();
Expand Down Expand Up @@ -369,6 +369,23 @@ protected override void DeserializeCore(XmlElement nodeElement, SaveContext cont
}

#endregion

public bool Equals(PortModel other)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last time I tried overriding equals there were a bunch of unexpected failures where reference equality was expected throughout the codebase instead of equality by guid - (I can't remember what type this was on) - just a consideration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, I'm checking for guid equality only if reference equality fails. From what I see in other nodemodel types, it looks like the equality check will either be true or false in both cases (reference equality + guid equality) since if the same port model is being reused, both conditions will be true, and if a new port model is created, still both conditions will be false, unless the new ports are created using the same guids as the old ones, which is what I'm enforcing here explicitly for dummy nodes.

{
if (other == null) return false;

if (this == other) return true;

if (GUID == other.GUID) return true;

return false;
}

public override int GetHashCode()
{
return GUID.GetHashCode();
}

}

/// <summary>
Expand Down
30 changes: 30 additions & 0 deletions test/DynamoCoreWpfTests/RecordedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,36 @@ public void RedoDeletedNodeShowsConnector()
});
}

[Test, RequiresSTA]
public void TestUnresolvedCodeBlockNodeUndo()
{
bool undo_1 = false;
bool undo_2 = false;
bool undo_3 = false;
RunCommandsFromFile("TestUnresolvedCodeBlockNodeUndo.xml", (commandTag) =>
{
var workspace = ViewModel.Model.CurrentWorkspace;
Assert.IsNotNull(workspace);

if (commandTag == "Undo_1")
{
undo_1 = true;
}
else if (commandTag == "Undo_2")
{
undo_2 = true;
}
else if (commandTag == "Undo_3")
{
undo_3 = true;
}
});

Assert.IsTrue(undo_1);
Assert.IsTrue(undo_2);
Assert.IsTrue(undo_3);
}

/// <summary>
/// Creates a Code Block Node with a single line comment and multi line comment
/// checks if the ports are created properly and at the correct height
Expand Down
94 changes: 94 additions & 0 deletions test/core/recorded/TestUnresolvedCodeBlockNodeUndo.dyn
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"Uuid": "0e5aec87-f0db-46dc-a7a0-e13d05b74a76",
"IsCustomNode": false,
"Description": null,
"Name": "TestUnresolvedCodeBlockNodeUndo",
"ElementResolver": {
"ResolutionMap": {}
},
"Inputs": [],
"Outputs": [],
"Nodes": [
{
"ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore",
"NodeType": "FunctionNode",
"FunctionSignature": "Lists.Manage.ReplaceNulls@var,var",
"Id": "50580245505a483b994b14d1b38d691c",
"Inputs": [
{
"Id": "45071948e0ca4de7b7e7854a11256693",
"Name": "Data",
"Description": "var",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
},
{
"Id": "c1a7e3f5ed9f43a6ab26c6d6f59f74fa",
"Name": "ReplaceWith",
"Description": "var",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Outputs": [
{
"Id": "3dca242246fd45048bb743b957909984",
"Name": "var[]..[]",
"Description": "var[]..[]",
"UsingDefaultValue": false,
"Level": 2,
"UseLevels": false,
"KeepListStructure": false
}
],
"Replication": "Auto",
"Description": "Manage.ReplaceNulls (Data: var, ReplaceWith: var): var[]..[]"
}
],
"Connectors": [],
"Dependencies": [],
"NodeLibraryDependencies": [],
"Bindings": [],
"View": {
"Dynamo": {
"ScaleFactor": 1.0,
"HasRunWithoutCrash": true,
"IsVisibleInDynamoLibrary": true,
"Version": "2.6.0.7481",
"RunType": "Manual",
"RunPeriod": "1000"
},
"Camera": {
"Name": "Background Preview",
"EyeX": -17.0,
"EyeY": 24.0,
"EyeZ": 50.0,
"LookX": 12.0,
"LookY": -13.0,
"LookZ": -58.0,
"UpX": 0.0,
"UpY": 1.0,
"UpZ": 0.0
},
"NodeViews": [
{
"ShowGeometry": true,
"Name": "Manage.ReplaceNulls",
"Id": "50580245505a483b994b14d1b38d691c",
"IsSetAsInput": false,
"IsSetAsOutput": false,
"Excluded": false,
"X": 1465.785850242029,
"Y": 338.9393205772858
}
],
"Annotations": [],
"X": -790.23067822776329,
"Y": 4.6725830650765374,
"Zoom": 1.0
}
}
108 changes: 108 additions & 0 deletions test/core/recorded/TestUnresolvedCodeBlockNodeUndo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<Commands ExitAfterPlayback="true" PauseAfterPlaybackInMs="10" CommandIntervalInMs="20">
<OpenFileCommand XmlFilePath=".\TestUnresolvedCodeBlockNodeUndo.dyn" />
<SelectModelCommand Modifiers="0">
<ModelGuid>00000000-0000-0000-0000-000000000000</ModelGuid>
</SelectModelCommand>
<CreateNodeCommand X="1248.23067822776" Y="375.327416934923" DefaultPosition="false" TransformCoordinates="true">
<ModelGuid>739d4254-1347-421e-bf14-c146f60ac45b</ModelGuid>
<Dynamo.Graph.Nodes.CodeBlockNodeModel guid="739d4254-1347-421e-bf14-c146f60ac45b" type="Dynamo.Graph.Nodes.CodeBlockNodeModel" nickname="Code Block" x="1156" y="344" isVisible="true" lacing="Disabled" isSelectedInput="False" isSelectedOutput="False" IsFrozen="false" isPinned="false" CodeText="safsd;" ShouldFocus="false">
<PortInfo index="0" default="False" name="safsd" />
<OutPortInfo LineIndex="0" />
</Dynamo.Graph.Nodes.CodeBlockNodeModel>
</CreateNodeCommand>
<UpdateModelValueCommand Name="Code" Value="safsd" WorkspaceGuid="0e5aec87-f0db-46dc-a7a0-e13d05b74a76">
<ModelGuid>739d4254-1347-421e-bf14-c146f60ac45b</ModelGuid>
</UpdateModelValueCommand>
<SelectModelCommand Modifiers="0">
<ModelGuid>00000000-0000-0000-0000-000000000000</ModelGuid>
</SelectModelCommand>
<CreateNodeCommand X="1229.23067822776" Y="505.327416934923" DefaultPosition="false" TransformCoordinates="true">
<ModelGuid>4fcc7262-5953-4e3c-8186-0a60f523c542</ModelGuid>
<Dynamo.Graph.Nodes.CodeBlockNodeModel guid="4fcc7262-5953-4e3c-8186-0a60f523c542" type="Dynamo.Graph.Nodes.CodeBlockNodeModel" nickname="Code Block" x="1137" y="474" isVisible="true" lacing="Disabled" isSelectedInput="False" isSelectedOutput="False" IsFrozen="false" isPinned="false" CodeText="0;" ShouldFocus="false">
<OutPortInfo LineIndex="0" />
</Dynamo.Graph.Nodes.CodeBlockNodeModel>
</CreateNodeCommand>
<UpdateModelValueCommand Name="Code" Value="0" WorkspaceGuid="0e5aec87-f0db-46dc-a7a0-e13d05b74a76">
<ModelGuid>4fcc7262-5953-4e3c-8186-0a60f523c542</ModelGuid>
</UpdateModelValueCommand>
<SelectModelCommand Modifiers="0">
<ModelGuid>00000000-0000-0000-0000-000000000000</ModelGuid>
</SelectModelCommand>
<CreateNodeCommand X="1847.23067822776" Y="324.327416934923" DefaultPosition="false" TransformCoordinates="true">
<ModelGuid>83063f49-2d6c-4f05-b370-0cf03d60cb09</ModelGuid>
<Dynamo.Graph.Nodes.CodeBlockNodeModel guid="83063f49-2d6c-4f05-b370-0cf03d60cb09" type="Dynamo.Graph.Nodes.CodeBlockNodeModel" nickname="Code Block" x="1755" y="293" isVisible="true" lacing="Disabled" isSelectedInput="False" isSelectedOutput="False" IsFrozen="false" isPinned="false" CodeText="sdafd;" ShouldFocus="false">
<PortInfo index="0" default="False" name="sdafd" />
<OutPortInfo LineIndex="0" />
</Dynamo.Graph.Nodes.CodeBlockNodeModel>
</CreateNodeCommand>
<SelectModelCommand Modifiers="0">
<ModelGuid>00000000-0000-0000-0000-000000000000</ModelGuid>
</SelectModelCommand>
<UpdateModelValueCommand Name="Code" Value="sdafd" WorkspaceGuid="0e5aec87-f0db-46dc-a7a0-e13d05b74a76">
<ModelGuid>83063f49-2d6c-4f05-b370-0cf03d60cb09</ModelGuid>
</UpdateModelValueCommand>
<MakeConnectionCommand PortIndex="0" Type="1" ConnectionMode="0">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</MakeConnectionCommand>
<MakeConnectionCommand PortIndex="0" Type="0" ConnectionMode="1">
<ModelGuid>83063f49-2d6c-4f05-b370-0cf03d60cb09</ModelGuid>
</MakeConnectionCommand>
<MakeConnectionCommand PortIndex="0" Type="1" ConnectionMode="0">
<ModelGuid>739d4254-1347-421e-bf14-c146f60ac45b</ModelGuid>
</MakeConnectionCommand>
<MakeConnectionCommand PortIndex="0" Type="0" ConnectionMode="1">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</MakeConnectionCommand>
<MakeConnectionCommand PortIndex="0" Type="1" ConnectionMode="0">
<ModelGuid>4fcc7262-5953-4e3c-8186-0a60f523c542</ModelGuid>
</MakeConnectionCommand>
<MakeConnectionCommand PortIndex="1" Type="0" ConnectionMode="1">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</MakeConnectionCommand>
<SelectModelCommand Modifiers="0">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1642.23067822776" Y="429.327416934923" DragOperation="0" />
<DragSelectionCommand X="1697.23067822776" Y="204.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<SelectModelCommand Modifiers="0">
<ModelGuid>83063f49-2d6c-4f05-b370-0cf03d60cb09</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1814.23067822776" Y="364.327416934923" DragOperation="0" />
<DragSelectionCommand X="1846.23067822776" Y="533.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<PausePlaybackCommand Tag="Undo_1" PauseDurationInMs="100" />
<SelectModelCommand Modifiers="0">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</SelectModelCommand>
<SelectModelCommand Modifiers="0">
<ModelGuid>00000000-0000-0000-0000-000000000000</ModelGuid>
</SelectModelCommand>
<SelectInRegionCommand X="1539.23067822776" Y="454.327416934923" Width="3" Height="3" IsCrossSelection="true" />
<SelectModelCommand Modifiers="0">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1537.23067822776" Y="449.327416934923" DragOperation="0" />
<DragSelectionCommand X="1481.23067822776" Y="273.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<SelectModelCommand Modifiers="0">
<ModelGuid>4fcc7262-5953-4e3c-8186-0a60f523c542</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1204.23067822776" Y="544.327416934923" DragOperation="0" />
<DragSelectionCommand X="1325.23067822776" Y="685.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<PausePlaybackCommand Tag="Undo_2" PauseDurationInMs="100" />
<SelectModelCommand Modifiers="0">
<ModelGuid>50580245-505a-483b-994b-14d1b38d691c</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1519.23067822776" Y="445.327416934923" DragOperation="0" />
<DragSelectionCommand X="1459.23067822776" Y="308.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<SelectModelCommand Modifiers="0">
<ModelGuid>739d4254-1347-421e-bf14-c146f60ac45b</ModelGuid>
</SelectModelCommand>
<DragSelectionCommand X="1258.23067822776" Y="412.327416934923" DragOperation="0" />
<DragSelectionCommand X="1190.23067822776" Y="250.327416934923" DragOperation="1" />
<UndoRedoCommand CmdOperation="0" />
<PausePlaybackCommand Tag="Undo_3" PauseDurationInMs="100" />
</Commands>