diff --git a/src/DynamoCore/Graph/Annotations/AnnotationModel.cs b/src/DynamoCore/Graph/Annotations/AnnotationModel.cs index b42312d5c7c..1febdd9cb29 100644 --- a/src/DynamoCore/Graph/Annotations/AnnotationModel.cs +++ b/src/DynamoCore/Graph/Annotations/AnnotationModel.cs @@ -290,58 +290,26 @@ internal void UpdateBoundaryFromSelection() var regionY = groupModels.Min(y => y.Y) - ExtendSize - (TextBlockHeight == 0.0 ? MinTextHeight : TextBlockHeight); //calculates the distance between the nodes - var xDistance = groupModels.Max(x => x.X) - regionX; - var yDistance = groupModels.Max(x => x.Y) - regionY; - - var widthandheight = CalculateWidthAndHeight(); - - var maxWidth = widthandheight.Item1; - var maxHeight = widthandheight.Item2; + var xDistance = groupModels.Max(x => (x.X + x.Width)) - regionX; + var yDistance = groupModels.Max(x => (x.Y + x.Height)) - regionY; // InitialTop is to store the Y value without the Textblock height this.InitialTop = groupModels.Min(y => y.Y); + var region = new Rect2D { X = regionX, Y = regionY, - Width = xDistance + maxWidth + ExtendSize, - Height = yDistance + maxHeight + ExtendSize + Width = xDistance + ExtendSize, + Height = yDistance + ExtendSize + ExtendYHeight }; - + this.X = region.X; this.Y = region.Y; this.Width = Math.Max(region.Width, TextMaxWidth + ExtendSize); this.Height = region.Height; - //Calculate the boundary if there is any overlap - ModelBase overlap = null; - foreach (var nodesList in Nodes) - { - if (!region.Contains(nodesList.Rect)) - { - overlap = nodesList; - if (overlap.Rect.Top < this.X || - overlap.Rect.Bottom > region.Bottom) //Overlap in height - increase the region height - { - if (overlap.Rect.Bottom - region.Bottom > 0) - { - this.Height += overlap.Rect.Bottom - region.Bottom + ExtendSize + ExtendYHeight; - } - region.Height = this.Height; - } - if (overlap.Rect.Left < this.Y || - overlap.Rect.Right > region.Right) //Overlap in width - increase the region width - { - if (overlap.Rect.Right - region.Right > 0) - { - this.Width += overlap.Rect.Right - region.Right + ExtendSize; - } - region.Width = this.Width; - } - } - } - //Initial Height is to store the Actual height of the group. //that is the height should be the initial height without the textblock height. if (this.InitialHeight <= 0.0) @@ -358,20 +326,7 @@ internal void UpdateBoundaryFromSelection() /// Group the Models based on Height and Width /// /// the width and height of the last model - private Tuple CalculateWidthAndHeight() - { - var xgroup = Nodes.OrderBy(x => x.X).ToList(); - var ygroup = Nodes.OrderBy(x => x.Y).ToList(); - double yheight = ygroup.Last().Height; - - //If the last model is Node, then increase the height so that - //node border does not overlap with the group - if (ygroup.Last() is NodeModel) - yheight = yheight + ExtendYHeight; - return Tuple.Create(xgroup.Last().Width, yheight); - } - #region Serialization/Deserialization Methods protected override bool UpdateValueCore(UpdateValueParams updateValueParams) diff --git a/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs b/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs index fd0601491a5..9572837615e 100644 --- a/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs +++ b/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs @@ -11,7 +11,8 @@ internal class ListEncoderDecoder : IPyObjectEncoder, IPyObjectDecoder private static readonly Type[] decodableTypes = new Type[] { typeof(IList), typeof(ArrayList), - typeof(IList<>), typeof(List<>) + typeof(IList<>), typeof(List<>), + typeof(IEnumerable), typeof(IEnumerable<>) }; public bool CanDecode(PyObject objectType, Type targetType) @@ -30,7 +31,7 @@ public bool CanEncode(Type type) public bool TryDecode(PyObject pyObj, out T value) { - if (!PySequence.IsSequenceType(pyObj)) + if (!PyIter.IsIterable(pyObj)) { value = default; return false; diff --git a/src/Libraries/DSIronPython/IronPythonCodeCompletionProviderCore.cs b/src/Libraries/DSIronPython/IronPythonCodeCompletionProviderCore.cs index f1c9b734bfb..4be71074758 100644 --- a/src/Libraries/DSIronPython/IronPythonCodeCompletionProviderCore.cs +++ b/src/Libraries/DSIronPython/IronPythonCodeCompletionProviderCore.cs @@ -1046,8 +1046,7 @@ public void Initialize(string dynamoCorePath) } // If IronPython.Std folder is excluded from DynamoCore (which could be user mistake or integrator exclusion) - // Or if the execution path is different than Dynamo root folder - if (!Directory.Exists(pythonLibDir) || pythonLibDir != executionPath) + if (!Directory.Exists(pythonLibDir)) { // Try to load IronPython from extension package pythonLibDir = Path.Combine((new DirectoryInfo(Path.GetDirectoryName(executionPath))).Parent.FullName, IronPythonEvaluator.packageExtraFolderName, IronPythonEvaluator.PythonLibName); diff --git a/src/Libraries/DSIronPython/IronPythonEvaluator.cs b/src/Libraries/DSIronPython/IronPythonEvaluator.cs index 0ceae74b9cb..94077a020dc 100644 --- a/src/Libraries/DSIronPython/IronPythonEvaluator.cs +++ b/src/Libraries/DSIronPython/IronPythonEvaluator.cs @@ -64,7 +64,6 @@ private static string PythonStandardLibPath() pythonLibDir = Path.Combine(Path.GetDirectoryName(executionPath), PythonLibName); // If IronPython.Std folder is excluded from DynamoCore (which could be user mistake or integrator exclusion) - // Or if the execution path is different than Dynamo root folder if (!Directory.Exists(pythonLibDir)) { // Try to load IronPython from extension package diff --git a/test/DynamoCoreTests/DynamoCoreTests.csproj b/test/DynamoCoreTests/DynamoCoreTests.csproj index 89e4a928bfd..60503bcf2c7 100644 --- a/test/DynamoCoreTests/DynamoCoreTests.csproj +++ b/test/DynamoCoreTests/DynamoCoreTests.csproj @@ -95,7 +95,10 @@ + + + diff --git a/test/DynamoCoreTests/Graph/Nodes/NodeAttributesTests.cs b/test/DynamoCoreTests/Graph/Nodes/NodeAttributesTests.cs new file mode 100644 index 00000000000..f3ac7096e3f --- /dev/null +++ b/test/DynamoCoreTests/Graph/Nodes/NodeAttributesTests.cs @@ -0,0 +1,151 @@ +using System; +using System.Linq; +using CoreNodeModels.Properties; +using Dynamo.Graph.Nodes; +using NUnit.Framework; + +namespace Dynamo.Tests +{ + /// + /// This file contains tests for the classes in the Attributes file. + /// + [TestFixture] + class NodeAttributesTests + { + [Test] + [Category("UnitTests")] + public void NodeSearchTagsAttributeConstructorTest() + { + //resourceType is null + string tagsID = "tagsID"; + Type resourceType = null; + + Assert.Throws(() => _ = new NodeSearchTagsAttribute(tagsID, resourceType)); + } + + [Test] + [Category("UnitTests")] + public void NodeDescriptionAttributeConstructorTest() + { + //resourceType is null + Assert.Throws(() => _ = new NodeDescriptionAttribute("", null)); + + //resourceType is valid + string descriptionResourceID = "WatchNodeDescription"; + Type resourceType = typeof(Resources); + + var attr = new NodeDescriptionAttribute(descriptionResourceID, resourceType); + Assert.AreEqual(Resources.WatchNodeDescription, attr.ElementDescription); + + //resourceType is valid but descriptionResourceID is not + descriptionResourceID = "Nil"; + resourceType = typeof(Resources); + + attr = new NodeDescriptionAttribute(descriptionResourceID, resourceType); + Assert.AreEqual(descriptionResourceID, attr.ElementDescription); + } + + [Test] + [Category("UnitTests")] + public void DoNotLoadOnPlatformsAttributeConstructorTest() + { + //values is null + var attr = new DoNotLoadOnPlatformsAttribute(null); + Assert.AreEqual(null, attr.Values); + + //values is valid + attr = new DoNotLoadOnPlatformsAttribute(new string[] { "" }); + Assert.AreEqual(1, attr.Values.Length); + } + + [Test] + [Category("UnitTests")] + public void NodeObsoleteAttributeConstructorTest() + { + //base with message + var attr = new NodeObsoleteAttribute("Message"); + Assert.AreEqual("Message", attr.Message); + + //resourceType is null + Assert.Throws(() => _ = new NodeObsoleteAttribute("", null)); + + //resourceType is valid + string descriptionResourceID = "WatchNodeDescription"; + Type resourceType = typeof(Resources); + + attr = new NodeObsoleteAttribute(descriptionResourceID, resourceType); + Assert.AreEqual(Resources.WatchNodeDescription, attr.Message); + + //resourceType is valid but descriptionResourceID is not + descriptionResourceID = "Nil"; + resourceType = typeof(Resources); + + attr = new NodeObsoleteAttribute(descriptionResourceID, resourceType); + Assert.AreEqual(descriptionResourceID, attr.Message); + } + + [Test] + [Category("UnitTests")] + public void InPortNamesAttributeConstructorTest() + { + //resourceType is null + var attr = new InPortNamesAttribute(null, new string[] { "" }); + Assert.AreEqual(0, attr.PortNames.Count()); + + //resourceType is valid + string[] resourceNames = { "WatchNodeDescription" }; + Type resourceType = typeof(Resources); + + attr = new InPortNamesAttribute(resourceType, resourceNames); + Assert.AreEqual(1, attr.PortNames.Count()); + } + + [Test] + [Category("UnitTests")] + public void InPortTypesAttributeConstructorTest() + { + //resourceType is null + var attr = new InPortTypesAttribute(null, new string[] { "" }); + Assert.AreEqual(0, attr.PortTypes.Count()); + + //resourceType is valid + string[] resourceNames = { "WatchNodeDescription" }; + Type resourceType = typeof(Resources); + + attr = new InPortTypesAttribute(resourceType, resourceNames); + Assert.AreEqual(1, attr.PortTypes.Count()); + } + + [Test] + [Category("UnitTests")] + public void OutPortNamesAttributeConstructorTest() + { + //resourceType is null + var attr = new OutPortNamesAttribute(null, new string[] { "" }); + Assert.AreEqual(0, attr.PortNames.Count()); + + //resourceType is valid + string[] resourceNames = { "WatchNodeDescription" }; + Type resourceType = typeof(Resources); + + attr = new OutPortNamesAttribute(resourceType, resourceNames); + Assert.AreEqual(1, attr.PortNames.Count()); + } + + [Test] + [Category("UnitTests")] + public void OutPortTypesAttributeConstructorTest() + { + //resourceType is null + var attr = new OutPortTypesAttribute(null, new string[] { "" }); + Assert.AreEqual(0, attr.PortTypes.Count()); + + //resourceType is valid + string[] resourceNames = { "WatchNodeDescription" }; + Type resourceType = typeof(Resources); + + attr = new OutPortTypesAttribute(resourceType, resourceNames); + Assert.AreEqual(1, attr.PortTypes.Count()); + } + } +} \ No newline at end of file diff --git a/test/DynamoCoreTests/Graph/Workspaces/CustomNodeWorkspaceModelTests.cs b/test/DynamoCoreTests/Graph/Workspaces/CustomNodeWorkspaceModelTests.cs new file mode 100644 index 00000000000..4ba8349b3a1 --- /dev/null +++ b/test/DynamoCoreTests/Graph/Workspaces/CustomNodeWorkspaceModelTests.cs @@ -0,0 +1,60 @@ +using System.IO; +using System.Linq; +using Dynamo.Graph.Workspaces; +using NUnit.Framework; + +namespace Dynamo.Tests +{ + /// + /// Class containing tests for the CustomNodeWorkspaceModel class + /// + [TestFixture] + class CustomNodeWorkspaceModelTests : DynamoModelTestBase + { + public void OpenTestFile(string folder, string fileName) + { + var examplePath = Path.Combine(TestDirectory, folder, fileName); + OpenModel(examplePath); + } + + [Test] + [Category("UnitTests")] + public void OnPropertyNameChangedTest() + { + OpenTestFile(@"core\CustomNodes", "add_Read_only.dyf"); + var nodeWorkspace = CurrentDynamoModel.Workspaces.FirstOrDefault(x => x is CustomNodeWorkspaceModel); + Assert.IsNotNull(nodeWorkspace); + + OpenTestFile(@"core\CustomNodes", "TestAdd.dyn"); + var homeWorkspace = CurrentDynamoModel.CurrentWorkspace as HomeWorkspaceModel; + Assert.NotNull(homeWorkspace); + + //Changes the Name property so that the event is raised + nodeWorkspace.Name = "NewNodeName"; + + var resultNode = homeWorkspace.Nodes.FirstOrDefault(x => x.Name == "NewNodeName"); + Assert.IsNotNull(resultNode); + } + + [Test] + [Category("UnitTests")] + public void GetSharedNameTest() + { + var fileName = "add_Read_only"; + OpenTestFile(@"core\CustomNodes", fileName+".dyf"); + var nodeWorkspace = CurrentDynamoModel.Workspaces.FirstOrDefault(x => x is CustomNodeWorkspaceModel); + Assert.IsNotNull(nodeWorkspace); + + var result = nodeWorkspace.GetSharedName(); + Assert.AreEqual(fileName,result); + + //Set fileName to null to simulate it is not a saved file + nodeWorkspace.FileName = null; + var expected = nodeWorkspace.Name; + + result = nodeWorkspace.GetSharedName(); + + Assert.AreEqual(expected,result); + } + } +} diff --git a/test/DynamoCoreTests/Graph/Workspaces/HomeWorkspaceModelTests.cs b/test/DynamoCoreTests/Graph/Workspaces/HomeWorkspaceModelTests.cs new file mode 100644 index 00000000000..2e6185176c0 --- /dev/null +++ b/test/DynamoCoreTests/Graph/Workspaces/HomeWorkspaceModelTests.cs @@ -0,0 +1,58 @@ +using System.IO; +using Dynamo.Graph.Workspaces; +using Dynamo.Models; +using NUnit.Framework; + +namespace Dynamo.Tests +{ + /// + /// Class containing tests for the HomeWorkspaceModel class + /// + [TestFixture] + class HomeWorkspaceModelTests : DynamoModelTestBase + { + private bool eventWasRaised; + private string objectFileName; + + public void OpenTestFile(string folder, string fileName) + { + var examplePath = Path.Combine(TestDirectory, folder, fileName); + OpenModel(examplePath); + } + + [SetUp] + public void Init() + { + eventWasRaised = false; + objectFileName = ""; + } + + [Test] + [Category("UnitTests")] + public void OnPreviewGraphCompletedTest() + { + //Loads a file with a valid graph on the Home workspace + OpenTestFile(@"core\number", "TestBigNumber.dyn"); + var homeWorkspace = CurrentDynamoModel.CurrentWorkspace as HomeWorkspaceModel; + Assert.NotNull(homeWorkspace); + + //Gets results from raised event + homeWorkspace.SetNodeDeltaState += EventHandler; + + homeWorkspace.Run(); + homeWorkspace.GetExecutingNodes(true); + + homeWorkspace.SetNodeDeltaState -= EventHandler; + + Assert.IsTrue(eventWasRaised); + Assert.AreEqual(homeWorkspace.FileName, objectFileName); + } + + private void EventHandler (object workspace, DeltaComputeStateEventArgs d) + { + eventWasRaised = true; + var eventParamWorkspace = workspace as HomeWorkspaceModel; + objectFileName = eventParamWorkspace.FileName; + } + } +} diff --git a/test/Engine/FFITarget/DummyCollection.cs b/test/Engine/FFITarget/DummyCollection.cs index 73f34f82362..47e79b0cdc8 100644 --- a/test/Engine/FFITarget/DummyCollection.cs +++ b/test/Engine/FFITarget/DummyCollection.cs @@ -12,6 +12,11 @@ public static IList ReturnIList(IEnumerable data) return data.ToList(); } + public static IEnumerable ReturnIEnumerable(IEnumerable data) + { + return data; + } + public static IEnumerable ReturnIEnumerableOfInt(IEnumerable data) { return data; diff --git a/test/Libraries/DynamoPythonTests/PythonEngineSelectorTests.cs b/test/Libraries/DynamoPythonTests/PythonEngineSelectorTests.cs index ada0ba9e5aa..e2a0dc2c96e 100644 --- a/test/Libraries/DynamoPythonTests/PythonEngineSelectorTests.cs +++ b/test/Libraries/DynamoPythonTests/PythonEngineSelectorTests.cs @@ -16,24 +16,12 @@ protected override void GetLibrariesToPreload(List libraries) base.GetLibrariesToPreload(libraries); } - /// - /// This test will cover the initial state of the Singleton - /// - [Test] - public void TestEngineSelectorInitial_State() - { - Assert.AreEqual(false, PythonEngineSelector.lazy.IsValueCreated); - Assert.AreEqual(false, PythonEngineSelector.IsCPythonEnabled); - Assert.AreEqual(false, PythonEngineSelector.IsIronPythonEnabled); - } - /// /// This test will cover the use case of the API to query certain Python engine ability for evaluation /// [Test] public void TestEngineSelectorInitialization() { - Assert.AreEqual(false, PythonEngineSelector.lazy.IsValueCreated); PythonEngineSelector.Instance.GetEvaluatorInfo(PythonEngineVersion.IronPython2, out string evaluatorClass, out string evaluationMethod); Assert.AreEqual(true, PythonEngineSelector.lazy.IsValueCreated); Assert.AreEqual(evaluatorClass, PythonEngineSelector.IronPythonEvaluatorClass); diff --git a/test/Libraries/DynamoPythonTests/PythonEvalTestsWithLibraries.cs b/test/Libraries/DynamoPythonTests/PythonEvalTestsWithLibraries.cs index b4c1825582d..9ea2da3e077 100644 --- a/test/Libraries/DynamoPythonTests/PythonEvalTestsWithLibraries.cs +++ b/test/Libraries/DynamoPythonTests/PythonEvalTestsWithLibraries.cs @@ -52,6 +52,8 @@ public void TestListDecoding() import sys import clr clr.AddReference('DSCoreNodes') +clr.AddReference('FFITarget') +from FFITarget import DummyCollection from DSCore import List l = ['a'] @@ -66,7 +68,7 @@ from DSCore import List l3 = [[1,2],[3,4]] # Python list (nested) => .NET IList> -flatennedList = List.Flatten(l3) +flattenedList = List.Flatten(l3) l4 = [] # Python list (empty) => .NET IList @@ -74,13 +76,21 @@ from DSCore import List sum = 0 # Python-wrapped .NET List can be iterated over -for i in flatennedList: +for i in flattenedList: sum = sum + i -OUT = untypedList, typedList, flatennedList, elementCount, sum +l5 = [1,2,3,4] +# Python list => .NET IEnumerable<> +max = List.MaximumItem(l5) + +# Python list => .NET IEnumerable +enumerable = DummyCollection.ReturnIEnumerable(l2) + +OUT = untypedList, typedList, flattenedList, elementCount, sum, max, enumerable "; var empty = new ArrayList(); - var expected = new ArrayList { new ArrayList { "a", "b", "c" }, new ArrayList { "b", "b" }, new ArrayList { 1, 2, 3, 4 }, 0, 10 }; + var expected = new ArrayList { new ArrayList { "a", "b", "c" }, new ArrayList { "b", "b" }, new ArrayList { 1, 2, 3, 4 }, 0, 10, 4 + , new ArrayList { "a", "b" } }; foreach (var pythonEvaluator in Evaluators) { var result = pythonEvaluator(code, empty, empty); @@ -182,8 +192,8 @@ public void TestDictionaryDecodingCPython() import sys import clr clr.AddReference('FFITarget') -clr.AddReference('DesignScriptBuiltin') -from DesignScript.Builtin import Dictionary +clr.AddReference('DSCoreNodes') +from DSCore import List from FFITarget import DummyCollection d = {'one': 1, 'two': 2, 'three': 3} @@ -196,17 +206,87 @@ from FFITarget import DummyCollection typedDictionary = DummyCollection.AcceptDictionary(d) typedDictionary['four'] = 4 -OUT = untypedDictionary, typedDictionary +# Python dict => .NET IEnumerable - Returns keys in both engines +sortedKeys = List.Sort(d) + +OUT = untypedDictionary, typedDictionary, sortedKeys "; var empty = new ArrayList(); - var expected = new Dictionary { + var expectedDictionary = new Dictionary { { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } }; + var expectedKeys = new List { "one", "three", "two" }; var result = DSCPython.CPythonEvaluator.EvaluatePythonScript(code, empty, empty); Assert.IsTrue(result is IList); - foreach (var dict in result as IList) + var resultList = result as IList; + for (int i = 0; i < 2; i++) + { + Assert.IsTrue(resultList[i] is IDictionary); + DictionaryAssert(expectedDictionary, resultList[i] as IDictionary); + } + Assert.IsTrue(resultList[2] is IList); + CollectionAssert.AreEqual(expectedKeys, resultList[2] as IList); + } + + [Test] + public void TestDictionaryViewsDecoding() + { + var code = @" +import clr +clr.AddReference('DSCoreNodes') +from DSCore import List + +d = {'one': 1, 'two': 2, 'three': 3} + +dk = List.AddItemToEnd('four', d.keys()) +dv = List.AddItemToEnd(4, d.values()) +di = List.AddItemToEnd(('four', 4), d.items()) + +OUT = dk, dv, di +"; + var empty = new ArrayList(); + var expected = new ArrayList[] { + new ArrayList { "one", "two", "three", "four" }, + new ArrayList { 1, 2, 3, 4 }, + new ArrayList { new ArrayList { "one", 1 }, new ArrayList { "two", 2 }, new ArrayList { "three", 3 }, new ArrayList { "four", 4 } } + }; + foreach (var pythonEvaluator in Evaluators) + { + var result = pythonEvaluator(code, empty, empty); + Assert.IsTrue(result is IEnumerable); + var i = 0; + foreach (var item in result as IEnumerable) + { + Assert.IsTrue(item is IEnumerable); + CollectionAssert.AreEquivalent(expected[i], item as IEnumerable); + i++; + } + } + } + + [Test] + public void TestSetDecodingCPython() + { + var code = @" +import clr +clr.AddReference('DSCoreNodes') +from DSCore import List + +s = { 'hello' } +fs = frozenset(s) +# Python set => .NET IList - Does not work in IronPython +s2 = List.AddItemToEnd('world', s) +fs2 = List.AddItemToEnd('world', fs) +OUT = s2, fs2 +"; + var empty = new ArrayList(); + var expected = new string[] { "hello", "world" }; + var result = DSCPython.CPythonEvaluator.EvaluatePythonScript(code, empty, empty); + Assert.IsTrue(result is IEnumerable); + foreach (var item in result as IEnumerable) { - DictionaryAssert(expected, dict as IDictionary); + Assert.IsTrue(item is IEnumerable); + CollectionAssert.AreEquivalent(expected, item as IEnumerable); } }