Skip to content

Commit

Permalink
Add known issues to Summary page and details for DateTime formatting (u…
Browse files Browse the repository at this point in the history
…nicode-org#256)

* Add plural rules to CPP

* Add the Rust datetime fmt code

* Rust datetime fmt and updates to ICU4C and NodeJS (unicode-org#240)

* Add plural rules to CPP

* Starting ICU4X datetime fmt

* DateTime format: Set default timezone explicitly

* Fix formatting

* Added ICU4X timezone computation - not working yet!

* DateTime generator updated to ISO formatted string

* DateTime updates for Node and ICU4C.

* Formatted src/datetimefmt.rs

* Updated using CustomTimeZone in ICU4X date time fmt

* Cargo clippified

* Remove unused function

* Update version to ~1.3

* Known issues now being computed and shown in reports

* Add diff output for both failing tests and known issues

* Known issues for date/time now displayed

* Removing this unneeded file

* Remove unused known_issues_data.csv

* Update schema/check_test_output.py

Co-authored-by: Elango Cheran <[email protected]>

* Update testdriver/ddtargs.py

Co-authored-by: Elango Cheran <[email protected]>

* Update testdriver/ddtargs.py

Co-authored-by: Elango Cheran <[email protected]>

* Changed structure of code computing known issues.

* Reorder and rename functions in check_known_issues.py

* renaming test_data --> test

* Update test for replaced digits

* Update verifier/check_known_issues.py

Co-authored-by: Elango Cheran <[email protected]>

---------

Co-authored-by: Elango Cheran <[email protected]>
  • Loading branch information
sven-oly and echeran authored Aug 9, 2024
1 parent 6c137c5 commit 9fb3f87
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 187 deletions.
2 changes: 1 addition & 1 deletion schema/check_test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def main(args):
test_type = schema_files.TEST_FILE_TO_TEST_TYPE_MAP[test_file_prefix]
test_type_set.add(test_type)
except BaseException as err:
logging.error('!!! %s for file %s', err, file
logging.info('No file (%s) during schema check output: %s', file, err
)
for dir in icu_dirs:
icu_version_set.add(os.path.basename(dir))
Expand Down
7 changes: 5 additions & 2 deletions testdriver/ddtargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ def __init__(self, args):
self.parser.add_argument('--custom_verifier', default=None) #

self.parser.add_argument(
'--run_serially', default=None,
help='Execute tests in series rather than in parallel')
'--run_serial', default=None,
help='Set if execution should be done serially. Parallel is the default.')

self.options = self.parser.parse_args(args)

Expand Down Expand Up @@ -93,6 +93,9 @@ def __init__(self, args):
self.parser.add_argument('--test_verifier',
help='Flag to run in test mode', default=None)

self.parser.add_argument('--run_serial', default=None,
help='Set if execution should be done serially. Parallel is the default.')

self.options = self.parser.parse_args(args)
return

Expand Down
6 changes: 3 additions & 3 deletions testdriver/testdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self):
self.test_plans = []
self.debug = False

self.run_serially = False # Default is to operate in parallel
self.run_serial = False # Default is to operate in parallel

logging.config.fileConfig("../logging.conf")

Expand All @@ -40,7 +40,7 @@ def set_args(self, arg_options):
self.icuVersion = arg_options.icu_version
self.cldrVersion = arg_options.cldr

self.run_serially = arg_options.run_serially
self.run_serial = arg_options.run_serial

# Create "test plans" for each option
for test_type in arg_options.test_type:
Expand Down Expand Up @@ -125,7 +125,7 @@ def main(args):
# print('ARGS = %s' % (args))
driver.parse_args(args[1:])

if driver.run_serially:
if driver.run_serial:
driver.run_plans()
else:
driver.run_plans_parallel()
Expand Down
172 changes: 172 additions & 0 deletions verifier/check_known_issues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# Functions to handle Known Issue category of results


from report_template import reportTemplate

from collections import defaultdict
from enum import Enum

from difflib import HtmlDiff
from difflib import Differ
from difflib import SequenceMatcher

from datetime import datetime

import glob
import json
import logging
import logging.config
import os
from string import Template
import sys

sys.path.append('../testdriver')
import datasets as ddt_data

# For information on characters and scripts
import unicodedata

# Handle known issues database

# Automatically compute some known issues with certain patterns of differences
# in actual output vs. expected

# E.g., NBSP vs SP in NodeJS DateTime in ICU73, ...

# Constants
NBSP = '\u202f'
SP = '\u0020'


# Global KnownIssue Info types and strings
class knownIssueType(Enum):
known_issue_nbsp_sp = 'ASCII Space instead of NBSP'
known_issue_replaced_numerals = 'Not creating non-ASCII numerals'

# TODO! Load known issues from file of known problems rather than hardcoding the detection in each test

# Tests for specific kinds of known issues
def diff_nbsp_vs_ascii_space(actual, expected_value):
# Returns the ID of this if the only difference in the two strings
# is Narrow Non-breaking Space (NBSP) in expected vs. ASCII space in the actual result.
# Found in datetime testing.
if not expected_value or not actual:
return None

# If replacing all the NBSP characdters in expected gives the actual result,
# then the only differences were with this type of space in formatted output.
if expected_value.replace(NBSP, SP) == actual:
return knownIssueType.known_issue_nbsp_sp
else:
return None


def numerals_replaced_by_another_numbering_system(expected, actual):
# If the only difference are one type of digit
# where other digits were expected, return True
# Found in datetime testing.
# Returns an known issue ID (or string) if the the numbering system changed

# sm_opcodes describe the change to turn expected string into the actual string
# See https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.get_opcodes
sm = SequenceMatcher(None, expected, actual)
sm_opcodes = sm.get_opcodes()

digit_replace = False
non_digit_replacement = False

# sm_opcodes describe the changes to turn expected string into the actual string
# See https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.get_opcodes
# The tuple is [tag, i1, i2, j1, j2]
# Tag indicates the type of change.
# i1:i2 is the range of the substring in expected
# j1:j2 is the range of the substring in actual

for diff in sm_opcodes:
tag = diff[0] # 'replace', 'delete', 'insert', or 'equal'
old_val = expected[diff[1]:diff[2]]
new_val = actual[diff[3]:diff[4]]
if tag == 'replace':
# expected[i1:i2] was replaced by actual[j1:j2]
if old_val.isdigit() and new_val.isdigit():
# TODO!! : check the value of the numeral
# If the same value, then its a numbering system difference
if unicodedata.numeric(old_val) == unicodedata.numeric(new_val):
digit_replace = True
else:
# Both were digits but different numeric values
non_digit_replacement = True
else:
# a digit was replaced with a non-digit
non_digit_replacement = True

# Only true if the only changes were replacing digits
if digit_replace and not non_digit_replace:
return knownIssueType.known_issue_replaced_numerals
else:
return None


def check_datetime_known_issues(test):
# Examine a single test for date/time isses
# Returns known issues identified for this test in this category
remove_this_one = False
try:
result = test['result']
expected = test['expected']
is_ki = diff_nbsp_vs_ascii_space(result, expected)
if is_ki:
# Mark the test with this issue
test['known_issue'] = knownIssueType.known_issue_nbsp_sp.value
remove_this_one = True

is_ki = numerals_replaced_by_another_numbering_system(result, expected)
if is_ki:
test['known_issue_id'] = knownIssueType.known_issue_replaced_numerals.value
remove_this_one = True

except BaseException as err:
# Can't get the info
pass

return remove_this_one


def compute_known_issues_for_single_test(test_type, test):
# Based on the type of test, check known issues against the expected vs. actual
# results

# Returns True if this single test is an example of one or moore known issues,
known_issue_found = False
if test_type == ddt_data.testType.datetime_fmt.value:
known_issue_found = check_datetime_known_issues(test)

# TODO: Add checks here for known issues in other test types

return known_issue_found

def check_issues(test_type, test_results_to_check):
# Look at the array of test result types, failure, error, unsupported
# Extract any tests from these that are known issues
# Return the list of tests that are known issues
#
known_issues_list = []

for category in test_results_to_check:
test_indices_with_known_issues = set()
index = 0

for test in category:
is_known_issue = compute_known_issues_for_single_test(test_type, test)
if is_known_issue:
known_issues_list.append(test)
test_indices_with_known_issues.add(index)
index += 1

# Remove those that were marked as known issues
# Reverse order to not confuse the position while deleting
rev_indices = sorted(test_indices_with_known_issues, reverse=True)
for index in rev_indices:
del category[index]

return known_issues_list
76 changes: 42 additions & 34 deletions verifier/detail_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
font-size:20px;
}

