Skip to content

Commit

Permalink
Improve code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
prakanth97 committed Mar 20, 2024
1 parent a42d466 commit 0d7066b
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 33 deletions.
2 changes: 1 addition & 1 deletion ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[ballerina]
dependencies-toml-version = "2"
distribution-version = "2201.8.5"
distribution-version = "2201.8.4"

[[package]]
org = "ballerina"
Expand Down
119 changes: 115 additions & 4 deletions ballerina/tests/fromXml_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -2647,7 +2647,7 @@ function testRecordAsRestTypeForFromXmlStringWithType() returns error? {

@test:Config
function testRecordArrayAsRestTypeForFromXmlStringWithType() returns error? {
string xmlStr = string `<Data>
string xmlStr1 = string `<Data>
<A>
<C>A_C_1</C>
<D>A_D_1</D>
Expand All @@ -2669,10 +2669,88 @@ function testRecordArrayAsRestTypeForFromXmlStringWithType() returns error? {
record {
string C;
}[]...;
|} rec = check fromXmlStringWithType(xmlStr);
|} rec1 = check fromXmlStringWithType(xmlStr1);
test:assertEquals(rec1.length(), 2);
test:assertEquals(rec1.get("A"), [{C:"A_C_1", D:"A_D_1"},{C:"A_C_2", D:"A_D_2"}]);
test:assertEquals(rec1.get("B"), [{C:"B_C_1", D:"B_D_1"},{C:"B_C_2", D:"B_D_2"}]);

string xmlStr2 = string `
<Data>
<Depth1>
<A>1</A>
<A>2</A>
<B>2</B>
<B>5</B>
</Depth1>
<value>3</value>
</Data>
`;

record {|
string value;
record {|
int[]...;
|}...;
|} rec2 = check fromXmlStringWithType(xmlStr2);
test:assertEquals(rec2.length(), 2);
test:assertEquals(rec2.get("Depth1"), {A: [1, 2], B: [2, 5]});
test:assertEquals(rec2.get("value"), "3");

record {|
int value;
record {|
string[]...;
|}...;
|} rec3 = check fromXmlStringWithType(xmlStr2);
test:assertEquals(rec3.length(), 2);
test:assertEquals(rec3.get("Depth1"), {A: ["1", "2"], B: ["2", "5"]});
test:assertEquals(rec3.get("value"), 3);
}

