Skip to content

Commit

Permalink
Fix XML deserialization for over-consumption (#29)
Browse files Browse the repository at this point in the history
We read a token too much in `unmarshalXxx` functions. The bug went
unnoticed as all our examples used indented XML, which eclipsed the
over-consumption.

In this patch, we remove the `unmarshalXxx`, as they turn out to be
redundant, and use `readXxxWithLookahead` to appropriately read the
tokens without over-consumption.

Fixes #24.
  • Loading branch information
mristin authored May 16, 2024
1 parent 17a77b5 commit 6620ab1
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 1,386 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
assetAdministrationShells/*[0]/embeddedDataSpecifications/*[0]/dataSpecificationContent: Expected a start element, but got an end element dataSpecificationContent in namespace https://admin-shell.io/aas/3/0
assetAdministrationShells/*[0]/embeddedDataSpecifications/*[0]/dataSpecificationContent: Expected a start element, but got text Unexpected string value
Original file line number Diff line number Diff line change
@@ -1 +1 @@
submodels/*[0]/submodelElements/*[0]/inputVariables/*[0]/value: Expected a start element, but got an end element value in namespace https://admin-shell.io/aas/3/0
submodels/*[0]/submodelElements/*[0]/inputVariables/*[0]/value: Expected a start element, but got text Unexpected string value
176 changes: 176 additions & 0 deletions xmlization/test/edge_cases_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package xmlization_test

import (
"bytes"
"encoding/xml"
aastypes "github.com/aas-core-works/aas-core3.0-golang/types"
aasxmlization "github.com/aas-core-works/aas-core3.0-golang/xmlization"
"strings"
"testing"
)

func TestRobustToNewline(t *testing.T) {
// See:
// https://github.com/aas-core-works/aas-core3.0-golang/issues/24
//
// We relied erroneously on whitespace between the elements which eclipsed the bug
// where we read into the content of a class property instead of letting the called
// function move the cursor.
text := ("<environment xmlns=\"https://admin-shell.io/aas/3/0\">" +
"<submodels>" +
"<submodel><id>some-unique-global-identifier</id></submodel>" +
"</submodels>" +
"</environment>")

reader := strings.NewReader(text)
decoder := xml.NewDecoder(reader)

deserialized, deseriaErr := aasxmlization.Unmarshal(decoder)

source := "Minimal example to reproduce robustness to newlines"

ok := assertNoDeserializationError(t, deseriaErr, source)
if !ok {
return
}

if _, ok := deserialized.(aastypes.IEnvironment); !ok {
t.Fatalf(
"Expected an instance of IEnvironment, "+
"but got %T: %v",
deserialized, deserialized,
)
return
}

buf := &bytes.Buffer{}
encoder := xml.NewEncoder(buf)
encoder.Indent("", "\t")

seriaErr := aasxmlization.Marshal(encoder, deserialized, true)
ok = assertNoSerializationError(t, seriaErr, source)
if !ok {
return
}

roundTrip := string(buf.Bytes())

expected := `<environment xmlns="https://admin-shell.io/aas/3/0">
<submodels>
<submodel>
<id>some-unique-global-identifier</id>
</submodel>
</submodels>
</environment>`
if roundTrip != expected {
t.Fatalf(
"Expected round-trip serialization to be `%v`, but got `%v`",
expected, roundTrip,
)
}
}

func TestRobustToNewlineOnDispatch(t *testing.T) {
// See:
// https://github.com/aas-core-works/aas-core3.0-golang/issues/24
//
// Note that both `dataSpecificationContent` and `dataSpecificationIec61360` are
// on the same line (right in the middle).
text := `<environment xmlns="https://admin-shell.io/aas/3/0">
<conceptDescriptions>
<conceptDescription>
<id>0173-1#02-AAR529#004</id>
<embeddedDataSpecifications>
<embeddedDataSpecification>
<dataSpecification>
<type>ExternalReference</type>
<keys>
<key>
<type>GlobalReference</type>
<value>https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0</value>
</key>
</keys>
</dataSpecification>
<dataSpecificationContent><dataSpecificationIec61360>
<preferredName>
<langStringPreferredNameTypeIec61360>
<language>en</language>
<text>kilogram</text>
</langStringPreferredNameTypeIec61360>
</preferredName>
</dataSpecificationIec61360>
</dataSpecificationContent>
</embeddedDataSpecification>
</embeddedDataSpecifications>
</conceptDescription>
</conceptDescriptions>
</environment>`

reader := strings.NewReader(text)
decoder := xml.NewDecoder(reader)

deserialized, deseriaErr := aasxmlization.Unmarshal(decoder)

pth := "Issue #24"

ok := assertNoDeserializationError(t, deseriaErr, pth)
if !ok {
return
}

if _, ok := deserialized.(aastypes.IEnvironment); !ok {
t.Fatalf(
"Expected an instance of IEnvironment, "+
"but got %T: %v",
deserialized, deserialized,
)
return
}

buf := &bytes.Buffer{}
encoder := xml.NewEncoder(buf)
encoder.Indent("", "\t")

seriaErr := aasxmlization.Marshal(encoder, deserialized, true)
ok = assertNoSerializationError(t, seriaErr, pth)
if !ok {
return
}

roundTrip := string(buf.Bytes())

expected := `<environment xmlns="https://admin-shell.io/aas/3/0">
<conceptDescriptions>
<conceptDescription>
<id>0173-1#02-AAR529#004</id>
<embeddedDataSpecifications>
<embeddedDataSpecification>
<dataSpecificationContent>
<dataSpecificationIec61360>
<preferredName>
<langStringPreferredNameTypeIec61360>
<language>en</language>
<text>kilogram</text>
</langStringPreferredNameTypeIec61360>
</preferredName>
</dataSpecificationIec61360>
</dataSpecificationContent>
<dataSpecification>
<type>ExternalReference</type>
<keys>
<key>
<type>GlobalReference</type>
<value>https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0</value>
</key>
</keys>
</dataSpecification>
</embeddedDataSpecification>
</embeddedDataSpecifications>
</conceptDescription>
</conceptDescriptions>
</environment>`

if expected != roundTrip {
t.Fatalf("Expected `%v`, got `%v`", expected, roundTrip)
}
}
Loading

0 comments on commit 6620ab1

Please sign in to comment.