Skip to content

Commit 7cd5ae3

Browse files
Copilotromanett
andauthored
Fix ExtractValueFromVariant method call condition (#3382)
* Initial plan * Changes before error encountered Co-authored-by: romanett <[email protected]> * Fix ExtractValueFromVariant condition and add comprehensive tests Co-authored-by: romanett <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: romanett <[email protected]>
1 parent 05e171a commit 7cd5ae3

File tree

2 files changed

+203
-1
lines changed

2 files changed

+203
-1
lines changed

Stack/Opc.Ua.Types/State/BaseVariableState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ public object Value
523523
get => m_value;
524524
set
525525
{
526-
if (value == null && IsValueType)
526+
if (value != null && IsValueType)
527527
{
528528
value = ExtractValueFromVariant(null, value, false);
529529
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/* ========================================================================
2+
* Copyright (c) 2005-2018 The OPC Foundation, Inc. All rights reserved.
3+
*
4+
* OPC Foundation MIT License 1.00
5+
*
6+
* Permission is hereby granted, free of charge, to any person
7+
* obtaining a copy of this software and associated documentation
8+
* files (the "Software"), to deal in the Software without
9+
* restriction, including without limitation the rights to use,
10+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the
12+
* Software is furnished to do so, subject to the following
13+
* conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be
16+
* included in all copies or substantial portions of the Software.
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24+
* OTHER DEALINGS IN THE SOFTWARE.
25+
*
26+
* The complete license agreement can be found here:
27+
* http://opcfoundation.org/License/MIT/1.00/
28+
* ======================================================================*/
29+
30+
using NUnit.Framework;
31+
using Opc.Ua.Tests;
32+
using Assert = NUnit.Framework.Legacy.ClassicAssert;
33+
34+
namespace Opc.Ua.Types.Tests.State
35+
{
36+
/// <summary>
37+
/// Tests for ExtractValueFromVariant method in BaseVariableState.
38+
/// </summary>
39+
[TestFixture]
40+
[Category("ExtractValueFromVariant")]
41+
[SetCulture("en-us")]
42+
[SetUICulture("en-us")]
43+
[Parallelizable]
44+
public class ExtractValueFromVariantTests
45+
{
46+
private IServiceMessageContext m_context;
47+
private ITelemetryContext m_telemetry;
48+
49+
[OneTimeSetUp]
50+
protected void OneTimeSetUp()
51+
{
52+
m_telemetry = NUnitTelemetryContext.Create();
53+
m_context = new ServiceMessageContext(m_telemetry);
54+
}
55+
56+
[OneTimeTearDown]
57+
protected void OneTimeTearDown()
58+
{
59+
CoreUtils.SilentDispose(m_context);
60+
}
61+
62+
/// <summary>
63+
/// Test that setting a value wrapped in an ExtensionObject extracts the body correctly.
64+
/// </summary>
65+
[Test]
66+
public void PropertyStateExtractsValueFromExtensionObject()
67+
{
68+
// Create a PropertyState for Argument type (IEncodeable)
69+
var propertyState = new PropertyState<Argument>(null);
70+
71+
// Create an Argument (IEncodeable type that can be in ExtensionObject)
72+
var testArg = new Argument("arg1", DataTypeIds.String, -1, "test description");
73+
74+
// Wrap in ExtensionObject
75+
var extensionObject = new ExtensionObject(testArg);
76+
77+
// Set the value using the base Value property (object type)
78+
// This should trigger ExtractValueFromVariant to unwrap the ExtensionObject
79+
((BaseVariableState)propertyState).Value = extensionObject;
80+
81+
// The value should be extracted from the ExtensionObject
82+
Assert.IsNotNull(propertyState.Value);
83+
Assert.AreEqual("arg1", propertyState.Value.Name);
84+
Assert.AreEqual("test description", propertyState.Value.Description.Text);
85+
}
86+
87+
/// <summary>
88+
/// Test that setting a value wrapped in an ExtensionObject for a complex type extracts correctly.
89+
/// </summary>
90+
[Test]
91+
public void PropertyStateExtractsComplexTypeFromExtensionObject()
92+
{
93+
// Create a PropertyState for RelativePath type (IEncodeable)
94+
var propertyState = new PropertyState<RelativePath>(null);
95+
96+
// Create a RelativePath (IEncodeable type)
97+
var testValue = new RelativePath
98+
{
99+
Elements = new RelativePathElementCollection
100+
{
101+
new RelativePathElement
102+
{
103+
TargetName = new QualifiedName("TestName"),
104+
IsInverse = false
105+
}
106+
}
107+
};
108+
109+
var extensionObject = new ExtensionObject(testValue);
110+
111+
// Set the value
112+
((BaseVariableState)propertyState).Value = extensionObject;
113+
114+
// The value should be extracted
115+
Assert.IsNotNull(propertyState.Value);
116+
Assert.IsNotNull(propertyState.Value.Elements);
117+
Assert.AreEqual(1, propertyState.Value.Elements.Count);
118+
Assert.AreEqual("TestName", propertyState.Value.Elements[0].TargetName.Name);
119+
}
120+
121+
/// <summary>
122+
/// Test that setting a direct value (not wrapped) still works correctly.
123+
/// </summary>
124+
[Test]
125+
public void PropertyStateAcceptsDirectValue()
126+
{
127+
var propertyState = new PropertyState<string>(null);
128+
var testString = "DirectValue";
129+
130+
// Set value directly (not in ExtensionObject)
131+
((BaseVariableState)propertyState).Value = testString;
132+
133+
Assert.AreEqual(testString, propertyState.Value);
134+
}
135+
136+
/// <summary>
137+
/// Test that setting null value works correctly.
138+
/// </summary>
139+
[Test]
140+
public void PropertyStateAcceptsNullValue()
141+
{
142+
var propertyState = new PropertyState<string>(null);
143+
144+
// Set null value
145+
((BaseVariableState)propertyState).Value = null;
146+
147+
Assert.IsNull(propertyState.Value);
148+
}
149+
150+
/// <summary>
151+
/// Test with BaseDataVariableState to ensure the fix works for all variable types.
152+
/// </summary>
153+
[Test]
154+
public void BaseDataVariableStateExtractsValueFromExtensionObject()
155+
{
156+
var variableState = new BaseDataVariableState<Argument>(null);
157+
158+
// Create an Argument (IEncodeable type)
159+
var testArg = new Argument("testArg", DataTypeIds.Int32, -1, "test description");
160+
var extensionObject = new ExtensionObject(testArg);
161+
162+
((BaseVariableState)variableState).Value = extensionObject;
163+
164+
Assert.IsNotNull(variableState.Value);
165+
Assert.AreEqual("testArg", variableState.Value.Name);
166+
}
167+
168+
/// <summary>
169+
/// Test that Variant values are properly unwrapped.
170+
/// </summary>
171+
[Test]
172+
public void PropertyStateExtractsValueFromVariant()
173+
{
174+
var propertyState = new PropertyState<string>(null);
175+
var testString = "VariantValue";
176+
var variant = new Variant(testString);
177+
178+
// Use WrappedValue property which calls ExtractValueFromVariant
179+
propertyState.WrappedValue = variant;
180+
181+
Assert.AreEqual(testString, propertyState.Value);
182+
}
183+
184+
/// <summary>
185+
/// Test that Variant with ExtensionObject is properly unwrapped.
186+
/// </summary>
187+
[Test]
188+
public void PropertyStateExtractsValueFromVariantWithExtensionObject()
189+
{
190+
var propertyState = new PropertyState<Argument>(null);
191+
var testArg = new Argument("variantArg", DataTypeIds.Double, -1, "test description");
192+
var extensionObject = new ExtensionObject(testArg);
193+
var variant = new Variant(extensionObject);
194+
195+
// Use WrappedValue property
196+
propertyState.WrappedValue = variant;
197+
198+
Assert.IsNotNull(propertyState.Value);
199+
Assert.AreEqual("variantArg", propertyState.Value.Name);
200+
}
201+
}
202+
}

0 commit comments

Comments
 (0)