Skip to content

Commit

Permalink
Merge pull request #56 from SasinduDilshara/implement_enum_singleton_…
Browse files Browse the repository at this point in the history
…support

Implement enum singleton support
  • Loading branch information
gimantha authored Nov 29, 2024
2 parents 40ee711 + 192a0b9 commit 139af66
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 3 deletions.
2 changes: 1 addition & 1 deletion ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ path = "../native/build/libs/data.xmldata-native-1.1.0-SNAPSHOT.jar"
groupId = "io.ballerina.stdlib"
artifactId = "constraint-native"
version = "1.6.0"
path = "./lib/constraint-native-1.6.0-20241121-170800-002e6d6.jar"
path = "./lib/constraint-native-1.6.0-20241122-133100-98689e2.jar"
214 changes: 214 additions & 0 deletions ballerina/tests/test_finite_types.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
//
// WSO2 LLC. 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.

import ballerina/test;

enum EnumA {
A = "A",
B,
C = "C2"
}

type FiniteType true|"A"|1|2;

@test:Config
function testFiniteTypes() returns error? {
record {|
EnumA a;
"A"|"B"|"C" b;
record {|
"A"|"B"|"C" c;
EnumA d;
|} nested;
|} r = check parseAsType(xml `<Root><a>A</a><b>B</b><nested><c>B</c><d>B</d></nested></Root>`);
test:assertEquals(r, {a: "A", b: "B", nested: {c: "B", d: "B"}});
}

@test:Config
function testFiniteTypesWithNestedRecords() returns error? {
record {|
EnumA a;
FiniteType b;
record {|
FiniteType c;
FiniteType e;
EnumA d;
|} nested;
|} r = check parseAsType(xml `<Root><a>C2</a><b>1</b><nested><c>2</c><d>A</d><e>true</e></nested></Root>`);
test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
}

@test:Config
function testFiniteTypeArrays() returns error? {
record {|
EnumA[] a;
("A"|"B"|"C")[] b;
record {|
("A"|"B"|"C")[] c;
EnumA[] d;
|} nested;
|} r = check parseAsType(xml `<Root><a>A</a><a>A</a><b>B</b><b>B</b><nested><c>B</c><c>B</c><d>B</d><d>B</d></nested></Root>`);
test:assertEquals(r, {a: ["A", "A"], b: ["B", "B"], nested: {c: ["B", "B"], d: ["B", "B"]}});
}

@test:Config
function testFiniteTypeArrays2() returns error? {
record {|
EnumA[] a;
FiniteType[] b;
record {|
FiniteType[] c;
FiniteType[] e;
EnumA[] d;
|} nested;
|} r = check parseAsType(xml `<Root><a>C2</a><a>C2</a><b>1</b><b>1</b><nested><c>2</c><c>2</c><d>A</d><d>A</d><e>true</e><e>true</e></nested></Root>`);
test:assertEquals(r, {a: ["C2", "C2"], b: [1, 1], nested: {c: [2, 2], d: ["A", "A"], e: [true, true]}});
}

@test:Config
function testFiniteTypesWithXmlString() returns error? {
record {|
EnumA a;
"A"|"B"|"C" b;
record {|
"A"|"B"|"C" c;
EnumA d;
|} nested;
|} r = check parseString(string `<Root><a>A</a><b>B</b><nested><c>B</c><d>B</d></nested></Root>`);
test:assertEquals(r, {a: "A", b: "B", nested: {c: "B", d: "B"}});
}

@test:Config
function testFiniteTypesWithNestedRecordsWithXmlString() returns error? {
record {|
EnumA a;
FiniteType b;
record {|
FiniteType c;
FiniteType e;
EnumA d;
|} nested;
|} r = check parseString(string `<Root><a>C2</a><b>1</b><nested><c>2</c><d>A</d><e>true</e></nested></Root>`);
test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
}

@test:Config
function testFiniteTypeArraysWithXmlString() returns error? {
record {|
EnumA[] a;
("A"|"B"|"C")[] b;
record {|
("A"|"B"|"C")[] c;
EnumA[] d;
|} nested;
|} r = check parseString(string `<Root><a>A</a><a>A</a><b>B</b><b>B</b><nested><c>B</c><c>B</c><d>B</d><d>B</d></nested></Root>`);
test:assertEquals(r, {a: ["A", "A"], b: ["B", "B"], nested: {c: ["B", "B"], d: ["B", "B"]}});
}

@test:Config
function testFiniteTypeArraysWithXmlString2() returns error? {
record {|
EnumA[] a;
FiniteType[] b;
record {|
FiniteType[] c;
FiniteType[] e;
EnumA[] d;
|} nested;
|} r = check parseString(string `<Root><a>C2</a><a>C2</a><b>1</b><b>1</b><nested><c>2</c><c>2</c><d>A</d><d>A</d><e>true</e><e>true</e></nested></Root>`);
test:assertEquals(r, {a: ["C2", "C2"], b: [1, 1], nested: {c: [2, 2], d: ["A", "A"], e: [true, true]}});
}
type NestedRec record {|
@Name {
value: "c2"
}
FiniteType c;
FiniteType e;
@Name {
value: "d2"
}
EnumA d;
|};

@test:Config
function testFiniteTypesWithNameAnnotations() returns error? {
record {|
EnumA a;
FiniteType b;
NestedRec nested;
|} r = check parseAsType(xml `<Root><a>C2</a><b>1</b><nested><c2>2</c2><d2>A</d2><e>true</e></nested></Root>`);
test:assertEquals(r, {a: "C2", b: 1, nested: {c: 2, d: "A", e: true}});
}

type FiniteValue 100f;

