|
16 | 16 | import static org.opensearch.ml.common.utils.StringUtils.*;
|
17 | 17 |
|
18 | 18 | import java.io.IOException;
|
| 19 | +import java.lang.reflect.Constructor; |
19 | 20 | import java.util.ArrayList;
|
20 | 21 | import java.util.Arrays;
|
21 | 22 | import java.util.HashMap;
|
|
31 | 32 | import org.opensearch.OpenSearchParseException;
|
32 | 33 | import org.opensearch.action.ActionRequestValidationException;
|
33 | 34 |
|
| 35 | +import com.google.gson.JsonElement; |
| 36 | +import com.google.gson.TypeAdapter; |
| 37 | +import com.google.gson.reflect.TypeToken; |
34 | 38 | import com.jayway.jsonpath.JsonPath;
|
35 | 39 |
|
36 | 40 | public class StringUtilsTest {
|
@@ -949,4 +953,133 @@ public void testParseStringArrayToList_Null() {
|
949 | 953 | assertEquals(0, array.size());
|
950 | 954 | }
|
951 | 955 |
|
| 956 | + // reflect method for PlainDoubleAdapter |
| 957 | + private static TypeAdapter<Double> createPlainDoubleAdapter() { |
| 958 | + try { |
| 959 | + Class<?> clazz = Class.forName("org.opensearch.ml.common.utils.StringUtils$PlainDoubleAdapter"); |
| 960 | + Constructor<?> constructor = clazz.getDeclaredConstructor(); |
| 961 | + constructor.setAccessible(true); |
| 962 | + Object adapterInstance = constructor.newInstance(); |
| 963 | + return (TypeAdapter<Double>) adapterInstance; |
| 964 | + } catch (Exception e) { |
| 965 | + throw new RuntimeException("Failed to create PlainDoubleAdapter via reflection", e); |
| 966 | + } |
| 967 | + } |
| 968 | + |
| 969 | + @Test |
| 970 | + public void testSerializeScientificNotation_RemovesExponent() { |
| 971 | + Map<String, Object> data = Map.of("test1", 1e30, "test2", 1.2e3, "test3", 9.5e-3, "test4", 1.56e-30); |
| 972 | + |
| 973 | + String json = StringUtils.PLAIN_NUMBER_GSON.toJson(data); |
| 974 | + |
| 975 | + assertTrue(json.contains("1000000000000000000000000000000")); |
| 976 | + assertTrue(json.contains("1200")); |
| 977 | + assertTrue(json.contains("0.0095")); |
| 978 | + assertTrue(json.contains("0.00000000000000000000000000000156")); |
| 979 | + |
| 980 | + } |
| 981 | + |
| 982 | + @Test |
| 983 | + public void testSerializeInteger_RemovesDecimalPoint() { |
| 984 | + Map<String, Object> data = Map.of("intLike", 42.0); |
| 985 | + |
| 986 | + String json = StringUtils.PLAIN_NUMBER_GSON.toJson(data); |
| 987 | + |
| 988 | + assertTrue(json.contains("42")); |
| 989 | + assertFalse(json.contains("42.0")); |
| 990 | + } |
| 991 | + |
| 992 | + @Test |
| 993 | + public void testSerializeNaNAndInfinity_BecomesNull() { |
| 994 | + Map<String, Double> data = new HashMap<>(); |
| 995 | + data.put("nul", null); |
| 996 | + data.put("nan", Double.NaN); |
| 997 | + data.put("inf", Double.POSITIVE_INFINITY); |
| 998 | + data.put("ninf", Double.NEGATIVE_INFINITY); |
| 999 | + |
| 1000 | + String json = StringUtils.PLAIN_NUMBER_GSON.toJson(data); |
| 1001 | + |
| 1002 | + assertTrue(json.contains("\"nan\":null")); |
| 1003 | + assertTrue(json.contains("\"inf\":null")); |
| 1004 | + assertTrue(json.contains("\"ninf\":null")); |
| 1005 | + assertTrue(json.contains("\"nul\":null")); |
| 1006 | + |
| 1007 | + assertFalse(json.contains("NaN")); |
| 1008 | + assertFalse(json.contains("Infinity")); |
| 1009 | + } |
| 1010 | + |
| 1011 | + @Test |
| 1012 | + public void testDeserializeBackToDouble() { |
| 1013 | + String json = "{\"value\": 12345.6789}"; |
| 1014 | + |
| 1015 | + Map<?, ?> result = StringUtils.PLAIN_NUMBER_GSON.fromJson(json, Map.class); |
| 1016 | + |
| 1017 | + Object value = result.get("value"); |
| 1018 | + assertTrue(value instanceof Double); |
| 1019 | + assertEquals(12345.6789, (Double) value, 1e-7); |
| 1020 | + } |
| 1021 | + |
| 1022 | + @Test |
| 1023 | + public void testQuotedScientificNotation_RemainsString() { |
| 1024 | + String json = "{\"code\":\"1e-6\"}"; |
| 1025 | + |
| 1026 | + Map<?, ?> result = StringUtils.PLAIN_NUMBER_GSON.fromJson(json, Map.class); |
| 1027 | + |
| 1028 | + assertEquals("1e-6", result.get("code")); |
| 1029 | + } |
| 1030 | + |
| 1031 | + @Test |
| 1032 | + public void testSerializeFloatScientificNotation_RemovesExponent_InPojo() { |
| 1033 | + java.util.Map<String, Float> data = new java.util.LinkedHashMap<>(); |
| 1034 | + data.put("fObj", 1.23e-5f); |
| 1035 | + data.put("fPrim", 9.5e-3f); |
| 1036 | + |
| 1037 | + String json = StringUtils.PLAIN_NUMBER_GSON.toJson(data); |
| 1038 | + |
| 1039 | + assertTrue(json.contains("\"fObj\":0.0000123")); |
| 1040 | + |
| 1041 | + assertTrue(json.contains("\"fPrim\":0.0095") || json.contains("\"fPrim\":9.5E-3") || json.contains("\"fPrim\":9.5e-3")); |
| 1042 | + } |
| 1043 | + |
| 1044 | + @Test |
| 1045 | + public void testSerializeFloatNaNAndInfinity_BecomesNull_InPojo() { |
| 1046 | + java.util.Map<String, Float> data = new java.util.LinkedHashMap<>(); |
| 1047 | + data.put("fObj", Float.NaN); |
| 1048 | + data.put("fPrimBox", Float.POSITIVE_INFINITY); |
| 1049 | + data.put("fNull", null); |
| 1050 | + |
| 1051 | + String json = StringUtils.PLAIN_NUMBER_GSON.toJson(data); |
| 1052 | + |
| 1053 | + assertTrue(json.contains("\"fObj\":null")); |
| 1054 | + assertTrue(json.contains("\"fNull\":null")); |
| 1055 | + assertTrue(json.contains("\"fPrimBox\":null") || !json.contains("\"fPrimBox\"")); |
| 1056 | + } |
| 1057 | + |
| 1058 | + @Test |
| 1059 | + public void testDeserializeScientificNotation_ToFloatAndPrimitive() { |
| 1060 | + String jsonObj = "{\"fObj\":1.23e-5}"; |
| 1061 | + java.lang.reflect.Type mapType = new com.google.gson.reflect.TypeToken<java.util.Map<String, Float>>() { |
| 1062 | + }.getType(); |
| 1063 | + java.util.Map<String, Float> m = StringUtils.PLAIN_NUMBER_GSON.fromJson(jsonObj, mapType); |
| 1064 | + assertEquals(1.23e-5f, m.get("fObj"), 1e-9f); |
| 1065 | + |
| 1066 | + String jsonArr = "[4.56e1]"; |
| 1067 | + float[] arr = StringUtils.PLAIN_NUMBER_GSON.fromJson(jsonArr, float[].class); |
| 1068 | + assertEquals(45.6f, arr[0], 1e-6f); |
| 1069 | + } |
| 1070 | + |
| 1071 | + @Test |
| 1072 | + public void testDeserializeNullFloat_ToNull() { |
| 1073 | + String json = "{\"fObj\":null,\"fPrim\":1.0}"; |
| 1074 | + |
| 1075 | + java.lang.reflect.Type mapType = new TypeToken<java.util.Map<String, JsonElement>>() { |
| 1076 | + }.getType(); |
| 1077 | + java.util.Map<String, JsonElement> m = StringUtils.PLAIN_NUMBER_GSON.fromJson(json, mapType); |
| 1078 | + |
| 1079 | + assertTrue(m.containsKey("fObj")); |
| 1080 | + assertTrue(m.get("fObj").isJsonNull()); |
| 1081 | + |
| 1082 | + assertTrue(m.get("fPrim").isJsonPrimitive()); |
| 1083 | + assertEquals(1.0f, m.get("fPrim").getAsFloat(), 1e-9f); |
| 1084 | + } |
952 | 1085 | }
|
0 commit comments