@test:Config
function testAddingContentFieldWhenRestTypeAsExpTypeForFromXmlStringWithType() returns error? {
string xmlStr = string `
<Data>
<A a="attribute_a">2</A>
<B><C c="attribute_c">3</C></B>
</Data>
`;

record {} rec = check fromXmlStringWithType(xmlStr);
test:assertEquals(rec.length(), 2);
test:assertEquals(rec.get("A"), [{C:"A_C_1", D:"A_D_1"},{C:"A_C_2", D:"A_D_2"}]);
test:assertEquals(rec.get("B"), [{C:"B_C_1", D:"B_D_1"},{C:"B_C_2", D:"B_D_2"}]);
test:assertEquals(rec.get("A"), {\#content: 2, a: "attribute_a"});
test:assertEquals(rec.get("B"), {C: {\#content: 3, c: "attribute_c"}});

record {|
string A;
record {} B;
|} val2 = check fromXmlStringWithType(xmlStr);
test:assertEquals(val2.length(), 2);
test:assertEquals(val2.A, "2");
test:assertEquals(val2.B, {C: {\#content: 3, c: "attribute_c"}});
}

@test:Config
function testAddingContentFieldWhenRestTypeAsExpTypeForFromXmlWithType() returns error? {
xml xmlVal = xml `
<Data>
<A a="attribute_a">2</A>
<B><C c="attribute_c">3</C></B>
</Data>
`;

record {} rec = check fromXmlWithType(xmlVal);
test:assertEquals(rec.length(), 2);
test:assertEquals(rec.get("A"), {\#content: 2, a: "attribute_a"});
test:assertEquals(rec.get("B"), {C: {\#content: 3, c: "attribute_c"}});

record {|
string A;
record {} B;
|} val2 = check fromXmlWithType(xmlVal);
test:assertEquals(val2.length(), 2);
test:assertEquals(val2.A, "2");
test:assertEquals(val2.B, {C: {\#content: 3, c: "attribute_c"}});
}

// Negative cases
Expand Down Expand Up @@ -2974,3 +3052,36 @@ function testCommentMiddleInContentNegative2() {
|}|error rec2 = fromXmlWithType(xmlVal);
test:assertEquals((<error>rec2).message(), "invalid type expected 'int' but found 'string'");
}

@test:Config {
groups: ["fromXml"]
}
function testUnsupportedTypeNegative() {
xml xmlVal1 = xml `
<Data>
<A>1</A>
<A>2</A>
</Data>
`;
record {|
xml[] A;
|}|error err1 = fromXmlWithType(xmlVal1);
test:assertEquals((<error>err1).message(), "unsupported input type");

xml xmlVal2 = xml `
<Data>
<A>
<a>1</a>
</A>
</Data>
`;
record {|
record {|string a;|}|record {|string b;|} A;
|}|error err2 = fromXmlWithType(xmlVal2);
test:assertEquals((<error>err2).message(), "unsupported input type");

record {|
record {|string a;|}? A;
|}|error err3 = fromXmlWithType(xmlVal2);
test:assertEquals((<error>err3).message(), "unsupported input type");
}
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,39 @@ public static boolean isAnydataOrJson(int typeTag) {
return typeTag == TypeTags.ANYDATA_TAG || typeTag == TypeTags.JSON_TAG;
}

public static boolean isAnydataOrJsonArray(Type type) {
if (type.getTag() != TypeTags.ARRAY_TAG) {
return false;
public static boolean isSupportedType(Type type) {
switch (type.getTag()) {
case TypeTags.NULL_TAG, TypeTags.INT_TAG, TypeTags.BYTE_TAG, TypeTags.FLOAT_TAG, TypeTags.DECIMAL_TAG,
TypeTags.BOOLEAN_TAG, TypeTags.STRING_TAG, TypeTags.RECORD_TYPE_TAG, TypeTags.MAP_TAG,
TypeTags.JSON_TAG, TypeTags.ANYDATA_TAG -> {
return true;
}
case TypeTags.ARRAY_TAG -> {
return isSupportedType(((ArrayType) type).getElementType());
}
case TypeTags.UNION_TAG -> {
return isSupportedUnionType((UnionType) type);
}
case TypeTags.TYPE_REFERENCED_TYPE_TAG -> {
return isSupportedType(TypeUtils.getReferredType(type));
}
}
return false;
}

private static boolean isSupportedUnionType(UnionType type) {
for (Type memberType : type.getMemberTypes()) {
switch (memberType.getTag()) {
case TypeTags.RECORD_TYPE_TAG, TypeTags.OBJECT_TYPE_TAG, TypeTags.MAP_TAG, TypeTags.JSON_TAG,
TypeTags.ANYDATA_TAG, TypeTags.XML_TAG -> {
return false;
}
case TypeTags.UNION_TAG -> {
return !isSupportedUnionType(type);
}
}
}
return isAnydataOrJson(((ArrayType) type).getElementType().getTag());
return true;

Check warning on line 336 in native/src/main/java/io/ballerina/stdlib/data/xmldata/utils/DataUtils.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/data/xmldata/utils/DataUtils.java#L335-L336

Added lines #L335 - L336 were not covered by tests
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ private void parseRootElement(XMLStreamReader xmlStreamReader,
handleAttributes(xmlStreamReader, xmlParserData);
}

@SuppressWarnings("unchecked")
private void readText(XMLStreamReader xmlStreamReader,
boolean isCData,
XmlParserData xmlParserData) throws XMLStreamException {
Expand Down Expand Up @@ -289,7 +290,6 @@ private void readText(XMLStreamReader xmlStreamReader,
}
}

@SuppressWarnings("unchecked")
private void convertTextAndUpdateCurrentNode(BMap<BString, Object> currentNode,
BMap<BString, Object> parent,
BString currentFieldName,
Expand All @@ -302,9 +302,7 @@ private void convertTextAndUpdateCurrentNode(BMap<BString, Object> currentNode,
currentNode.put(StringUtils.fromString(Constants.CONTENT), result);
} else if (parent.get(currentFieldName) instanceof BArray bArray) {
bArray.add(bArray.getLength() - 1, result);
} else if (parent instanceof BArray) {
((BArray) parent).append(result);
} else {
} else {
parent.put(currentFieldName, result);
}

Expand All @@ -316,6 +314,7 @@ private void convertTextAndUpdateCurrentNode(BMap<BString, Object> currentNode,
xmlParserData.siblings = xmlParserData.parents.pop();
}

@SuppressWarnings("unchecked")
private void addTextToCurrentNodeIfExpTypeIsArray(ArrayType fieldType, BString bFieldName, BString bText,
XmlParserData xmlParserData) {
int elementTypeTag = TypeUtils.getReferredType(fieldType.getElementType()).getTag();
Expand All @@ -326,7 +325,6 @@ private void addTextToCurrentNodeIfExpTypeIsArray(ArrayType fieldType, BString b
BArray tempArr = (BArray) ((BMap<BString, Object>) xmlParserData.nodesStack.peek()).get(bFieldName);
tempArr.add(tempArr.getLength() - 1, convertStringToRestExpType(bText, fieldType));
}
default -> xmlParserData.currentNode.put(bFieldName, convertStringToRestExpType(bText, fieldType));
}
}

Expand Down Expand Up @@ -395,9 +393,8 @@ private Object convertStringToRestExpType(BString value, Type expType) {
throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_REST_TYPE, expType.getName());
}

private Object buildDocument(XmlParserData xmlParserData) {
private void buildDocument(XmlParserData xmlParserData) {
validateRequiredFields(xmlParserData);
return xmlParserData.currentNode;
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -494,9 +491,8 @@ private void readElement(XMLStreamReader xmlStreamReader, XmlParserData xmlParse

updateNextArrayMember(xmlStreamReader, xmlParserData, fieldName, fieldType, referredType);
}
case TypeTags.MAP_TAG, TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG -> {
updateNextMap(xmlParserData, fieldName, fieldType);
}
case TypeTags.MAP_TAG, TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG ->
updateNextMap(xmlParserData, fieldName, fieldType);
}
}

Expand Down Expand Up @@ -699,11 +695,11 @@ private BString readElementRest(XMLStreamReader xmlStreamReader, XmlParserData x
}

Object currentElement = xmlParserData.currentNode.get(currentFieldName);
xmlParserData.nodesStack.add(xmlParserData.currentNode);

if (currentElement instanceof BArray) {
int elemTypeTag = ((BArray) currentElement).getElementType().getTag();
if (elemTypeTag == TypeTags.ANYDATA_TAG || elemTypeTag == TypeTags.JSON_TAG) {
xmlParserData.nodesStack.add(xmlParserData.currentNode);
xmlParserData.parents.push(xmlParserData.siblings);
xmlParserData.siblings = new LinkedHashMap<>();
updateExpectedTypeStacksOfRestType(restType, xmlParserData);
Expand All @@ -722,6 +718,7 @@ private BString readElementRest(XMLStreamReader xmlStreamReader, XmlParserData x

int elemTypeTag = tempArray.getElementType().getTag();
if (elemTypeTag == TypeTags.ANYDATA_TAG || elemTypeTag == TypeTags.JSON_TAG) {
xmlParserData.nodesStack.add(xmlParserData.currentNode);
xmlParserData.parents.push(xmlParserData.siblings);
xmlParserData.siblings = new LinkedHashMap<>();
updateExpectedTypeStacksOfRestType(restType, xmlParserData);
Expand Down Expand Up @@ -758,6 +755,7 @@ private void endElementRest(XMLStreamReader xmlStreamReader, XmlParserData xmlPa
xmlParserData.siblings.put(elemQName, true);
}

@SuppressWarnings("unchecked")
private void readTextRest(XMLStreamReader xmlStreamReader,
BString currentFieldName,
boolean isCData,
Expand All @@ -783,30 +781,24 @@ private void readTextRest(XMLStreamReader xmlStreamReader,
}

convertTextRestAndUpdateCurrentNodeForRestType(xmlParserData.currentNode,
(BMap<BString, Object>) xmlParserData.nodesStack.peek(), currentFieldName, bText,
restType, xmlParserData);
(BMap<BString, Object>) xmlParserData.nodesStack.peek(), currentFieldName, bText, restType);
}

@SuppressWarnings("unchecked")
private void convertTextRestAndUpdateCurrentNodeForRestType(BMap<BString, Object> currentNode,
BMap<BString, Object> parent,
BString currentFieldName,
BString bText, Type restType,
XmlParserData xmlParserData) {
BString bText, Type restType) {
Object currentElement = currentNode.get(currentFieldName);
Object result = convertStringToRestExpType(bText, restType);

if (currentElement == null &&
(DataUtils.isAnydataOrJson(restType.getTag()) || DataUtils.isAnydataOrJsonArray(restType)) &&
if (currentElement == null && DataUtils.isAnydataOrJson(restType.getTag()) &&
parent != null && parent.get(currentFieldName) instanceof BArray bArray) {
bArray.add(bArray.getLength() - 1, result);
return;
}

if (currentElement == null && !currentNode.isEmpty()) { // Add text to the #content field
currentNode.put(StringUtils.fromString(Constants.CONTENT), result);
xmlParserData.currentNode = parent;
} else if (currentElement instanceof BArray) {
if (currentElement instanceof BArray) {
((BArray) currentElement).append(result);
} else if (currentElement instanceof BMap && !((BMap<BString, Object>) currentElement).isEmpty()) {
((BMap<BString, Object>) currentElement).put(StringUtils.fromString(Constants.CONTENT), result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ private void convertElement(BXmlItem xmlItem, XmlAnalyzerData analyzerData) {

BMap<BString, Object> mapValue = (BMap<BString, Object>) currentNode;
Type currentFieldType = TypeUtils.getReferredType(currentField.getFieldType());
if (!DataUtils.isSupportedType(currentFieldType)) {
throw DiagnosticLog.error(DiagnosticErrorCode.UNSUPPORTED_TYPE, currentFieldType);
}

String fieldName = currentField.getFieldName();
BString bCurrentFieldName = StringUtils.fromString(fieldName);
switch (currentFieldType.getTag()) {
Expand Down Expand Up @@ -245,7 +249,7 @@ private BMap<BString, Object> updateNextRecord(BXmlItem xmlItem, RecordType reco
updateNextValue(recordType, fieldName, fieldType, currentMapValue, analyzerData);
QName qName = xmlItem.getQName();
DataUtils.validateTypeNamespace(qName.getPrefix(), qName.getNamespaceURI(), recordType);
handleAttributes(xmlItem, nextValue, recordType, analyzerData);
handleAttributes(xmlItem, nextValue, analyzerData);
return nextValue;
}

Expand Down Expand Up @@ -502,11 +506,11 @@ private BXml validateRootElement(BXml xml, RecordType recordType, XmlAnalyzerDat

// Keep track of fields and attributes
DataUtils.updateExpectedTypeStacks(recordType, analyzerData);
handleAttributes(xmlItem, (BMap<BString, Object>) currentNode, recordType, analyzerData);
handleAttributes(xmlItem, (BMap<BString, Object>) currentNode, analyzerData);
return xmlItem.getChildrenSeq();
}

private void handleAttributes(BXmlItem xmlItem, BMap<BString, Object> currentNode, RecordType recordType,
private void handleAttributes(BXmlItem xmlItem, BMap<BString, Object> currentNode,
XmlAnalyzerData analyzerData) {
HashSet<String> innerElements = findAllInnerElement(xmlItem);
BMap<BString, BString> attributeMap = xmlItem.getAttributesMap();
Expand Down

0 comments on commit 0d7066b

Please sign in to comment.