using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; using UnityEngine; using UnityEditor.ShaderGraph; namespace UnityEditor.Graphing.UnitTests { [TestFixture] public class BaseMaterialGraphTests { [OneTimeSetUp] public void RunBeforeAnyTests() { Debug.unityLogger.logHandler = new ConsoleLogHandler(); } [Test] public void TestCanCreateBaseMaterialGraph() { var graph = new TestMaterialGraph(); Assert.AreEqual(0, graph.edges.Count()); Assert.AreEqual(0, graph.GetNodes().Count()); } [Test] public void TestCanAddNodeToBaseMaterialGraph() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); Assert.AreEqual("Test Node", graph.GetNodes().FirstOrDefault().name); Assert.AreEqual(graph, node.owner); } [Test] public void TestCanRemoveNodeFromBaseMaterialGraph() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); graph.RemoveNode(graph.GetNodes().FirstOrDefault()); Assert.AreEqual(0, graph.GetNodes().Count()); } [Test] public void TestCanModifyNodeDrawState() { var node = new TestNode(); node.name = "Test Node"; var drawState = node.drawState; var newPos = new Rect(10, 10, 0, 0); drawState.position = newPos; drawState.expanded = false; node.drawState = drawState; Assert.AreEqual(drawState, node.drawState); Assert.AreEqual(newPos, node.drawState.position); Assert.IsFalse(node.drawState.expanded); } private class SetErrorNode : TestNode { public void SetError() { hasError = true; } public void ClearError() { hasError = false; } } [Test] public void TestChildClassCanModifyErrorState() { var node = new SetErrorNode(); node.SetError(); Assert.IsTrue(node.hasError); node.ClearError(); Assert.IsFalse(node.hasError); } [Test] public void TestNodeGUIDCanBeRewritten() { var node = new TestNode(); var guid = node.guid; var newGuid = node.RewriteGuid(); Assert.AreNotEqual(guid, newGuid); } public class TestableNode : TestNode { public const int Input0 = 0; public const int Input1 = 1; public const int Input2 = 2; public const int Output0 = 3; public const int Output1 = 4; public const int Output2 = 5; public TestableNode() { AddSlot(new TestSlot(Input0, "Input", SlotType.Input)); AddSlot(new TestSlot(Input1, "Input", SlotType.Input)); AddSlot(new TestSlot(Input2, "Input", SlotType.Input)); AddSlot(new TestSlot(Output0, "Output", SlotType.Output)); AddSlot(new TestSlot(Output1, "Output", SlotType.Output)); AddSlot(new TestSlot(Output2, "Output", SlotType.Output)); } } [Test] public void TestRemoveNodeFromBaseMaterialGraphCleansEdges() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var edge = graph.edges.FirstOrDefault(); Assert.AreEqual(createdEdge, edge); graph.RemoveNode(outputNode); Assert.AreEqual(1, graph.GetNodes().Count()); Assert.AreEqual(0, graph.edges.Count()); Assert.AreEqual(inputNode, graph.GetNodes().FirstOrDefault()); } private class NoDeleteNode : TestNode { public override bool canDeleteNode { get { return false; } } } [Test] public void TestCanNotRemoveNoDeleteNodeFromBaseMaterialGraph() { var graph = new TestMaterialGraph(); var node = new NoDeleteNode(); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); graph.RemoveNode(graph.GetNodes().FirstOrDefault()); Assert.AreEqual(1, graph.GetNodes().Count()); } private class OnEnableNode : TestNode, IOnAssetEnabled { public bool called = false; public void OnEnable() { called = true; } } [Test] public void TestSerializedGraphDelegatesOnEnableCalls() { var graph = new TestMaterialGraph(); var node = new OnEnableNode(); node.name = "Test Node"; graph.AddNode(node); Assert.IsFalse(node.called); graph.OnEnable(); Assert.IsTrue(node.called); } [Test] public void TestCanFindNodeInBaseMaterialGraph() { var graph = new TestMaterialGraph(); var node = new TestNode(); graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); Assert.IsNotNull(graph.GetNodeFromGuid(node.guid)); Assert.IsNull(graph.GetNodeFromGuid(Guid.NewGuid())); } [Test] public void TestCanAddSlotToTestNode() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.AddSlot(new TestSlot(1, "input", SlotType.Input)); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); var found = graph.GetNodes().FirstOrDefault(); Assert.AreEqual(1, found.GetInputSlots().Count()); Assert.AreEqual(1, found.GetInputSlots().FirstOrDefault().id); Assert.AreEqual(1, found.GetOutputSlots().Count()); Assert.AreEqual(0, found.GetOutputSlots().FirstOrDefault().id); Assert.AreEqual(2, found.GetSlots().Count()); } [Test] public void TestCanNotAddNullSlotToTestNode() { var node = new TestNode(); node.AddSlot(null); node.name = "Test Node"; Assert.AreEqual(0, node.GetOutputSlots().Count()); } [Test] public void TestCanRemoveSlotFromTestNode() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.AddSlot(new TestSlot(1, "input", SlotType.Input)); graph.AddNode(node); Assert.AreEqual(2, node.GetSlots().Count()); Assert.AreEqual(1, node.GetInputSlots().Count()); Assert.AreEqual(1, node.GetOutputSlots().Count()); node.RemoveSlot(1); Assert.AreEqual(1, node.GetSlots().Count()); Assert.AreEqual(0, node.GetInputSlots().Count()); Assert.AreEqual(1, node.GetOutputSlots().Count()); } [Test] public void TestCanRemoveSlotsWithNonMathingNameFromTestNode() { var graph = new TestMaterialGraph(); var node = new TestableNode(); graph.AddNode(node); Assert.AreEqual(6, node.GetSlots().Count()); Assert.AreEqual(3, node.GetInputSlots().Count()); Assert.AreEqual(3, node.GetOutputSlots().Count()); node.RemoveSlotsNameNotMatching(new[] {TestableNode.Input1}); Assert.AreEqual(1, node.GetSlots().Count()); Assert.AreEqual(1, node.GetInputSlots().Count()); Assert.AreEqual(0, node.GetOutputSlots().Count()); Assert.IsNull(node.FindInputSlot(TestableNode.Input0)); Assert.IsNotNull(node.FindInputSlot(TestableNode.Input1)); Assert.IsNull(node.FindInputSlot(TestableNode.Input2)); } [Test] public void TestCanNotAddDuplicateSlotToTestNode() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); var found = graph.GetNodes().FirstOrDefault(); Assert.AreEqual(0, found.GetInputSlots().Count()); Assert.AreEqual(1, found.GetOutputSlots().Count()); Assert.AreEqual(1, found.GetSlots().Count()); } [Test] public void TestCanUpdateDisplaynameByReaddingSlotToTestNode() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.AddSlot(new TestSlot(0, "output_updated", SlotType.Output)); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); var found = graph.GetNodes().FirstOrDefault(); Assert.AreEqual(0, found.GetInputSlots().Count()); Assert.AreEqual(1, found.GetOutputSlots().Count()); Assert.AreEqual(1, found.GetSlots().Count()); var slot = found.GetOutputSlots().FirstOrDefault(); Assert.AreEqual("output_updated", slot.displayName); } [Test] public void TestCanUpdateSlotPriority() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output, 0)); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); var found = graph.GetNodes().FirstOrDefault(); Assert.AreEqual(0, found.GetInputSlots().Count()); Assert.AreEqual(1, found.GetOutputSlots().Count()); Assert.AreEqual(1, found.GetSlots().Count()); var slot = found.GetOutputSlots().FirstOrDefault(); Assert.AreEqual(0, slot.priority); slot.priority = 2; Assert.AreEqual(2, slot.priority); } [Test] public void TestCanUpdateSlotPriorityByReaddingSlotToTestNode() { var graph = new TestMaterialGraph(); var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output, 0)); node.AddSlot(new TestSlot(0, "output", SlotType.Output, 5)); node.name = "Test Node"; graph.AddNode(node); Assert.AreEqual(1, graph.GetNodes().Count()); var found = graph.GetNodes().FirstOrDefault(); Assert.AreEqual(0, found.GetInputSlots().Count()); Assert.AreEqual(1, found.GetOutputSlots().Count()); Assert.AreEqual(1, found.GetSlots().Count()); var slot = found.GetOutputSlots().FirstOrDefault(); Assert.AreEqual(5, slot.priority); } [Test] public void TestCanUpdateSlotDisplayName() { var node = new TestNode(); node.AddSlot(new TestSlot(0, "output", SlotType.Output)); node.name = "Test Node"; Assert.AreEqual(0, node.GetInputSlots().Count()); Assert.AreEqual(1, node.GetOutputSlots().Count()); Assert.AreEqual(1, node.GetSlots().Count()); var slot = node.GetOutputSlots().FirstOrDefault(); Assert.IsNotNull(slot); Assert.AreEqual("output", slot.displayName); slot.displayName = "test"; Assert.AreEqual("test", slot.displayName); } [Test] public void TestCanFindSlotOnTestNode() { var node = new TestableNode(); Assert.AreEqual(6, node.GetSlots().Count()); Assert.IsNotNull(node.FindInputSlot(TestableNode.Input0)); Assert.IsNull(node.FindInputSlot(TestableNode.Output0)); Assert.IsNotNull(node.FindOutputSlot(TestableNode.Output0)); Assert.IsNull(node.FindOutputSlot(TestableNode.Input0)); Assert.IsNotNull(node.FindSlot(TestableNode.Input0)); Assert.IsNotNull(node.FindSlot(TestableNode.Output0)); Assert.IsNull(node.FindSlot(555)); } [Test] public void TestCanFindSlotReferenceOnTestNode() { var node = new TestableNode(); Assert.AreEqual(6, node.GetSlots().Count()); Assert.IsNotNull(node.GetSlotReference(TestableNode.Input0)); Assert.IsNotNull(node.GetSlotReference(TestableNode.Output0)); Assert.Throws(() => node.GetSlotReference(555)); } [Test] public void TestCanConnectAndTraverseTwoNodesOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var edge = graph.edges.FirstOrDefault(); Assert.AreEqual(createdEdge, edge); var foundOutputNode = graph.GetNodeFromGuid(edge.outputSlot.nodeGuid); var foundOutputSlot = foundOutputNode.FindOutputSlot(edge.outputSlot.slotId); Assert.AreEqual(outputNode, foundOutputNode); Assert.IsNotNull(foundOutputSlot); var foundInputNode = graph.GetNodeFromGuid(edge.inputSlot.nodeGuid); var foundInputSlot = foundInputNode.FindInputSlot(edge.inputSlot.slotId); Assert.AreEqual(inputNode, foundInputNode); Assert.IsNotNull(foundInputSlot); } [Test] public void TestCanConnectAndTraverseThreeNodesOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var middleNode = new TestableNode(); graph.AddNode(middleNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(3, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), middleNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); graph.Connect(middleNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(2, graph.edges.Count()); var edgesOnMiddleNode = NodeUtils.GetAllEdges(middleNode); Assert.AreEqual(2, edgesOnMiddleNode.Count()); List result = new List(); NodeUtils.DepthFirstCollectNodesFromNode(result, inputNode); Assert.AreEqual(3, result.Count); result.Clear(); NodeUtils.DepthFirstCollectNodesFromNode(result, inputNode, NodeUtils.IncludeSelf.Exclude); Assert.AreEqual(2, result.Count); result.Clear(); NodeUtils.DepthFirstCollectNodesFromNode(result, null); Assert.AreEqual(0, result.Count); } [Test] public void TestExceptionIfBadNodeConfigurationWorks() { var node = new TestableNode(); Assert.DoesNotThrow( () => NodeUtils.SlotConfigurationExceptionIfBadConfiguration( node, new[] {TestableNode.Input0, TestableNode.Input1, TestableNode.Input2}, new[] {TestableNode.Output0, TestableNode.Output1, TestableNode.Output2, }) ); Assert.Throws( () => NodeUtils.SlotConfigurationExceptionIfBadConfiguration( node, new[] {666, TestableNode.Input1, TestableNode.Input2}, new[] {TestableNode.Output0, TestableNode.Output1, TestableNode.Output2, }) ); Assert.Throws( () => NodeUtils.SlotConfigurationExceptionIfBadConfiguration( node, new[] {TestableNode.Input0, TestableNode.Input1, TestableNode.Input2}, new[] {666, TestableNode.Output1, TestableNode.Output2, }) ); Assert.DoesNotThrow( () => NodeUtils.SlotConfigurationExceptionIfBadConfiguration( node, new[] {TestableNode.Input0}, new[] {TestableNode.Output0}) ); } [Test] public void TestConectionToSameInputReplacesOldInput() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var edge = graph.edges.FirstOrDefault(); Assert.AreEqual(createdEdge, edge); var createdEdge2 = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var edge2 = graph.edges.FirstOrDefault(); Assert.AreEqual(createdEdge2, edge2); } [Test] public void TestRemovingSlotRemovesConnectedEdges() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); outputNode.RemoveSlot(TestableNode.Output0); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestCanNotConnectToNullSlot() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge2 = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), new SlotReference(Guid.NewGuid(), 666)); Assert.AreEqual(0, graph.edges.Count()); Assert.IsNull(createdEdge2); } [Test] public void TestCanNotConnectTwoOuputSlotsOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var outputNode2 = new TestableNode(); graph.AddNode(outputNode2); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge = graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), outputNode2.GetSlotReference(TestableNode.Output0)); Assert.IsNull(createdEdge); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestCanNotConnectTwoInputSlotsOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var inputNode = new TestableNode(); graph.AddNode(inputNode); var inputNode2 = new TestableNode(); graph.AddNode(inputNode2); Assert.AreEqual(2, graph.GetNodes().Count()); var createdEdge = graph.Connect(inputNode.GetSlotReference(TestableNode.Input0), inputNode2.GetSlotReference(TestableNode.Input0)); Assert.IsNull(createdEdge); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestRemovingNodeRemovesConectedEdgesOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); graph.RemoveNode(graph.GetNodes().FirstOrDefault()); Assert.AreEqual(1, graph.GetNodes().Count()); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestRemovingEdgeOnBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); graph.RemoveEdge(graph.edges.FirstOrDefault()); Assert.AreEqual(2, graph.GetNodes().Count()); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestRemovingElementsFromBaseMaterialGraph() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); graph.RemoveElements(graph.GetNodes(), graph.edges); Assert.AreEqual(0, graph.GetNodes().Count()); Assert.AreEqual(0, graph.edges.Count()); } [Test] public void TestCanGetEdgesOnBaseMaterialGraphFromSlotReference() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); Assert.AreEqual(1, graph.GetEdges(inputNode.GetSlotReference(TestableNode.Input0)).Count()); Assert.AreEqual(1, graph.GetEdges(outputNode.GetSlotReference(TestableNode.Output0)).Count()); Assert.Throws(() => outputNode.GetSlotReference(666)); } [Test] public void TestGetInputsWithNoConnection() { var graph = new TestMaterialGraph(); var outputNode = new TestableNode(); graph.AddNode(outputNode); var inputNode = new TestableNode(); graph.AddNode(inputNode); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(outputNode.GetSlotReference(TestableNode.Output0), inputNode.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var slots = inputNode.GetInputsWithNoConnection(); Assert.AreEqual(2, slots.Count()); CollectionAssert.AreEqual(new[] { TestableNode.Input1, TestableNode.Input2 }, slots.Select(x => x.id)); } [Test] public void TestCyclicConnectionsAreNotAllowedOnGraph() { var graph = new TestMaterialGraph(); var nodeA = new TestableNode(); graph.AddNode(nodeA); var nodeB = new TestableNode(); graph.AddNode(nodeB); Assert.AreEqual(2, graph.GetNodes().Count()); graph.Connect(nodeA.GetSlotReference(TestableNode.Output0), nodeB.GetSlotReference(TestableNode.Input0)); Assert.AreEqual(1, graph.edges.Count()); var edge = graph.Connect(nodeB.GetSlotReference(TestableNode.Output0), nodeA.GetSlotReference(TestableNode.Input0)); Assert.IsNull(edge); Assert.AreEqual(1, graph.edges.Count()); } } }