Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kdwsdl2cpp: Avoid potential type collisions in nested complexTypes #91

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions kdwsdl2cpp/schema/attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ void Attribute::List::dump()
}
}

bool operator==(const Attribute& lhs, const Attribute& rhs)
{
return (// XmlElement:
lhs.isNull() == rhs.isNull()
&& lhs.name() == rhs.name()
&& lhs.nameSpace() == rhs.nameSpace()
// Attribute:
&& lhs.type() == rhs.type()
&& lhs.defaultValue() == rhs.defaultValue()
&& lhs.fixedValue() == rhs.fixedValue()
&& lhs.isQualified() == rhs.isQualified()
&& lhs.attributeUse() == rhs.attributeUse()
&& lhs.reference() == rhs.reference());
//Note: Ignoring documentation()
}

} // namespace XSD

QDebug operator<<(QDebug dbg, const XSD::Attribute &attr)
Expand Down
6 changes: 6 additions & 0 deletions kdwsdl2cpp/schema/attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ class SCHEMA_EXPORT Attribute : public XmlElement
Private *d;
};

bool operator==(const Attribute& lhs, const Attribute& rhs);
inline bool operator!=(const Attribute& lhs, const Attribute& rhs)
{
return !(lhs == rhs);
}

}

SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::Attribute &attr);
Expand Down
11 changes: 11 additions & 0 deletions kdwsdl2cpp/schema/attributegroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,15 @@ Attribute::List AttributeGroup::attributes() const
return d->mAttributes;
}

bool operator==(const AttributeGroup& lhs, const AttributeGroup& rhs)
{
return (// XmlElement:
lhs.isNull() == rhs.isNull()
&& lhs.name() == rhs.name()
&& lhs.nameSpace() == rhs.nameSpace()
// AttributeGroup:
&& lhs.reference() == rhs.reference()
&& lhs.attributes() == rhs.attributes());
}

}
6 changes: 6 additions & 0 deletions kdwsdl2cpp/schema/attributegroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class SCHEMA_EXPORT AttributeGroup : public XmlElement
Private *d;
};

bool operator==(const AttributeGroup& lhs, const AttributeGroup& rhs);
inline bool operator!=(const AttributeGroup& lhs, const AttributeGroup& rhs)
{
return !(lhs == rhs);
}

}

#endif
21 changes: 21 additions & 0 deletions kdwsdl2cpp/schema/complextype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ ComplexType::~ComplexType()

ComplexType &ComplexType::operator=(const ComplexType &other)
{
XSDType::operator=(other);
if (this == &other) {
return *this;
}
Expand Down Expand Up @@ -265,6 +266,26 @@ ComplexTypeList::iterator ComplexTypeList::findComplexType(const QName &qualifie
return end();
}

bool operator==(const ComplexType& lhs, const ComplexType& rhs)
{
return (// XmlElement:
lhs.isNull() == rhs.isNull()
&& lhs.name() == rhs.name()
&& lhs.nameSpace() == rhs.nameSpace()
// XsdType:
&& lhs.contentModel() == rhs.contentModel()
&& lhs.substitutionElementName() == rhs.substitutionElementName()
// ComplexType:
&& lhs.baseDerivation() == rhs.baseDerivation()
&& lhs.baseTypeName() == rhs.baseTypeName()
&& lhs.arrayType() == rhs.arrayType()
&& lhs.elements() == rhs.elements()
&& lhs.attributes() == rhs.attributes()
&& lhs.attributeGroups() == rhs.attributeGroups());
// Note: Ignoring XmlElement::annotations(),
// ComplexType::documentation(), isAnonymous(), isConflicting(), derivedTypes()
}

} // namespace XSD

QDebug operator<<(QDebug dbg, const XSD::ComplexType &type)
Expand Down
6 changes: 6 additions & 0 deletions kdwsdl2cpp/schema/complextype.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ class SCHEMA_EXPORT ComplexTypeList : public QList<ComplexType>
iterator findComplexType(const QName &qualifiedName);
};

bool operator==(const ComplexType& lhs, const ComplexType& rhs);
inline bool operator!=(const ComplexType& lhs, const ComplexType& rhs)
{
return !(lhs == rhs);
}

} // namespace XSD

SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::ComplexType &type);
Expand Down
41 changes: 41 additions & 0 deletions kdwsdl2cpp/schema/element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,47 @@ void ElementList::dump()
}
}

