Skip to content

Commit 1c89ec2

Browse files
Remove NodeIds from StructureFieldDefinition (#133)
* Issue Resolved. * Add Testing for Structure Field Definitions
1 parent 9013039 commit 1c89ec2

File tree

4 files changed

+226
-8
lines changed

4 files changed

+226
-8
lines changed

NodeSetToAML.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,18 +2818,24 @@ private void ProcessReferenceType(ref InterfaceClassLibType icl, NodeId nodeId)
28182818
MinimizeNodeId( nodeIdAttribute );
28192819
}
28202820

2821-
private void RemoveUnwantedNodeIdAttribute( AttributeType attribute )
2821+
2822+
private void RemoveUnwantedAttribute(AttributeType attributeType, string attributeName)
28222823
{
2823-
if (attribute != null)
2824+
if (attributeType != null)
28242825
{
2825-
AttributeType unwantedNodeIdAttribute = attribute.Attribute["NodeId"];
2826-
if (unwantedNodeIdAttribute != null)
2826+
AttributeType unwantedAttribute = attributeType.Attribute[attributeName];
2827+
if (unwantedAttribute != null)
28272828
{
2828-
attribute.Attribute.RemoveElement(unwantedNodeIdAttribute);
2829+
attributeType.Attribute.RemoveElement(unwantedAttribute);
28292830
}
28302831
}
28312832
}
28322833

2834+
private void RemoveUnwantedNodeIdAttribute(AttributeType attribute)
2835+
{
2836+
RemoveUnwantedAttribute(attribute, "NodeId");
2837+
}
2838+
28332839
private void RemoveNodeIdsFromDefinition(AttributeType attribute)
28342840
{
28352841
if (attribute != null)
@@ -3162,6 +3168,11 @@ private void AddStructureFieldDefinition( AttributeFamilyType attribute, UANode
31623168
"IsOptional", "Boolean", new Variant( field.IsOptional) );
31633169

31643170
SetArrayDimensions( structureFieldAttribute.Attribute, field.ArrayDimensions );
3171+
RemoveUnwantedAttribute(structureFieldAttribute.Attribute["ArrayDimensions"], "StructureFieldDefinition");
3172+
if ( string.IsNullOrEmpty(field.ArrayDimensions))
3173+
{
3174+
RemoveUnwantedAttribute(structureFieldAttribute.Attribute["ArrayDimensions"], "UInt32");
3175+
}
31653176

31663177
AddModifyAttribute( structureFieldAttribute.Attribute,
31673178
"AllowSubtypes", "Boolean", new Variant( field.AllowSubTypes ) );
@@ -3176,13 +3187,20 @@ private void AddStructureFieldDefinition( AttributeFamilyType attribute, UANode
31763187
"Description", "LocalizedText", new Variant( localizedText ) );
31773188
}
31783189

3190+
RemoveUnwantedAttribute(structureFieldAttribute.Attribute["Description"],
3191+
"StructureFieldDefinition");
3192+
31793193
// Remove the NodeId from the structure Field
31803194
AttributeType nodeIdAttribute = structureFieldAttribute.Attribute[ "DataType" ];
31813195
if( nodeIdAttribute != null )
31823196
{
31833197
structureFieldAttribute.Attribute.RemoveElement( nodeIdAttribute );
31843198
}
31853199

3200+
RemoveUnwantedNodeIdAttribute(structureFieldAttribute);
3201+
RemoveNodeIdsFromDefinition(structureFieldAttribute);
3202+
3203+
31863204
fieldDefinitionAttribute.Attribute.Insert( structureFieldAttribute );
31873205
}
31883206
}

SystemTest/NodeSetFiles/TestAml.xml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<Alias Alias="SessionDiagnosticsDataType">i=865</Alias>
4141
<Alias Alias="SessionSecurityDiagnosticsDataType">i=868</Alias>
4242
<Alias Alias="SubscriptionDiagnosticsDataType">i=874</Alias>
43+
<Alias Alias="TransmitQosDataType">i=23604</Alias>
4344
<Alias Alias="NegotiationStatus">i=24216</Alias>
4445
<Alias Alias="LowLevelStructure">ns=1;i=3003</Alias>
4546

