1269 lines
59 KiB
C#
1269 lines
59 KiB
C#
using System.Reflection;
|
|
using NodePipeline.Abstractions.Interfaces.Nodes;
|
|
using NodePipeline.Engine.CodeGeneration;
|
|
using NodePipeline.Engine.CodeGeneration.Abstractions.Models;
|
|
using NodePipeline.Engine.Tests.CodeGeneratorTests.Fixtures;
|
|
using NodePipeline.Engine.Tests.CodeGeneratorTests.Fixtures.MockNodes;
|
|
|
|
namespace NodePipeline.Engine.Tests.CodeGeneratorTests;
|
|
|
|
public class NodeFactoryGeneratorTests
|
|
{
|
|
#region CreateNode
|
|
|
|
[Fact]
|
|
public void CreateNodeMethod_ContainsAllNodeCases()
|
|
{
|
|
// Arrange
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "CreateNode");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "CreateNode method not found in generated code.");
|
|
|
|
// Act & Assert
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{node.Type}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
if (node.HasParameterlessConstructor)
|
|
{
|
|
Assert.Contains($"node = new {node.TypeNameFull}();", caseBlock);
|
|
Assert.Contains("break;", caseBlock);
|
|
}
|
|
else
|
|
{
|
|
Assert.Contains(
|
|
"throw new NodeCanNotBeInitializedWithoutFactoryException(pipelineId, config.Type, config.Id);",
|
|
caseBlock);
|
|
}
|
|
}
|
|
|
|
Assert.Contains("InitializeNodeFields(pipelineId, node, config.Id);", generatedCode);
|
|
Assert.Contains("return node ?? throw new NodeWasNotInitializedException(pipelineId, config.Type, config.Id);",
|
|
generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetAllPorts
|
|
|
|
[Fact]
|
|
public void GetAllPortsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"public Dictionary<NodePortKey, NodePortInfo> GetAllPorts(string pipelineId, HashSet<string> nodeTypes, Dictionary<string, IEnumerable<string>> nodeList)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodeInputPorts
|
|
|
|
[Fact]
|
|
public void GetNodeInputPortsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"public IEnumerable<NodePortInfo> GetNodeInputPorts(string pipelineId, string nodeType, string nodeId)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ConnectPortsStruct
|
|
|
|
[Fact]
|
|
public void ConnectPortsStruct_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignatureV1 =
|
|
"private void ConnectPortsStruct<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false) where T : struct";
|
|
const string methodSignatureV2 =
|
|
"private void ConnectPortsStruct<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false)\n where T : struct";
|
|
var methodSignatureV3 =
|
|
"private void ConnectPortsStruct<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs,"
|
|
+ Environment.NewLine +
|
|
" string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false)"
|
|
+ Environment.NewLine + " where T : struct";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2)
|
|
|| generatedCode.Contains(methodSignatureV3));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ConnectPortsClass
|
|
|
|
[Fact]
|
|
public void ConnectPortsClass_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignatureV1 =
|
|
"private void ConnectPortsClass<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false) where T : class";
|
|
const string methodSignatureV2 =
|
|
"private void ConnectPortsClass<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false)\n where T : class";
|
|
var methodSignatureV3 =
|
|
"private void ConnectPortsClass<T>(string pipelineId, string nodeId,string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs,"
|
|
+ Environment.NewLine +
|
|
" string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool disallowNullableOutput = false, bool isRequired = false)"
|
|
+ Environment.NewLine + " where T : class";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2)
|
|
|| generatedCode.Contains(methodSignatureV3));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TryConnectPorts
|
|
|
|
[Fact]
|
|
public void TryConnectPorts_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignatureV1 =
|
|
"private PortConnectionInfo? TryConnectPorts<T>(string pipelineId, string nodeId, string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool isRequired = false) where T : notnull";
|
|
const string methodSignatureV2 =
|
|
"private PortConnectionInfo? TryConnectPorts<T>(string pipelineId, string nodeId, string nodeType, INodeField<T>? nodeInput, string nodeInputName, Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool isRequired = false)\n where T : notnull";
|
|
var methodSignatureV3 =
|
|
"private PortConnectionInfo? TryConnectPorts<T>(string pipelineId, string nodeId, string nodeType, INodeField<T>? nodeInput, string nodeInputName,"
|
|
+ Environment.NewLine +
|
|
" Dictionary<string, InputSource> inputs, string inputKey, IReadOnlyDictionary<string, INode> createdNodes, bool isRequired = false)"
|
|
+ Environment.NewLine + " where T : notnull";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2)
|
|
|| generatedCode.Contains(methodSignatureV3));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDefaultValue
|
|
|
|
[Fact]
|
|
public void GetDefaultValue_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature = "private static T? GetDefaultValue<T>()";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
[Fact]
|
|
public void PortConnectionInfo_ShouldBeDeclaredInGeneratedCode()
|
|
{
|
|
const string recordDeclaration =
|
|
"private record PortConnectionInfo(bool Connected, object? OutputFieldObj, string FromPortName, string FromNodeType, string FromNodeId);";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(recordDeclaration, generatedCode);
|
|
}
|
|
|
|
#region InitializeNodeFields
|
|
|
|
[Fact]
|
|
public void InitializeNodeFieldsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature = "private void InitializeNodeFields(string pipelineId, INode node, string nodeId)";
|
|
// var methodSignature = $"private static Dictionary<NodePortKey, NodePortInfo> Get__{GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__NodePorts(string nodeId)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void InitializeNodeFieldsMethod_ContainsSwitchCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var methodName = "InitializeNodeFields";
|
|
var tCountByNodes = new Dictionary<NodeDescriptor, int>();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
Assert.Contains($"case {node.TypeNameFull} t", methodCode);
|
|
if (!tCountByNodes.TryGetValue(node, out var value)) tCountByNodes.Add(node, 1);
|
|
else tCountByNodes[node] = ++value;
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId);", methodCode);
|
|
Assert.DoesNotContain(tCountByNodes.Values, q => q > 1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region InitializeNodeFieldsSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificInitializeNodeFieldsMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodSignature =
|
|
$"private static void Initialize__{nodeDescriptor.TypeNameShortSanitized}__NodeFields({nodeDescriptor.TypeNameFull} node, string nodeId)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificInitializeNodeFieldsMethod_InitializesAllFields(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodName = $"Initialize__{nodeDescriptor.TypeNameShortSanitized}__NodeFields";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
|
|
foreach (var nodeField in nodeDescriptor.Fields)
|
|
{
|
|
var nodeFieldType = string.Concat(nodeField.ValueType, nodeField.IsNullableValueType ? "?" : string.Empty);
|
|
var initNodeFieldCodeV1 =
|
|
$"node.{nodeField.PropertyName} = new NodePipeline.Abstractions.Models.NodeField<{nodeFieldType}>()"
|
|
+ Environment.NewLine + " {"
|
|
+ Environment.NewLine + $" Name = \"{nodeField.FieldName}\","
|
|
+ Environment.NewLine +
|
|
$" Code = NodeFieldCodeGenerator.GenerateFieldCode(nodeId, \"{nodeField.FieldName}\", FieldDirection.{nodeField.Direction.ToString()}),"
|
|
+ Environment.NewLine +
|
|
$" Direction = FieldDirection.{nodeField.Direction.ToString()},"
|
|
+ Environment.NewLine + " };";
|
|
var initNodeFieldCodeV2 =
|
|
$"node.{nodeField.PropertyName} = new NodePipeline.Abstractions.Models.NodeField<{nodeFieldType}>()"
|
|
+ Environment.NewLine + " {"
|
|
+ Environment.NewLine + $" Name = \"{nodeField.FieldName}\","
|
|
+ Environment.NewLine +
|
|
$" Code = NodeFieldCodeGenerator.GenerateFieldCode(nodeId, \"{nodeField.FieldName}\", FieldDirection.{nodeField.Direction.ToString()}),"
|
|
+ Environment.NewLine +
|
|
$" Direction = FieldDirection.{nodeField.Direction.ToString()},"
|
|
+ Environment.NewLine +
|
|
" // Description intentionally omitted for runtime"
|
|
+ Environment.NewLine + " };";
|
|
Assert.True(methodCode.Contains(initNodeFieldCodeV1) || methodCode.Contains(initNodeFieldCodeV2));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetParameterCodes
|
|
|
|
[Fact]
|
|
public void GetParameterCodesMethod_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetParameterCodes");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetParameterCodes method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{node.Type}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock),
|
|
$"Case block for node {(string.IsNullOrEmpty(node.Type) ? node.TypeNameFull : node.Type)} not found.");
|
|
|
|
Assert.Contains($"return GetParameterCodesFor__{node.TypeNameShortSanitized}__Node();", caseBlock);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Generate_GetParameterCodesMethod_ContainsAllNodeCasesWithCorrectReturnMethods()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetParameterCodes");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetParameterCodes method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{node.Type}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock),
|
|
$"Case block for node {(string.IsNullOrEmpty(node.Type) ? node.TypeNameFull : node.Type)} not found.");
|
|
|
|
var expectedMethodName = $"return GetParameterCodesFor__{node.TypeNameShortSanitized}__Node();";
|
|
Assert.Contains(expectedMethodName, caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine + " throw new NodeTypeNotFoundException(nodeType);",
|
|
methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetParameterCodesSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(OneParameterNode), "CreateMultipleNodesModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificGetParameterCodesMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var methodSignature =
|
|
$"private IEnumerable<string> GetParameterCodesFor__{TestHelper.GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__Node()";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterCodesMethod_HasCorrectName()
|
|
{
|
|
var nodeDescriptor = SimpleNamedNode.GetDescriptor();
|
|
var methodSignature =
|
|
$"private IEnumerable<string> GetParameterCodesFor__{nodeDescriptor.TypeNameShortSanitized}__Node()";
|
|
var model = TestNodeModelFactory.CreateSimpleNamedNodeModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterCodesMethod_ContainsAllParameters()
|
|
{
|
|
var methodName = $"GetParameterCodesFor__{typeof(ThreeParameterNode).FullName}__Node";
|
|
var generatedCode = NodeFactoryGenerator.Generate(TestNodeModelFactory.CreateThreeParameterNodeModel());
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found.");
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var node = model.Nodes.First(n => n.Type == nameof(ThreeParameterNode));
|
|
Assert.NotNull(node);
|
|
var nodeParameters = node.Fields.Where(q => q.Direction == FieldDirection.Parameter);
|
|
|
|
foreach (var param in nodeParameters) Assert.Contains($"\"{param.FieldName}\"", methodCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterCodesMethod_ContainsAllParameterNamesWithAttributeSupport()
|
|
{
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var node = model.Nodes[0];
|
|
var methodName = $"GetParameterCodesFor__{node.TypeNameShortSanitized}__Node";
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"Method {methodName} not found in generated code.");
|
|
|
|
foreach (var param in node.Fields.Where(q => q.Direction == FieldDirection.Parameter))
|
|
Assert.Contains($"\"{param.FieldName}\"", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodePorts
|
|
|
|
[Fact]
|
|
public void GetNodePortsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"private Dictionary<NodePortKey, NodePortInfo> GetNodePorts(string pipelineId, string nodeType, string nodeId)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetNodePortsMethod_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetNodePorts");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetNodePorts method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var nodeType = node.Type;
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{nodeType}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {nodeType} not found.");
|
|
|
|
Assert.Contains($"return Get__{node.TypeNameShortSanitized}__NodePorts(nodeId);", caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, nodeType, nodeId);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodePortsSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificGetNodePortsMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var methodSignature =
|
|
$"private static Dictionary<NodePortKey, NodePortInfo> Get__{TestHelper.GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__NodePorts(string nodeId)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetNodePortsMethod_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetNodePorts");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetNodePorts method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var nodeType = string.IsNullOrEmpty(node.Type) ? node.TypeNameFull : node.Type;
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{nodeType}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {nodeType} not found.");
|
|
|
|
Assert.Contains($"return Get__{node.TypeNameShortSanitized}__NodePorts(nodeId);", caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, nodeType, nodeId);", methodCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetNodePortsMethod_ContainsCorrectInputProperty()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var methodName = $"Get__{node.TypeNameShortSanitized}__NodePorts";
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"Method {methodName} not found in generated code.");
|
|
|
|
foreach (var field in node.Fields.Where(f => f.Direction is FieldDirection.Input or FieldDirection.Output))
|
|
{
|
|
var isInputString = (field.Direction == FieldDirection.Input).ToString().ToLower();
|
|
Assert.Contains($"new NodePortKey(nodeId, \"{field.FieldName}\", {isInputString})", methodCode);
|
|
var portInfoParameters = ExtractNodePortInfoParametersFromMethodCode(methodCode, field.FieldName);
|
|
Assert.Equal(isInputString, portInfoParameters.ElementAtOrDefault(5));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetNodePortsMethod_ContainsCorrectPortValueType()
|
|
{
|
|
var model = TestNodeModelFactory.CreateThreePortNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var methodName = $"Get__{node.TypeNameShortSanitized}__NodePorts";
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"Method {methodName} not found in generated code.");
|
|
|
|
foreach (var field in node.Fields.Where(f => f.Direction is FieldDirection.Input or FieldDirection.Output))
|
|
{
|
|
var portInfoParameters = ExtractNodePortInfoParametersFromMethodCode(methodCode, field.FieldName);
|
|
Assert.Equal($"typeof({field.ValueType})", portInfoParameters.ElementAtOrDefault(1));
|
|
Assert.Equal(field.IsNullableValueType.ToString().ToLower(), portInfoParameters.ElementAtOrDefault(2));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("CreateThreePortNodeModel")]
|
|
[InlineData("CreateThreePortNode2Model")]
|
|
public void SpecificGetNodePortsMethod_ContainsCorrectRequiredProperty(string factoryMethod)
|
|
{
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var methodName = $"Get__{node.TypeNameShortSanitized}__NodePorts";
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"Method {methodName} not found in generated code.");
|
|
|
|
foreach (var field in node.Fields.Where(f => f.Direction is FieldDirection.Input or FieldDirection.Output))
|
|
{
|
|
var isRequired = field.Metadata?.IsRequired == true;
|
|
var portInfoParameters = ExtractNodePortInfoParametersFromMethodCode(methodCode, field.FieldName);
|
|
Assert.Equal(isRequired.ToString().ToLower(), portInfoParameters.ElementAtOrDefault(3));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("CreateThreePortNodeModel")]
|
|
[InlineData("CreateThreePortNode2Model")]
|
|
public void SpecificGetNodePortsMethod_ContainsCorrectDisallowNullableInputProperty(string factoryMethod)
|
|
{
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var methodName = $"Get__{node.TypeNameShortSanitized}__NodePorts";
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"Method {methodName} not found in generated code.");
|
|
|
|
foreach (var field in node.Fields.Where(f => f.Direction is FieldDirection.Input or FieldDirection.Output))
|
|
{
|
|
var disallowNullableOutput = field.Metadata?.DisallowNullableOutput == true;
|
|
var portInfoParameters = ExtractNodePortInfoParametersFromMethodCode(methodCode, field.FieldName);
|
|
Assert.Equal(disallowNullableOutput.ToString().ToLower(), portInfoParameters.ElementAtOrDefault(4));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string[] ExtractNodePortInfoParameters(string nodePortInfoCode)
|
|
{
|
|
const string prefix = "new NodePortInfo(";
|
|
if (nodePortInfoCode.Length < prefix.Length + 2) throw new Exception();
|
|
var parametersString = nodePortInfoCode.Substring(prefix.Length, nodePortInfoCode.Length - (prefix.Length + 1));
|
|
return parametersString.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
|
}
|
|
|
|
private static string[] ExtractNodePortInfoParametersFromMethodCode(string methodCode, string fieldName)
|
|
{
|
|
var portInfoIndex = methodCode.IndexOf($"new NodePortInfo(\"{fieldName}\"", StringComparison.Ordinal);
|
|
var endIndex = methodCode.IndexOf(Environment.NewLine, portInfoIndex + 1, StringComparison.Ordinal);
|
|
return ExtractNodePortInfoParameters(methodCode.Substring(portInfoIndex + 1, endIndex - portInfoIndex - 1));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ReadParameterValue
|
|
|
|
[Fact]
|
|
public void ReadParameterValue_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"public object? ReadParameterValue(string pipelineId, string nodeId, string nodeType, string parameterName, string? valueString)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadParameterValue_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "ReadParameterValue");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "ReadParameterValue method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var nodeType = node.Type;
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{nodeType}\"):";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {nodeType} not found.");
|
|
|
|
Assert.Contains(
|
|
$"return ReadParameterValueFrom__{node.TypeNameShortSanitized}__Node(pipelineId, nodeType, nodeId, parameterName, valueString);",
|
|
caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine + " throw new NodeTypeNotFoundException(nodeType);",
|
|
methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ReadParameterValueSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificReadParameterValueMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var methodSignature =
|
|
$"private static object? ReadParameterValueFrom__{TestHelper.GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__Node(string pipelineId, string nodeType, string nodeId, string parameterName, string? valueString)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificReadParameterValueMethod_ContainsAllParameters()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"ReadParameterValueFrom__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Parameter))
|
|
{
|
|
var parameterName = parameter.FieldName;
|
|
var caseLabel = $"case \"{parameterName}\":";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for parameter {parameter} not found.");
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeParameterNotFoundException(pipelineId, parameterName, nodeType, nodeId);",
|
|
methodCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificReadParameterValueMethod_ReturnsCallsMethodWithAppropriateType()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"ReadParameterValueFrom__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Parameter))
|
|
{
|
|
var parameterName = parameter.FieldName;
|
|
var caseLabel = $"case \"{parameterName}\":";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for parameter {parameter} not found.");
|
|
Assert.Contains($"return ParseParameter<{parameter.ValueType}>(valueString);", caseBlock);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodeOutputs
|
|
|
|
[Fact]
|
|
public void GetNodeOutputs_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"private IReadOnlyDictionary<string, object> GetNodeOutputs(string pipelineId, string nodeId, INode node)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetNodeOutputs_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetNodeOutputs");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "ReadParameterValue method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var @case = $"case {node.TypeNameFull} t";
|
|
var caseLabel = methodCode[methodCode.IndexOf(@case, StringComparison.Ordinal)..].Split(':')[0];
|
|
var tNumberString = caseLabel[@case.Length..];
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
Assert.Contains($"return Get__{node.TypeNameShortSanitized}__NodeOutputs(nodeId, t{tNumberString});",
|
|
caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodeOutputsSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificGetNodeOutputsMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodSignature =
|
|
$"private IReadOnlyDictionary<string, object> Get__{nodeDescriptor.TypeNameShortSanitized}__NodeOutputs(string nodeId, {nodeDescriptor.TypeNameFull} node)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetNodeOutputsMethod_ContainsAllOutputPorts()
|
|
{
|
|
var nodeDescriptor = ThreePortNode.GetDescriptor();
|
|
var methodName = $"Get__{nodeDescriptor.TypeNameShortSanitized}__NodeOutputs";
|
|
|
|
|
|
var model = TestNodeModelFactory.CreateThreePortNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
foreach (var outputPort in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Output))
|
|
Assert.Contains(
|
|
$"{{ NodeFieldCodeGenerator.GenerateFieldCode(nodeId, \"{outputPort.FieldName}\", FieldDirection.Output), node.{outputPort.PropertyName} }},",
|
|
methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetNodeParametersValues
|
|
|
|
[Fact]
|
|
public void SetNodeParametersValues_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"public void SetNodeParametersValues<TNode>(string pipelineId, TNode node, string nodeId, Dictionary<string, object?> parameters) where TNode : INode";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetNodeParametersValues_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "SetNodeParametersValues");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "SetNodeParametersValues method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var @case = $"case {node.TypeNameFull} t";
|
|
var caseLabel = methodCode[methodCode.IndexOf(@case, StringComparison.Ordinal)..].Split(':')[0];
|
|
var tNumberString = caseLabel[@case.Length..];
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
var expectedString =
|
|
$"Set__{node.TypeNameShortSanitized}__NodeParametersValues(t{tNumberString}, nodeId, parameters);"
|
|
+ Environment.NewLine + " break;";
|
|
Assert.Contains(expectedString, caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetNodeParametersValuesSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificSetNodeParametersValuesMethod_ShouldExistInGeneratedCode(Type mockNodeType,
|
|
string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodSignature =
|
|
$"private static void Set__{nodeDescriptor.TypeNameShortSanitized}__NodeParametersValues({nodeDescriptor.TypeNameFull} node, string nodeId, Dictionary<string, object?> parameters)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificSetNodeParametersValuesMethod_ContainsAllParameters()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"Set__{nodeDescriptor.TypeNameShortSanitized}__NodeParametersValues";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Parameter))
|
|
{
|
|
// var ifString = methodCode[methodCode.IndexOf($"if (parameters.TryGetValue(\"{parameter.FieldName}\", out var val{i})")..]
|
|
var ifString =
|
|
methodCode[
|
|
methodCode.IndexOf($"if (parameters.TryGetValue(\"{parameter.FieldName}\", out var val",
|
|
StringComparison.Ordinal)..]
|
|
.Split(Environment.NewLine)[0];
|
|
var valueNumberString =
|
|
ifString[ifString.IndexOf("out var ", StringComparison.Ordinal)..].Split(')')[0][11..];
|
|
var valueNumber = int.Parse(valueNumberString);
|
|
// var parameterType = string.Concat(parameter.ValueType, parameter.IsNullableValueType ? "?" : string.Empty);
|
|
var parameterType = parameter.ValueType;
|
|
var setParameterCode =
|
|
$"if (parameters.TryGetValue(\"{parameter.FieldName}\", out var val{valueNumber}) && val{valueNumber} is {parameterType} typedVal{valueNumber})"
|
|
+ Environment.NewLine +
|
|
$" node.{parameter.PropertyName}.Value = typedVal{valueNumberString};";
|
|
Assert.Contains(setParameterCode, methodCode);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetParameterDefaultValue
|
|
|
|
[Fact]
|
|
public void GetParameterDefaultValue_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature = "public object? GetParameterDefaultValue(string nodeType, string parameterName)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterDefaultValue_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var codeSubstring =
|
|
generatedCode[
|
|
generatedCode.IndexOf("public object? GetParameterDefaultValue(", StringComparison.Ordinal)..];
|
|
var methodCode = TestHelper.ExtractMethod(codeSubstring, "GetParameterDefaultValue");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetParameterDefaultValue method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var caseLabel = $"case var t when t == NodeNamePrefixSettings.TrimNodeType(\"{node.Type}\")";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
Assert.Contains($"return GetParameterDefaultValueFor__{node.TypeNameShortSanitized}__Node(parameterName);",
|
|
caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeParameterNotFoundException(parameterName, nodeType);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetParameterDefaultValueSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificGetParameterDefaultValueMethod_ShouldExistInGeneratedCode(Type mockNodeType,
|
|
string factoryMethod)
|
|
{
|
|
var methodSignature =
|
|
$"private static object? GetParameterDefaultValueFor__{TestHelper.GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__Node(string parameterName)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterDefaultValueMethod_ContainsAllParameters()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"GetParameterDefaultValueFor__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Parameter))
|
|
{
|
|
var parameterName = parameter.FieldName;
|
|
var caseLabel = $"case \"{parameterName}\":";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for parameter {parameter} not found.");
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
$" throw new NodeParameterNotFoundException(parameterName, \"{nodeDescriptor.Type}\");",
|
|
methodCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterDefaultValueMethod_CallMethodWithAppropriateType()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"GetParameterDefaultValueFor__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Parameter))
|
|
{
|
|
var parameterName = parameter.FieldName;
|
|
var caseLabel = $"case \"{parameterName}\":";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
//TODO: or without "?"?
|
|
var parameterType = string.Concat(parameter.ValueType, parameter.IsNullableValueType ? "?" : string.Empty);
|
|
if (parameter.Metadata?.DefaultValue == null)
|
|
Assert.Contains($"return GetDefaultValue<{parameterType}>();", caseBlock);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificGetParameterDefaultValueMethod_ReturnsCallsMethodWithAppropriateType()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"GetParameterDefaultValueFor__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
var parametersWithDefaultValues = nodeDescriptor.Fields
|
|
.Where(f => f is { Direction: FieldDirection.Parameter, Metadata.DefaultValue: not null });
|
|
|
|
foreach (var parameter in parametersWithDefaultValues)
|
|
{
|
|
var parameterName = parameter.FieldName;
|
|
var caseLabel = $"case \"{parameterName}\":";
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.Contains($"return {parameter.Metadata!.DefaultValue};", caseBlock);
|
|
}
|
|
}
|
|
|
|
|
|
//TODO: test OneParameterWithoutParameterlessConstructorNode and parameter without ParameterlessConstructor
|
|
|
|
#endregion
|
|
|
|
#region GetNodeType
|
|
|
|
[Fact]
|
|
public void GetNodeType_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"private static string GetNodeType(string pipelineId, string nodeId, INode node)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetNodeType_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "GetNodeType");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "GetNodeType method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var @case = $"case {node.TypeNameFull}:";
|
|
var caseLabel = methodCode[methodCode.IndexOf(@case, StringComparison.Ordinal)..].Split(':')[0];
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
Assert.Contains($"return NodeNamePrefixSettings.TrimNodeType(\"{node.Type}\");", caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ConnectPorts
|
|
|
|
[Fact]
|
|
public void ConnectPorts_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature =
|
|
"public void ConnectPorts<TNode>(string pipelineId, TNode node, string nodeId, Dictionary<string, InputSource> inputs, IReadOnlyDictionary<string, INode> createdNodes) where TNode : INode";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConnectPorts_ContainsAllNodeCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, "ConnectPorts");
|
|
Assert.False(string.IsNullOrEmpty(methodCode), "ConnectPorts method not found in generated code.");
|
|
|
|
foreach (var node in model.Nodes)
|
|
{
|
|
var @case = $"case {node.TypeNameFull} t";
|
|
var caseLabel = methodCode[methodCode.IndexOf(@case, StringComparison.Ordinal)..].Split(':')[0];
|
|
var tNumberString = caseLabel[@case.Length..];
|
|
var caseBlock = TestHelper.ExtractSwitchCase(methodCode, caseLabel);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
var caseText =
|
|
$"Connect__{node.TypeNameShortSanitized}__NodePorts(pipelineId, t{tNumberString}, nodeId, inputs, createdNodes);"
|
|
+ Environment.NewLine + " break;";
|
|
Assert.Contains(caseText, caseBlock);
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new NodeNotFoundException(pipelineId, node.GetType().Name, nodeId);", methodCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ConnectPortsSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(ThreePortNode2), "CreateThreePortNode2Model")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificConnectPortsMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodSignature =
|
|
$"private void Connect__{nodeDescriptor.TypeNameShortSanitized}__NodePorts(string pipelineId, {nodeDescriptor.TypeNameFull} node, string nodeId, Dictionary<string, InputSource> inputs, IReadOnlyDictionary<string, INode> createdNodes)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificMethod_CallsBindingMethodForAllNodeOutputPorts()
|
|
{
|
|
var nodeDescriptor = ThreePortNode.GetDescriptor();
|
|
var methodName = $"Connect__{nodeDescriptor.TypeNameShortSanitized}__NodePorts";
|
|
|
|
var model = TestNodeModelFactory.CreateThreePortNodeModel();
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
foreach (var port in nodeDescriptor.Fields.Where(f =>
|
|
f.Direction == FieldDirection.Input || f.Direction == FieldDirection.Output))
|
|
{
|
|
var connectPortMethodCallStringV1 =
|
|
$"ConnectPortsStruct(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
var connectPortMethodCallStringV2 =
|
|
$"ConnectPortsClass(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
if (port.Direction == FieldDirection.Input)
|
|
Assert.True(methodCode.Contains(connectPortMethodCallStringV1) ||
|
|
methodCode.Contains(connectPortMethodCallStringV2));
|
|
else
|
|
Assert.False(methodCode.Contains(connectPortMethodCallStringV1) ||
|
|
methodCode.Contains(connectPortMethodCallStringV2));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(ThreePortNode2), "CreateThreePortNode2Model")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificMethod_ConnectPortsMethodCallOfRequiredInputPortShouldHaveIsRequiredParameterSet(
|
|
Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodName = $"Connect__{nodeDescriptor.TypeNameShortSanitized}__NodePorts";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var port in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Input))
|
|
{
|
|
var connectPortMethodCallString =
|
|
$"ConnectPortsStruct(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
var parametersString =
|
|
methodCode[
|
|
(methodCode.IndexOf(connectPortMethodCallString, StringComparison.Ordinal) +
|
|
connectPortMethodCallString.Length)..].Split(';')[0];
|
|
if (port.Metadata?.IsRequired == true) Assert.Contains("isRequired: true", parametersString);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(ThreePortNode2), "CreateThreePortNode2Model")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificMethod_ConnectPortsMethodCallOfRequiredInputPortShouldHaveDisallowNullableOutputParameterSet(
|
|
Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodName = $"Connect__{nodeDescriptor.TypeNameShortSanitized}__NodePorts";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var port in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Input))
|
|
{
|
|
var connectPortMethodCallStringV1 =
|
|
$"ConnectPortsStruct(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
var connectPortMethodCallStringV2 =
|
|
$"ConnectPortsClass(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
var parametersString = (methodCode.Contains(connectPortMethodCallStringV1)
|
|
? methodCode[
|
|
(methodCode.IndexOf(connectPortMethodCallStringV1, StringComparison.Ordinal) +
|
|
connectPortMethodCallStringV1.Length)..]
|
|
: methodCode.Contains(connectPortMethodCallStringV2)
|
|
? methodCode[
|
|
(methodCode.IndexOf(connectPortMethodCallStringV2, StringComparison.Ordinal) +
|
|
connectPortMethodCallStringV2.Length)..]
|
|
: null
|
|
)?.Split(';')[0] ?? string.Empty;
|
|
if (port.Metadata?.DisallowNullableOutput == true)
|
|
Assert.True(parametersString.Contains("disallowNullableOutput:true") ||
|
|
parametersString.Contains("disallowNullableOutput: true"));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreePortNodeWithReferenceAndStructInputs),
|
|
"CreateThreePortNodeWithReferenceAndStructInputsModel")]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(ThreePortNode2), "CreateThreePortNode2Model")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificMethod_CallAppropriateConnectPortsMethodBasedOnPortValueType(Type mockNodeType,
|
|
string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodName = $"Connect__{nodeDescriptor.TypeNameShortSanitized}__NodePorts";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
Assert.False(string.IsNullOrEmpty(methodCode), $"{methodName} method not found in generated code.");
|
|
|
|
foreach (var port in nodeDescriptor.Fields.Where(f => f.Direction == FieldDirection.Input))
|
|
{
|
|
var methodSuffix = port.IsValueReferenceType ? "Class" : "Struct";
|
|
var connectPortMethodCallString =
|
|
// $"ConnectPorts{methodSuffix}<{port.ValueType.TrimEnd('?')}>(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
$"ConnectPorts{methodSuffix}(pipelineId, nodeId, \"{nodeDescriptor.TypeNameShort}\", node.{port.PropertyName}, nameof(node.{port.PropertyName}), inputs, \"{port.FieldName}\", createdNodes";
|
|
Assert.Contains(connectPortMethodCallString, methodCode);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ParseParameter
|
|
|
|
[Fact]
|
|
public void ParseParameter_ShouldExistInGeneratedCode()
|
|
{
|
|
const string methodSignature = "private static T? ParseParameter<T>(string? valueString)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseParameter_ShouldContainAllEnumsMentionedInModelNodes()
|
|
{
|
|
const string methodName = "ParseParameter";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesWithEnumParametersModel();
|
|
|
|
var generatedCode = NodeFactoryGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
var assemblyEnumTypes = Assembly.GetAssembly(GetType())!
|
|
.GetTypes()
|
|
.Where(q => q.IsEnum)
|
|
.Select(q => q.FullName)
|
|
.Distinct().ToHashSet();
|
|
var allEnums = model.Nodes
|
|
.SelectMany(q => q.Fields)
|
|
.Where(q => q.Direction == FieldDirection.Parameter && assemblyEnumTypes.Contains(q.ValueType))
|
|
.Select(q => q.ValueType)
|
|
.Distinct();
|
|
foreach (var enumTypeString in allEnums)
|
|
{
|
|
var expectedString =
|
|
$"if (type == typeof({enumTypeString})) return (T)(object)Enum.Parse<{enumTypeString}>(valueString);";
|
|
Assert.Contains(expectedString, methodCode);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
//service
|
|
|
|
|
|
//TODO: test usings
|
|
//TODO: test public properties
|
|
} |