Skip to content

Commit

Permalink
Add ICU4J executor functionality for number formatter (unicode-org#166)
Browse files Browse the repository at this point in the history
* Add ICU4J classes representing input / output data for number formatter testing
* Implement logic for ICU4J executor's number formatter testing
* Generalize allowable types of JSON values, support default values for enums
* Fix number type fields during JSON parsing
* Update ICU4J test type interface to support error case handling
  • Loading branch information
echeran authored Jan 24, 2024
1 parent a4f4834 commit 53f4fdf
Show file tree
Hide file tree
Showing 23 changed files with 726 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,29 @@ public static void printResponseString(String responseString) {
System.out.println(responseString);
}

public static io.lacuna.bifurcan.Map<String,String> parseInputLine(String inputLine) {
TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
Map<String,String> parsedInputJavaMap = ExecutorUtils.GSON.fromJson(inputLine, mapType);
public static io.lacuna.bifurcan.Map<String,Object> parseInputLine(String inputLine) {
Map<String,Object> parsedInputJavaMap = stringMapFromString(inputLine);

io.lacuna.bifurcan.Map<String,String> parsedInputPersistentMap =
io.lacuna.bifurcan.Map<String,Object> parsedInputPersistentMap =
io.lacuna.bifurcan.Map.from(parsedInputJavaMap);

return parsedInputPersistentMap;
}

public static String formatAsJson(io.lacuna.bifurcan.IMap<String,String> mapData) {
java.util.Map<String,String> jMap = new HashMap<>();
for (Iterator<IEntry<String, String>> it = mapData.stream().iterator(); it.hasNext(); ) {
IEntry<String, String> entry = it.next();
public static String formatAsJson(io.lacuna.bifurcan.IMap<String,Object> mapData) {
java.util.Map<String,Object> jMap = new HashMap<>();
for (Iterator<IEntry<String, Object>> it = mapData.stream().iterator(); it.hasNext(); ) {
IEntry<String, Object> entry = it.next();
jMap.put(entry.key(), entry.value());
}
return GSON.toJson(jMap);
}

public static Map<String,Object> stringMapFromString(String s) {
TypeToken<Map<String, Object>> mapType = new TypeToken<Map<String, Object>>(){};
Map<String,Object> parsedInputJavaMap = ExecutorUtils.GSON.fromJson(s, mapType);

return parsedInputJavaMap;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

import com.google.gson.reflect.TypeToken;
import com.ibm.icu.impl.locale.XCldrStub.ImmutableMap;
import com.ibm.icu.number.NumberFormatter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.unicode.conformance.testtype.ITestType;
import org.unicode.conformance.testtype.ITestTypeOutputJson;
import org.unicode.conformance.testtype.collator.CollatorTester;
import org.unicode.conformance.testtype.langnames.LangNamesTester;
import org.unicode.conformance.testtype.likelysubtags.LikelySubtagsTester;
import org.unicode.conformance.testtype.numberformatter.NumberFormatterTester;

/**
* Hello world!
Expand Down Expand Up @@ -97,37 +100,49 @@ public static String getVersionResponse() {

public static String getTestCaseResponse(String inputLine) throws Exception {

io.lacuna.bifurcan.Map<String,String> parsedInputPersistentMap =
io.lacuna.bifurcan.Map<String,Object> parsedInputPersistentMap =
ExecutorUtils.parseInputLine(inputLine);

Optional<String> testTypeOpt = parsedInputPersistentMap.get("test_type");
Optional<Object> testTypeOpt = parsedInputPersistentMap.get("test_type");

if (!testTypeOpt.isPresent()) {
io.lacuna.bifurcan.IMap<String,String> response =
io.lacuna.bifurcan.IMap<String,Object> response =
parsedInputPersistentMap
.put("error", "Error in input")
.put("error_msg", "Error in input found in executor before execution");

return ExecutorUtils.formatAsJson(response);
} else {
String testTypeStr = testTypeOpt.get();
String testTypeStr = (String) testTypeOpt.get();
ITestType testType;
if (testTypeStr.equals("collation_short")) {
testType = CollatorTester.INSTANCE;
} else if (testTypeStr.equals("lang_names")) {
testType = LangNamesTester.INSTANCE;
} else if (testTypeStr.equals("likely_subtags")) {
testType = LikelySubtagsTester.INSTANCE;
} else if (testTypeStr.equals("number_fmt")) {
testType = NumberFormatterTester.INSTANCE;
} else {
io.lacuna.bifurcan.IMap<String,String> response =
io.lacuna.bifurcan.IMap<String,Object> response =
parsedInputPersistentMap
.put("error", "Error in input")
.put("error_msg", "Error in input found in executor before execution");

return ExecutorUtils.formatAsJson(response);
}

return testType.getFinalOutputFromInput(parsedInputPersistentMap);
try {
return testType.getFinalOutputFromInput(parsedInputPersistentMap);
} catch (Exception e) {
ITestTypeOutputJson defaultOutput = testType.getDefaultOutputJson();
return ExecutorUtils.formatAsJson(
testType.convertOutputToMap(defaultOutput)
.put("label", parsedInputPersistentMap.get("label", null))
.put("error", "Error in input")
.put("error_msg", "Error in handling test case: " + e.getMessage())
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

public interface ITestType {

default io.lacuna.bifurcan.Map<String,String> parseInput(String inputLine) {
default io.lacuna.bifurcan.Map<String,Object> parseInput(String inputLine) {
return ExecutorUtils.parseInputLine(inputLine);
}

ITestTypeInputJson inputMapToJson(io.lacuna.bifurcan.Map<String,String> inputMapData);
ITestTypeInputJson inputMapToJson(io.lacuna.bifurcan.Map<String,Object> inputMapData);

default ITestTypeInputJson parseInputJson(String inputLine) {
io.lacuna.bifurcan.Map<String,String> inputMapData =
io.lacuna.bifurcan.Map<String,Object> inputMapData =
parseInput(inputLine);
ITestTypeInputJson inputJson = inputMapToJson(inputMapData);

Expand All @@ -20,20 +20,24 @@ default ITestTypeInputJson parseInputJson(String inputLine) {

ITestTypeOutputJson execute(ITestTypeInputJson inputJson);

ITestTypeOutputJson getDefaultOutputJson();

io.lacuna.bifurcan.IMap<String,Object> convertOutputToMap(ITestTypeOutputJson outputJson);

String formatOutputJson(ITestTypeOutputJson outputJson);

default ITestTypeOutputJson getStructuredOutputFromInputStr(String inputLine) {
io.lacuna.bifurcan.Map<String,String> inputMapData = parseInput(inputLine);
io.lacuna.bifurcan.Map<String,Object> inputMapData = parseInput(inputLine);
return getStructuredOutputFromInput(inputMapData);
}

default ITestTypeOutputJson getStructuredOutputFromInput(io.lacuna.bifurcan.Map<String,String> inputMapData) {
default ITestTypeOutputJson getStructuredOutputFromInput(io.lacuna.bifurcan.Map<String,Object> inputMapData) {
ITestTypeInputJson inputJson = inputMapToJson(inputMapData);
ITestTypeOutputJson outputJson = execute(inputJson);
return outputJson;
}

default String getFinalOutputFromInput(io.lacuna.bifurcan.Map<String,String> inputMapData) throws Exception {
default String getFinalOutputFromInput(io.lacuna.bifurcan.Map<String,Object> inputMapData) throws Exception {
ITestTypeOutputJson outputJson = getStructuredOutputFromInput(inputMapData);
String formattedOutput = formatOutputJson(outputJson);
return formattedOutput;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.ibm.icu.text.Collator;
import com.ibm.icu.text.RuleBasedCollator;
import com.ibm.icu.util.ULocale;
import io.lacuna.bifurcan.IMap;
import io.lacuna.bifurcan.Map;
import java.util.Optional;
import org.unicode.conformance.ExecutorUtils;
Expand All @@ -19,63 +20,63 @@ public class CollatorTester implements ITestType {
//

@Override
public ITestTypeInputJson inputMapToJson(Map<String, String> inputMapData) {
public ITestTypeInputJson inputMapToJson(Map<String, Object> inputMapData) {
CollatorInputJson result = new CollatorInputJson();
result.test_type = inputMapData.get("test_type", null);
result.label = inputMapData.get("label", null);
result.test_type = (String) inputMapData.get("test_type", null);
result.label = (String) inputMapData.get("label", null);

// TODO: clean up after schema validation gets turned on at runtime
result.s1 = inputMapData.get("s1", null);
result.s1 = (String) inputMapData.get("s1", null);
if (result.s1 == null) {
result.s1 = inputMapData.get("string1", null);
result.s1 = (String) inputMapData.get("string1", null);
}

// TODO: clean up after schema validation gets turned on at runtime
result.s2 = inputMapData.get("s2", null);
result.s2 = (String) inputMapData.get("s2", null);
if (result.s2 == null) {
result.s2 = inputMapData.get("string2", null);
result.s2 = (String) inputMapData.get("string2", null);
}

result.locale = inputMapData.get("locale", null);
result.locale = (String) inputMapData.get("locale", null);

boolean ignorePunctuation = false;
Optional<String> ignorePunctuationStr = inputMapData.get("ignorePunctuation");
Optional<Object> ignorePunctuationStr = inputMapData.get("ignorePunctuation");
try {
if (ignorePunctuationStr.isPresent()) {
ignorePunctuation = Boolean.parseBoolean(ignorePunctuationStr.get());
ignorePunctuation = Boolean.parseBoolean((String) ignorePunctuationStr.get());
}
} catch (Exception e) {
// do nothing, default is false
}
result.ignorePunctuation = ignorePunctuation;

int line = 0;
Optional<String> lineStr = inputMapData.get("line");
Optional<Object> lineStr = inputMapData.get("line");
try {
if (lineStr.isPresent()) {
line = Integer.parseInt(lineStr.get());
line = Integer.parseInt((String) lineStr.get());
}
} catch (Exception e) {
// do nothing, default is 0
}
result.line = line;

result.compare_type = inputMapData.get("compare_type", null);
result.test_description = inputMapData.get("test_description", null);
result.compare_type = (String) inputMapData.get("compare_type", null);
result.test_description = (String) inputMapData.get("test_description", null);

// TODO: implement this correctly recursively (either using APIs or else DIY)
String[] attrs;
Optional<String> attrsString = inputMapData.get("attributes");
Optional<Object> attrsString = inputMapData.get("attributes");
if (attrsString.isPresent()) {
attrs = new String[]{ attrsString.get() };
attrs = new String[]{ (String) attrsString.get() };
} else {
attrs = new String[]{};
}
result.attributes = attrs;

result.rules = inputMapData.get("rules", null);
result.compare_comment = inputMapData.get("compare_comment", null);
result.warning = inputMapData.get("warning", null);
result.rules = (String) inputMapData.get("rules", null);
result.compare_comment = (String) inputMapData.get("compare_comment", null);
result.warning = (String) inputMapData.get("warning", null);

return result;
}
Expand All @@ -85,7 +86,7 @@ public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
CollatorInputJson input = (CollatorInputJson) inputJson;

// partially construct output
CollatorOutputJson output = new CollatorOutputJson();
CollatorOutputJson output = (CollatorOutputJson) getDefaultOutputJson();
output.label = input.label;
output.s1 = input.s1;
output.s2 = input.s2;
Expand Down Expand Up @@ -124,6 +125,25 @@ public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
// If we get here, it's a pass/fail result (supported options and no runtime errors/exceptions)
return output;
}

@Override
public ITestTypeOutputJson getDefaultOutputJson() {
CollatorOutputJson output = new CollatorOutputJson();
output.result = false;

return output;
}

@Override
public IMap<String, Object> convertOutputToMap(ITestTypeOutputJson outputJson) {
CollatorOutputJson output = (CollatorOutputJson) outputJson;
return new io.lacuna.bifurcan.Map<String,Object>()
.put("label", output.label)
.put("result", output.result)
.put("s1", output.s1)
.put("s2", output.s2);
}

@Override
public String formatOutputJson(ITestTypeOutputJson outputJson) {
return ExecutorUtils.GSON.toJson((CollatorOutputJson) outputJson);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.unicode.conformance.testtype.langnames;

import com.ibm.icu.util.ULocale;
import io.lacuna.bifurcan.IMap;
import io.lacuna.bifurcan.Map;
import org.unicode.conformance.ExecutorUtils;
import org.unicode.conformance.testtype.ITestType;
Expand All @@ -14,14 +15,14 @@ public class LangNamesTester implements ITestType {
public static LangNamesTester INSTANCE = new LangNamesTester();

@Override
public ITestTypeInputJson inputMapToJson(Map<String, String> inputMapData) {
public ITestTypeInputJson inputMapToJson(Map<String, Object> inputMapData) {
LangNamesInputJson result = new LangNamesInputJson();

result.test_type = inputMapData.get("test_type", null);
result.label = inputMapData.get("label", null);
result.test_type = (String) inputMapData.get("test_type", null);
result.label = (String) inputMapData.get("label", null);

result.language_label = inputMapData.get("language_label", null);
result.locale_label = inputMapData.get("locale_label", null);
result.language_label = (String) inputMapData.get("language_label", null);
result.locale_label = (String) inputMapData.get("locale_label", null);

return result;
}
Expand All @@ -31,7 +32,7 @@ public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
LangNamesInputJson input = (LangNamesInputJson) inputJson;

// partially construct output
LangNamesOutputJson output = new LangNamesOutputJson();
LangNamesOutputJson output = (LangNamesOutputJson) getDefaultOutputJson();
output.label = input.label;

try {
Expand All @@ -47,6 +48,21 @@ public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
return output;
}

@Override
public ITestTypeOutputJson getDefaultOutputJson() {
return new LangNamesOutputJson();
}

@Override
public IMap<String, Object> convertOutputToMap(ITestTypeOutputJson outputJson) {
LangNamesOutputJson output = (LangNamesOutputJson) outputJson;
return new io.lacuna.bifurcan.Map<String,Object>()
.put("label", output.label)
.put("result", output.result)
.put("language_label", output.language_label)
.put("local_label", output.locale_label);
}

@Override
public String formatOutputJson(ITestTypeOutputJson outputJson) {
return ExecutorUtils.GSON.toJson((LangNamesOutputJson) outputJson);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.unicode.conformance.testtype.likelysubtags;

import com.ibm.icu.util.ULocale;
import io.lacuna.bifurcan.IMap;
import io.lacuna.bifurcan.Map;
import org.unicode.conformance.ExecutorUtils;
import org.unicode.conformance.testtype.ITestType;
Expand All @@ -12,14 +13,14 @@ public class LikelySubtagsTester implements ITestType {
public static LikelySubtagsTester INSTANCE = new LikelySubtagsTester();

@Override
public ITestTypeInputJson inputMapToJson(Map<String, String> inputMapData) {
public ITestTypeInputJson inputMapToJson(Map<String, Object> inputMapData) {
LikelySubtagsInputJson result = new LikelySubtagsInputJson();

result.test_type = inputMapData.get("test_type", null);
result.label = inputMapData.get("label", null);
result.locale = inputMapData.get("locale", null);
result.test_type = (String) inputMapData.get("test_type", null);
result.label = (String) inputMapData.get("label", null);
result.locale = (String) inputMapData.get("locale", null);
result.option = LikelySubtagsTestOption.valueOf(
inputMapData.get("option", null)
(String) inputMapData.get("option", null)
);

return result;
Expand All @@ -45,6 +46,21 @@ public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) {
return output;
}

@Override
public ITestTypeOutputJson getDefaultOutputJson() {
return new LikelySubtagsOutputJson();
}

@Override
public IMap<String, Object> convertOutputToMap(ITestTypeOutputJson outputJson) {
LikelySubtagsOutputJson output = (LikelySubtagsOutputJson) outputJson;
return new io.lacuna.bifurcan.Map<String,Object>()
.put("label", output.label)
.put("locale", output.locale)
.put("result", output.result)
.put("option", output.option);
}

@Override
public String formatOutputJson(ITestTypeOutputJson outputJson) {
return ExecutorUtils.GSON.toJson((LikelySubtagsOutputJson) outputJson);
Expand Down
Loading

0 comments on commit 53f4fdf

Please sign in to comment.