380 lines
18 KiB
C#
380 lines
18 KiB
C#
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 NodeValidatorGeneratorTests
|
|
{
|
|
#region GetAllPorts
|
|
|
|
[Fact]
|
|
public void GetAllPortsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignatureV1 =
|
|
"private IReadOnlyDictionary<NodePortKey, NodePortInfo> GetAllPorts(string pipelineId, INodeFactory nodeFactory, List<NodeConfig> allNodes)";
|
|
var methodSignatureV2 =
|
|
"private IReadOnlyDictionary<NodePortKey, NodePortInfo> GetAllPorts(string pipelineId, INodeFactory nodeFactory,"
|
|
+ Environment.NewLine + " List<NodeConfig> allNodes)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodeFieldValidator
|
|
|
|
[Fact]
|
|
public void GetNodeFieldValidatorMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature = "private INodeFieldValidator<T> GetNodeFieldValidator<T>(Type validatorType)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ValidateNodePorts
|
|
|
|
[Fact]
|
|
public void ValidateNodePortsMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignatureV1 =
|
|
"private ValidationResult ValidateNodePorts(string pipelineId, INodeFactory nodeFactory, string nodeType, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, out Dictionary<string, NodeFieldValidationResult> inputPortValidationResults, CultureInfo cultureInfo)";
|
|
var methodSignatureV2 =
|
|
"private ValidationResult ValidateNodePorts(string pipelineId, INodeFactory nodeFactory, string nodeType, string nodeId,"
|
|
+ Environment.NewLine +
|
|
" IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports,"
|
|
+ Environment.NewLine +
|
|
" out Dictionary<string, List<NodeFieldValidationResult>> inputPortValidationResults, CultureInfo cultureInfo)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ValidateInputPort
|
|
|
|
[Fact]
|
|
public void ValidateInputPortMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignatureV1 =
|
|
"private NodeFieldValidationResult ValidateInputPort(string nodeId, NodePortInfo inputPort, InputSource connection, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)";
|
|
var methodSignatureV2 =
|
|
"private NodeFieldValidationResult ValidateInputPort(string nodeId, NodePortInfo inputPort, InputSource connection,"
|
|
+ Environment.NewLine +
|
|
" IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNodeValidator
|
|
|
|
[Fact]
|
|
public void GetNodeValidatorMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature = "private INodeValidator GetNodeValidator(Type validatorType)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CheckRequiredNodeParameter
|
|
|
|
[Fact]
|
|
public void CheckRequiredNodeParameterMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature =
|
|
"private NodeFieldValidationResult CheckRequiredNodeParameter<T>(string nodeId, NodePipeline.Abstractions.Models.NodeField<T> nodeField, string nodeParameterName, CultureInfo cultureInfo)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SuccessNodeValidationResult
|
|
|
|
[Fact]
|
|
public void SuccessNodeValidationResultMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature =
|
|
"private static NodeValidationResult SuccessNodeValidationResult(bool hasWarnings, Dictionary<string, List<NodeFieldValidationResult>> fieldResults, Dictionary<string, List<NodeFieldValidationResult>> portResults)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetErrorValidationResult
|
|
|
|
[Fact]
|
|
public void GetErrorValidationResultMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature =
|
|
"private NodeValidationResult GetErrorValidationResult(ValidationResult validationResult, string nodeId, Dictionary<string, List<NodeFieldValidationResult>> fieldResults, Dictionary<string, List<NodeFieldValidationResult>> portResults, CultureInfo cultureInfo)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SuccessNodeFieldValidationResult
|
|
|
|
[Fact]
|
|
public void SuccessNodeFieldValidationResultMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignature = "private static NodeFieldValidationResult SuccessNodeFieldValidationResult()";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.Contains(methodSignature, generatedCode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateValidationResult
|
|
|
|
[Fact]
|
|
public void UpdateValidationResultMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignatureV1 =
|
|
"private static void UpdateValidationResult(ValidationResult validationResult, ref ValidationResult parametersValidationResult)";
|
|
var methodSignatureV2 = "private static void UpdateValidationResult(ValidationResult validationResult,"
|
|
+ Environment.NewLine + " ref ValidationResult parametersValidationResult)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ValidateNode
|
|
|
|
[Fact]
|
|
public void ValidateNodeMethod_ShouldExistInGeneratedCode()
|
|
{
|
|
var methodSignatureV1 =
|
|
"public NodeValidationResult ValidateNode(string pipelineId, INodeFactory nodeFactory, NodeConfig nodeConfig, List<NodeConfig> allNodes, Dictionary<string, object?> parameters, CultureInfo cultureInfo)";
|
|
var methodSignatureV2 =
|
|
"public NodeValidationResult ValidateNode(string pipelineId, INodeFactory nodeFactory, NodeConfig nodeConfig," +
|
|
Environment.NewLine +
|
|
"List<NodeConfig> allNodes, Dictionary<string, object?> parameters, CultureInfo cultureInfo)";
|
|
// var methodSignature = $"private static Dictionary<NodePortKey, NodePortInfo> Get__{GetNodeDescriptorFromMockNode(mockNodeType).TypeNameShortSanitized}__NodePorts(string nodeId)";
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
[Fact]
|
|
public void InitializeNodeFieldsMethod_ContainsSwitchCases()
|
|
{
|
|
var model = TestNodeModelFactory.CreateMultipleNodesModel();
|
|
var methodName = "ValidateNode";
|
|
var tCountByNodes = new Dictionary<NodeDescriptor, int>();
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
|
|
var firstTextV1 = "var node = nodeFactory.CreateNode(pipelineId, nodeConfig);"
|
|
+ Environment.NewLine +
|
|
" nodeFactory.SetNodeParametersValues(pipelineId, node, nodeConfig.Id, parameters);"
|
|
+ Environment.NewLine + " var nodeConnections = allNodes.SelectMany(q => q.Inputs"
|
|
+ Environment.NewLine +
|
|
" .Select(x => new KeyValuePair<string, InputSource>(GetNodeInputKey(q.Id, x.Key), x.Value))"
|
|
+ Environment.NewLine + " ).ToDictionary(q => q.Key, q => q.Value);"
|
|
+ Environment.NewLine + " var ports = GetAllPorts(pipelineId, nodeFactory, allNodes);";
|
|
var firstTextV2 = "var node = nodeFactory.CreateNode(pipelineId, nodeConfig);"
|
|
+ Environment.NewLine +
|
|
" nodeFactory.SetNodeParametersValues(pipelineId, node, nodeConfig.Id, parameters);"
|
|
+ Environment.NewLine +
|
|
" var nodeConnections = allNodes.SelectMany(q => q.Inputs.Select(x => new KeyValuePair<string, InputSource>(GetNodeInputKey(q.Id, x.Key), x.Value))).ToDictionary(q => q.Key, q => q.Value);"
|
|
+ Environment.NewLine + " var ports = GetAllPorts(pipelineId, nodeFactory, allNodes);";
|
|
Assert.True(methodCode.Contains(firstTextV1)
|
|
|| methodCode.Contains(firstTextV2));
|
|
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, @case);
|
|
Assert.False(string.IsNullOrEmpty(caseBlock), $"Case block for node {node.Type} not found.");
|
|
|
|
// var expectedCode = $"return Validate__{node.TypeNameShortSanitized}__Node(pipelineId, nodeFactory, t{tNumberString}, nodeConfig.Id, nodeConnections, ports, cultureInfo);";
|
|
// Assert.Contains(expectedCode, caseBlock);
|
|
Assert.Contains(
|
|
$"return Validate__{node.TypeNameShortSanitized}__Node(pipelineId, nodeFactory, t{tNumberString}, nodeConfig.Id, nodeConnections, ports, cultureInfo);",
|
|
caseBlock);
|
|
if (!tCountByNodes.TryGetValue(node, out var value)) tCountByNodes.Add(node, 1);
|
|
else tCountByNodes[node] = ++value;
|
|
}
|
|
|
|
Assert.Contains(
|
|
"default:" + Environment.NewLine +
|
|
" throw new UnknownNodeTypeException(nodeConfig.Type, nodeConfig.Id);", methodCode);
|
|
Assert.DoesNotContain(tCountByNodes.Values, q => q > 1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ValidateNodeSpecific
|
|
|
|
[Theory]
|
|
[InlineData(typeof(ThreeParameterNode), "CreateThreeParameterNodeModel")]
|
|
[InlineData(typeof(ThreePortNode), "CreateThreePortNodeModel")]
|
|
[InlineData(typeof(SimpleNamedNode), "CreateSimpleNamedNodeModel")]
|
|
public void SpecificValidateNodeMethod_ShouldExistInGeneratedCode(Type mockNodeType, string factoryMethod)
|
|
{
|
|
var nodeDescriptor = TestHelper.GetNodeDescriptorFromMockNode(mockNodeType);
|
|
var methodSignatureV1 =
|
|
$"private NodeValidationResult Validate__{nodeDescriptor.TypeNameShortSanitized}__Node(string pipelineId, INodeFactory nodeFactory, {nodeDescriptor.TypeNameFull} node,"
|
|
+ Environment.NewLine +
|
|
" string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)";
|
|
var methodSignatureV2 =
|
|
$"private NodeValidationResult Validate__{nodeDescriptor.TypeNameShortSanitized}__Node(string pipelineId, INodeFactory nodeFactory, {nodeDescriptor.TypeNameFull} node, string nodeId, IReadOnlyDictionary<string, InputSource> nodePortConnections, IReadOnlyDictionary<NodePortKey, NodePortInfo> ports, CultureInfo cultureInfo)";
|
|
var model = TestHelper.GetNodeModel(factoryMethod);
|
|
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
Assert.True(generatedCode.Contains(methodSignatureV1)
|
|
|| generatedCode.Contains(methodSignatureV2));
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificValidateNodeMethod_ShouldCallCheckRequiredNodeParameterOnlyForRequiredFields()
|
|
{
|
|
var nodeDescriptor = ThreeParameterNode.GetDescriptor();
|
|
var methodName = $"Validate__{nodeDescriptor.TypeNameShortSanitized}__Node";
|
|
|
|
var model = TestNodeModelFactory.CreateThreeParameterNodeModel();
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
var methodCode = TestHelper.ExtractMethod(generatedCode, methodName);
|
|
|
|
foreach (var parameter in nodeDescriptor.Fields.Where(q => q.Direction == FieldDirection.Parameter))
|
|
{
|
|
var expectedSecondPart =
|
|
$"CheckRequiredNodeParameter<{parameter.ValueType}>(nodeId, node.{parameter.PropertyName}, \"{parameter.FieldName}\", cultureInfo);";
|
|
if (parameter.Metadata?.IsRequired == true)
|
|
Assert.Contains(expectedSecondPart, methodCode);
|
|
else
|
|
Assert.DoesNotContain(expectedSecondPart, methodCode);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificValidateNodeMethod_ShouldContainAppropriateValidatorAtPropertyWithStringLengthConstraint()
|
|
{
|
|
string MethodName(NodeDescriptor n)
|
|
{
|
|
return $"Validate__{n.TypeNameShortSanitized}__Node";
|
|
}
|
|
|
|
string ExpectedString(NodeFieldDescriptor f)
|
|
{
|
|
return
|
|
$"= new StringLengthValidator(PipelineLocalizationProvider, {TestHelper.NumberToString(f.Metadata!.StringMinLength)}, {TestHelper.NumberToString(f.Metadata!.StringMaxLength)}).Validate(node.{f.PropertyName});";
|
|
}
|
|
|
|
var nodeDescriptor1 = ThreeParameterNode.GetDescriptor();
|
|
var nodeDescriptor2 = ThreeParameterNode2.GetDescriptor();
|
|
var nodeDescriptor3 = ThreeParameterNode3.GetDescriptor();
|
|
|
|
var model = TestNodeModelFactory.CreateMultipleNodesWithStringParameterLengthConstraints();
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
var m1 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor2));
|
|
var f1 = nodeDescriptor2.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode2.Parameter3));
|
|
var m2 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor1));
|
|
var f2 = nodeDescriptor1.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode.Parameter2));
|
|
var m3 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor3));
|
|
var f3 = nodeDescriptor3.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode3.Parameter3));
|
|
var es1 = ExpectedString(f1);
|
|
var es2 = ExpectedString(f2);
|
|
var es3 = ExpectedString(f3);
|
|
|
|
//check minlength constraint
|
|
Assert.Contains(es1, m1);
|
|
//check maxlength constraint
|
|
Assert.Contains(es2, m2);
|
|
//check length between constraint
|
|
Assert.Contains(es3, m3);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpecificValidateNodeMethod_ShouldContainAppropriateValidatorAtPropertyWithIntValidationConstraint()
|
|
{
|
|
string MethodName(NodeDescriptor n)
|
|
{
|
|
return $"Validate__{n.TypeNameShortSanitized}__Node";
|
|
}
|
|
|
|
string ExpectedString(NodeFieldDescriptor f)
|
|
{
|
|
return
|
|
$"= new NumberRangeValidator<{f.ValueType}>(PipelineLocalizationProvider, {TestHelper.NumberToString(f.Metadata!.NumberMinBound)}, {TestHelper.NumberToString(f.Metadata!.NumberMaxBound)}).Validate(node.{f.PropertyName});";
|
|
}
|
|
|
|
var nodeDescriptor1 = ThreeParameterNode.GetDescriptor();
|
|
var nodeDescriptor2 = ThreeParameterNode2.GetDescriptor();
|
|
|
|
var model = TestNodeModelFactory.CreateMultipleNodesWithStringParameterLengthConstraints();
|
|
var generatedCode = NodeValidatorGenerator.Generate(model);
|
|
|
|
var m1 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor2));
|
|
var f1 = nodeDescriptor2.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode2.Parameter1));
|
|
var m2 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor2));
|
|
var f2 = nodeDescriptor2.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode2.Parameter2));
|
|
var m3 = TestHelper.ExtractMethod(generatedCode, MethodName(nodeDescriptor1));
|
|
var f3 = nodeDescriptor1.Fields.First(q => q.PropertyName == nameof(ThreeParameterNode.Parameter1));
|
|
var es1 = ExpectedString(f1);
|
|
var es2 = ExpectedString(f2);
|
|
var es3 = ExpectedString(f3);
|
|
|
|
//check minlength constraint
|
|
Assert.Contains(es1, m1);
|
|
//check maxlength constraint
|
|
Assert.Contains(es2, m2);
|
|
//check length between constraint
|
|
Assert.Contains(es3, m3);
|
|
}
|
|
|
|
#endregion
|
|
} |