From 9a1aa2dbefdf7571f352f7e4c32411ce57da7a57 Mon Sep 17 00:00:00 2001 From: Elango Cheran Date: Thu, 11 Jan 2024 01:58:17 +0000 Subject: [PATCH 1/2] Add Display Names component tests to ICU4J executor (#159) --- .../unicode/conformance/Icu4jExecutor.java | 5 +- .../langnames/LangNamesInputJson.java | 15 +++++ .../langnames/LangNamesOutputJson.java | 20 +++++++ .../testtype/langnames/LangNamesTester.java | 60 +++++++++++++++++++ .../conformance/langnames/LangNamesTest.java | 22 +++++++ executors/test_strings.txt | 34 +++++------ run_config.json | 15 +++++ schema/collation_short/test_schema.json | 2 +- schema/language_names/test_schema.json | 2 +- 9 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesInputJson.java create mode 100644 executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesOutputJson.java create mode 100644 executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesTester.java create mode 100644 executors/icu4j/73/executor-icu4j/src/test/java/org/unicode/conformance/langnames/LangNamesTest.java diff --git a/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/Icu4jExecutor.java b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/Icu4jExecutor.java index 580f6e59..b2e02c53 100644 --- a/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/Icu4jExecutor.java +++ b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/Icu4jExecutor.java @@ -10,6 +10,7 @@ import java.util.Optional; import org.unicode.conformance.testtype.ITestType; import org.unicode.conformance.testtype.collator.CollatorTester; +import org.unicode.conformance.testtype.langnames.LangNamesTester; /** * Hello world! @@ -111,7 +112,9 @@ public static String getTestCaseResponse(String inputLine) throws Exception { String testTypeStr = testTypeOpt.get(); ITestType testType; if (testTypeStr.equals("collation_short")) { - testType = new CollatorTester(); + testType = CollatorTester.INSTANCE; + } else if (testTypeStr.equals("lang_names")) { + testType = LangNamesTester.INSTANCE; } else { io.lacuna.bifurcan.IMap response = parsedInputPersistentMap diff --git a/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesInputJson.java b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesInputJson.java new file mode 100644 index 00000000..a1ae247b --- /dev/null +++ b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesInputJson.java @@ -0,0 +1,15 @@ +package org.unicode.conformance.testtype.langnames; + +import org.unicode.conformance.testtype.ITestTypeInputJson; + +public class LangNamesInputJson implements ITestTypeInputJson { + + public String test_type; + + public String label; + + public String language_label; + + public String locale_label; + +} diff --git a/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesOutputJson.java b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesOutputJson.java new file mode 100644 index 00000000..0b0c3f9d --- /dev/null +++ b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesOutputJson.java @@ -0,0 +1,20 @@ +package org.unicode.conformance.testtype.langnames; + +import org.unicode.conformance.testtype.ITestTypeOutputJson; + +public class LangNamesOutputJson implements ITestTypeOutputJson { + + public String test_type; + + public String label; + + public String language_label; + + public String locale_label; + + public String result; + + public String error; + + public String error_message; +} diff --git a/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesTester.java b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesTester.java new file mode 100644 index 00000000..c5825b9c --- /dev/null +++ b/executors/icu4j/73/executor-icu4j/src/main/java/org/unicode/conformance/testtype/langnames/LangNamesTester.java @@ -0,0 +1,60 @@ +package org.unicode.conformance.testtype.langnames; + +import com.ibm.icu.util.ULocale; +import io.lacuna.bifurcan.Map; +import org.unicode.conformance.ExecutorUtils; +import org.unicode.conformance.testtype.ITestType; +import org.unicode.conformance.testtype.ITestTypeInputJson; +import org.unicode.conformance.testtype.ITestTypeOutputJson; +import org.unicode.conformance.testtype.collator.CollatorInputJson; +import org.unicode.conformance.testtype.collator.CollatorOutputJson; + +public class LangNamesTester implements ITestType { + + public static LangNamesTester INSTANCE = new LangNamesTester(); + + @Override + public ITestTypeInputJson inputMapToJson(Map inputMapData) { + LangNamesInputJson result = new LangNamesInputJson(); + + result.test_type = inputMapData.get("test_type", null); + result.label = inputMapData.get("label", null); + + result.language_label = inputMapData.get("language_label", null); + result.locale_label = inputMapData.get("locale_label", null); + + return result; + } + + @Override + public ITestTypeOutputJson execute(ITestTypeInputJson inputJson) { + LangNamesInputJson input = (LangNamesInputJson) inputJson; + + // partially construct output + LangNamesOutputJson output = new LangNamesOutputJson(); + output.label = input.label; + + try { + String displayNameResult = getDisplayLanguageString(input); + output.result = displayNameResult; + } catch (Exception e) { + output.error = "error running test"; + output.error = e.getMessage(); + return output; + } + + // If we get here, it's a pass/fail result (supported options and no runtime errors/exceptions) + return output; + } + + @Override + public String formatOutputJson(ITestTypeOutputJson outputJson) { + return ExecutorUtils.GSON.toJson((LangNamesOutputJson) outputJson); + } + + public String getDisplayLanguageString(LangNamesInputJson input) { + String localeID = input.language_label; + String displayLocaleID = input.locale_label; + return ULocale.getDisplayNameWithDialect(localeID, displayLocaleID); + } +} diff --git a/executors/icu4j/73/executor-icu4j/src/test/java/org/unicode/conformance/langnames/LangNamesTest.java b/executors/icu4j/73/executor-icu4j/src/test/java/org/unicode/conformance/langnames/LangNamesTest.java new file mode 100644 index 00000000..80b34e3a --- /dev/null +++ b/executors/icu4j/73/executor-icu4j/src/test/java/org/unicode/conformance/langnames/LangNamesTest.java @@ -0,0 +1,22 @@ +package org.unicode.conformance.langnames; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.unicode.conformance.testtype.langnames.LangNamesOutputJson; +import org.unicode.conformance.testtype.langnames.LangNamesTester; + +public class LangNamesTest { + + @Test + public void testLocaleAndDisplayLocale() { + String testInput = + "{\"test_type\": \"lang_names\", \"label\": \"01\", \"language_label\": \"fr\", \"locale_label\": \"de\"}"; + + LangNamesOutputJson output = + (LangNamesOutputJson) LangNamesTester.INSTANCE.getStructuredOutputFromInputStr(testInput); + + assertEquals("Französisch", output.result); + } + +} diff --git a/executors/test_strings.txt b/executors/test_strings.txt index 0c8aec46..87830778 100644 --- a/executors/test_strings.txt +++ b/executors/test_strings.txt @@ -44,23 +44,23 @@ {"test_type": "collation_short", "label":"00008","s1":"ä","s2":"ä","compare_type":"=","test_description":" simple CEs & expansions","rules":"&\\x01\n<<<\\u0300\n&9<\\x00\n&\\uA00A\\uA00B=\\uA002\n&\\uA00A\\uA00B\\u00050005=\\uA003"} ======= -{"test_type": "display_names", "label": "01", "language_label": "en", "locale_label": "af"} -{"test_type": "display_names", "label": "01", "language_label": "", "locale_label": "fr"} -{"test_type": "display_names", "label": "01", "language_label": "de", "locale_label": "fr"} -{"test_type": "display_names", "label": "02", "language_label": "fr", "locale_label": "de"} -{"test_type": "display_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "ja"} -{"test_type": "display_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "pt-PT"} -{"test_type": "display_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "zh-CN"} -{"test_type": "display_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "es"} -{"test_type": "display_names", "label": "LANG_af_NA", "language_label": "en", "locale_label": "af_NA"} -{"label":"188691","language_label":"zh_MO","locale_label":"en_150","test_type":"language_display_name"} -{"label":"188691","language_label":"zh-TW","locale_label":"en","test_type":"language_display_name"} -{"label":"188691","language_label":"zh","locale_label":"en","test_type":"language_display_name"} -{"label":"zh zh","language_label":"zh","locale_label":"zh","test_type":"language_display_name"} -{"label":"en zh","language_label":"en","locale_label":"zh-CN","test_type":"language_display_name"} -{"label":"188691","language_label":"zh-CN","locale_label":"en","test_type":"language_display_name"} - -{"label":"zh en-150","language_label":"zh","locale_label":"en_150","test_type":"language_display_name"} +{"test_type": "lang_names", "label": "01", "language_label": "en", "locale_label": "af"} +{"test_type": "lang_names", "label": "01", "language_label": "", "locale_label": "fr"} +{"test_type": "lang_names", "label": "01", "language_label": "de", "locale_label": "fr"} +{"test_type": "lang_names", "label": "02", "language_label": "fr", "locale_label": "de"} +{"test_type": "lang_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "ja"} +{"test_type": "lang_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "pt-PT"} +{"test_type": "lang_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "zh-CN"} +{"test_type": "lang_names", "label": "LANG_ABC", "language_label": "en", "locale_label": "es"} +{"test_type": "lang_names", "label": "LANG_af_NA", "language_label": "en", "locale_label": "af_NA"} +{"label":"188691","language_label":"zh_MO","locale_label":"en_150","test_type":"lang_names"} +{"label":"188691","language_label":"zh-TW","locale_label":"en","test_type":"lang_names"} +{"label":"188691","language_label":"zh","locale_label":"en","test_type":"lang_names"} +{"label":"zh zh","language_label":"zh","locale_label":"zh","test_type":"lang_names"} +{"label":"en zh","language_label":"en","locale_label":"zh-CN","test_type":"lang_names"} +{"label":"188691","language_label":"zh-CN","locale_label":"en","test_type":"lang_names"} + +{"label":"zh en-150","language_label":"zh","locale_label":"en_150","test_type":"lang_names"} # COLLATION {"test_type": "coll_shift_short", "label": "COLL_ABC1", "string1": "de", "string2" : "da"} diff --git a/run_config.json b/run_config.json index 8ac9511e..49bb141b 100644 --- a/run_config.json +++ b/run_config.json @@ -240,5 +240,20 @@ ], "per_execution": 10000 } + }, + { + "prereq": { + "name": "mvn-icu4j-73-shaded", + "version": "73", + "command": "mvn -f ../executors/icu4j/73/executor-icu4j/pom.xml package" + }, + "run": { + "icu_version": "icu73", + "exec": "icu4j", + "test_type": [ + "lang_names" + ], + "per_execution": 10000 + } } ] diff --git a/schema/collation_short/test_schema.json b/schema/collation_short/test_schema.json index 85b28291..c6235355 100644 --- a/schema/collation_short/test_schema.json +++ b/schema/collation_short/test_schema.json @@ -19,7 +19,7 @@ "description":" Obsolete tag to be removed and replaced with test Type" }, "tests": { - "description": "list of N test for collation each of type collation_short", + "description": "list of N tests for collation each of type collation_short", "type": ["array", "null"], "items": { "type": "object", diff --git a/schema/language_names/test_schema.json b/schema/language_names/test_schema.json index 22542df0..b5b23ff0 100644 --- a/schema/language_names/test_schema.json +++ b/schema/language_names/test_schema.json @@ -32,7 +32,7 @@ } }, "tests": { - "description": "list of N tests for likely subtags", + "description": "list of N tests for language names", "type": "array", "items": { "type": "object", From 4b641e1e91ebabaafe7f3346c64b828d4445df66 Mon Sep 17 00:00:00 2001 From: Craig Cornelius Date: Wed, 10 Jan 2024 18:15:21 -0800 Subject: [PATCH 2/2] Update ICU number format to use skeletons when available (#157) * Adding ICU4C running collation tests - first try * Cache ICU4C binaries in GH and locally, only if they don't exist * Install JSON-C dependency if not installed at beginning of CI or e2e script * Fix bash if condition syntax * Updating CPP number_fmt to use skeletons if available * Fix some reporting and some skeletons * Reduce extraneous output from schema validation and verification steps * Allow click to capture test in detail lists * Fix typo --------- Co-authored-by: Elango Cheran --- executors/cpp/number_fmt.cpp | 20 +++++- executors/test_strings.txt | 11 +++ schema/number_format/test_schema.json | 6 +- schema/schema_validator.py | 16 +---- testgen/testdata_gen.py | 29 +++++++- verifier/detail_template.html | 27 ++++++-- verifier/testreport.py | 97 +++++++++++++-------------- 7 files changed, 130 insertions(+), 76 deletions(-) diff --git a/executors/cpp/number_fmt.cpp b/executors/cpp/number_fmt.cpp index 749b5f73..118d946d 100644 --- a/executors/cpp/number_fmt.cpp +++ b/executors/cpp/number_fmt.cpp @@ -232,7 +232,7 @@ UNumberSignDisplay set_sign_display(json_object* options_obj) { const string test_numfmt(json_object *json_in) { UErrorCode status = U_ZERO_ERROR; - // Locale information + // label information json_object *label_obj = json_object_object_get(json_in, "label"); string label_string = json_object_get_string(label_obj); @@ -250,6 +250,15 @@ const string test_numfmt(json_object *json_in) { const Locale displayLocale(locale_string.c_str()); + // Try using the skeleton to create the formatter + json_object *skelecton_obj = json_object_object_get(json_in, "skeleton"); + UnicodeString unicode_skeleton_string; + string skeleton_string; + if (skeleton_obj) { + skeleton_string = json_object_get_string(skeleton_obj); + unicode_skeleton_string = skeleton_string.c_str(); + } + // Get options json_object *notation_obj; json_object *unit_obj; @@ -278,7 +287,7 @@ const string test_numfmt(json_object *json_in) { IntegerWidth integerWidth_setting = IntegerWidth::zeroFillTo(1); MeasureUnit unit_setting = NoUnit::base(); Notation notation_setting = Notation::simple(); - Precision precision_setting = Precision::unlimited(); + Precision precision_setting = Precision::integer(); // TODO? = Precision::unlimited(); Scale scale_setting = Scale::none(); UNumberSignDisplay signDisplay_setting = UNUM_SIGN_AUTO; UNumberFormatRoundingMode rounding_setting = UNUM_ROUND_HALFEVEN; @@ -471,6 +480,12 @@ const string test_numfmt(json_object *json_in) { } } + if (skeleton_obj) { + cout << "# SKELETON " << skeleton_string << endl; + cout << "# LOCALE " << locale_string << endl; + nf = NumberFormatter::forSkeleton(unicode_skeleton_string, status).locale(displayLocale); + } + else { // Use settings to initialize the formatter nf = NumberFormatter::withLocale(displayLocale) .notation(notation_setting) @@ -484,6 +499,7 @@ const string test_numfmt(json_object *json_in) { .sign(signDisplay_setting) .unit(unit_setting) .unitWidth(unit_width_setting); + } if (U_FAILURE(status)) { test_result = error_message.c_str(); diff --git a/executors/test_strings.txt b/executors/test_strings.txt index 87830778..bb38394e 100644 --- a/executors/test_strings.txt +++ b/executors/test_strings.txt @@ -147,6 +147,17 @@ # FOR TESTING REJECTION OF UNKNOWN TYPE {"test_type": "bogus_fmt", "label":"NUM_2345", "input": "23.45","locale":"it","options":{"maximumFractionDigits":3}} +{"test_type": "number_fmt", "label":"0019","locale":"es-MX","skeleton":"compact-short currency/EUR unit-width-narrow","input":"91827.3645","options":{"notation":"compact","compactDisplay":"short","style":"currency","currencyDisplay":"narrowSymbol","currency":"EUR","unitDisplay":"narrow","maximumFractionDigits":2}} +{"test_type": "number_fmt", "label":"0019-2","locale":"es-MX","skeleton":"compact-short currency/EUR unit-width-narrow","input":"91827.3645","options":{"notation":"compact","compactDisplay":"short","style":"currency","currencyDisplay":"narrowSymbol","currency":"EUR","unitDisplay":"narrow"}} + +{"test_type": "number_fmt", "label":"0648","locale":"es-MX","skeleton":"compact-short percent decimal-always","input":"0","options":{"notation":"compact","compactDisplay":"short","style":"unit","unit":"percent","conformanceDecimalAlways":true,"maximumFractionDigits":2}} +{"test_type": "number_fmt", "label":"0648-no-max-fraction","locale":"es-MX","skeleton":"compact-short percent decimal-always","input":"0","options":{"notation":"compact","compactDisplay":"short","style":"unit","unit":"percent","conformanceDecimalAlways":true}} +{"test_type": "number_fmt", "label":"0649","locale":"es-MX","skeleton":"compact-short percent decimal-always","input":"91827.3645","options":{"notation":"compact","compactDisplay":"short","style":"unit","unit":"percent","conformanceDecimalAlways":true,"maximumFractionDigits":2}} +{"test_type": "number_fmt", "label":"0649","locale":"es-MX","skeleton":"compact-short percent decimal-always","input":"91827.3645","options":{"notation":"compact","compactDisplay":"short","style":"unit","unit":"percent","conformanceDecimalAlways":true}} +{"test_type": "number_fmt", "label":"5913","op":"format", "locale": "en", "skeleton":".00","input":"123456789","options":{"roundingMode":"halfEven","minimumIntegerDigits":1,"maximumFractionDigits":0,"useGrouping":false}} +{"test_type": "number_fmt", "label":"5913","op":"format", "locale":"es-MX", "skeleton":"percent .##/@@@+","input":"123456789.9876543210","options":{"roundingMode":"halfEven","minimumIntegerDigits":1,"maximumFractionDigits":0,"useGrouping":false}} + + # LOCALE_INFO {"test_type":"likely_subtags", "option":"maximize", "locale":"en", "label":"en_max"} {"test_type":"likely_subtags", "option":"minimize", "locale":"en-US", "label":"en_min"} diff --git a/schema/number_format/test_schema.json b/schema/number_format/test_schema.json index d413a9fd..ddc8a161 100644 --- a/schema/number_format/test_schema.json +++ b/schema/number_format/test_schema.json @@ -46,8 +46,12 @@ "description": "language tag for formatting the output", "type": "string" }, + "pattern": { + "description": "Pattern-style description of parameters. May be used to create a skeleton.", + "type": "string" + }, "skeleton": { - "description": "Skeleton-style description of parameters. Informational only. ", + "description": "Skeleton-style description of parameters. ", "type": "string" }, "input": { diff --git a/schema/schema_validator.py b/schema/schema_validator.py index d285d622..fcb8b528 100644 --- a/schema/schema_validator.py +++ b/schema/schema_validator.py @@ -71,8 +71,6 @@ def validate_json_file(self, schema_file_path, data_file_path): # Now check this! try: validate(data_to_check, schema) - logging.info('This test output file validates: %s, %s:', - data_file_path, schema_file_path) return True, None except ValidationError as err: logging.error('ValidationError for test output %s and schema %s', @@ -92,9 +90,6 @@ def validate_test_data_with_schema(self): all_results = [] for test_type in self.test_types: for icu_version in self.icu_versions: - if self.debug > 0: - logging.info('Checking test data %s, %s', test_type, icu_version) - logging.info('Checking %s, %s', test_type, icu_version) result_data = self.check_test_data_schema(icu_version, test_type) logging.debug('test result data = %s', result_data) msg = result_data['err_info'] @@ -111,7 +106,7 @@ def validate_test_data_with_schema(self): def check_test_data_schema(self, icu_version, test_type): # Check the generated test data for structure agains the schema - logging.info('Validating %s with icu version %s', test_type, icu_version) + logging.info('Validating %s with %s', test_type, icu_version) # Check test output vs. the test data schema schema_verify_file = os.path.join( self.schema_base, test_type, 'test_schema.json') @@ -150,7 +145,7 @@ def check_test_data_schema(self, icu_version, test_type): def check_test_output_schema(self, icu_version, test_type, executor): # Check the output of the tests for structure against the schema - logging.info('Validating %s with icu version %s', test_type, icu_version) + logging.info('Validating test output: %s %s %s', executor , test_type, icu_version) # Check test output vs. the schema schema_file_name = SCHEMA_FILE_MAP[test_type]['result_data']['schema_file'] @@ -177,9 +172,7 @@ def check_test_output_schema(self, icu_version, test_type, executor): result, err_msg = self.validate_json_file(schema_verify_file, test_result_file) results['result'] = result results['err_info'] = err_msg - if result: - logging.info('Result data %s validated with %s, ICU %s', test_type, executor, icu_version) - else: + if not result: logging.error('Result data %s FAILED with %s ICU %s: %s', test_type, executor, icu_version, err_msg) return results @@ -235,7 +228,6 @@ def validate_test_output_with_schema(self): for executor in self.executors: for icu_version in self.icu_versions: for test_type in self.test_types: - logging.info('Checking %s, %s, %s', test_type, icu_version, executor) results = self.check_test_output_schema(icu_version, test_type, executor) if not results['data_file_name']: # This is not an error but simple a test that wasn't run. @@ -243,8 +235,6 @@ def validate_test_output_with_schema(self): if not results['result']: logging.warning('VALIDATION FAILS: %s %s %s. MSG=%s', test_type, icu_version, executor, results['err_info']) - else: - logging.info('VALIDATION WORKS: %s %s %s', test_type, icu_version, executor) all_results.append(results) return all_results diff --git a/testgen/testdata_gen.py b/testgen/testdata_gen.py index 5cc59aa9..93c25b91 100644 --- a/testgen/testdata_gen.py +++ b/testgen/testdata_gen.py @@ -555,7 +555,8 @@ def resolveOptions(raw_options, skeleton_list): if ('maximumFractionDigits' not in resolved and ('notation' in resolved and resolved['notation'] == 'compact')): - resolved['maximumFractionDigits'] = 2 + pass + # NOT NECESSARY resolved['maximumFractionDigits'] = 2 if skeleton_list and 'percent' in skeleton_list: resolved['style'] = 'unit' @@ -577,6 +578,19 @@ def generateDcmlFmtTestDataObjects(rawtestdata, count=0): all_tests_list = [] verify_list = [] + # Transforming patterns to skeltons + pattern_to_skeleton = { + '0.0000E0': 'scientific .0000/@', + '00': 'integer-width/##00 group-off', + # '0.00': '.##/@@@', # TODO: Fix this skeleton + '@@@': '@@@ group-off', + '@@###': '@@### group-off', + '#': '@ group-off', + '@@@@E0': 'scientific/+e .0000/@@+', + '0.0##@E0': 'scientific/+e .##/@@+', + '0005': 'integer-width/0000 precision-increment/0005' + } + expected = len(test_list) + count max_digits = computeMaxDigitsForCount(expected) @@ -588,7 +602,18 @@ def generateDcmlFmtTestDataObjects(rawtestdata, count=0): pattern, round_mode, test_input, expected = parseDcmlFmtTestData(item) rounding_mode = mapRoundingToECMA402(round_mode) label = str(count).rjust(max_digits, '0') - entry = {'label': label, 'op': 'format', 'skeleton': pattern , 'input': test_input, 'options': {} } + + # TODO!!: Look up the patterns to make skeletons + if pattern in pattern_to_skeleton: + skeleton = pattern_to_skeleton[pattern] + else: + skeleton = None + + if skeleton: + entry = {'label': label, 'op': 'format', 'pattern': pattern, 'skeleton': skeleton , 'input': test_input, 'options': {} } + else: + # Unknown skeleton + entry = {'label': label, 'op': 'format', 'pattern': pattern, 'input': test_input, 'options': {} } json_part = mapFmtSkeletonToECMA402([pattern]) diff --git a/verifier/detail_template.html b/verifier/detail_template.html index 1f5553e4..88f88dd4 100644 --- a/verifier/detail_template.html +++ b/verifier/detail_template.html @@ -94,6 +94,9 @@ diff --git a/verifier/testreport.py b/verifier/testreport.py index 211a850a..551e3d28 100644 --- a/verifier/testreport.py +++ b/verifier/testreport.py @@ -476,10 +476,10 @@ def create_html_report(self): failure_json_path = os.path.join(self.report_directory, "failure_parameters.json") try: file = open(failure_json_path, mode='w', encoding='utf-8') - file.write(json.dumps(fail_characterized)) + file.write(json.dumps(flat_combined_dict)) file.close() except Exception as err: - logging.warning('!! %s: Cannot write fail_characterized data', err) + logging.warning('!! %s: Cannot write %s fail_characterized data', failure_json_path, err) return html_output @@ -495,10 +495,12 @@ def flatten_and_combine(self, input_dict, input_simple): continue if type(value) == list: flat_items[key] = value + elif type(value) == set: + flat_items[key] = sorted(value) else: for key2, value2 in value.items(): key_new = str(key) + '.' + str(key2) - flat_items[key_new] = value2 + flat_items[key_new] = sorted(value2) # Sort in reverse order by length of item flat_combined_dict = self.combine_same_sets_of_labels(flat_items) @@ -530,9 +532,9 @@ def characterize_failures_by_options(self, tests, result_type): locale = None if locale: if locale in results['locale']: - results['locale'][locale].append(label) + results['locale'][locale].add(label) else: - results['locale'][locale] = [label] + results['locale'][locale] = set([label]) options = input_data.get('options') if options: @@ -541,9 +543,9 @@ def characterize_failures_by_options(self, tests, result_type): if key not in results: results[key] = {} if value in results[key]: - results[key][value].append(label) + results[key][value].add(label) else: - results[key][value] = [label] + results[key][value] = set(label) # Try fields in language_names for key in ['language_label', 'locale_label']: @@ -553,9 +555,9 @@ def characterize_failures_by_options(self, tests, result_type): if key not in results: results[key] = {} if value in results[key]: - results[key][value].append(label) + results[key][value].add(label) else: - results[key][value] = [label] + results[key][value] = set(label) except: continue @@ -567,9 +569,9 @@ def characterize_failures_by_options(self, tests, result_type): if key not in results: results[key] = {} if value in results[key]: - results[key][value].append(label) + results[key][value].add(label) else: - results[key][value] = [label] + results[key][value] = set(label) except: continue @@ -580,22 +582,12 @@ def characterize_failures_by_options(self, tests, result_type): if key not in results: results[key] = {} if value in results[key]: - results[key][value].append(label) + results[key][value].add(label) else: - results[key][value] = [label] + results[key][value] = set(label) except: continue - for key in ['language_label', 'ignorePunctuation', 'compare_result', 'compare_type', 'test_description']: - if test.get(key): # For collation results - value = test[key] - # TODO: Check for option_keys in input_data - if key not in results: - results[key] = {} - if value in results[key]: - results[key][value].append(label) - else: - results[key][value] = [label] # Look at the input_data part of the test result # TODO: Check the error_detail and error pars, too. @@ -607,7 +599,7 @@ def characterize_failures_by_options(self, tests, result_type): # Special case for input_data / options. special_key = 'options' - if input_data.get(special_key): + if input_data and input_data.get(special_key): options = input_data[special_key] self.add_to_results_by_key(label, results, options, test, options.keys()) @@ -636,24 +628,25 @@ def add_to_results_by_key(self, label, results, input_data, test, key_list): if key not in results: results[key] = {} if value in results[key]: - results[key][value].append(label) + results[key][value].add(label) else: - results[key][value] = [label] + results[key][value] = set() + results[key][value].add(label) except: continue def check_simple_text_diffs(self): results = defaultdict(list) - results['insert'] = [] - results['delete'] = [] - results['insert_digit'] = [] - results['insert_space'] = [] - results['delete_digit'] = [] - results['delete_space'] = [] - results['replace_digit'] = [] - results['exponent_diff'] = [] - results['replace'] = [] - results['parens'] = [] # Substitions of brackets for parens, etc. + results['insert'] = set() + results['delete'] = set() + results['insert_digit'] = set() + results['insert_space'] = set() + results['delete_digit'] = set() + results['delete_space'] = set() + results['replace_digit'] = set() + results['exponent_diff'] = set() + results['replace'] = set() + results['parens'] = set() # Substitions of brackets for parens, etc. for fail in self.failing_tests: label = fail['label'] @@ -685,24 +678,24 @@ def check_simple_text_diffs(self): new_val = actual[diff[1]:diff[2]] if kind == 'replace': if old_val.isdigit() and new_val.isdigit(): - results['replace_digit'].append(label) + results['replace_digit'].add(label) else: - results['replace'].append(label) + results['replace'].add(label) elif kind == "delete": if old_val.isdigit(): - results['delete_digit'].append(label) + results['delete_digit'].add(label) elif old_val.isspace(): - results['delete_space'].append(label) + results['delete_space'].add(label) else: - results['delete'].append(label) + results['delete'].add(label) elif kind == "insert": if new_val.isdigit(): - results['insert_digit'].append(label) + results['insert_digit'].add(label) elif old_val.isspace(): - results['insert_space'].append(label) + results['insert_space'].add(label) else: - results['insert'].append(label) + results['insert'].add(label) else: pass @@ -721,25 +714,25 @@ def check_simple_text_diffs(self): for x in changes: if x[0] == '+': if x[2] in [' ', '\u00a0', '\u202f', '\u3000']: - results['insert_space'].append(label) + results['insert_space'].add(label) elif x[2] in ['+', '0', '+0']: - results['exponent_diff'].append(label) + results['exponent_diff'].add(label) else: - results['insert'].append(label) + results['insert'].add(label) if x[0] == '-': if x[2] in ['+', '0', '+0']: - results['exponent_diff'].append(label) + results['exponent_diff'].add(label) - # Check for substitued types of parentheses, brackets, brackes + # Check for substtituted types of parentheses, brackets, brackes if '[' in expected and '(' in actual: actual_parens = actual.replace('(', '[').replace(')', ']') if actual_parens == expected: - results['parens'].append(label) + results['parens'].add(label) elif '(' in expected and '[' in actual: actual_parens = actual.replace('[', '(').replace(')', ']') if actual_parens == expected: - results['parens'].append(label) + results['parens'].add(label) except KeyError: # a non-string result continue @@ -755,7 +748,7 @@ def save_characterized_file(self, characterized_data, characterized_type): file.write(json_data) file.close() except BaseException as error: - logging.error("CANNOT WRITE CHARACTERIZE FILE FOR %s", characterized_type) + logging.error("CANNOT WRITE CHARACTERIZE FILE FOR %s at ", characterized_type, character_file_path) return def create_html_diff_report(self):