PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
test_gsdml.cpp
Go to the documentation of this file.
1
3
4#include <gtest/gtest.h>
5
6#include <filesystem>
7#include <fstream>
8#include <string>
9#include <tuple>
10#include <vector>
11
12#include "profinet/gsdml.h"
13
14namespace profinet::gsdml
15{
16
17namespace
18{
19
20// =============================================================================
21// Test fixtures
22// =============================================================================
23
25constexpr const char* MINIMAL_GSDML = R"xml(
26<ISO15745Profile>
27 <ProfileBody>
28 <DeviceIdentity VendorID="0x002A" DeviceID="0x0003"/>
29 <DeviceFunction>
30 <Name Value="Test Device"/>
31 </DeviceFunction>
32 <ApplicationProcess>
33 <DeviceAccessPointList>
34 <DeviceAccessPointItem ID="DAP_1"
35 ModuleIdentNumber="0x00000001"
36 SubmoduleIdentNumber="0x00000001">
37 <SystemDefinedSubmoduleList>
38 <InterfaceSubmoduleItem
39 Subslot="0x8000"
40 SubmoduleIdentNumber="0x00000100"/>
41 <PortSubmoduleItem
42 Subslot="0x8001"
43 SubmoduleIdentNumber="0x00000200"/>
44 </SystemDefinedSubmoduleList>
45 <VirtualSubmoduleList>
46 <VirtualSubmoduleItem ID="DAP_Sub"
47 SubmoduleIdentNumber="0x00000001">
48 <IOData>
49 <Input>
50 <DataItem DataType="Unsigned8"/>
51 </Input>
52 </IOData>
53 </VirtualSubmoduleItem>
54 </VirtualSubmoduleList>
55 <UseableModules>
56 <ModuleItemRef ModuleItemTarget="MOD_INPUT"
57 AllowedInSlots="1..5"/>
58 <ModuleItemRef ModuleItemTarget="MOD_OUTPUT"
59 AllowedInSlots="1..5"/>
60 </UseableModules>
61 <PredefinedPnioModules>
62 <PnioModuleItemRef ModuleItemTarget="MOD_INPUT"
63 FixedInSlots="1"/>
64 <PnioModuleItemRef ModuleItemTarget="MOD_OUTPUT"
65 FixedInSlots="2"/>
66 </PredefinedPnioModules>
67 </DeviceAccessPointItem>
68 </DeviceAccessPointList>
69 <ModuleList>
70 <ModuleItem ID="MOD_INPUT"
71 ModuleIdentNumber="0x00000010">
72 <VirtualSubmoduleList>
73 <VirtualSubmoduleItem ID="MOD_IN_Sub"
74 SubmoduleIdentNumber="0x00000001">
75 <IOData>
76 <Input>
77 <DataItem DataType="OctetString" Length="4"/>
78 </Input>
79 </IOData>
80 </VirtualSubmoduleItem>
81 </VirtualSubmoduleList>
82 </ModuleItem>
83 <ModuleItem ID="MOD_OUTPUT"
84 ModuleIdentNumber="0x00000020">
85 <VirtualSubmoduleList>
86 <VirtualSubmoduleItem ID="MOD_OUT_Sub"
87 SubmoduleIdentNumber="0x00000001">
88 <IOData>
89 <Output>
90 <DataItem DataType="Unsigned16"/>
91 </Output>
92 </IOData>
93 </VirtualSubmoduleItem>
94 </VirtualSubmoduleList>
95 </ModuleItem>
96 </ModuleList>
97 </ApplicationProcess>
98 </ProfileBody>
99</ISO15745Profile>
100)xml";
101
103constexpr const char* NAMESPACED_GSDML = R"xml(
104<ISO15745Profile xmlns="http://www.profibus.com/GSDML/2.4">
105 <ProfileBody>
106 <DeviceIdentity VendorID="0x0042" DeviceID="0x0007"/>
107 <ApplicationProcess>
108 <DeviceAccessPointList>
109 <DeviceAccessPointItem ID="DAP_NS"
110 ModuleIdentNumber="0x00000002"
111 SubmoduleIdentNumber="0x00000001">
112 <VirtualSubmoduleList>
113 <VirtualSubmoduleItem ID="Sub1"
114 SubmoduleIdentNumber="0x00000001">
115 <IOData>
116 <Input>
117 <DataItem DataType="Unsigned32"/>
118 </Input>
119 </IOData>
120 </VirtualSubmoduleItem>
121 </VirtualSubmoduleList>
122 </DeviceAccessPointItem>
123 </DeviceAccessPointList>
124 <ModuleList>
125 <ModuleItem ID="MOD_A"
126 ModuleIdentNumber="0x000000AA">
127 <VirtualSubmoduleList>
128 <VirtualSubmoduleItem ID="MOD_A_Sub"
129 SubmoduleIdentNumber="0x00000001">
130 <IOData>
131 <Output>
132 <DataItem DataType="Float32"/>
133 </Output>
134 </IOData>
135 </VirtualSubmoduleItem>
136 </VirtualSubmoduleList>
137 </ModuleItem>
138 </ModuleList>
139 </ApplicationProcess>
140 </ProfileBody>
141</ISO15745Profile>
142)xml";
143
145constexpr const char* DATA_TYPES_GSDML = R"xml(
146<ISO15745Profile>
147 <ProfileBody>
148 <DeviceIdentity VendorID="42" DeviceID="7"/>
149 <ApplicationProcess>
150 <DeviceAccessPointList>
151 <DeviceAccessPointItem ID="DAP"
152 ModuleIdentNumber="1"
153 SubmoduleIdentNumber="1">
154 <VirtualSubmoduleList>
155 <VirtualSubmoduleItem ID="DATA"
156 SubmoduleIdentNumber="1">
157 <IOData>
158 <Input>
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"/>
168 </Input>
169 </IOData>
170 </VirtualSubmoduleItem>
171 </VirtualSubmoduleList>
172 </DeviceAccessPointItem>
173 </DeviceAccessPointList>
174 <ModuleList/>
175 </ApplicationProcess>
176 </ProfileBody>
177</ISO15745Profile>
178)xml";
179
181class GsdmlTest : public ::testing::Test
182{
183 protected:
187 static GSDMLDevice Parse(const std::string& xml)
188 {
189 return ParseGsdmlString(xml);
190 }
191
197 static const rpc::IOSlot& FindSlot(const std::vector<rpc::IOSlot>& slots,
198 std::uint16_t slot,
199 std::uint16_t subslot)
200 {
201 for (const auto& value : slots)
202 {
203 if (value.slot == slot && value.subslot == subslot)
204 {
205 return value;
206 }
207 }
208
209 ADD_FAILURE() << "Slot " << slot << ":" << subslot << " was not found";
210 return slots.front();
211 }
212
217 static std::vector<rpc::IOSlot> FindSlots(const std::vector<rpc::IOSlot>& slots,
218 std::uint16_t slot)
219 {
220 std::vector<rpc::IOSlot> result;
221
222 for (const auto& value : slots)
223 {
224 if (value.slot == slot)
225 {
226 result.push_back(value);
227 }
228 }
229
230 return result;
231 }
232};
233
234// =============================================================================
235// Data item / IOData tests
236// =============================================================================
237
239TEST_F(GsdmlTest, Unsigned8HasLengthOne)
240{
241 const auto dev = Parse(R"xml(
242<ISO15745Profile>
243 <ProfileBody>
244 <DeviceIdentity VendorID="1" DeviceID="2"/>
245 <ApplicationProcess>
246 <DeviceAccessPointList>
247 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
248 <VirtualSubmoduleList>
249 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
250 <IOData>
251 <Input>
252 <DataItem DataType="Unsigned8"/>
253 </Input>
254 </IOData>
255 </VirtualSubmoduleItem>
256 </VirtualSubmoduleList>
257 </DeviceAccessPointItem>
258 </DeviceAccessPointList>
259 </ApplicationProcess>
260 </ProfileBody>
261</ISO15745Profile>
262)xml");
263
264 const auto slots = dev.BuildIoSlots();
265
266 EXPECT_EQ(slots.size(), 1U);
267 EXPECT_EQ(slots[0].inputLength, 1U);
268 EXPECT_EQ(slots[0].outputLength, 0U);
269}
270
272TEST_F(GsdmlTest, Unsigned16HasLengthTwo)
273{
274 const auto dev = Parse(R"xml(
275<ISO15745Profile>
276 <ProfileBody>
277 <DeviceIdentity VendorID="1" DeviceID="2"/>
278 <ApplicationProcess>
279 <DeviceAccessPointList>
280 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
281 <VirtualSubmoduleList>
282 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
283 <IOData>
284 <Input>
285 <DataItem DataType="Unsigned16"/>
286 </Input>
287 </IOData>
288 </VirtualSubmoduleItem>
289 </VirtualSubmoduleList>
290 </DeviceAccessPointItem>
291 </DeviceAccessPointList>
292 </ApplicationProcess>
293 </ProfileBody>
294</ISO15745Profile>
295)xml");
296
297 const auto slots = dev.BuildIoSlots();
298
299 ASSERT_EQ(slots.size(), 1U);
300 EXPECT_EQ(slots[0].inputLength, 2U);
301}
302
304TEST_F(GsdmlTest, Unsigned32HasLengthFour)
305{
306 const auto dev = Parse(R"xml(
307<ISO15745Profile>
308 <ProfileBody>
309 <DeviceIdentity VendorID="1" DeviceID="2"/>
310 <ApplicationProcess>
311 <DeviceAccessPointList>
312 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
313 <VirtualSubmoduleList>
314 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
315 <IOData>
316 <Output>
317 <DataItem DataType="Unsigned32"/>
318 </Output>
319 </IOData>
320 </VirtualSubmoduleItem>
321 </VirtualSubmoduleList>
322 </DeviceAccessPointItem>
323 </DeviceAccessPointList>
324 </ApplicationProcess>
325 </ProfileBody>
326</ISO15745Profile>
327)xml");
328
329 const auto slots = dev.BuildIoSlots();
330
331 ASSERT_EQ(slots.size(), 1U);
332 EXPECT_EQ(slots[0].outputLength, 4U);
333}
334
336TEST_F(GsdmlTest, Float32HasLengthFour)
337{
338 const auto dev = Parse(R"xml(
339<ISO15745Profile>
340 <ProfileBody>
341 <DeviceIdentity VendorID="1" DeviceID="2"/>
342 <ApplicationProcess>
343 <DeviceAccessPointList>
344 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
345 <VirtualSubmoduleList>
346 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
347 <IOData>
348 <Input>
349 <DataItem DataType="Float32"/>
350 </Input>
351 </IOData>
352 </VirtualSubmoduleItem>
353 </VirtualSubmoduleList>
354 </DeviceAccessPointItem>
355 </DeviceAccessPointList>
356 </ApplicationProcess>
357 </ProfileBody>
358</ISO15745Profile>
359)xml");
360
361 const auto slots = dev.BuildIoSlots();
362
363 ASSERT_EQ(slots.size(), 1U);
364 EXPECT_EQ(slots[0].inputLength, 4U);
365}
366
368TEST_F(GsdmlTest, Float64HasLengthEight)
369{
370 const auto dev = Parse(R"xml(
371<ISO15745Profile>
372 <ProfileBody>
373 <DeviceIdentity VendorID="1" DeviceID="2"/>
374 <ApplicationProcess>
375 <DeviceAccessPointList>
376 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
377 <VirtualSubmoduleList>
378 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
379 <IOData>
380 <Input>
381 <DataItem DataType="Float64"/>
382 </Input>
383 </IOData>
384 </VirtualSubmoduleItem>
385 </VirtualSubmoduleList>
386 </DeviceAccessPointItem>
387 </DeviceAccessPointList>
388 </ApplicationProcess>
389 </ProfileBody>
390</ISO15745Profile>
391)xml");
392
393 const auto slots = dev.BuildIoSlots();
394
395 ASSERT_EQ(slots.size(), 1U);
396 EXPECT_EQ(slots[0].inputLength, 8U);
397}
398
400TEST_F(GsdmlTest, Integer16HasLengthTwo)
401{
402 const auto dev = Parse(R"xml(
403<ISO15745Profile>
404 <ProfileBody>
405 <DeviceIdentity VendorID="1" DeviceID="2"/>
406 <ApplicationProcess>
407 <DeviceAccessPointList>
408 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
409 <VirtualSubmoduleList>
410 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
411 <IOData>
412 <Input>
413 <DataItem DataType="Integer16"/>
414 </Input>
415 </IOData>
416 </VirtualSubmoduleItem>
417 </VirtualSubmoduleList>
418 </DeviceAccessPointItem>
419 </DeviceAccessPointList>
420 </ApplicationProcess>
421 </ProfileBody>
422</ISO15745Profile>
423)xml");
424
425 const auto slots = dev.BuildIoSlots();
426
427 ASSERT_EQ(slots.size(), 1U);
428 EXPECT_EQ(slots[0].inputLength, 2U);
429}
430
432TEST_F(GsdmlTest, BooleanHasLengthOne)
433{
434 const auto dev = Parse(R"xml(
435<ISO15745Profile>
436 <ProfileBody>
437 <DeviceIdentity VendorID="1" DeviceID="2"/>
438 <ApplicationProcess>
439 <DeviceAccessPointList>
440 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
441 <VirtualSubmoduleList>
442 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
443 <IOData>
444 <Input>
445 <DataItem DataType="Boolean"/>
446 </Input>
447 </IOData>
448 </VirtualSubmoduleItem>
449 </VirtualSubmoduleList>
450 </DeviceAccessPointItem>
451 </DeviceAccessPointList>
452 </ApplicationProcess>
453 </ProfileBody>
454</ISO15745Profile>
455)xml");
456
457 const auto slots = dev.BuildIoSlots();
458
459 ASSERT_EQ(slots.size(), 1U);
460 EXPECT_EQ(slots[0].inputLength, 1U);
461}
462
464TEST_F(GsdmlTest, OctetStringUsesExplicitLength)
465{
466 const auto dev = Parse(R"xml(
467<ISO15745Profile>
468 <ProfileBody>
469 <DeviceIdentity VendorID="1" DeviceID="2"/>
470 <ApplicationProcess>
471 <DeviceAccessPointList>
472 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
473 <VirtualSubmoduleList>
474 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
475 <IOData>
476 <Input>
477 <DataItem DataType="OctetString" Length="10"/>
478 </Input>
479 </IOData>
480 </VirtualSubmoduleItem>
481 </VirtualSubmoduleList>
482 </DeviceAccessPointItem>
483 </DeviceAccessPointList>
484 </ApplicationProcess>
485 </ProfileBody>
486</ISO15745Profile>
487)xml");
488
489 const auto slots = dev.BuildIoSlots();
490
491 ASSERT_EQ(slots.size(), 1U);
492 EXPECT_EQ(slots[0].inputLength, 10U);
493}
494
496TEST_F(GsdmlTest, VisibleStringUsesExplicitLength)
497{
498 const auto dev = Parse(R"xml(
499<ISO15745Profile>
500 <ProfileBody>
501 <DeviceIdentity VendorID="1" DeviceID="2"/>
502 <ApplicationProcess>
503 <DeviceAccessPointList>
504 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
505 <VirtualSubmoduleList>
506 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
507 <IOData>
508 <Output>
509 <DataItem DataType="VisibleString" Length="32"/>
510 </Output>
511 </IOData>
512 </VirtualSubmoduleItem>
513 </VirtualSubmoduleList>
514 </DeviceAccessPointItem>
515 </DeviceAccessPointList>
516 </ApplicationProcess>
517 </ProfileBody>
518</ISO15745Profile>
519)xml");
520
521 const auto slots = dev.BuildIoSlots();
522
523 ASSERT_EQ(slots.size(), 1U);
524 EXPECT_EQ(slots[0].outputLength, 32U);
525}
526
528TEST_F(GsdmlTest, MultipleDataItemsAreAccumulated)
529{
530 const auto dev = Parse(R"xml(
531<ISO15745Profile>
532 <ProfileBody>
533 <DeviceIdentity VendorID="1" DeviceID="2"/>
534 <ApplicationProcess>
535 <DeviceAccessPointList>
536 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
537 <VirtualSubmoduleList>
538 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
539 <IOData>
540 <Input>
541 <DataItem DataType="Unsigned16"/>
542 <DataItem DataType="Unsigned8"/>
543 <DataItem DataType="OctetString" Length="5"/>
544 </Input>
545 </IOData>
546 </VirtualSubmoduleItem>
547 </VirtualSubmoduleList>
548 </DeviceAccessPointItem>
549 </DeviceAccessPointList>
550 </ApplicationProcess>
551 </ProfileBody>
552</ISO15745Profile>
553)xml");
554
555 const auto slots = dev.BuildIoSlots();
556
557 ASSERT_EQ(slots.size(), 1U);
558 EXPECT_EQ(slots[0].inputLength, 8U);
559}
560
562TEST_F(GsdmlTest, MissingIoDataProducesZeroLength)
563{
564 const auto dev = Parse(R"xml(
565<ISO15745Profile>
566 <ProfileBody>
567 <DeviceIdentity VendorID="1" DeviceID="2"/>
568 <ApplicationProcess>
569 <DeviceAccessPointList>
570 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
571 <VirtualSubmoduleList>
572 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1"/>
573 </VirtualSubmoduleList>
574 </DeviceAccessPointItem>
575 </DeviceAccessPointList>
576 </ApplicationProcess>
577 </ProfileBody>
578</ISO15745Profile>
579)xml");
580
581 const auto slots = dev.BuildIoSlots();
582
583 ASSERT_EQ(slots.size(), 1U);
584 EXPECT_EQ(slots[0].inputLength, 0U);
585 EXPECT_EQ(slots[0].outputLength, 0U);
586}
587
589TEST_F(GsdmlTest, MissingInputDirectionProducesZeroInputLength)
590{
591 const auto dev = Parse(R"xml(
592<ISO15745Profile>
593 <ProfileBody>
594 <DeviceIdentity VendorID="1" DeviceID="2"/>
595 <ApplicationProcess>
596 <DeviceAccessPointList>
597 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
598 <VirtualSubmoduleList>
599 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
600 <IOData>
601 <Output>
602 <DataItem DataType="Unsigned16"/>
603 </Output>
604 </IOData>
605 </VirtualSubmoduleItem>
606 </VirtualSubmoduleList>
607 </DeviceAccessPointItem>
608 </DeviceAccessPointList>
609 </ApplicationProcess>
610 </ProfileBody>
611</ISO15745Profile>
612)xml");
613
614 const auto slots = dev.BuildIoSlots();
615
616 ASSERT_EQ(slots.size(), 1U);
617 EXPECT_EQ(slots[0].inputLength, 0U);
618 EXPECT_EQ(slots[0].outputLength, 2U);
619}
620
622TEST_F(GsdmlTest, EmptyInputProducesZeroLength)
623{
624 const auto dev = Parse(R"xml(
625<ISO15745Profile>
626 <ProfileBody>
627 <DeviceIdentity VendorID="1" DeviceID="2"/>
628 <ApplicationProcess>
629 <DeviceAccessPointList>
630 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
631 <VirtualSubmoduleList>
632 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
633 <IOData>
634 <Input/>
635 </IOData>
636 </VirtualSubmoduleItem>
637 </VirtualSubmoduleList>
638 </DeviceAccessPointItem>
639 </DeviceAccessPointList>
640 </ApplicationProcess>
641 </ProfileBody>
642</ISO15745Profile>
643)xml");
644
645 const auto slots = dev.BuildIoSlots();
646
647 ASSERT_EQ(slots.size(), 1U);
648 EXPECT_EQ(slots[0].inputLength, 0U);
649}
650
651// =============================================================================
652// Device identity and module parsing
653// =============================================================================
654
656TEST_F(GsdmlTest, ParsesVendorAndDeviceId)
657{
658 const auto dev = Parse(MINIMAL_GSDML);
659
660 EXPECT_EQ(dev.vendorId, 0x002AU);
661 EXPECT_EQ(dev.deviceId, 0x0003U);
662}
663
665TEST_F(GsdmlTest, MissingVendorNameProducesEmptyString)
666{
667 const auto dev = Parse(MINIMAL_GSDML);
668
669 EXPECT_TRUE(dev.vendorName.empty());
670}
671
673TEST_F(GsdmlTest, ParsesDeviceName)
674{
675 const auto dev = Parse(MINIMAL_GSDML);
676
677 EXPECT_EQ(dev.deviceName, "Test Device");
678}
679
681TEST_F(GsdmlTest, ParsesDapModuleIdent)
682{
683 const auto dev = Parse(MINIMAL_GSDML);
684
685 EXPECT_EQ(dev.dapModuleIdentNumber, 0x00000001U);
686}
687
689TEST_F(GsdmlTest, ParsesDapSubmoduleIdent)
690{
691 const auto dev = Parse(MINIMAL_GSDML);
692
693 EXPECT_EQ(dev.dapSubmoduleIdentNumber, 0x00000001U);
694}
695
697TEST_F(GsdmlTest, ParsesDapVirtualSubmodule)
698{
699 const auto dev = Parse(MINIMAL_GSDML);
700
701 ASSERT_NE(dev.FindModule("DAP_1"), nullptr);
702
703 const auto* module = dev.FindModule("DAP_1");
704
705 ASSERT_NE(module, nullptr);
706 ASSERT_EQ(module->submodules.size(), 1U);
707
708 const auto& submodule = module->submodules.at("DAP_Sub");
709
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);
714}
715
717TEST_F(GsdmlTest, ParsesModules)
718{
719 const auto dev = Parse(MINIMAL_GSDML);
720
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);
725}
726
728TEST_F(GsdmlTest, ParsesInputModule)
729{
730 const auto dev = Parse(MINIMAL_GSDML);
731
732 const auto* module = dev.FindModule("MOD_INPUT");
733
734 ASSERT_NE(module, nullptr);
735 EXPECT_EQ(module->moduleIdentNumber, 0x00000010U);
736 ASSERT_EQ(module->submodules.size(), 1U);
737
738 const auto& submodule = module->submodules.at("MOD_IN_Sub");
739
740 EXPECT_EQ(submodule.inputLength, 4);
741 EXPECT_EQ(submodule.outputLength, 0);
742}
743
745TEST_F(GsdmlTest, ParsesOutputModule)
746{
747 const auto dev = Parse(MINIMAL_GSDML);
748
749 const auto* module = dev.FindModule("MOD_OUTPUT");
750
751 ASSERT_NE(module, nullptr);
752 EXPECT_EQ(module->moduleIdentNumber, 0x00000020U);
753 ASSERT_EQ(module->submodules.size(), 1U);
754
755 const auto& submodule = module->submodules.at("MOD_OUT_Sub");
756
757 EXPECT_EQ(submodule.inputLength, 0);
758 EXPECT_EQ(submodule.outputLength, 2);
759}
760
762TEST_F(GsdmlTest, FindUnknownModuleReturnsNull)
763{
764 const auto dev = Parse(MINIMAL_GSDML);
765
766 EXPECT_EQ(dev.FindModule("NONEXISTENT"), nullptr);
767}
768
769// =============================================================================
770// Namespace handling
771// =============================================================================
772
774TEST_F(GsdmlTest, ParsesVendorIdWithNamespace)
775{
776 const auto dev = Parse(NAMESPACED_GSDML);
777
778 EXPECT_EQ(dev.vendorId, 0x0042U);
779}
780
782TEST_F(GsdmlTest, ParsesDeviceIdWithNamespace)
783{
784 const auto dev = Parse(NAMESPACED_GSDML);
785
786 EXPECT_EQ(dev.deviceId, 0x0007U);
787}
788
790TEST_F(GsdmlTest, ParsesDapWithNamespace)
791{
792 const auto dev = Parse(NAMESPACED_GSDML);
793
794 EXPECT_EQ(dev.dapModuleIdentNumber, 0x00000002U);
795 EXPECT_NE(dev.FindModule("DAP_NS"), nullptr);
796}
797
799TEST_F(GsdmlTest, ParsesDapIoWithNamespace)
800{
801 const auto dev = Parse(NAMESPACED_GSDML);
802
803 const auto* dap = dev.FindModule("DAP_NS");
804
805 ASSERT_NE(dap, nullptr);
806 ASSERT_EQ(dap->submodules.size(), 1U);
807
808 EXPECT_EQ(dap->submodules.at("Sub1").inputLength, 4);
809}
810
812TEST_F(GsdmlTest, ParsesModuleWithNamespace)
813{
814 const auto dev = Parse(NAMESPACED_GSDML);
815
816 const auto* module = dev.FindModule("MOD_A");
817
818 ASSERT_NE(module, nullptr);
819 EXPECT_EQ(module->moduleIdentNumber, 0x000000AAU);
820 EXPECT_EQ(module->submodules.at("MOD_A_Sub").outputLength, 4);
821}
822
824TEST_F(GsdmlTest, ParsesDifferentNamespaceVersion)
825{
826 const std::string xml = std::string(NAMESPACED_GSDML)
827 .replace(std::string(NAMESPACED_GSDML).find("GSDML/2.4"), 9, "GSDML/2.3");
828
829 const auto dev = Parse(xml);
830
831 EXPECT_EQ(dev.vendorId, 0x0042U);
832 EXPECT_NE(dev.FindModule("DAP_NS"), nullptr);
833}
834
835// =============================================================================
836// BuildIoSlots
837// =============================================================================
838
840TEST_F(GsdmlTest, BuildIoSlotsUsesFixedModules)
841{
842 const auto dev = Parse(MINIMAL_GSDML);
843 const auto slots = dev.BuildIoSlots();
844
845 EXPECT_EQ(slots.size(), 5U);
846}
847
849TEST_F(GsdmlTest, BuildIoSlotsPlacesDapAtSlotZero)
850{
851 const auto dev = Parse(MINIMAL_GSDML);
852 const auto slots = dev.BuildIoSlots();
853
854 const auto dapSlots = FindSlots(slots, 0);
855
856 EXPECT_EQ(dapSlots.size(), 3U);
857}
858
860TEST_F(GsdmlTest, BuildIoSlotsPlacesDapSubmoduleAtSubslotOne)
861{
862 const auto dev = Parse(MINIMAL_GSDML);
863 const auto slots = dev.BuildIoSlots();
864
865 const auto& slot = FindSlot(slots, 0, 1);
866
867 EXPECT_EQ(slot.inputLength, 1U);
868 EXPECT_EQ(slot.outputLength, 0U);
869 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
870 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
871}
872
874TEST_F(GsdmlTest, DISABLED_BuildIoSlotsPlacesInterfaceSubmodule)
875{
876 const auto dev = Parse(MINIMAL_GSDML);
877 const auto slots = dev.BuildIoSlots();
878
879 const auto& slot = FindSlot(slots, 0, 0x8000);
880
881 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
882 EXPECT_EQ(slot.submoduleIdent, 0x00000100U);
883 EXPECT_EQ(slot.inputLength, 0U);
884 EXPECT_EQ(slot.outputLength, 0U);
885}
886
888TEST_F(GsdmlTest, DISABLED_BuildIoSlotsPlacesPortSubmodule)
889{
890 const auto dev = Parse(MINIMAL_GSDML);
891 const auto slots = dev.BuildIoSlots();
892
893 const auto& slot = FindSlot(slots, 0, 0x8001);
894
895 EXPECT_EQ(slot.moduleIdent, 0x00000001U);
896 EXPECT_EQ(slot.submoduleIdent, 0x00000200U);
897}
898
900TEST_F(GsdmlTest, BuildIoSlotsPlacesInputModule)
901{
902 const auto dev = Parse(MINIMAL_GSDML);
903 const auto slots = dev.BuildIoSlots();
904
905 const auto& slot = FindSlot(slots, 1, 1);
906
907 EXPECT_EQ(slot.inputLength, 4U);
908 EXPECT_EQ(slot.outputLength, 0U);
909 EXPECT_EQ(slot.moduleIdent, 0x00000010U);
910 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
911}
912
914TEST_F(GsdmlTest, BuildIoSlotsPlacesOutputModule)
915{
916 const auto dev = Parse(MINIMAL_GSDML);
917 const auto slots = dev.BuildIoSlots();
918
919 const auto& slot = FindSlot(slots, 2, 1);
920
921 EXPECT_EQ(slot.inputLength, 0U);
922 EXPECT_EQ(slot.outputLength, 2U);
923 EXPECT_EQ(slot.moduleIdent, 0x00000020U);
924 EXPECT_EQ(slot.submoduleIdent, 0x00000001U);
925}
926
928TEST_F(GsdmlTest, BuildIoSlotsSupportsExplicitAssignments)
929{
930 const auto dev = Parse(MINIMAL_GSDML);
931
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"},
935 };
936
937 const auto slots = dev.BuildIoSlots(assignment);
938
939 const auto& output = FindSlot(slots, 3, 1);
940 const auto& input = FindSlot(slots, 5, 1);
941
942 EXPECT_EQ(output.outputLength, 2U);
943 EXPECT_EQ(input.inputLength, 4U);
944}
945
947TEST_F(GsdmlTest, BuildIoSlotsPreservesExplicitAssignmentOrder)
948{
949 const auto dev = Parse(MINIMAL_GSDML);
950
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"},
954 };
955
956 const auto slots = dev.BuildIoSlots(assignment);
957
958 ASSERT_EQ(slots.size(), 5U);
959
960 EXPECT_EQ(slots[3].slot, 5U);
961 EXPECT_EQ(slots[4].slot, 3U);
962}
963
965TEST_F(GsdmlTest, BuildIoSlotsRejectsUnknownModule)
966{
967 const auto dev = Parse(MINIMAL_GSDML);
968
969 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
970 {1, "NONEXISTENT", 1, "S"},
971 };
972
973 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
974}
975
977TEST_F(GsdmlTest, BuildIoSlotsRejectsUnknownSubmodule)
978{
979 const auto dev = Parse(MINIMAL_GSDML);
980
981 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
982 {1, "MOD_INPUT", 1, "NONEXISTENT"},
983 };
984
985 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
986}
987
989TEST_F(GsdmlTest, BuildIoSlotsRejectsDisallowedSlot)
990{
991 const auto dev = Parse(MINIMAL_GSDML);
992
993 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
994 {9, "MOD_INPUT", 1, "MOD_IN_Sub"},
995 };
996
997 EXPECT_THROW(dev.BuildIoSlots(assignment), std::invalid_argument);
998}
999
1001TEST_F(GsdmlTest, BuildIoSlotsAllowsUnrestrictedModule)
1002{
1003 const auto xml = R"xml(
1004<ISO15745Profile>
1005 <ProfileBody>
1006 <DeviceIdentity VendorID="1" DeviceID="2"/>
1007 <ApplicationProcess>
1008 <DeviceAccessPointList>
1009 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1010 </DeviceAccessPointList>
1011 <ModuleList>
1012 <ModuleItem ID="MOD" ModuleIdentNumber="2">
1013 <VirtualSubmoduleList>
1014 <VirtualSubmoduleItem ID="SUB" SubmoduleIdentNumber="3">
1015 <IOData>
1016 <Input>
1017 <DataItem DataType="Unsigned8"/>
1018 </Input>
1019 </IOData>
1020 </VirtualSubmoduleItem>
1021 </VirtualSubmoduleList>
1022 </ModuleItem>
1023 </ModuleList>
1024 </ApplicationProcess>
1025 </ProfileBody>
1026</ISO15745Profile>
1027)xml";
1028
1029 const auto dev = Parse(xml);
1030
1031 const std::vector<std::tuple<int, std::string, int, std::string>> assignment = {
1032 {99, "MOD", 1, "SUB"},
1033 };
1034
1035 const auto slots = dev.BuildIoSlots(assignment);
1036
1037 ASSERT_EQ(slots.size(), 1U);
1038 EXPECT_EQ(slots[0].slot, 99U);
1039}
1040
1042TEST_F(GsdmlTest, BuildIoSlotsMaintainsSlotOrder)
1043{
1044 const auto dev = Parse(MINIMAL_GSDML);
1045 const auto slots = dev.BuildIoSlots();
1046
1047 ASSERT_EQ(slots.size(), 5U);
1048
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);
1054}
1055
1056// =============================================================================
1057// Edge cases
1058// =============================================================================
1059
1061TEST_F(GsdmlTest, ModuleWithoutIoDataHasZeroLengths)
1062{
1063 const auto xml = R"xml(
1064<ISO15745Profile>
1065 <ProfileBody>
1066 <ApplicationProcess>
1067 <DeviceAccessPointList>
1068 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1069 </DeviceAccessPointList>
1070 <ModuleList>
1071 <ModuleItem ID="NO_IO" ModuleIdentNumber="0x99">
1072 <VirtualSubmoduleList>
1073 <VirtualSubmoduleItem ID="S1" SubmoduleIdentNumber="1"/>
1074 </VirtualSubmoduleList>
1075 </ModuleItem>
1076 </ModuleList>
1077 </ApplicationProcess>
1078 </ProfileBody>
1079</ISO15745Profile>
1080)xml";
1081
1082 const auto dev = Parse(xml);
1083 const auto* module = dev.FindModule("NO_IO");
1084
1085 ASSERT_NE(module, nullptr);
1086 ASSERT_EQ(module->submodules.size(), 1U);
1087
1088 EXPECT_EQ(module->submodules.at("S1").inputLength, 0);
1089 EXPECT_EQ(module->submodules.at("S1").outputLength, 0);
1090}
1091
1093TEST_F(GsdmlTest, ModuleWithoutVirtualSubmoduleListHasNoSubmodules)
1094{
1095 const auto xml = R"xml(
1096<ISO15745Profile>
1097 <ProfileBody>
1098 <DeviceIdentity VendorID="1" DeviceID="2"/>
1099 <ApplicationProcess>
1100 <DeviceAccessPointList>
1101 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1102 </DeviceAccessPointList>
1103 <ModuleList>
1104 <ModuleItem ID="EMPTY" ModuleIdentNumber="0xFF"/>
1105 </ModuleList>
1106 </ApplicationProcess>
1107 </ProfileBody>
1108</ISO15745Profile>
1109)xml";
1110
1111 const auto dev = Parse(xml);
1112 const auto* module = dev.FindModule("EMPTY");
1113
1114 ASSERT_NE(module, nullptr);
1115 EXPECT_TRUE(module->submodules.empty());
1116}
1117
1119TEST_F(GsdmlTest, MissingDeviceIdentityProducesZeroIds)
1120{
1121 const auto xml = R"xml(
1122<ISO15745Profile>
1123 <ProfileBody>
1124 <ApplicationProcess>
1125 <DeviceAccessPointList>
1126 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1127 </DeviceAccessPointList>
1128 </ApplicationProcess>
1129 </ProfileBody>
1130</ISO15745Profile>
1131)xml";
1132
1133 const auto dev = Parse(xml);
1134
1135 EXPECT_EQ(dev.vendorId, 0U);
1136 EXPECT_EQ(dev.deviceId, 0U);
1137}
1138
1140TEST_F(GsdmlTest, MissingDapProducesEmptyDapInformation)
1141{
1142 const auto xml = R"xml(
1143<ISO15745Profile>
1144 <ProfileBody>
1145 <DeviceIdentity VendorID="1" DeviceID="2"/>
1146 <ApplicationProcess>
1147 <ModuleList/>
1148 </ApplicationProcess>
1149 </ProfileBody>
1150</ISO15745Profile>
1151)xml";
1152
1153 const auto dev = Parse(xml);
1154
1155 EXPECT_EQ(dev.dapModuleIdentNumber, 0U);
1156 EXPECT_EQ(dev.dapSubmoduleIdentNumber, 0U);
1157 EXPECT_TRUE(dev.systemSubmodules.empty());
1158}
1159
1161TEST_F(GsdmlTest, DapWithoutUseableModulesProducesOnlyDapSlots)
1162{
1163 const auto xml = R"xml(
1164<ISO15745Profile>
1165 <ProfileBody>
1166 <DeviceIdentity VendorID="1" DeviceID="2"/>
1167 <ApplicationProcess>
1168 <DeviceAccessPointList>
1169 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1170 <VirtualSubmoduleList>
1171 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1172 <IOData>
1173 <Input>
1174 <DataItem DataType="Unsigned8"/>
1175 </Input>
1176 </IOData>
1177 </VirtualSubmoduleItem>
1178 </VirtualSubmoduleList>
1179 </DeviceAccessPointItem>
1180 </DeviceAccessPointList>
1181 <ModuleList/>
1182 </ApplicationProcess>
1183 </ProfileBody>
1184</ISO15745Profile>
1185)xml";
1186
1187 const auto dev = Parse(xml);
1188 const auto slots = dev.BuildIoSlots();
1189
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);
1194}
1195
1197TEST_F(GsdmlTest, MalformedXmlThrows)
1198{
1199 EXPECT_THROW(Parse("<ISO15745Profile><ProfileBody>"), std::runtime_error);
1200}
1201
1203TEST_F(GsdmlTest, EmptyXmlThrows)
1204{
1205 EXPECT_THROW(Parse(""), std::runtime_error);
1206}
1207
1209TEST_F(GsdmlTest, WhitespaceOnlyXmlThrows)
1210{
1211 EXPECT_THROW(Parse(" \n\t "), std::runtime_error);
1212}
1213
1214// =============================================================================
1215// ParseGsdml file tests
1216// =============================================================================
1217
1219TEST_F(GsdmlTest, ParseGsdmlReadsFile)
1220{
1221 const auto path = std::filesystem::temp_directory_path() / "gsdml_test.xml";
1222
1223 {
1224 std::ofstream file(path);
1225 ASSERT_TRUE(file.is_open());
1226 file << MINIMAL_GSDML;
1227 }
1228
1229 const auto dev = ParseGsdml(path.string());
1230
1231 EXPECT_EQ(dev.vendorId, 0x002AU);
1232 EXPECT_EQ(dev.deviceId, 0x0003U);
1233 EXPECT_EQ(dev.modules.size(), 3U);
1234
1235 std::filesystem::remove(path);
1236}
1237
1239TEST_F(GsdmlTest, ParseGsdmlThrowsForMissingFile)
1240{
1241 const auto path = std::filesystem::temp_directory_path() / "definitely_missing_gsdml_file.xml";
1242
1243 EXPECT_THROW(ParseGsdml(path.string()), std::runtime_error);
1244}
1245
1246// =============================================================================
1247// Text resolution
1248// =============================================================================
1249
1251TEST_F(GsdmlTest, ResolvesExternalTextId)
1252{
1253 const auto xml = R"xml(
1254<ISO15745Profile>
1255 <ProfileBody>
1256 <DeviceIdentity VendorID="1" DeviceID="2">
1257 <Name TextId="T_VENDOR"/>
1258 </DeviceIdentity>
1259 <ApplicationProcess>
1260 <ExternalTextList>
1261 <PrimaryLanguage>
1262 <Text TextId="T_VENDOR" Value="Vendor Name"/>
1263 </PrimaryLanguage>
1264 </ExternalTextList>
1265 <DeviceAccessPointList>
1266 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1267 </DeviceAccessPointList>
1268 </ApplicationProcess>
1269 </ProfileBody>
1270</ISO15745Profile>
1271)xml";
1272
1273 const auto dev = Parse(xml);
1274
1275 EXPECT_EQ(dev.vendorName, "Vendor Name");
1276}
1277
1279TEST_F(GsdmlTest, ResolvesLiteralNameValue)
1280{
1281 const auto xml = R"xml(
1282<ISO15745Profile>
1283 <ProfileBody>
1284 <DeviceIdentity VendorID="1" DeviceID="2">
1285 <Name Value="Literal Vendor"/>
1286 </DeviceIdentity>
1287 <ApplicationProcess>
1288 <DeviceAccessPointList>
1289 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1"/>
1290 </DeviceAccessPointList>
1291 </ApplicationProcess>
1292 </ProfileBody>
1293</ISO15745Profile>
1294)xml";
1295
1296 const auto dev = Parse(xml);
1297
1298 EXPECT_EQ(dev.vendorName, "Literal Vendor");
1299}
1300
1301// =============================================================================
1302// Numeric parsing
1303// =============================================================================
1304
1306TEST_F(GsdmlTest, ParsesHexadecimalIdentifiers)
1307{
1308 const auto dev = Parse(MINIMAL_GSDML);
1309
1310 EXPECT_EQ(dev.vendorId, 42U);
1311 EXPECT_EQ(dev.deviceId, 3U);
1312 EXPECT_EQ(dev.dapModuleIdentNumber, 1U);
1313}
1314
1316TEST_F(GsdmlTest, ParsesDecimalIdentifiers)
1317{
1318 const auto dev = Parse(DATA_TYPES_GSDML);
1319
1320 EXPECT_EQ(dev.vendorId, 42U);
1321 EXPECT_EQ(dev.deviceId, 7U);
1322}
1323
1325TEST_F(GsdmlTest, InvalidNumericAttributeFallsBackToZero)
1326{
1327 const auto xml = R"xml(
1328<ISO15745Profile>
1329 <ProfileBody>
1330 <DeviceIdentity VendorID="not-a-number" DeviceID="7"/>
1331 <ApplicationProcess>
1332 <DeviceAccessPointList>
1333 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="invalid"/>
1334 </DeviceAccessPointList>
1335 </ApplicationProcess>
1336 </ProfileBody>
1337</ISO15745Profile>
1338)xml";
1339
1340 const auto dev = Parse(xml);
1341
1342 EXPECT_EQ(dev.vendorId, 0U);
1343 EXPECT_EQ(dev.deviceId, 7U);
1344 EXPECT_EQ(dev.dapModuleIdentNumber, 0U);
1345}
1346
1347// =============================================================================
1348// DataItem metadata
1349// =============================================================================
1350
1352TEST_F(GsdmlTest, ParsesDataItemMetadata)
1353{
1354 const auto xml = R"xml(
1355<ISO15745Profile>
1356 <ProfileBody>
1357 <DeviceIdentity VendorID="1" DeviceID="2"/>
1358 <ApplicationProcess>
1359 <DeviceAccessPointList>
1360 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1361 <VirtualSubmoduleList>
1362 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1363 <IOData>
1364 <Input>
1365 <DataItem DataType="Unsigned16" TextId="VALUE"/>
1366 </Input>
1367 </IOData>
1368 </VirtualSubmoduleItem>
1369 </VirtualSubmoduleList>
1370 </DeviceAccessPointItem>
1371 </DeviceAccessPointList>
1372 </ApplicationProcess>
1373 </ProfileBody>
1374</ISO15745Profile>
1375)xml";
1376
1377 const auto dev = Parse(xml);
1378 const auto* dap = dev.FindModule("DAP");
1379
1380 ASSERT_NE(dap, nullptr);
1381
1382 const auto& submodule = dap->submodules.at("S");
1383
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);
1388}
1389
1391TEST_F(GsdmlTest, SeparatesInputAndOutputDataItems)
1392{
1393 const auto xml = R"xml(
1394<ISO15745Profile>
1395 <ProfileBody>
1396 <DeviceIdentity VendorID="1" DeviceID="2"/>
1397 <ApplicationProcess>
1398 <DeviceAccessPointList>
1399 <DeviceAccessPointItem ID="DAP" ModuleIdentNumber="1">
1400 <VirtualSubmoduleList>
1401 <VirtualSubmoduleItem ID="S" SubmoduleIdentNumber="1">
1402 <IOData>
1403 <Input>
1404 <DataItem DataType="Unsigned8"/>
1405 </Input>
1406 <Output>
1407 <DataItem DataType="Unsigned32"/>
1408 </Output>
1409 </IOData>
1410 </VirtualSubmoduleItem>
1411 </VirtualSubmoduleList>
1412 </DeviceAccessPointItem>
1413 </DeviceAccessPointList>
1414 </ApplicationProcess>
1415 </ProfileBody>
1416</ISO15745Profile>
1417)xml";
1418
1419 const auto dev = Parse(xml);
1420 const auto* dap = dev.FindModule("DAP");
1421
1422 ASSERT_NE(dap, nullptr);
1423
1424 const auto& submodule = dap->submodules.at("S");
1425
1426 ASSERT_EQ(submodule.inputItems.size(), 1U);
1427 ASSERT_EQ(submodule.outputItems.size(), 1U);
1428
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);
1433}
1434
1435} // namespace
1436
1437} // namespace profinet::gsdml
Declares the GSDML parser and PROFINET device-description data model.
GSDMLDevice ParseGsdmlString(const std::string &xml)
Parse GSDML content already held in memory.
Definition gsdml.cpp:1114
GSDMLDevice ParseGsdml(const std::string &path)
Parse a GSDML file into a GSDMLDevice.
Definition gsdml.cpp:1398
TEST_F(GsdmlRealDeviceTest, ParsesAumaGsdml)