bool operator==(const Element& lhs, const Element& rhs)
{
return (// XmlElement:
lhs.isNull() == rhs.isNull()
&& lhs.name() == rhs.name()
&& lhs.nameSpace() == rhs.nameSpace()
// Element:
&& lhs.type() == rhs.type()
&& lhs.groupId() == rhs.groupId()
&& lhs.minOccurs() == rhs.minOccurs()
&& lhs.maxOccurs() == rhs.maxOccurs()
&& lhs.defaultValue() == rhs.defaultValue()
&& lhs.isQualified() == rhs.isQualified()
&& lhs.nillable() == rhs.nillable()
&& lhs.occurrence() == rhs.occurrence()
&& lhs.reference() == rhs.reference()
&& lhs.compositor().type() == rhs.compositor().type()
&& lhs.hasSubstitutions() == rhs.hasSubstitutions());
//Note: Ignoring documentation
}

bool operator==(const ElementList& lhs, const ElementList& rhs)
{
if (lhs.count() != rhs.count())
return false;

// Ordered vs. unordered composition should be specified for a whole composition, but
// as the Compositor::Type is determined during parsing (per element)
// comparing per element should be semantically identic:
for (int i = 0; i < lhs.count(); i++) {
const Element& e = lhs.at(i);
if (e.compositor().type() == Compositor::Sequence // ordered
&& rhs.at(i) != e)
return false;
else if (e.compositor().type() != Compositor::Sequence // unordered
&& !rhs.contains(e))
return false;
}
return true;
}

} // namespace XSD

QDebug operator<<(QDebug dbg, const XSD::Element &element)
Expand Down
12 changes: 12 additions & 0 deletions kdwsdl2cpp/schema/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ class SCHEMA_EXPORT ElementList : public QList<Element>
void dump();
};

bool operator==(const Element& lhs, const Element& rhs);
inline bool operator!=(const Element& lhs, const Element& rhs)
{
return !(lhs == rhs);
}

bool operator==(const ElementList& lhs, const ElementList& rhs);
inline bool operator!=(const ElementList& lhs, const ElementList& rhs)
{
return !(lhs == rhs);
}

}

SCHEMA_EXPORT QDebug operator<<(QDebug dbg, const XSD::Element &element);
Expand Down
6 changes: 6 additions & 0 deletions kdwsdl2cpp/schema/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ bool Group::isResolved() const
return !d->mElements.isEmpty() || d->mReference.isEmpty();
}

bool operator==(const Group& lhs, const Group& rhs)
{
return (lhs.reference() == rhs.reference()
&& lhs.elements() == rhs.elements()); // FIXME:
}

}