@@ -308,6 +309,8 @@
308309
</Definition>
309310
</UADataType>
310311

312+
313+
311314
<UAVariableType ValueRank="-2" NodeId="ns=1;i=2003" BrowseName="1:ComplexVariableType">
312315
<DisplayName>ComplexVariableType</DisplayName>
313316
<References>
@@ -318,8 +321,30 @@
318321
</References>
319322
</UAVariableType>
320323

324+
<UADataType NodeId="ns=1;i=3006" BrowseName="1:PublisherQosDataType">
325+
<DisplayName>PublisherQosDataType</DisplayName>
326+
<Category>UAFX AutomationComponent Base</Category>
327+
<Category>UAFX FunctionalEntity Base</Category>
328+
<Documentation>https://reference.opcfoundation.org/UAFX/Part81/v100/docs/10.36</Documentation>
329+
<References>
330+
<!--<Reference ReferenceType="HasEncoding" BrowseName="Default Binary">ns=1;i=5024</Reference>
331+
<Reference ReferenceType="HasEncoding" BrowseName="Default JSON">ns=1;i=5026</Reference>
332+
<Reference ReferenceType="HasEncoding" BrowseName="Default XML">ns=1;i=5025</Reference>-->
333+
<Reference ReferenceType="HasSubtype" IsForward="false">i=22</Reference>
334+
</References>
335+
<Definition Name="1:PublisherQosDataType">
336+
<Field Name="QosCategory" DataType="String" IsOptional="true" MaxStringLength="123">
337+
<Description Locale="en">Quality of Service Category</Description>
338+
</Field>
339+
<Field Name="DatagramQos" DataType="TransmitQosDataType" ValueRank="2" ArrayDimensions="2,3" AllowSubTypes="true">
340+
<Description>Transmit Quality of Service</Description>
341+
</Field>
342+
<Field Name="NoDescription" DataType="String" IsOptional="false" MaxStringLength="321"/>
343+
</Definition>
344+
</UADataType>
345+
321346

322-
<UAObject SymbolicName="http___opcfoundation_org_UA_FX_AML_TESTING" NodeId="ns=1;i=5000" BrowseName="1:http://opcfoundation.org/UA/FX/AML/TESTING" ParentNodeId="i=11715">
347+
<UAObject SymbolicName="http___opcfoundation_org_UA_FX_AML_TESTING" NodeId="ns=1;i=5000" BrowseName="1:http://opcfoundation.org/UA/FX/AML/TESTING" ParentNodeId="i=11715">
323348
<DisplayName>http://opcfoundation.org/UA/FX/AML/TESTING</DisplayName>
324349
<References>
325350
<Reference ReferenceType="HasComponent" IsForward="false">i=11715</Reference>
@@ -3538,7 +3563,7 @@
35383563
<!-- Next Numbers
35393564
ObjectType 1009
35403565
VariableType 2006
3541-
DataType 3006
3566+
DataType 3007
35423567
Object 5025
35433568
Variable 6238
35443569
-->