#diff_area {
.diff_area {
font-size: 24px;
font-color: blue;
}
Expand Down Expand Up @@ -231,9 +231,9 @@
['Results', 'Count', {role:'style'}],
['Passing', test_results['pass'].json.length, '#44ff77'],
['Failing', test_results['fail'].json.length, '#ff0000'],
['Known issues', test_results['known_issue'].json.length, '#ff8200'],
['Errors', test_results['error'].json.length, '#ffdd00'],
['Unsupported', test_results['unsupported'].json.length, '#777777'],
['Known issues', test_results['known_issue'].json.length, '#ff8200']
['Unsupported', test_results['unsupported'].json.length, '#777777']
];
const chart = new google.visualization.BarChart(chart_output_area);
let chart_data = google.visualization.arrayToDataTable(input_data);
Expand Down Expand Up @@ -347,13 +347,19 @@
fill_pagination("#characterized-pagination-container_" + item_type,
"#characterized-data-container_" + item_type,
selected_json_data,
"selected_" + item_type);
item_type);
}

// UL Template for pagination.js
function simpleTemplating(data, c_type) {
let possible_fields = ['label', 'expected', 'result', 'error', 'error_detail',
'options', 'input_data', 'actual_options'];
// Support output to different regions, depending on the type
// of the data, e.g., "fail", "known_issue", etc.
const diff_area_name = "diff_area_" + c_type;
const onclick_call =
'"captureInputDataOnClick(this);" onmouseover="hoverDiffText(this,' + diff_area_name + ');"';

let table_opening =
'<table id="table_' + c_type +
'" class="class_' + c_type + '">';
Expand All @@ -377,7 +383,7 @@
} else {
output = item[key];
}
html.push('<td onclick="captureInputDataOnClick(this);" onmouseover="hoverDiffText(this);">' + output +'</td>');
html.push('<td onclick=' + onclick_call +'>' + output +'</td>');
}
}
html.push("</tr>");
Expand Down Expand Up @@ -637,8 +643,9 @@
navigator.clipboard.writeText(output);
}

