You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/10/26 15:46:43 UTC

[plc4x] 01/02: - Continued working on the serializer/parser testsuite for go

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 75bc37050414cda0fc5654c8315d052df88e269f
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Oct 26 16:46:15 2020 +0100

    - Continued working on the serializer/parser testsuite for go
---
 .../BaseFreemarkerLanguageTemplateHelper.java      |   7 +-
 .../apache/plc4x/language/go/GoLanguageOutput.java |   5 +-
 .../templates/go/parser-factory-template.ftlh      |  95 +++++++++++
 .../apache/plc4x/java/s7/utils/StaticHelper.java   |  10 ++
 sandbox/plc4go/cmd/main/drivers/modbus_test.go     |   2 +-
 .../tests/modbus_parser_serializer_test.go}        |  20 +--
 sandbox/plc4go/go.mod                              |   2 +
 sandbox/plc4go/go.sum                              |   8 +-
 .../bacnetip/readwrite/model/ParserHelper.go       |  78 +++++++++
 .../knxnetip/readwrite/model/ParserHelper.go       |  90 ++++++++++
 .../plc4go/modbus/readwrite/model/ParserHelper.go  |  62 +++++++
 .../internal/plc4go/s7/readwrite/model/DataItem.go |  16 ++
 .../plc4go/s7/readwrite/model/ParserHelper.go      |  87 ++++++++++
 .../plc4go/s7/readwrite/model/S7StaticHelper.go    |   4 +
 .../plc4go/testutils/ParserSerializerTestRunner.go | 185 ++++++++++++++++++++-
 sandbox/plc4go/internal/plc4go/utils/CastUtils.go  |  26 +++
 .../plc4go/utils/ParserHelper.go}                  |  12 +-
 .../plc4go/utils/Serializable.go}                  |  12 +-
 18 files changed, 677 insertions(+), 44 deletions(-)

diff --git a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
index 74b91ff..0ce48c9 100644
--- a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
+++ b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
@@ -98,10 +98,15 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
         return flavorName;
     }
 
