4#include <gtest/gtest.h>
25constexpr const char* MINIMAL_GSDML = R
"xml(
28 <DeviceIdentity VendorID="0x002A" DeviceID="0x0003"/>
30 <Name Value="Test Device"/>
33 <DeviceAccessPointList>
34 <DeviceAccessPointItem ID="DAP_1"
35 ModuleIdentNumber="0x00000001"
36 SubmoduleIdentNumber="0x00000001">
37 <SystemDefinedSubmoduleList>
38 <InterfaceSubmoduleItem
40 SubmoduleIdentNumber="0x00000100"/>
43 SubmoduleIdentNumber="0x00000200"/>
44 </SystemDefinedSubmoduleList>
45 <VirtualSubmoduleList>
46 <VirtualSubmoduleItem ID="DAP_Sub"
47 SubmoduleIdentNumber="0x00000001">
50 <DataItem DataType="Unsigned8"/>
53 </VirtualSubmoduleItem>
54 </VirtualSubmoduleList>
56 <ModuleItemRef ModuleItemTarget="MOD_INPUT"
57 AllowedInSlots="1..5"/>
58 <ModuleItemRef ModuleItemTarget="MOD_OUTPUT"
59 AllowedInSlots="1..5"/>
61 <PredefinedPnioModules>
62 <PnioModuleItemRef ModuleItemTarget="MOD_INPUT"
64 <PnioModuleItemRef ModuleItemTarget="MOD_OUTPUT"
66 </PredefinedPnioModules>
67 </DeviceAccessPointItem>
68 </DeviceAccessPointList>
70 <ModuleItem ID="MOD_INPUT"
71 ModuleIdentNumber="0x00000010">
72 <VirtualSubmoduleList>
73 <VirtualSubmoduleItem ID="MOD_IN_Sub"
74 SubmoduleIdentNumber="0x00000001">
77 <DataItem DataType="OctetString" Length="4"/>
80 </VirtualSubmoduleItem>
81 </VirtualSubmoduleList>
83 <ModuleItem ID="MOD_OUTPUT"
84 ModuleIdentNumber="0x00000020">
85 <VirtualSubmoduleList>
86 <VirtualSubmoduleItem ID="MOD_OUT_Sub"
87 SubmoduleIdentNumber="0x00000001">
90 <DataItem DataType="Unsigned16"/>
93 </VirtualSubmoduleItem>
94 </VirtualSubmoduleList>
103constexpr const char* NAMESPACED_GSDML = R
"xml(
104<ISO15745Profile xmlns="http://www.profibus.com/GSDML/2.4">
106 <DeviceIdentity VendorID="0x0042" DeviceID="0x0007"/>
108 <DeviceAccessPointList>
109 <DeviceAccessPointItem ID="DAP_NS"
110 ModuleIdentNumber="0x00000002"
111 SubmoduleIdentNumber="0x00000001">
112 <VirtualSubmoduleList>
113 <VirtualSubmoduleItem ID="Sub1"
114 SubmoduleIdentNumber="0x00000001">
117 <DataItem DataType="Unsigned32"/>
120 </VirtualSubmoduleItem>
121 </VirtualSubmoduleList>
122 </DeviceAccessPointItem>
123 </DeviceAccessPointList>
125 <ModuleItem ID="MOD_A"
126 ModuleIdentNumber="0x000000AA">
127 <VirtualSubmoduleList>
128 <VirtualSubmoduleItem ID="MOD_A_Sub"
129 SubmoduleIdentNumber="0x00000001">
132 <DataItem DataType="Float32"/>
135 </VirtualSubmoduleItem>
136 </VirtualSubmoduleList>
139 </ApplicationProcess>
145constexpr const char* DATA_TYPES_GSDML = R
"xml(
148 <DeviceIdentity VendorID="42" DeviceID="7"/>
150 <DeviceAccessPointList>
151 <DeviceAccessPointItem ID="DAP"
152 ModuleIdentNumber="1"
153 SubmoduleIdentNumber="1">
154 <VirtualSubmoduleList>
155 <VirtualSubmoduleItem ID="DATA"
156 SubmoduleIdentNumber="1">
159 <DataItem DataType="Unsigned8"/>
160 <DataItem DataType="Unsigned16"/>
161 <DataItem DataType="Unsigned32"/>
162 <DataItem DataType="Float32"/>
163 <DataItem DataType="Float64"/>
164 <DataItem DataType="Integer16"/>
165 <DataItem DataType="Boolean"/>
166 <DataItem DataType="OctetString" Length="10"/>
167 <DataItem DataType="VisibleString" Length="32"/>
170 </VirtualSubmoduleItem>
171 </VirtualSubmoduleList>
172 </DeviceAccessPointItem>
173 </DeviceAccessPointList>
175 </ApplicationProcess>
181class GsdmlTest :
public ::testing::Test
187 static GSDMLDevice Parse(
const std::string& xml)
197 static const rpc::IOSlot& FindSlot(
const std::vector<rpc::IOSlot>& slots,
199 std::uint16_t subslot)
201 for (
const auto& value : slots)
203 if (value.slot == slot && value.subslot == subslot)
209 ADD_FAILURE() <<
"Slot " << slot <<
":" << subslot <<
" was not found";
210 return slots.front();
217 static std::vector<rpc::IOSlot> FindSlots(
const std::vector<rpc::IOSlot>& slots,
220 std::vector<rpc::IOSlot> result;
222 for (
const auto& value : slots)
224 if (value.slot == slot)
226 result.push_back(value);
239TEST_F(GsdmlTest, Unsigned8HasLengthOne)
241 const auto dev = Parse(R
"xml(
244 <DeviceIdentity VendorID="1" DeviceID="2"/>
246 <DeviceAccessPointList>
247 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
248 <VirtualSubmoduleList>
249 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
252 <DataItem DataType="Unsigned8"/>
255 </VirtualSubmoduleItem>
256 </VirtualSubmoduleList>
257 </DeviceAccessPointItem>
258 </DeviceAccessPointList>
259 </ApplicationProcess>
264 const auto slots = dev.BuildIoSlots();
266 EXPECT_EQ(slots.size(), 1U);
267 EXPECT_EQ(slots[0].inputLength, 1U);
268 EXPECT_EQ(slots[0].outputLength, 0U);
272TEST_F(GsdmlTest, Unsigned16HasLengthTwo)
274 const auto dev = Parse(R
"xml(
277 <DeviceIdentity VendorID="1" DeviceID="2"/>
279 <DeviceAccessPointList>
280 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
281 <VirtualSubmoduleList>
282 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
285 <DataItem DataType="Unsigned16"/>
288 </VirtualSubmoduleItem>
289 </VirtualSubmoduleList>
290 </DeviceAccessPointItem>
291 </DeviceAccessPointList>
292 </ApplicationProcess>
297 const auto slots = dev.BuildIoSlots();
299 ASSERT_EQ(slots.size(), 1U);
300 EXPECT_EQ(slots[0].inputLength, 2U);
304TEST_F(GsdmlTest, Unsigned32HasLengthFour)
306 const auto dev = Parse(R
"xml(
309 <DeviceIdentity VendorID="1" DeviceID="2"/>
311 <DeviceAccessPointList>
312 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
313 <VirtualSubmoduleList>
314 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
317 <DataItem DataType="Unsigned32"/>
320 </VirtualSubmoduleItem>
321 </VirtualSubmoduleList>
322 </DeviceAccessPointItem>
323 </DeviceAccessPointList>
324 </ApplicationProcess>
329 const auto slots = dev.BuildIoSlots();
331 ASSERT_EQ(slots.size(), 1U);
332 EXPECT_EQ(slots[0].outputLength, 4U);
336TEST_F(GsdmlTest, Float32HasLengthFour)
338 const auto dev = Parse(R
"xml(
341 <DeviceIdentity VendorID="1" DeviceID="2"/>
343 <DeviceAccessPointList>
344 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
345 <VirtualSubmoduleList>
346 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
349 <DataItem DataType="Float32"/>
352 </VirtualSubmoduleItem>
353 </VirtualSubmoduleList>
354 </DeviceAccessPointItem>
355 </DeviceAccessPointList>
356 </ApplicationProcess>
361 const auto slots = dev.BuildIoSlots();
363 ASSERT_EQ(slots.size(), 1U);
364 EXPECT_EQ(slots[0].inputLength, 4U);
368TEST_F(GsdmlTest, Float64HasLengthEight)
370 const auto dev = Parse(R
"xml(
373 <DeviceIdentity VendorID="1" DeviceID="2"/>
375 <DeviceAccessPointList>
376 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
377 <VirtualSubmoduleList>
378 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
381 <DataItem DataType="Float64"/>
384 </VirtualSubmoduleItem>
385 </VirtualSubmoduleList>
386 </DeviceAccessPointItem>
387 </DeviceAccessPointList>
388 </ApplicationProcess>
393 const auto slots = dev.BuildIoSlots();
395 ASSERT_EQ(slots.size(), 1U);
396 EXPECT_EQ(slots[0].inputLength, 8U);
400TEST_F(GsdmlTest, Integer16HasLengthTwo)
402 const auto dev = Parse(R
"xml(
405 <DeviceIdentity VendorID="1" DeviceID="2"/>
407 <DeviceAccessPointList>
408 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
409 <VirtualSubmoduleList>
410 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
413 <DataItem DataType="Integer16"/>
416 </VirtualSubmoduleItem>
417 </VirtualSubmoduleList>
418 </DeviceAccessPointItem>
419 </DeviceAccessPointList>
420 </ApplicationProcess>
425 const auto slots = dev.BuildIoSlots();
427 ASSERT_EQ(slots.size(), 1U);
428 EXPECT_EQ(slots[0].inputLength, 2U);
432TEST_F(GsdmlTest, BooleanHasLengthOne)
434 const auto dev = Parse(R
"xml(
437 <DeviceIdentity VendorID="1" DeviceID="2"/>
439 <DeviceAccessPointList>
440 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
441 <VirtualSubmoduleList>
442 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
445 <DataItem DataType="Boolean"/>
448 </VirtualSubmoduleItem>
449 </VirtualSubmoduleList>
450 </DeviceAccessPointItem>
451 </DeviceAccessPointList>
452 </ApplicationProcess>
457 const auto slots = dev.BuildIoSlots();
459 ASSERT_EQ(slots.size(), 1U);
460 EXPECT_EQ(slots[0].inputLength, 1U);
464TEST_F(GsdmlTest, OctetStringUsesExplicitLength)
466 const auto dev = Parse(R
"xml(
469 <DeviceIdentity VendorID="1" DeviceID="2"/>
471 <DeviceAccessPointList>
472 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
473 <VirtualSubmoduleList>
474 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
477 <DataItem DataType="OctetString" Length="10"/>
480 </VirtualSubmoduleItem>
481 </VirtualSubmoduleList>
482 </DeviceAccessPointItem>
483 </DeviceAccessPointList>
484 </ApplicationProcess>
489 const auto slots = dev.BuildIoSlots();
491 ASSERT_EQ(slots.size(), 1U);
492 EXPECT_EQ(slots[0].inputLength, 10U);
496TEST_F(GsdmlTest, VisibleStringUsesExplicitLength)
498 const auto dev = Parse(R
"xml(
501 <DeviceIdentity VendorID="1" DeviceID="2"/>
503 <DeviceAccessPointList>
504 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
505 <VirtualSubmoduleList>
506 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
509 <DataItem DataType="VisibleString" Length="32"/>
512 </VirtualSubmoduleItem>
513 </VirtualSubmoduleList>
514 </DeviceAccessPointItem>
515 </DeviceAccessPointList>
516 </ApplicationProcess>
521 const auto slots = dev.BuildIoSlots();
523 ASSERT_EQ(slots.size(), 1U);
524 EXPECT_EQ(slots[0].outputLength, 32U);
528TEST_F(GsdmlTest, MultipleDataItemsAreAccumulated)
530 const auto dev = Parse(R
"xml(
533 <DeviceIdentity VendorID="1" DeviceID="2"/>
535 <DeviceAccessPointList>
536 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
537 <VirtualSubmoduleList>
538 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
541 <DataItem DataType="Unsigned16"/>
542 <DataItem DataType="Unsigned8"/>
543 <DataItem DataType="OctetString" Length="5"/>
546 </VirtualSubmoduleItem>
547 </VirtualSubmoduleList>
548 </DeviceAccessPointItem>
549 </DeviceAccessPointList>
550 </ApplicationProcess>
555 const auto slots = dev.BuildIoSlots();
557 ASSERT_EQ(slots.size(), 1U);
558 EXPECT_EQ(slots[0].inputLength, 8U);
562TEST_F(GsdmlTest, MissingIoDataProducesZeroLength)
564 const auto dev = Parse(R
"xml(
567 <DeviceIdentity VendorID="1" DeviceID="2"/>
569 <DeviceAccessPointList>
570 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
571 <VirtualSubmoduleList>
572 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1"/>
573 </VirtualSubmoduleList>
574 </DeviceAccessPointItem>
575 </DeviceAccessPointList>
576 </ApplicationProcess>
581 const auto slots = dev.BuildIoSlots();
583 ASSERT_EQ(slots.size(), 1U);
584 EXPECT_EQ(slots[0].inputLength, 0U);
585 EXPECT_EQ(slots[0].outputLength, 0U);
589TEST_F(GsdmlTest, MissingInputDirectionProducesZeroInputLength)
591 const auto dev = Parse(R
"xml(
594 <DeviceIdentity VendorID="1" DeviceID="2"/>
596 <DeviceAccessPointList>
597 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
598 <VirtualSubmoduleList>
599 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
602 <DataItem DataType="Unsigned16"/>
605 </VirtualSubmoduleItem>
606 </VirtualSubmoduleList>
607 </DeviceAccessPointItem>
608 </DeviceAccessPointList>
609 </ApplicationProcess>
614 const auto slots = dev.BuildIoSlots();
616 ASSERT_EQ(slots.size(), 1U);
617 EXPECT_EQ(slots[0].inputLength, 0U);
618 EXPECT_EQ(slots[0].outputLength, 2U);
622TEST_F(GsdmlTest, EmptyInputProducesZeroLength)
624 const auto dev = Parse(R
"xml(
627 <DeviceIdentity VendorID="1" DeviceID="2"/>
629 <DeviceAccessPointList>
630 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
631 <VirtualSubmoduleList>
632 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
636 </VirtualSubmoduleItem>
637 </VirtualSubmoduleList>
638 </DeviceAccessPointItem>
639 </DeviceAccessPointList>
640 </ApplicationProcess>
645 const auto slots = dev.BuildIoSlots();
647 ASSERT_EQ(slots.size(), 1U);
648 EXPECT_EQ(slots[0].inputLength, 0U);
656TEST_F(GsdmlTest, ParsesVendorAndDeviceId)
658 const auto dev = Parse(MINIMAL_GSDML);
660 EXPECT_EQ(dev.vendorId, 0x002AU);
661 EXPECT_EQ(dev.deviceId, 0x0003U);
665TEST_F(GsdmlTest, MissingVendorNameProducesEmptyString)
667 const auto dev = Parse(MINIMAL_GSDML);
669 EXPECT_TRUE(dev.vendorName.empty());
673TEST_F(GsdmlTest, ParsesDeviceName)
675 const auto dev = Parse(MINIMAL_GSDML);
677 EXPECT_EQ(dev.deviceName,
"Test Device");
681TEST_F(GsdmlTest, ParsesDapModuleIdent)
683 const auto dev = Parse(MINIMAL_GSDML);
685 EXPECT_EQ(dev.dapModuleIdentNumber, 0x00000001U);
689TEST_F(GsdmlTest, ParsesDapSubmoduleIdent)
691 const auto dev = Parse(MINIMAL_GSDML);
693 EXPECT_EQ(dev.dapSubmoduleIdentNumber, 0x00000001U);
697TEST_F(GsdmlTest, ParsesDapVirtualSubmodule)
699 const auto dev = Parse(MINIMAL_GSDML);
701 ASSERT_NE(dev.FindModule(
"DAP_1"),
nullptr);
703 const auto*
module = dev.FindModule("DAP_1");
705 ASSERT_NE(module,
nullptr);
706 ASSERT_EQ(module->submodules.size(), 1U);
708 const auto& submodule =
module->submodules.at("DAP_Sub");
710 EXPECT_EQ(submodule.id,
"DAP_Sub");
711 EXPECT_EQ(submodule.submoduleIdentNumber, 0x00000001U);
712 EXPECT_EQ(submodule.inputLength, 1);
713 EXPECT_EQ(submodule.outputLength, 0);
717TEST_F(GsdmlTest, ParsesModules)
719 const auto dev = Parse(MINIMAL_GSDML);
721 EXPECT_EQ(dev.modules.size(), 3U);
722 EXPECT_NE(dev.FindModule(
"DAP_1"),
nullptr);
723 EXPECT_NE(dev.FindModule(
"MOD_INPUT"),
nullptr);
724 EXPECT_NE(dev.FindModule(
"MOD_OUTPUT"),
nullptr);
728TEST_F(GsdmlTest, ParsesInputModule)
730 const auto dev = Parse(MINIMAL_GSDML);
732 const auto*
module = dev.FindModule("MOD_INPUT");
734 ASSERT_NE(module,
nullptr);
735 EXPECT_EQ(module->moduleIdentNumber, 0x00000010U);
736 ASSERT_EQ(module->submodules.size(), 1U);
738 const auto& submodule =
module->submodules.at("MOD_IN_Sub");
740 EXPECT_EQ(submodule.inputLength, 4);
741 EXPECT_EQ(submodule.outputLength, 0);
745TEST_F(GsdmlTest, ParsesOutputModule)
747 const auto dev = Parse(MINIMAL_GSDML);
749 const auto*
module = dev.FindModule("MOD_OUTPUT");
751 ASSERT_NE(module,
nullptr);
752 EXPECT_EQ(module->moduleIdentNumber, 0x00000020U);
753 ASSERT_EQ(module->submodules.size(), 1U);
755 const auto& submodule =
module->submodules.at("MOD_OUT_Sub");
757 EXPECT_EQ(submodule.inputLength, 0);
758 EXPECT_EQ(submodule.outputLength, 2);
762TEST_F(GsdmlTest, FindUnknownModuleReturnsNull)
764 const auto dev = Parse(MINIMAL_GSDML);
766 EXPECT_EQ(dev.FindModule(
"NONEXISTENT"),
nullptr);
774TEST_F(GsdmlTest, ParsesVendorIdWithNamespace)
776 const auto dev = Parse(NAMESPACED_GSDML);
778 EXPECT_EQ(dev.vendorId, 0x0042U);
782TEST_F(GsdmlTest, ParsesDeviceIdWithNamespace)
784 const auto dev = Parse(NAMESPACED_GSDML);
786 EXPECT_EQ(dev.deviceId, 0x0007U);
790TEST_F(GsdmlTest, ParsesDapWithNamespace)
792 const auto dev = Parse(NAMESPACED_GSDML);
794 EXPECT_EQ(dev.dapModuleIdentNumber, 0x00000002U);
795 EXPECT_NE(dev.FindModule(
"DAP_NS"),
nullptr);
799TEST_F(GsdmlTest, ParsesDapIoWithNamespace)
801 const auto dev = Parse(NAMESPACED_GSDML);
803 const auto* dap = dev.FindModule(
"DAP_NS");
805 ASSERT_NE(dap,
nullptr);
806 ASSERT_EQ(dap->submodules.size(), 1U);
808 EXPECT_EQ(dap->submodules.at(
"Sub1").inputLength, 4);
812TEST_F(GsdmlTest, ParsesModuleWithNamespace)
814 const auto dev = Parse(NAMESPACED_GSDML);
816 const auto*
module = dev.FindModule("MOD_A");
818 ASSERT_NE(module,
nullptr);
819 EXPECT_EQ(module->moduleIdentNumber, 0x000000AAU);
820 EXPECT_EQ(module->submodules.at(
"MOD_A_Sub").outputLength, 4);
824TEST_F(GsdmlTest, ParsesDifferentNamespaceVersion)
826 const std::string xml = std::string(NAMESPACED_GSDML)
827 .replace(std::string(NAMESPACED_GSDML).find(
"GSDML/2.4"), 9,
"GSDML/2.3");
829 const auto dev = Parse(xml);
831 EXPECT_EQ(dev.vendorId, 0x0042U);
832 EXPECT_NE(dev.FindModule(
"DAP_NS"),
nullptr);
840TEST_F(GsdmlTest, BuildIoSlotsUsesFixedModules)
842 const auto dev = Parse(MINIMAL_GSDML);
843 const auto slots = dev.BuildIoSlots();
845 EXPECT_EQ(slots.size(), 5U);
849TEST_F(GsdmlTest, BuildIoSlotsPlacesDapAtSlotZero)
851 const auto dev = Parse(MINIMAL_GSDML);
852 const auto slots = dev.BuildIoSlots();
854 const auto dapSlots = FindSlots(slots, 0);
856 EXPECT_EQ(dapSlots.size(), 3U);
860TEST_F(GsdmlTest, BuildIoSlotsPlacesDapSubmoduleAtSubslotOne)
862 const auto dev = Parse(MINIMAL_GSDML);
863 const auto slots = dev.BuildIoSlots();
865 const auto& slot = FindSlot(slots, 0, 1);
867 EXPECT_EQ(slot.inputLength, 1U);
868 EXPECT_EQ(slot.outputLength, 0U);
869 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
870 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
874TEST_F(GsdmlTest, DISABLED_BuildIoSlotsPlacesInterfaceSubmodule)
876 const auto dev = Parse(MINIMAL_GSDML);
877 const auto slots = dev.BuildIoSlots();
879 const auto& slot = FindSlot(slots, 0, 0x8000);
881 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
882 EXPECT_EQ(slot.submoduleIdent, 0x00000100U);
883 EXPECT_EQ(slot.inputLength, 0U);
884 EXPECT_EQ(slot.outputLength, 0U);
888TEST_F(GsdmlTest, DISABLED_BuildIoSlotsPlacesPortSubmodule)
890 const auto dev = Parse(MINIMAL_GSDML);
891 const auto slots = dev.BuildIoSlots();
893 const auto& slot = FindSlot(slots, 0, 0x8001);
895 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
896 EXPECT_EQ(slot.submoduleIdent, 0x00000200U);
900TEST_F(GsdmlTest, BuildIoSlotsPlacesInputModule)
902 const auto dev = Parse(MINIMAL_GSDML);
903 const auto slots = dev.BuildIoSlots();
905 const auto& slot = FindSlot(slots, 1, 1);
907 EXPECT_EQ(slot.inputLength, 4U);
908 EXPECT_EQ(slot.outputLength, 0U);
909 EXPECT_EQ(slot.moduleIdent, 0x00000010U);
910 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
914TEST_F(GsdmlTest, BuildIoSlotsPlacesOutputModule)
916 const auto dev = Parse(MINIMAL_GSDML);
917 const auto slots = dev.BuildIoSlots();
919 const auto& slot = FindSlot(slots, 2, 1);
921 EXPECT_EQ(slot.inputLength, 0U);
922 EXPECT_EQ(slot.outputLength, 2U);
923 EXPECT_EQ(slot.moduleIdent, 0x00000020U);
924 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
928TEST_F(GsdmlTest, BuildIoSlotsSupportsExplicitAssignments)
930 const auto dev = Parse(MINIMAL_GSDML);
932 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
933 {3,
"MOD_OUTPUT", 1,
"MOD_OUT_Sub"},
934 {5,
"MOD_INPUT", 1,
"MOD_IN_Sub"},
937 const auto slots = dev.BuildIoSlots(assignment);
939 const auto& output = FindSlot(slots, 3, 1);
940 const auto& input = FindSlot(slots, 5, 1);
942 EXPECT_EQ(output.outputLength, 2U);
943 EXPECT_EQ(input.inputLength, 4U);
947TEST_F(GsdmlTest, BuildIoSlotsPreservesExplicitAssignmentOrder)
949 const auto dev = Parse(MINIMAL_GSDML);
951 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
952 {5,
"MOD_INPUT", 1,
"MOD_IN_Sub"},
953 {3,
"MOD_OUTPUT", 1,
"MOD_OUT_Sub"},
956 const auto slots = dev.BuildIoSlots(assignment);
958 ASSERT_EQ(slots.size(), 5U);
960 EXPECT_EQ(slots[3].slot, 5U);
961 EXPECT_EQ(slots[4].slot, 3U);
965TEST_F(GsdmlTest, BuildIoSlotsRejectsUnknownModule)
967 const auto dev = Parse(MINIMAL_GSDML);
969 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
970 {1,
"NONEXISTENT", 1,
"S"},
973 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
977TEST_F(GsdmlTest, BuildIoSlotsRejectsUnknownSubmodule)
979 const auto dev = Parse(MINIMAL_GSDML);
981 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
982 {1,
"MOD_INPUT", 1,
"NONEXISTENT"},
985 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
989TEST_F(GsdmlTest, BuildIoSlotsRejectsDisallowedSlot)
991 const auto dev = Parse(MINIMAL_GSDML);
993 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
994 {9,
"MOD_INPUT", 1,
"MOD_IN_Sub"},
997 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
1001TEST_F(GsdmlTest, BuildIoSlotsAllowsUnrestrictedModule)
1003 const auto xml = R
"xml(
1006 <DeviceIdentity VendorID="1" DeviceID="2"/>
1007 <ApplicationProcess>
1008 <DeviceAccessPointList>
1009 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1010 </DeviceAccessPointList>
1012 <ModuleItem ID="MOD" ModuleIdentNumber="2">
1013 <VirtualSubmoduleList>
1014 <VirtualSubmoduleItem ID="SUB" SubmoduleIdentNumber="3">
1017 <DataItem DataType="Unsigned8"/>
1020 </VirtualSubmoduleItem>
1021 </VirtualSubmoduleList>
1024 </ApplicationProcess>
1029 const auto dev = Parse(xml);
1031 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
1032 {99,
"MOD", 1,
"SUB"},
1035 const auto slots = dev.BuildIoSlots(assignment);
1037 ASSERT_EQ(slots.size(), 1U);
1038 EXPECT_EQ(slots[0].slot, 99U);
1042TEST_F(GsdmlTest, BuildIoSlotsMaintainsSlotOrder)
1044 const auto dev = Parse(MINIMAL_GSDML);
1045 const auto slots = dev.BuildIoSlots();
1047 ASSERT_EQ(slots.size(), 5U);
1049 EXPECT_EQ(slots[0].slot, 0U);
1050 EXPECT_EQ(slots[1].slot, 0U);
1051 EXPECT_EQ(slots[2].slot, 0U);
1052 EXPECT_EQ(slots[3].slot, 1U);
1053 EXPECT_EQ(slots[4].slot, 2U);
1061TEST_F(GsdmlTest, ModuleWithoutIoDataHasZeroLengths)
1063 const auto xml = R
"xml(
1066 <ApplicationProcess>
1067 <DeviceAccessPointList>
1068 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1069 </DeviceAccessPointList>
1071 <ModuleItem ID="NO_IO" ModuleIdentNumber="0x99">
1072 <VirtualSubmoduleList>
1073 <VirtualSubmoduleItem ID="S1" SubmoduleIdentNumber="1"/>
1074 </VirtualSubmoduleList>
1077 </ApplicationProcess>
1082 const auto dev = Parse(xml);
1083 const auto*
module = dev.FindModule("NO_IO");
1085 ASSERT_NE(module,
nullptr);
1086 ASSERT_EQ(module->submodules.size(), 1U);
1088 EXPECT_EQ(module->submodules.at(
"S1").inputLength, 0);
1089 EXPECT_EQ(module->submodules.at(
"S1").outputLength, 0);
1093TEST_F(GsdmlTest, ModuleWithoutVirtualSubmoduleListHasNoSubmodules)
1095 const auto xml = R
"xml(
1098 <DeviceIdentity VendorID="1" DeviceID="2"/>
1099 <ApplicationProcess>
1100 <DeviceAccessPointList>
1101 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1102 </DeviceAccessPointList>
1104 <ModuleItem ID="EMPTY" ModuleIdentNumber="0xFF"/>
1106 </ApplicationProcess>
1111 const auto dev = Parse(xml);
1112 const auto*
module = dev.FindModule("EMPTY");
1114 ASSERT_NE(module,
nullptr);
1115 EXPECT_TRUE(module->submodules.empty());
1119TEST_F(GsdmlTest, MissingDeviceIdentityProducesZeroIds)
1121 const auto xml = R
"xml(
1124 <ApplicationProcess>
1125 <DeviceAccessPointList>
1126 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1127 </DeviceAccessPointList>
1128 </ApplicationProcess>
1133 const auto dev = Parse(xml);
1135 EXPECT_EQ(dev.vendorId, 0U);
1136 EXPECT_EQ(dev.deviceId, 0U);
1140TEST_F(GsdmlTest, MissingDapProducesEmptyDapInformation)
1142 const auto xml = R
"xml(
1145 <DeviceIdentity VendorID="1" DeviceID="2"/>
1146 <ApplicationProcess>
1148 </ApplicationProcess>
1153 const auto dev = Parse(xml);
1155 EXPECT_EQ(dev.dapModuleIdentNumber, 0U);
1156 EXPECT_EQ(dev.dapSubmoduleIdentNumber, 0U);
1157 EXPECT_TRUE(dev.systemSubmodules.empty());
1161TEST_F(GsdmlTest, DapWithoutUseableModulesProducesOnlyDapSlots)
1163 const auto xml = R
"xml(
1166 <DeviceIdentity VendorID="1" DeviceID="2"/>
1167 <ApplicationProcess>
1168 <DeviceAccessPointList>
1169 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1170 <VirtualSubmoduleList>
1171 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1174 <DataItem DataType="Unsigned8"/>
1177 </VirtualSubmoduleItem>
1178 </VirtualSubmoduleList>
1179 </DeviceAccessPointItem>
1180 </DeviceAccessPointList>
1182 </ApplicationProcess>
1187 const auto dev = Parse(xml);
1188 const auto slots = dev.BuildIoSlots();
1190 ASSERT_EQ(slots.size(), 1U);
1191 EXPECT_EQ(slots[0].slot, 0U);
1192 EXPECT_EQ(slots[0].subslot, 1U);
1193 EXPECT_EQ(slots[0].inputLength, 1U);
1197TEST_F(GsdmlTest, MalformedXmlThrows)
1199 EXPECT_THROW(Parse(
"<ISO15745Profile><ProfileBody>"), std::runtime_error);
1203TEST_F(GsdmlTest, EmptyXmlThrows)
1205 EXPECT_THROW(Parse(
""), std::runtime_error);
1209TEST_F(GsdmlTest, WhitespaceOnlyXmlThrows)
1211 EXPECT_THROW(Parse(
" \n\t "), std::runtime_error);
1219TEST_F(GsdmlTest, ParseGsdmlReadsFile)
1221 const auto path = std::filesystem::temp_directory_path() /
"gsdml_test.xml";
1224 std::ofstream file(path);
1225 ASSERT_TRUE(file.is_open());
1226 file << MINIMAL_GSDML;
1231 EXPECT_EQ(dev.vendorId, 0x002AU);
1232 EXPECT_EQ(dev.deviceId, 0x0003U);
1233 EXPECT_EQ(dev.modules.size(), 3U);
1235 std::filesystem::remove(path);
1239TEST_F(GsdmlTest, ParseGsdmlThrowsForMissingFile)
1241 const auto path = std::filesystem::temp_directory_path() /
"definitely_missing_gsdml_file.xml";
1243 EXPECT_THROW(
ParseGsdml(path.string()), std::runtime_error);
1251TEST_F(GsdmlTest, ResolvesExternalTextId)
1253 const auto xml = R
"xml(
1256 <DeviceIdentity VendorID="1" DeviceID="2">
1257 <Name TextId="T_VENDOR"/>
1259 <ApplicationProcess>
1262 <Text TextId="T_VENDOR" Value="Vendor Name"/>
1265 <DeviceAccessPointList>
1266 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1267 </DeviceAccessPointList>
1268 </ApplicationProcess>
1273 const auto dev = Parse(xml);
1275 EXPECT_EQ(dev.vendorName,
"Vendor Name");
1279TEST_F(GsdmlTest, ResolvesLiteralNameValue)
1281 const auto xml = R
"xml(
1284 <DeviceIdentity VendorID="1" DeviceID="2">
1285 <Name Value="Literal Vendor"/>
1287 <ApplicationProcess>
1288 <DeviceAccessPointList>
1289 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1290 </DeviceAccessPointList>
1291 </ApplicationProcess>
1296 const auto dev = Parse(xml);
1298 EXPECT_EQ(dev.vendorName,
"Literal Vendor");
1306TEST_F(GsdmlTest, ParsesHexadecimalIdentifiers)
1308 const auto dev = Parse(MINIMAL_GSDML);
1310 EXPECT_EQ(dev.vendorId, 42U);
1311 EXPECT_EQ(dev.deviceId, 3U);
1312 EXPECT_EQ(dev.dapModuleIdentNumber, 1U);
1316TEST_F(GsdmlTest, ParsesDecimalIdentifiers)
1318 const auto dev = Parse(DATA_TYPES_GSDML);
1320 EXPECT_EQ(dev.vendorId, 42U);
1321 EXPECT_EQ(dev.deviceId, 7U);
1325TEST_F(GsdmlTest, InvalidNumericAttributeFallsBackToZero)
1327 const auto xml = R
"xml(
1330 <DeviceIdentity VendorID="not-a-number" DeviceID="7"/>
1331 <ApplicationProcess>
1332 <DeviceAccessPointList>
1333 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="invalid"/>
1334 </DeviceAccessPointList>
1335 </ApplicationProcess>
1340 const auto dev = Parse(xml);
1342 EXPECT_EQ(dev.vendorId, 0U);
1343 EXPECT_EQ(dev.deviceId, 7U);
1344 EXPECT_EQ(dev.dapModuleIdentNumber, 0U);
1352TEST_F(GsdmlTest, ParsesDataItemMetadata)
1354 const auto xml = R
"xml(
1357 <DeviceIdentity VendorID="1" DeviceID="2"/>
1358 <ApplicationProcess>
1359 <DeviceAccessPointList>
1360 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1361 <VirtualSubmoduleList>
1362 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1365 <DataItem DataType="Unsigned16" TextId="VALUE"/>
1368 </VirtualSubmoduleItem>
1369 </VirtualSubmoduleList>
1370 </DeviceAccessPointItem>
1371 </DeviceAccessPointList>
1372 </ApplicationProcess>
1377 const auto dev = Parse(xml);
1378 const auto* dap = dev.FindModule(
"DAP");
1380 ASSERT_NE(dap,
nullptr);
1382 const auto& submodule = dap->submodules.at(
"S");
1384 ASSERT_EQ(submodule.inputItems.size(), 1U);
1385 EXPECT_EQ(submodule.inputItems[0].dataType,
"Unsigned16");
1386 EXPECT_EQ(submodule.inputItems[0].textId,
"VALUE");
1387 EXPECT_EQ(submodule.inputItems[0].length, 2);
1391TEST_F(GsdmlTest, SeparatesInputAndOutputDataItems)
1393 const auto xml = R
"xml(
1396 <DeviceIdentity VendorID="1" DeviceID="2"/>
1397 <ApplicationProcess>
1398 <DeviceAccessPointList>
1399 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1400 <VirtualSubmoduleList>
1401 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1404 <DataItem DataType="Unsigned8"/>
1407 <DataItem DataType="Unsigned32"/>
1410 </VirtualSubmoduleItem>
1411 </VirtualSubmoduleList>
1412 </DeviceAccessPointItem>
1413 </DeviceAccessPointList>
1414 </ApplicationProcess>
1419 const auto dev = Parse(xml);
1420 const auto* dap = dev.FindModule(
"DAP");
1422 ASSERT_NE(dap,
nullptr);
1424 const auto& submodule = dap->submodules.at(
"S");
1426 ASSERT_EQ(submodule.inputItems.size(), 1U);
1427 ASSERT_EQ(submodule.outputItems.size(), 1U);
1429 EXPECT_EQ(submodule.inputItems[0].dataType,
"Unsigned8");
1430 EXPECT_EQ(submodule.outputItems[0].dataType,
"Unsigned32");
1431 EXPECT_EQ(submodule.inputLength, 1);
1432 EXPECT_EQ(submodule.outputLength, 4);
Declares the GSDML parser and PROFINET device-description data model.
GSDMLDevice ParseGsdmlString(const std::string &xml)
Parse GSDML content already held in memory.
GSDMLDevice ParseGsdml(const std::string &path)
Parse a GSDML file into a GSDMLDevice.
TEST_F(GsdmlRealDeviceTest, ParsesAumaGsdml)