// On hover, show the differen between expected and actual result.
function hoverDiffText(element) {
// On hover, show the difference between expected and actual result
// in the named area.
function hoverDiffText(element, diff_area) {
// First, get the row of this item.
const row = element.parentNode;
const text1 = row.children[1].innerHTML;
Expand All @@ -651,7 +658,6 @@
dmp.diff_cleanupSemantic(diff_text);
// And show the difference nicely.
const ds = dmp.diff_prettyHtml(diff_text);
const diff_area = document.getElementById("diff_area");
diff_area.innerHTML = ds;
}
</script>
Expand All @@ -672,7 +678,7 @@ <h2>$platform_info</h2>
<p><span id="total_summary_count">$total_tests</span> attempted. Pass: <span id="pass_summary_count">$passing_tests</span>,
Fail: <span id="fail_summary_count">$failing_tests</span>,
Errors: <span id="error_summary_count">$error_count</span>,
Unsupported: <span id="unsupported_summary_count">$unsupported</span>,
Unsupported: <span id="unsupported_summary_count">$unsupported</span></p>,
Known issues: <span id="known_issue_summary_count">$unsupported</span></p>
<div id='chart_div'>
</div>
Expand Down Expand Up @@ -717,7 +723,7 @@ <h2>Acknowledgements</h2>

<details>
<summary>Failing tests <span id='fail_count'>($failing_tests)</span></summary>
<div id="diff_area"><p></p></div>
<div id="diff_area_fail" class="diff_area_class"><p></p></div>
<div id="fail-pagination-container"></div>
<div id="fail-data-container"></div>
<div id='testFailuresCharacterized'>
Expand All @@ -741,6 +747,32 @@ <h2>Acknowledgements</h2>
</div>
</details> <!-- failing tests -->

<details>
<summary>Known issues <span id='known_issue_count'>($known_issue_count)</span></summary>
<div id="diff_area_known_issue" class="diff_area_class"><p></p></div>
<div id="known_issue-pagination-container"></div>
<div id="known_issue-data-container"></div>
<div id='testKnownIssueCharacterized'>
<details>
<summary class="known_issue">Known issues characterized</summary>
<div bp="grid">
<div bp="3">
<p>Filtered count = <span id='selectedCount_known_issue' name='selectedCount' class='known_issue'>0</span>
<button id="showSelected_known_issue" onclick="showSelectedItems(this, 'known_issue');">Update display</button>
<button id="clearSelected_known_issue" onclick="clearSelectedItems(this, 'known_issue');">Clear</button>
</p>
<div id='known_issue_characterized'>
</div>
</div> <!-- end of checkbox div -->
<div bp="9">
<div id="characterized-pagination-container_known_issue"></div>
<div id="characterized-data-container_known_issue"></div>
</div>
</div> <!-- grid end -->
</details>
</div>
</details>

<details>
<summary>Test errors <span id='error_count'>($error_count)</span></summary>
<h2 id='testErrors'>Test Errors ($error_count)</h2>
Expand Down Expand Up @@ -793,30 +825,6 @@ <h2 id='testErrors'>Test Errors ($error_count)</h2>
</div>
</details>

<details>
<summary>Known issues <span id='known_issue_count'>($known_issue_count)</span></summary>
<div id="known_issue-pagination-container"></div>
<div id="known_issue-data-container"></div>
<div id='testKnownIssueCharacterized'>
<details>
<summary class="known_issue">Known issues characterized</summary>
<div bp="grid">
<div bp="3">
<p>Filtered count = <span id='selectedCount_known_issue' name='selectedCount' class='known_issue'>0</span>
<button id="showSelected_known_issue" onclick="showSelectedItems(this, 'known_issue');">Update display</button>
<button id="clearSelected_known_issue" onclick="clearSelectedItems(this, 'known_issue');">Clear</button>
</p>
<div id='known_issue_characterized'>
</div>
</div> <!-- end of checkbox div -->
<div bp="9">
<div id="characterized-pagination-container_known_issue"></div>
<div id="characterized-data-container_known_issue"></div>
</div>
</div> <!-- grid end -->
</details>
</div>
</details>
</div>

</body>
Expand Down
Loading

0 comments on commit 9fb3f87

Please sign in to comment.