-    protected Map<String, TypeDefinition> getTypeDefinitions() {
+    public Map<String, TypeDefinition> getTypeDefinitions() {
         return types;
     }
 
+    public List<TypeDefinition> getComplexTypeRootDefinitions() {
+        return types.values().stream().filter(typeDefinition -> (typeDefinition instanceof ComplexTypeDefinition) &&
+            !(typeDefinition instanceof DiscriminatedComplexTypeDefinition)).collect(Collectors.toList());
+    }
+
     protected static Map<String, SimpleTypeReference> getBuiltInFieldTypes() {
         return builtInFields;
     }
diff --git a/build-utils/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java b/build-utils/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
index b16b36e..a0f91a6 100644
--- a/build-utils/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
+++ b/build-utils/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
@@ -41,9 +41,8 @@ public class GoLanguageOutput extends FreemarkerLanguageOutput {
 
     @Override
     protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) throws IOException {
-        /*return Collections.singletonList(
-            freemarkerConfiguration.getTemplate("templates/go/enum-package-info-template.ftlh"));*/
-        return Collections.emptyList();
+        return Collections.singletonList(
+            freemarkerConfiguration.getTemplate("templates/go/parser-factory-template.ftlh"));
     }
 
     @Override
diff --git a/build-utils/language-go/src/main/resources/templates/go/parser-factory-template.ftlh b/build-utils/language-go/src/main/resources/templates/go/parser-factory-template.ftlh
new file mode 100644
index 0000000..cc848bf
--- /dev/null
+++ b/build-utils/language-go/src/main/resources/templates/go/parser-factory-template.ftlh
@@ -0,0 +1,95 @@
+<#--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.go.GoLanguageTemplateHelper" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+<#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" -->
+<#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" -->
+<#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" -->
+<#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" -->
+<#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" -->
+<#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" -->
+<#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" -->
+<#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" -->
+<#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" -->
+<#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" -->
+<#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" -->
+<#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" -->
+<#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" -->
+<#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" -->
+<#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" -->
+<#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" -->
+${helper.fileName(protocolName, languageName, outputFlavor)?replace(".", "/")}/model/ParserHelper.go
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package model
+
+import (
+    "errors"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+)
+
+type ${protocolName?cap_first}ParserHelper struct {
+}
+
+func (m ${protocolName?cap_first}ParserHelper) Parse(typeName string, arguments []string, io *utils.ReadBuffer) (spi.Message, error) {
+    switch typeName {
+<#list helper.getComplexTypeRootDefinitions() as typeDefinition>
+    case "${typeDefinition.name}":
+    <#if typeDefinition.parserArguments?has_content>
+        <#list typeDefinition.parserArguments as parserArgument>
+            <#if helper.isSimpleTypeReference(parserArgument.type)>
+        ${parserArgument.name}, err := utils.StrTo${helper.getLanguageTypeNameForTypeReference(parserArgument.type)?cap_first}(arguments[${parserArgument?index}])
+        if err != nil {
+            return nil, err
+        }
+            <#else>
+        var ${parserArgument.name} I${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}
+            </#if>
+        </#list>
+    </#if>
+        return ${typeDefinition.name}Parse(io<#if typeDefinition.parserArguments?has_content>, <#list typeDefinition.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#list></#if>)
+</#list>
+    }
+    return nil, errors.New("Unsupported type " + typeName)
+}
+</#outputformat>
\ No newline at end of file
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index e76539c..71234e7 100644
--- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -137,4 +137,14 @@ public class StaticHelper {
         throw new NotImplementedException("Serializing STRING not implemented");
     }
 
+    public static String parseS7Char(ReadBuffer io, Object encoding) {
+        // Read the full size of the string.
+        return io.readString(8, (String) encoding);
+    }
+
+    public static void serializeS7Char(WriteBuffer io, PlcValue value, Object encoding) {
+        // TODO: Need to implement the serialization or we can't write strings
+        throw new NotImplementedException("Serializing STRING not implemented");
+    }
+
 }
diff --git a/sandbox/plc4go/cmd/main/drivers/modbus_test.go b/sandbox/plc4go/cmd/main/drivers/modbus_test.go
index 26b0c9a..139e472 100644
--- a/sandbox/plc4go/cmd/main/drivers/modbus_test.go
+++ b/sandbox/plc4go/cmd/main/drivers/modbus_test.go
@@ -36,7 +36,7 @@ import (
 
 func TestModbus(t *testing.T) {
 
-	testutils.NewParserSerializerTestsuite("")
+	testutils.RunParserSerializerTestsuite("")
 
 	test(t, "000000000006ff0408d20002", false)
 	test(t, "7cfe000000c9ff04c600000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000004000000000000000000000000000001db000001d600004a380000000000000000000000000000000000000000000000000000000000006461696d006e0000000000000000000000000000303100300000000000000000000000000000000000000000000000000000000000000000000000000000", true)
diff --git a/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go b/sandbox/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
similarity index 75%
copy from sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go
copy to sandbox/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
index 408a230..7594366 100644
--- a/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go
+++ b/sandbox/plc4go/cmd/main/drivers/tests/modbus_parser_serializer_test.go
@@ -16,21 +16,13 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-package testutils
+package tests
 
 import (
-	"fmt"
-	"log"
-	"os"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/testutils"
+    "testing"
 )
 
-type ParserSerializerTestsuite struct {
-}
-
-func NewParserSerializerTestsuite(testPath string) {
-	dir, err := os.Getwd()
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Println(dir)
-}
+func TestModbusParserSerializer(t *testing.T) {
+    testutils.RunParserSerializerTestsuite(t, "assets/testing/protocols/modbus/ParserSerializerTestsuite.xml")
+}
\ No newline at end of file
diff --git a/sandbox/plc4go/go.mod b/sandbox/plc4go/go.mod
index 12ff77e..99673e6 100644
--- a/sandbox/plc4go/go.mod
+++ b/sandbox/plc4go/go.mod
@@ -23,5 +23,7 @@ go 1.15
 require github.com/sirupsen/logrus v1.7.0
 
 require (
+	github.com/ajankovic/xdiff v0.0.1
 	github.com/icza/bitio v1.0.0
+	github.com/subchen/go-xmldom v1.1.2
 )
diff --git a/sandbox/plc4go/go.sum b/sandbox/plc4go/go.sum
index 0f6ce3d..e7a4d67 100644
--- a/sandbox/plc4go/go.sum
+++ b/sandbox/plc4go/go.sum
@@ -1,7 +1,9 @@
+github.com/ajankovic/xdiff v0.0.1 h1:V1cj8t5xwYzm6ZGPqPOlAc9AIajXuTEn41D/1MJBWMM=
+github.com/ajankovic/xdiff v0.0.1/go.mod h1:SUmEZ67uB97I0zkiuQ+lb+LOms9ipn8X+p+2RdJV710=
+github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307 h1:C735MoY/X+UOx6SECmHk5pVOj51h839Ph13pEoY8UmU=
+github.com/antchfx/xpath v0.0.0-20170515025933-1f3266e77307/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259 h1:ZHJ7+IGpuOXtVf6Zk/a3WuHQgkC+vXwaqfUBDFwahtI=
-github.com/golang-collections/go-datastructures v0.0.0-20150211160725-59788d5eb259/go.mod h1:9Qcha0gTWLw//0VNka1Cbnjvg3pNKGFdAm7E9sBabxE=
 github.com/icza/bitio v1.0.0 h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8=
 github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
 github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
@@ -12,5 +14,7 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/subchen/go-xmldom v1.1.2 h1:7evI2YqfYYOnuj+PBwyaOZZYjl3iWq35P6KfBUw9jeU=
+github.com/subchen/go-xmldom v1.1.2/go.mod h1:6Pg/HuX5/T4Jlj0IPJF1sRxKVoI/rrKP6LIMge9d5/8=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/sandbox/plc4go/internal/plc4go/bacnetip/readwrite/model/ParserHelper.go b/sandbox/plc4go/internal/plc4go/bacnetip/readwrite/model/ParserHelper.go
new file mode 100644
index 0000000..930ba37
--- /dev/null
+++ b/sandbox/plc4go/internal/plc4go/bacnetip/readwrite/model/ParserHelper.go
@@ -0,0 +1,78 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package model
+
+import (
+    "errors"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+)
+
+type BacnetipParserHelper struct {
+}
+
+func (m BacnetipParserHelper) Parse(typeName string, arguments []string, io *utils.ReadBuffer) (spi.Message, error) {
+    switch typeName {
+    case "APDU":
+        apduLength, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return APDUParse(io, apduLength)
+    case "BACnetTag":
+        return BACnetTagParse(io)
+    case "BACnetTagWithContent":
+        return BACnetTagWithContentParse(io)
+    case "BACnetError":
+        return BACnetErrorParse(io)
+    case "NLM":
+        apduLength, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return NLMParse(io, apduLength)
+    case "BACnetConfirmedServiceRequest":
+        len, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return BACnetConfirmedServiceRequestParse(io, len)
+    case "BACnetAddress":
+        return BACnetAddressParse(io)
+    case "BACnetConfirmedServiceACK":
+        return BACnetConfirmedServiceACKParse(io)
+    case "BACnetUnconfirmedServiceRequest":
+        len, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return BACnetUnconfirmedServiceRequestParse(io, len)
+    case "BACnetServiceAck":
+        return BACnetServiceAckParse(io)
+    case "BVLC":
+        return BVLCParse(io)
+    case "NPDU":
+        npduLength, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return NPDUParse(io, npduLength)
+    }
+    return nil, errors.New("Unsupported type " + typeName)
+}
diff --git a/sandbox/plc4go/internal/plc4go/knxnetip/readwrite/model/ParserHelper.go b/sandbox/plc4go/internal/plc4go/knxnetip/readwrite/model/ParserHelper.go
new file mode 100644
index 0000000..0743306
--- /dev/null
+++ b/sandbox/plc4go/internal/plc4go/knxnetip/readwrite/model/ParserHelper.go
@@ -0,0 +1,90 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package model
+
+import (
+    "errors"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+)
+
+type KnxnetipParserHelper struct {
+}
+
+func (m KnxnetipParserHelper) Parse(typeName string, arguments []string, io *utils.ReadBuffer) (spi.Message, error) {
+    switch typeName {
+    case "CEMIAdditionalInformation":
+        return CEMIAdditionalInformationParse(io)
+    case "HPAIControlEndpoint":
+        return HPAIControlEndpointParse(io)
+    case "TunnelingResponseDataBlock":
+        return TunnelingResponseDataBlockParse(io)
+    case "ConnectionResponseDataBlock":
+        return ConnectionResponseDataBlockParse(io)
+    case "TunnelingRequestDataBlock":
+        return TunnelingRequestDataBlockParse(io)
+    case "KNXGroupAddress":
+        numLevels, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return KNXGroupAddressParse(io, numLevels)
+    case "DIBDeviceInfo":
+        return DIBDeviceInfoParse(io)
+    case "DeviceConfigurationRequestDataBlock":
+        return DeviceConfigurationRequestDataBlockParse(io)
+    case "DeviceConfigurationAckDataBlock":
+        return DeviceConfigurationAckDataBlockParse(io)
+    case "DIBSuppSvcFamilies":
+        return DIBSuppSvcFamiliesParse(io)
+    case "ConnectionRequestInformation":
+        return ConnectionRequestInformationParse(io)
+    case "HPAIDiscoveryEndpoint":
+        return HPAIDiscoveryEndpointParse(io)
+    case "ProjectInstallationIdentifier":
+        return ProjectInstallationIdentifierParse(io)
+    case "KNXAddress":
+        return KNXAddressParse(io)
+    case "CEMIDataFrame":
+        return CEMIDataFrameParse(io)
+    case "ServiceId":
+        return ServiceIdParse(io)
+    case "KNXNetIPMessage":
+        return KNXNetIPMessageParse(io)
+    case "HPAIDataEndpoint":
+        return HPAIDataEndpointParse(io)
+    case "RelativeTimestamp":
+        return RelativeTimestampParse(io)
+    case "CEMI":
+        size, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return CEMIParse(io, size)
+    case "MACAddress":
+        return MACAddressParse(io)
+    case "CEMIFrame":
+        return CEMIFrameParse(io)
+    case "DeviceStatus":
+        return DeviceStatusParse(io)
+    case "IPAddress":
+        return IPAddressParse(io)
+    }
+    return nil, errors.New("Unsupported type " + typeName)
+}
diff --git a/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ParserHelper.go b/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ParserHelper.go
new file mode 100644
index 0000000..6f94f1f
--- /dev/null
+++ b/sandbox/plc4go/internal/plc4go/modbus/readwrite/model/ParserHelper.go
@@ -0,0 +1,62 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package model
+
+import (
+    "errors"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+)
+
+type ModbusParserHelper struct {
+}
+
+func (m ModbusParserHelper) Parse(typeName string, arguments []string, io *utils.ReadBuffer) (spi.Message, error) {
+    switch typeName {
+    case "ModbusPDUWriteFileRecordRequestItem":
+        return ModbusPDUWriteFileRecordRequestItemParse(io)
+    case "ModbusPDUReadFileRecordResponseItem":
+        return ModbusPDUReadFileRecordResponseItemParse(io)
+    case "ModbusConstants":
+        return ModbusConstantsParse(io)
+    case "ModbusTcpADU":
+        response, err := utils.StrToBool(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return ModbusTcpADUParse(io, response)
+    case "ModbusPDUWriteFileRecordResponseItem":
+        return ModbusPDUWriteFileRecordResponseItemParse(io)
+    case "ModbusPDU":
+        response, err := utils.StrToBool(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return ModbusPDUParse(io, response)
+    case "ModbusPDUReadFileRecordRequestItem":
+        return ModbusPDUReadFileRecordRequestItemParse(io)
+    case "ModbusSerialADU":
+        response, err := utils.StrToBool(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return ModbusSerialADUParse(io, response)
+    }
+    return nil, errors.New("Unsupported type " + typeName)
+}
diff --git a/sandbox/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
index c70dd05..8f80b6e 100644
--- a/sandbox/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
+++ b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/DataItem.go
@@ -166,6 +166,22 @@ func DataItemParse(io *utils.ReadBuffer, dataProtocolId uint8, stringLength int3
                 return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
             }
             return values.NewPlcLREAL(value), nil
+        case dataProtocolId == 41: // CHAR
+
+            // Manual Field (value)
+            value, _valueErr := StaticHelperParseS7Char(io, "UTF-8")
+            if _valueErr != nil {
+                return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
+            }
+            return values.NewPlcCHAR(value), nil
+        case dataProtocolId == 42: // CHAR
+
+            // Manual Field (value)
+            value, _valueErr := StaticHelperParseS7Char(io, "UTF-16")
+            if _valueErr != nil {
+                return nil, errors.New("Error parsing 'value' field " + _valueErr.Error())
+            }
+            return values.NewPlcCHAR(value), nil
         case dataProtocolId == 43: // STRING
 
             // Manual Field (value)
diff --git a/sandbox/plc4go/internal/plc4go/s7/readwrite/model/ParserHelper.go b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/ParserHelper.go
new file mode 100644
index 0000000..5e51dd9
--- /dev/null
+++ b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/ParserHelper.go
@@ -0,0 +1,87 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+package model
+
+import (
+    "errors"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+)
+
+type S7ParserHelper struct {
+}
+
+func (m S7ParserHelper) Parse(typeName string, arguments []string, io *utils.ReadBuffer) (spi.Message, error) {
+    switch typeName {
+    case "SzlId":
+        return SzlIdParse(io)
+    case "S7Message":
+        return S7MessageParse(io)
+    case "S7VarPayloadStatusItem":
+        return S7VarPayloadStatusItemParse(io)
+    case "S7Parameter":
+        messageType, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return S7ParameterParse(io, messageType)
+    case "SzlDataTreeItem":
+        return SzlDataTreeItemParse(io)
+    case "COTPPacket":
+        cotpLen, err := utils.StrToUint16(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return COTPPacketParse(io, cotpLen)
+    case "S7PayloadUserDataItem":
+        cpuFunctionType, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return S7PayloadUserDataItemParse(io, cpuFunctionType)
+    case "COTPParameter":
+        rest, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return COTPParameterParse(io, rest)
+    case "TPKTPacket":
+        return TPKTPacketParse(io)
+    case "S7Payload":
+        messageType, err := utils.StrToUint8(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        var parameter IS7Parameter
+        return S7PayloadParse(io, messageType, parameter)
+    case "S7VarRequestParameterItem":
+        return S7VarRequestParameterItemParse(io)
+    case "S7VarPayloadDataItem":
+        lastItem, err := utils.StrToBool(arguments[0])
+        if err != nil {
+            return nil, err
+        }
+        return S7VarPayloadDataItemParse(io, lastItem)
+    case "S7Address":
+        return S7AddressParse(io)
+    case "S7ParameterUserDataItem":
+        return S7ParameterUserDataItemParse(io)
+    }
+    return nil, errors.New("Unsupported type " + typeName)
+}
diff --git a/sandbox/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go
index 08bb781..64965ce 100644
--- a/sandbox/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go
+++ b/sandbox/plc4go/internal/plc4go/s7/readwrite/model/S7StaticHelper.go
@@ -135,3 +135,7 @@ func StaticHelperParseS7String(io *utils.ReadBuffer, stringLength int32, encodin
     }*/
     return "", nil
 }
+
+func StaticHelperParseS7Char(io *utils.ReadBuffer, encoding string) (uint8, error) {
+    return 0, nil
+}
\ No newline at end of file
diff --git a/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go b/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go
index 408a230..20de594 100644
--- a/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go
+++ b/sandbox/plc4go/internal/plc4go/testutils/ParserSerializerTestRunner.go
@@ -19,18 +19,185 @@
 package testutils
 
 import (
-	"fmt"
-	"log"
+    "encoding/hex"
+    "encoding/xml"
+    "errors"
+    "fmt"
+    "github.com/ajankovic/xdiff"
+    "github.com/ajankovic/xdiff/parser"
+    "github.com/subchen/go-xmldom"
 	"os"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/modbus/readwrite/model"
+    "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/utils"
+    "strconv"
+    "strings"
+    "testing"
 )
 
-type ParserSerializerTestsuite struct {
+func RunParserSerializerTestsuite(t *testing.T, testPath string) {
+    // Get the current working directory
+    path, err := os.Getwd()
+    if err != nil {
+        t.Error(err)
+    }
+
+    // Check if the test-file is available
+    info, err := os.Stat(path + "/../../../../" + testPath)
+    if os.IsNotExist(err) {
+        t.Error("Test-File doesn't exist")
+    }
+    if info.IsDir() {
+        t.Error("Test-File refers to a directory")
+    }
+
+    // Open a reader for this file
+    dat, err := os.Open(path + "/../../../../" + testPath)
+    if err != nil {
+        t.Error("Error opening file")
+    }
+
+    // Read the xml
+    node := xmldom.Must(xmldom.Parse(dat)).Root
+
+    if node.Name != "testsuite" {
+        t.Error("Invalid document structure")
+    }
+    var testsuiteName string
+    for _, childPtr := range node.Children {
+        curFailed := false
+        child := *childPtr
+        if child.Name == "name" {
+            testsuiteName = child.Text
+        } else if child.Name != "testcase" {
+            t.Error("Invalid document structure")
+            curFailed = true
+        } else {
+            t.Logf("running testsuite: %s test: %s", testsuiteName, (*(child.FindOneByName("name"))).Text)
+            rawInputText := (*(child.FindOneByName("raw"))).Text
+            rootType := (*(child.FindOneByName("root-type"))).Text
+            parserArgumentsXml := child.FindOneByName("parser-arguments")
+            var parserArguments []string
+            if parserArgumentsXml != nil {
+                for _, parserArgumentXml := range parserArgumentsXml.Children {
+                    parserArguments = append(parserArguments, parserArgumentXml.Text)
+                }
+            }
+            referenceXml := child.FindOneByName("xml")
+            normalizeXml(referenceXml)
+            referenceSerialized := referenceXml.FirstChild().XML()
+
+            // Get the raw input by decoding the hex-encoded binary input
+            rawInput, err := hex.DecodeString(rawInputText)
+            if err != nil {
+                t.Errorf("Error decoding test input")
+                t.Fail()
+                curFailed = true
+            }
+            readBuffer := utils.ReadBufferNew(rawInput)
+
+            // Parse the input according to the settings of the testcase
+            helper := new(model.ModbusParserHelper)
+            msg, err := helper.Parse(rootType, parserArguments, readBuffer)
+            if err != nil {
+                t.Error("Error parsing input data: " + err.Error())
+                t.Fail()
+                curFailed = true
+            }
+
+            // Serialize the parsed object to XML
+            actualSerialized, err := xml.Marshal(msg)
+            if err != nil {
+                t.Error("Error serializing the actual message: " + err.Error())
+                t.Fail()
+                curFailed = true
+            }
+
+            // Compare the actual and the expected xml
+            err = compareResults(actualSerialized, []byte(referenceSerialized))
+            if err != nil {
+                t.Error("Error comparing the results: " + err.Error())
+                t.Fail()
+                curFailed = true
+            }
+
+            // If all was ok, serialize the object again
+            s, ok := msg.(utils.Serializable)
+            if !ok {
+                t.Error("Couldn't cast message to Serializable")
+                t.Fail()
+                curFailed = true
+            }
+            writeBuffer := utils.WriteBufferNew()
+            err = s.Serialize(*writeBuffer)
+            if !ok {
+                t.Error("Couldn't serialize message back to byte array")
+                t.Fail()
+                curFailed = true
+            }
+
+            // Check if the output matches in size and content
+            rawOutput := writeBuffer.GetBytes()
+            if len(rawInput) != len(rawOutput) {
+                t.Error("Couldn't serialize message back to byte array")
+                t.Fail()
+                curFailed = true
+            }
+            for i, val := range rawInput {
+                if rawOutput[i] != val {
+                    t.Error("Raw output doesn't match input at position: " + strconv.Itoa(i))
+                    t.Fail()
+                    curFailed = true
+                }
+            }
+
+            if curFailed {
+                // All worked
+                t.Logf("FAILED")
+            } else {
+                // All worked
+                t.Logf("SUCCESS")
+            }
+        }
+    }
+    fmt.Printf("name = %v\n", node.Name)
 }
 
-func NewParserSerializerTestsuite(testPath string) {
-	dir, err := os.Getwd()
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Println(dir)
+// Mainly remove linebreaks from text content.
+func normalizeXml(input *xmldom.Node) {
+    if len(input.Children) > 0 {
+        for _, child := range input.Children {
+            normalizeXml(child)
+        }
+    }
+    if len(input.Text) > 0 {
+        if strings.Contains(input.Text, "\n") {
+            input.Text = strings.Replace(input.Text, "\n", "", -1)
+        }
+    }
 }
+
+func compareResults(actualString []byte, referenceString []byte) error {
+    // Now parse the xml strings of the actual and the reference in xdiff's dom
+    p := parser.New()
+    actual, err := p.ParseBytes(actualString)
+    if err != nil {
+        return errors.New("Error parsing actual input: " + err.Error())
+    }
+    reference, err := p.ParseBytes(referenceString)
+    if err != nil {
+        return errors.New("Error parsing reference input: " + err.Error())
+    }
+    // Use XDiff to actually do the comparison
+    diff, err := xdiff.Compare(actual, reference)
+    if err != nil {
+        return errors.New("Error comparing xml trees: " + err.Error())
+    }
+    if diff != nil {
+        enc := xdiff.NewTextEncoder(os.Stdout)
+        if err := enc.Encode(diff); err != nil {
+            return errors.New("Error outputting results: " + err.Error())
+        }
+        return errors.New("there were differences")
+    }
+    return nil
+}
\ No newline at end of file
diff --git a/sandbox/plc4go/internal/plc4go/utils/CastUtils.go b/sandbox/plc4go/internal/plc4go/utils/CastUtils.go
index 01b7006..46c15a0 100644
--- a/sandbox/plc4go/internal/plc4go/utils/CastUtils.go
+++ b/sandbox/plc4go/internal/plc4go/utils/CastUtils.go
@@ -18,6 +18,8 @@
 //
 package utils
 
+import "strconv"
+
 func Int8ToUint8(input []int8) []uint8 {
     output := make([]uint8, len(input))
     for i, _val := range input {
@@ -33,3 +35,27 @@ func Int8ToByte(input []int8) []byte {
     }
     return output
 }
+
+func StrToBool(str string) (bool, error) {
+    boolVal, err := strconv.ParseBool(str)
+    if err != nil {
+        return false, err
+    }
+    return boolVal, nil
+}
+
+func StrToUint8(str string) (uint8, error) {
+    intVal, err := strconv.ParseInt(str, 10, 8)
+    if err != nil {
+        return 0, err
+    }
+    return uint8(intVal), nil
+}
+
+func StrToUint16(str string) (uint16, error) {
+    intVal, err := strconv.ParseInt(str, 10, 16)
+    if err != nil {
+        return 0, err
+    }
+    return uint16(intVal), nil
+}
diff --git a/sandbox/plc4go/go.mod b/sandbox/plc4go/internal/plc4go/utils/ParserHelper.go
similarity index 80%
copy from sandbox/plc4go/go.mod
copy to sandbox/plc4go/internal/plc4go/utils/ParserHelper.go
index 12ff77e..b4b80d2 100644
--- a/sandbox/plc4go/go.mod
+++ b/sandbox/plc4go/internal/plc4go/utils/ParserHelper.go
@@ -16,12 +16,12 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-module plc4x.apache.org/plc4go-modbus-driver/v0
+package utils
 
-go 1.15
+import "plc4x.apache.org/plc4go-modbus-driver/v0/internal/plc4go/spi"
 
-require github.com/sirupsen/logrus v1.7.0
+type ParserHelper interface {
 
-require (
-	github.com/icza/bitio v1.0.0
-)
+    Parse(typeName string, arguments []string, io ReadBuffer) (spi.Message, error)
+
+}
diff --git a/sandbox/plc4go/go.mod b/sandbox/plc4go/internal/plc4go/utils/Serializable.go
similarity index 85%
copy from sandbox/plc4go/go.mod
copy to sandbox/plc4go/internal/plc4go/utils/Serializable.go
index 12ff77e..b73ffe1 100644
--- a/sandbox/plc4go/go.mod
+++ b/sandbox/plc4go/internal/plc4go/utils/Serializable.go
@@ -16,12 +16,8 @@
 // specific language governing permissions and limitations
 // under the License.
 //
-module plc4x.apache.org/plc4go-modbus-driver/v0
+package utils
 
-go 1.15
-
-require github.com/sirupsen/logrus v1.7.0
-
-require (
-	github.com/icza/bitio v1.0.0
-)
+type Serializable interface {
+    Serialize(io WriteBuffer) error
+}