From 60e7551dbd0305695c93c4dfc0c3503fad803b89 Mon Sep 17 00:00:00 2001 From: zhaoxi <535394140@qq.com> Date: Mon, 17 Feb 2025 15:14:26 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20OPC=20UA=20=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=A2=9E=E5=8A=A0=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=9A=84=E8=BD=AC=E6=8D=A2=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8C=E5=B9=B6=E5=A2=9E=E5=8A=A0=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E7=A9=BA=E9=97=B4=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/opcua/include/rmvl/opcua/variable.hpp | 34 +++++- modules/opcua/test/test_opcua_addrspace.cpp | 105 ++++++++++++++++++ modules/opcua/test/test_opcua_server.cpp | 25 +---- 3 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 modules/opcua/test/test_opcua_addrspace.cpp diff --git a/modules/opcua/include/rmvl/opcua/variable.hpp b/modules/opcua/include/rmvl/opcua/variable.hpp index 8c88550..519014d 100644 --- a/modules/opcua/include/rmvl/opcua/variable.hpp +++ b/modules/opcua/include/rmvl/opcua/variable.hpp @@ -60,7 +60,7 @@ class RMVL_EXPORTS_W VariableType final * @param[in] str 字符串 */ template - VariableType(const char (&str)[N]) : VariableType(std::string(str, N)) {} + VariableType(const char (&str)[N]) : VariableType(std::string(str)) {} /** * @brief 列表构造,设置默认值 @@ -72,6 +72,15 @@ class RMVL_EXPORTS_W VariableType final RMVL_W_SUBST("VT_List") VariableType(const std::vector &arr) : _value(arr), _data_type(DataType(typeid(Tp))), _size(arr.size()) {} + /** + * @brief 初始化列表构造,设置默认值 + * + * @tparam Tp 变量的存储数据类型,必须是基础类型 + * @param[in] il 初始化列表 + */ + template && !std::is_same_v>> + VariableType(std::initializer_list il) : VariableType(std::vector(il)) {} + /** * @brief 将变量类型节点转化为指定类型的数据 * @@ -178,6 +187,15 @@ class RMVL_EXPORTS_W Variable final RMVL_W_SUBST("V_List") Variable(const std::vector &arr) : _value(arr), _data_type(DataType(typeid(Tp))), _size(static_cast(arr.size())) {} + /** + * @brief 初始化列表构造,设置默认值 + * + * @tparam Tp 变量的存储数据类型,必须是基础类型 + * @param[in] il 初始化列表 + */ + template && !std::is_same_v>> + Variable(std::initializer_list il) : Variable(std::vector(il)) {} + /** * @brief 从变量类型创建新的变量节点 * @@ -197,7 +215,7 @@ class RMVL_EXPORTS_W Variable final /** * @brief 比较两个变量是否不等 - * @see `rm::Variable::operator==` + * @see rm::Variable::operator==() * * @param[in] val 另一个变量 * @return 是否不等 @@ -269,6 +287,8 @@ class RMVL_EXPORTS_W Variable final * - 属于非服务器层面的 ID 号,可用于完成路径搜索 * @brief * - 同一个命名空间 `ns` 下该名称不能重复 + * @brief + * - 仅用于标识服务器上的变量节点,不参与变量的比较 */ RMVL_W_RW std::string browse_name{}; @@ -278,6 +298,8 @@ class RMVL_EXPORTS_W Variable final * - 在服务器上对外展示的名字 - `en-US` * @brief * - 同一个命名空间 `ns` 下该名称可以相同 + * @brief + * - 仅用于标识服务器上的变量节点,不参与变量的比较 */ RMVL_W_RW std::string display_name{}; //! 变量的描述 @@ -302,8 +324,8 @@ class RMVL_EXPORTS_W Variable final * @param[in] val 变量类型的名称 * @param[in] ... 构造列表 */ -#define uaCreateVariableType(val, ...) \ - rm::VariableType val{__VA_ARGS__}; \ +#define uaCreateVariableType(val, ...) \ + rm::VariableType val = __VA_ARGS__; \ val.browse_name = val.display_name = val.description = #val /** @@ -312,8 +334,8 @@ class RMVL_EXPORTS_W Variable final * @param[in] val 变量的名称 * @param[in] ... 构造列表 */ -#define uaCreateVariable(val, ...) \ - rm::Variable val{__VA_ARGS__}; \ +#define uaCreateVariable(val, ...) \ + rm::Variable val = __VA_ARGS__; \ val.browse_name = val.display_name = val.description = #val //! 变量列表别名 diff --git a/modules/opcua/test/test_opcua_addrspace.cpp b/modules/opcua/test/test_opcua_addrspace.cpp new file mode 100644 index 0000000..e241d86 --- /dev/null +++ b/modules/opcua/test/test_opcua_addrspace.cpp @@ -0,0 +1,105 @@ +/** + * @file test_opcua_addrspace.cpp + * @author zhaoxi (535394140@qq.com) + * @brief OPC UA 地址空间模型单元测试 + * @version 1.0 + * @date 2025-02-17 + * + * @copyright Copyright 2025 (c), zhaoxi + * + */ + +#include + +#include "rmvl/opcua/object.hpp" + +namespace rm_test +{ + +TEST(OPC_UA_AddressSpace, Variable) +{ + // 单值构造 + rm::Variable val1 = 42; + EXPECT_EQ(val1.size(), 1); + EXPECT_EQ(val1.getDataType(), rm::tpInt32); + + rm::Variable val2 = 3.1415; + EXPECT_EQ(val2.size(), 1); + EXPECT_EQ(val2.getDataType(), rm::tpDouble); + + rm::Variable val3 = false; + EXPECT_EQ(val3.size(), 1); + EXPECT_EQ(val3.getDataType(), rm::tpBoolean); + + rm::Variable val4 = "test"; + EXPECT_EQ(val4.size(), 1); + EXPECT_EQ(val4.getDataType(), rm::tpString); + + rm::Variable val5 = std::string("test"); + EXPECT_EQ(val5.size(), 1); + EXPECT_EQ(val5.getDataType(), rm::tpString); + + // 列表构造 + rm::Variable arr1 = {1, 2, 3}; + EXPECT_EQ(arr1.size(), 3); + EXPECT_EQ(arr1.getDataType(), rm::tpInt32); + + rm::Variable arr2 = {3.142, 2.718, 1.414}; + EXPECT_EQ(arr2.size(), 3); + EXPECT_EQ(arr2.getDataType(), rm::tpDouble); + + rm::Variable arr3 = std::vector{1, 2, 3}; + EXPECT_EQ(arr3.size(), 3); + EXPECT_EQ(arr3.getDataType(), rm::tpInt32); + + // 单值比较 + EXPECT_EQ(val1, 42); + EXPECT_EQ(val2, 3.1415); + EXPECT_EQ(val3, false); + EXPECT_EQ(val4, "test"); + EXPECT_EQ(val5, val4); + + // 列表比较 + EXPECT_EQ(arr1, arr3); + std::vector arr{3.142, 2.718, 1.414}; + EXPECT_EQ(arr2, arr); +} + +TEST(OPC_UA_AddressSpace, VariableType) +{ + // 单值构造 + rm::VariableType vt1 = 42; + EXPECT_EQ(vt1.size(), 1); + EXPECT_EQ(vt1.getDataType(), rm::tpInt32); + + rm::VariableType vt2 = 3.1415; + EXPECT_EQ(vt2.size(), 1); + EXPECT_EQ(vt2.getDataType(), rm::tpDouble); + + rm::VariableType vt3 = false; + EXPECT_EQ(vt3.size(), 1); + EXPECT_EQ(vt3.getDataType(), rm::tpBoolean); + + rm::VariableType vt4 = "test"; + EXPECT_EQ(vt4.size(), 1); + EXPECT_EQ(vt4.getDataType(), rm::tpString); + + rm::VariableType vt5 = std::string("test"); + EXPECT_EQ(vt5.size(), 1); + EXPECT_EQ(vt5.getDataType(), rm::tpString); + + // 列表构造 + rm::VariableType at1 = {1, 2, 3}; + EXPECT_EQ(at1.size(), 3); + EXPECT_EQ(at1.getDataType(), rm::tpInt32); + + rm::VariableType at2 = {3.142, 2.718, 1.414}; + EXPECT_EQ(at2.size(), 3); + EXPECT_EQ(at2.getDataType(), rm::tpDouble); + + rm::VariableType at3 = std::vector{1, 2, 3}; + EXPECT_EQ(at3.size(), 3); + EXPECT_EQ(at3.getDataType(), rm::tpInt32); +} + +} // namespace rm_test \ No newline at end of file diff --git a/modules/opcua/test/test_opcua_server.cpp b/modules/opcua/test/test_opcua_server.cpp index c2cff8e..daf626b 100644 --- a/modules/opcua/test/test_opcua_server.cpp +++ b/modules/opcua/test/test_opcua_server.cpp @@ -18,28 +18,11 @@ namespace rm_test { -// 变量(类型)配置 -TEST(OPC_UA_Server, variable_config) -{ - // 变量类型节点、字符串 - rm::VariableType variable_type = "string_test"; - EXPECT_EQ(variable_type.size(), 1); - EXPECT_EQ(variable_type.getDataType(), UA_TYPES_STRING); - // 添加变量节点、双精度浮点数 - rm::Variable variable = 3.1415; - EXPECT_EQ(variable.size(), 1); - EXPECT_EQ(variable.getDataType(), UA_TYPES_DOUBLE); - // 添加变量节点、数组 - rm::Variable variable_array = std::vector{1, 2, 3}; - EXPECT_EQ(variable_array.size(), 3); - EXPECT_EQ(variable_array.getDataType(), UA_TYPES_INT32); -} - // 服务器添加变量节点 TEST(OPC_UA_Server, add_variable_node) { rm::Server srv(4810, "TestServer"); - rm::Variable variable{3.1415}; + rm::Variable variable = 3.1415; variable.browse_name = "test_double"; variable.description = "this is test double"; variable.display_name = "测试双精度浮点数"; @@ -68,9 +51,7 @@ TEST(OPC_UA_Server, add_data_source_variable_node) v.browse_name = v.display_name = "test_int"; v.description = "this is test int"; v.on_read = [&](const rm::NodeId &) -> rm::Variable { return data_source; }; - v.on_write = [&](const rm::NodeId &, const rm::Variable &val) { - data_source = val.cast(); - }; + v.on_write = [&](const rm::NodeId &, const rm::Variable &val) { data_source = val.cast(); }; auto node = srv.addDataSourceVariableNode(v); EXPECT_FALSE(node.empty()); srv.spinOnce(); @@ -80,7 +61,7 @@ TEST(OPC_UA_Server, add_data_source_variable_node) TEST(OPC_UA_Server, add_variable_type_node) { rm::Server srv(4830); - rm::VariableType variable_type{"string_test"}; + rm::VariableType variable_type = "string_test"; variable_type.browse_name = "test_string"; variable_type.description = "this is test string"; variable_type.display_name = "测试字符串";