SystemTest/TestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static CAEXDocument GetReadOnlyDocument( string filename )
7979
{
8080
foreach( FileInfo fileInfo in RetrieveFiles() )
8181
{
82-
if( fileInfo.Name.Equals( filename ) )
82+
if( fileInfo.Name.Equals( filename, StringComparison.OrdinalIgnoreCase ) )
8383
{
8484
AutomationMLContainer container = new AutomationMLContainer( fileInfo.FullName,
8585
System.IO.FileMode.Open, FileAccess.Read );
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using System.Collections.Generic;
3+
using Aml.Engine.CAEX;
4+
using Aml.Engine.CAEX.Extensions;
5+
using System.Linq;
6+
using System;
7+
using Opc.Ua;
8+
9+
namespace SystemTest
10+
{
11+
[TestClass]
12+
public class TestStructureFieldDefinition
13+
{
14+
CAEXDocument m_document = null;
15+
16+
#region Tests
17+
private const uint PublisherQosDataType = 3006;
18+
19+
[TestMethod, Timeout(TestHelper.UnitTestTimeout)]
20+
[DataRow(TestHelper.Uris.Root, Opc.Ua.DataTypes.AggregateConfiguration, DisplayName = "Root AggregateConfiguration")]
21+
[DataRow(TestHelper.Uris.Test, PublisherQosDataType, DisplayName = "AutomationComponent PublisherQosDataType")]
22+
23+
public void TestUnwantedAttributes(TestHelper.Uris uriId, uint nodeId)
24+
{
25+
AttributeFamilyType objectToTest = GetTestAttribute(uriId, nodeId);
26+
27+
foreach( AttributeType attribute in objectToTest.Attribute )
28+
{
29+
if ( attribute.Name != "NodeId")
30+
{
31+
AttributeType structureAttribute = GetAttribute(attribute, "StructureFieldDefinition");
32+
foreach(AttributeType definitionAttribute in structureAttribute.Attribute)
33+
{
34+
// Make sure there is no NodeId for the StructureFieldDefinition
35+
// It's always Opc.Ua.DataTypes.StructureField (101)
36+
Assert.IsFalse(definitionAttribute.Name.Contains("NodeId"));
37+
// Make sure the structure field does not have a NodeId either.
38+
// It's always the known datatype of the field.
39+
Assert.IsNull(definitionAttribute.Attribute["NodeId"]);
40+
if ( definitionAttribute.Name.Equals("Description"))
41+
{
42+
// Make sure there is no structure field Definition.
43+
// It's always a known datatype of localized text
44+
Assert.IsNull(definitionAttribute.Attribute["StructureFieldDefinition"],
45+
"Unexpected StructureFieldDefinition found in Description: " + structureAttribute.Name);
46+
}
47+
}
48+
}
49+
}
50+
}
51+
52+
[TestMethod, Timeout(TestHelper.UnitTestTimeout)]
53+
[DataRow("QosCategory","Name", "QosCategory")]
54+
[DataRow("QosCategory", "Description", "Quality of Service Category")]
55+
[DataRow("QosCategory", "ValueRank", "-1")]
56+
[DataRow("QosCategory", "ArrayDimensions", null)]
57+
[DataRow("QosCategory", "MaxStringLength", "123")]
58+
[DataRow("QosCategory", "IsOptional", "true")]
59+
[DataRow("QosCategory", "AllowSubtypes", "false")]
60+
61+
[DataRow("DatagramQos", "Name", "DatagramQos")]
62+
[DataRow("DatagramQos", "Description", "Transmit Quality of Service")]
63+
[DataRow("DatagramQos", "ValueRank", "2")]
64+
[DataRow("DatagramQos", "MaxStringLength", "0")]
65+
[DataRow("DatagramQos", "IsOptional", "false")]
66+
[DataRow("DatagramQos", "AllowSubtypes", "true")]
67+
68+
[DataRow("NoDescription", "Name", "NoDescription")]
69+
[DataRow("NoDescription", "Description", null)]
70+
[DataRow("NoDescription", "ValueRank", "-1")]
71+
[DataRow("NoDescription", "ArrayDimensions", null)]
72+
[DataRow("NoDescription", "MaxStringLength", "321")]
73+
[DataRow("NoDescription", "IsOptional", "false")]
74+
[DataRow("NoDescription", "AllowSubtypes", "false")]
75+
76+
public void TestAttributeValues(string variableName,
77+
string attributeName,
78+
string expectedValue)
79+
{
80+
AttributeValues(variableName, attributeName, expectedValue);
81+
}
82+
83+
[TestMethod, Timeout(TestHelper.UnitTestTimeout)]
84+
public void TestDescriptionLocale()
85+
{
86+
AttributeValues("QosCategory", "Description", "Quality of Service Category", "en");
87+
}
88+
89+
[TestMethod, Timeout(TestHelper.UnitTestTimeout)]
90+
public void TestArrayDimensions()
91+
{
92+
AttributeType structured = GetStructured(TestHelper.Uris.Test,
93+
PublisherQosDataType, "DatagramQos");
94+
AttributeType attribute = GetAttribute(structured, "ArrayDimensions");
95+
AttributeType first = GetAttribute(attribute, "0");
96+
Assert.AreEqual("2", first.Value, "Unexpected value for ArrayDimensions[0].");
97+
AttributeType second = GetAttribute(attribute, "1");
98+
Assert.AreEqual("3", second.Value, "Unexpected value for ArrayDimensions[1].");
99+
}
100+
101+
public void AttributeValues(string variableName,
102+
string attributeName,
103+
string expectedValue,
104+
string localeId = "")
105+
{
106+
AttributeFamilyType objectToTest = GetTestAttribute(TestHelper.Uris.Test,
107+
PublisherQosDataType);
108+
109+
AttributeType variableAttribute = GetAttribute(objectToTest.Attribute, variableName);
110+
AttributeType structured = GetAttribute(variableAttribute, "StructureFieldDefinition");
111+
AttributeType attribute = GetAttribute(structured.Attribute, attributeName);
112+
Assert.AreEqual(expectedValue, attribute.Value,
113+
$"Unexpected value for {variableName}.{attributeName} in {structured.Name}.");
114+
115+
if (!string.IsNullOrEmpty(localeId))
116+
{
117+
AttributeType locale = GetAttribute(attribute.Attribute, localeId);
118+
Assert.AreEqual(expectedValue, locale.Value,
119+
$"Unexpected locale value for {variableName}.{attributeName} in {structured.Name}.");
120+
}
121+
}
122+
123+
124+
125+
#endregion
126+
127+
#region Helpers
128+
129+
private CAEXDocument GetDocument()
130+
{
131+
if( m_document == null )
132+
{
133+
m_document = TestHelper.GetReadOnlyDocument( "TestAml.xml.amlx" );
134+
}
135+
Assert.IsNotNull( m_document, "Unable to retrieve Document" );
136+
return m_document;
137+
}
138+
139+
public AttributeFamilyType GetTestAttribute( TestHelper.Uris uriId, uint nodeId )
140+
{
141+
CAEXDocument document = GetDocument();
142+
string amlId = TestHelper.BuildAmlId("", uriId, nodeId.ToString() );
143+
Console.WriteLine( "Looking for " + amlId );
144+
CAEXObject initialObject = document.FindByID( amlId );
145+
Assert.IsNotNull( initialObject, "Unable to find Initial Object" );
146+
AttributeFamilyType theObject = initialObject as AttributeFamilyType;
147+
Assert.IsNotNull( theObject, "Unable to Cast Initial Object" );
148+
return theObject;
149+
}
150+
151+
public AttributeType GetAttribute(AttributeType attributeType, string attributeName)
152+
{
153+
Assert.IsNotNull(attributeType, "AttributeType is null");
154+
return GetAttribute(attributeType.Attribute, attributeName);
155+
}
156+
157+
public AttributeType GetAttribute( AttributeSequence attributes, string attributeName)
158+
{
159+
Assert.IsNotNull(attributes, "AttributeType is null");
160+
AttributeType result = attributes[attributeName];
161+
Assert.IsNotNull(result, "Unable to find Attribute " + attributeName);
162+
return result;
163+
}
164+
165+
public AttributeType GetStructured(TestHelper.Uris uriId, uint nodeId, string variableName)
166+
{
167+
AttributeFamilyType objectToTest = GetTestAttribute(uriId, nodeId);
168+
AttributeType variableAttribute = GetAttribute(objectToTest.Attribute, variableName);
169+
AttributeType structured = GetAttribute(variableAttribute, "StructureFieldDefinition");
170+
return structured;
171+
}
172+
173+
#endregion
174+
}
175+
}

0 commit comments

Comments
 (0)