@test:Config
function testRecordFieldWithSingleFiniteType() returns error? {
record {|
EnumA a;
"A" b;
record {|
FiniteValue c;
EnumA d;
|} nested;
|} r = check parseAsType(xml `<Root><a>A</a><b>A</b><nested><c>100.0</c><d>B</d></nested></Root>`);
test:assertEquals(r, {a: "A", b: "A", nested: {c: 100f, d: "B"}});
}

@test:Config
function testRecordFieldWithSingleFiniteType2() returns error? {
record {|
100f a;
200.1d b;
100d c;
200.1f d;
100f e;
200.1d f;
100d g;
200.1f h;
|} r = check parseAsType(xml `<Root><a>100</a><b>200.1</b><c>100</c><d>200.1</d><e>100.0</e><f>200.1</f><g>100.0</g><h>200.1</h></Root>`);
test:assertEquals(r, {a: 100f, b: 200.1d, c: 100d, d: 200.1f, e: 100f, f: 200.1d, g: 100d, h: 200.1f});
}

@test:Config
function testRecordFieldWithSingleFiniteType3() returns error? {
record {|
100f a;
|}|Error r = parseAsType(xml `<Root><a>100.01</a></Root>`);
test:assertTrue(r is Error);
test:assertEquals((<Error>r).message(), "'string' value '100.01' cannot be converted to '100.0f'");

record {|
100d a;
|}|Error r2 = parseAsType(xml `<Root><a>100.01</a></Root>`);
test:assertTrue(r2 is Error);
test:assertEquals((<Error>r2).message(), "'string' value '100.01' cannot be converted to '100d'");
}

@test:Config
function testRecordFieldWithSingleFiniteType4() returns error? {
record {|
200.1d|100f a;
200.1d|100d b;
100d|100f|200.1f c;
200.1f|200.1d|100f d;
200.1d|200.1f|100f e;
100d|100d|200.1d f;
100d|200.1d|200.1d g;
200.1f|200.1d|200.1d h;
|} r = check parseAsType(xml `<Root><a>100</a><b>200.1</b><c>100</c><d>200.1</d><e>100.0</e><f>200.1</f><g>100.0</g><h>200.1</h></Root>`);
test:assertEquals(r, {a: 100f, b: 200.1d, c: 100d, d: 200.1f, e: 100f, f: 200.1d, g: 100d, h: 200.1f});
}
37 changes: 37 additions & 0 deletions native/src/main/java/io/ballerina/lib/data/xmldata/FromString.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@
import io.ballerina.lib.data.xmldata.utils.DiagnosticLog;
import io.ballerina.runtime.api.creators.TypeCreator;
import io.ballerina.runtime.api.creators.ValueCreator;
import io.ballerina.runtime.api.types.FiniteType;
import io.ballerina.runtime.api.types.PredefinedTypes;
import io.ballerina.runtime.api.types.ReferenceType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.types.TypeTags;
import io.ballerina.runtime.api.types.UnionType;
import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.utils.TypeUtils;
import io.ballerina.runtime.api.values.BDecimal;
import io.ballerina.runtime.api.values.BError;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.api.values.BTypedesc;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
Expand Down Expand Up @@ -96,6 +99,8 @@ public static Object fromStringWithType(BString string, Type expType) {
return stringToUnion(string, JSON_TYPE_WITH_BASIC_TYPES);
case TypeTags.TYPE_REFERENCED_TYPE_TAG:
return fromStringWithType(string, ((ReferenceType) expType).getReferredType());
case TypeTags.FINITE_TYPE_TAG:
return stringToFiniteType(value, (FiniteType) expType);
default:
return returnError(value, expType.toString());
}
Expand All @@ -104,6 +109,38 @@ public static Object fromStringWithType(BString string, Type expType) {
}
}

private static Object stringToFiniteType(String value, FiniteType finiteType) {
return finiteType.getValueSpace().stream()
.filter(finiteValue -> !(convertToSingletonValue(value, finiteValue) instanceof BError))
.findFirst()
.orElseGet(() -> returnError(value, finiteType.toString()));
}

private static Object convertToSingletonValue(String str, Object singletonValue) {
String singletonStr = String.valueOf(singletonValue);
Type type = TypeUtils.getType(singletonValue);

if (singletonValue instanceof BDecimal decimalValue) {
BigDecimal bigDecimal = decimalValue.decimalValue();
if (bigDecimal.compareTo(new BigDecimal(str)) == 0) {
return fromStringWithType(StringUtils.fromString(str), type);
}
return returnError(str, singletonStr);
}

if (singletonValue instanceof Double doubleValue) {
if (doubleValue.compareTo(Double.valueOf(str)) == 0) {
return fromStringWithType(StringUtils.fromString(str), type);
}
return returnError(str, singletonStr);
}

if (str.equals(singletonStr)) {
return fromStringWithType(StringUtils.fromString(str), type);
}
return returnError(str, singletonStr);
}

private static Long stringToInt(String value) throws NumberFormatException {
return Long.parseLong(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ 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 -> {
TypeTags.JSON_TAG, TypeTags.ANYDATA_TAG, TypeTags.FINITE_TYPE_TAG -> {
return true;
}
case TypeTags.ARRAY_TAG -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ private Object convertStringToRestExpType(BString value, Type expType) {
return convertStringToRestExpType(value, ((ArrayType) expType).getElementType());
}
case TypeTags.INT_TAG, TypeTags.FLOAT_TAG, TypeTags.DECIMAL_TAG, TypeTags.STRING_TAG,
TypeTags.BOOLEAN_TAG, TypeTags.UNION_TAG -> {
TypeTags.BOOLEAN_TAG, TypeTags.UNION_TAG, TypeTags.FINITE_TYPE_TAG -> {
return convertStringToExpType(value, expType);
}
case TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG -> {
Expand Down

0 comments on commit 139af66

Please sign in to comment.