QDebug operator<<(QDebug dbg, const XSD::Group &group)
Expand Down
28 changes: 22 additions & 6 deletions kdwsdl2cpp/schema/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,29 @@ Element Parser::parseElement(ParserContext *context,
//qDebug() << "childName:" << childName.localName();
if (childName.localName() == QLatin1String("complexType")) {
ComplexType ct = parseComplexType(context, childElement);

ct.setName(newElement.name());
ct.setAnonymous(true);
d->mComplexTypes.append(ct);

if (debugParsing()) {
qDebug() << " found nested complexType element, type name is now element name, i.e. " << ct.name() << "newElement.setType" << ct.qualifiedName();
ct.setName(newElement.name());
int i = 0;
bool typeExists = false;
ComplexType existingType = d->mComplexTypes.complexType(QName(ct.nameSpace(), ct.name()));
while (existingType != ComplexType()) {
if (existingType == ct) {
if (debugParsing())
qDebug() << " Nested complexType of name" << ct.name() << "is structurally identical with existing complexType of the same name, skipping this instance...";
typeExists = true;
break;
} else {
ct.setName(newElement.name() + QString::number(++i));
existingType = d->mComplexTypes.complexType(QName(ct.nameSpace(), ct.name()));
}
}
if (!typeExists) {
d->mComplexTypes.append(ct);
if (debugParsing()) {
if (newElement.name() != ct.name())
qDebug() << " Detected type collision for nested complexType, updated name" << newElement.name() << "to" << ct.name();
qDebug() << " found nested complexType element, type name is now element name, i.e. " << ct.name() << "newElement.setType" << ct.qualifiedName();
}
}
newElement.setType(ct.qualifiedName());
} else if (childName.localName() == QLatin1String("simpleType")) {
Expand Down
1 change: 1 addition & 0 deletions kdwsdl2cpp/schema/xsdtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ XSDType::~XSDType()

XSDType &XSDType::operator=(const XSDType &other)
{
XmlElement::operator=(other);
if (this == &other) {
return *this;
}
Expand Down
28 changes: 28 additions & 0 deletions unittests/wsdl_document/mywsdl_document.wsdl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
<sequence>
<element name="TelegramHex" type="kdab:TelegramType"/>
<element name="TelegramBase64" type="xsd:base64Binary"/>
<xsd:element name="repeatedName">
<complexType>
<sequence>
<element name='intparam1' type='xsd:int'/>
</sequence>
</complexType>
</xsd:element>
</sequence>
</complexType>
</element>
Expand All @@ -57,6 +64,13 @@
<sequence>
<element name="TelegramHex" type="kdab:TelegramType"/>
<element name="TelegramBase64" type="xsd:base64Binary"/>
<xsd:element name="repeatedName">
<complexType>
<sequence>
<element name='stringparam1' type='xsd:string'/>
</sequence>
</complexType>
</xsd:element>
</sequence>
</complexType>
</element>
Expand Down Expand Up @@ -137,6 +151,13 @@
<sequence>
<element name='employeeName' type='kdab:EmployeeName'/>
<element name='repeatedChildren' type='kdab:TestRepeatedChildren'/>
<xsd:element name="repeatedName">
<complexType>
<sequence>
<element name='intparam1' type='xsd:int'/>
</sequence>
</complexType>
</xsd:element>
</sequence>
</complexType>
</element>
Expand All @@ -145,6 +166,13 @@
<complexType>
<sequence>
<element name='employeeCountry' type='kdab:LimitedString'/>
<xsd:element name="repeatedName">
<complexType>
<sequence>
<element name='stringparam1' type='xsd:string'/>
</sequence>
</complexType>
</xsd:element>
</sequence>
</complexType>
</element>
Expand Down
31 changes: 31 additions & 0 deletions unittests/wsdl_document/test_wsdl_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,33 @@ private Q_SLOTS:
params.setRepeatedChildren(children);
}

// Test repeated names in nested complex types
void testRepeatedNames()
{
// Just test the generated code, two different classes should have been
// created for two structurally different nested complex types of the
// same name:
KDAB__TelegramRequest req;
KDAB__RepeatedName repeatedName;
repeatedName.setIntparam1(0);
req.setRepeatedName(repeatedName);

KDAB__TelegramResponse resp;
KDAB__RepeatedName1 repeatedName1;
repeatedName1.setStringparam1("test1");
resp.setRepeatedName(repeatedName1);

KDAB__EmployeeNameParams params;
class KDAB__RepeatedName repeatedName_sameStructure;
repeatedName_sameStructure.setIntparam1(1);
params.setRepeatedName(repeatedName_sameStructure);

KDAB__EmployeeCountryResponse resp2;
KDAB__RepeatedName1 repeatedName1_sameStructure;
repeatedName1_sameStructure.setStringparam1("test2");
resp2.setRepeatedName(repeatedName1_sameStructure);
}

void testSoapVersion()
{
// Prepare response
Expand Down Expand Up @@ -714,6 +741,7 @@ public slots:
"David Ä Faure"
"</n1:employeeName>"
"<n1:repeatedChildren><n1:low>0</n1:low><n1:width>0</n1:width><n1:center>0</n1:center></n1:repeatedChildren>"
"<n1:repeatedName><n1:intparam1>0</n1:intparam1></n1:repeatedName>"
"</n1:EmployeeNameParams>"
"</soap:Body>" + xmlEnvEnd()
+ '\n'; // added by QXmlStreamWriter::writeEndDocument
Expand Down Expand Up @@ -997,6 +1025,7 @@ void WsdlDocumentTest::testServerPostByHand()
"<soap:Body>"
"<n1:EmployeeCountryResponse xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\">"
"<n1:employeeCountry>France</n1:employeeCountry>"
"<n1:repeatedName><n1:stringparam1/></n1:repeatedName>"
"</n1:EmployeeCountryResponse>"
"</soap:Body></soap:Envelope>\n";
QVERIFY(xmlBufferCompare(response, expected));
Expand Down Expand Up @@ -1059,6 +1088,7 @@ void WsdlDocumentTest::testSendTelegram()
QByteArray(xmlBegin) + "<TelegramRequest " + xmlNamespaces + ">"
"<TelegramHex>48656c6c6f</TelegramHex>"
"<TelegramBase64>SGVsbG8=</TelegramBase64>"
"<repeatedName><intparam1>0</intparam1></repeatedName>"
"</TelegramRequest>";
const QString msgNS = QString::fromLatin1("http://www.kdab.com/xml/MyWsdl/");
// Note that "qualified" is false in m_request, since it was created dynamically by the server -> no namespaces
Expand All @@ -1068,6 +1098,7 @@ void WsdlDocumentTest::testSendTelegram()
QByteArray(xmlBegin) + "<n1:TelegramResponse " + xmlNamespaces + " xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\">"
"<n1:TelegramHex>52656365697665642048656c6c6f</n1:TelegramHex>"
"<n1:TelegramBase64>UmVjZWl2ZWQgSGVsbG8=</n1:TelegramBase64>"
"<n1:repeatedName><n1:stringparam1></n1:stringparam1></n1:repeatedName>"
"</n1:TelegramResponse>";
// m_response, however, has qualified = true (set by the generated code).
QVERIFY(xmlBufferCompare(server->lastServerObject()->m_response.toXml(KDSoapValue::LiteralUse, msgNS), expectedResponseXml));
Expand Down