blob: 0c4c2c30782958de9a729cadc9005191424def2d [file] [log] [blame]
// © 2021 and later: Unicode, Inc. and others.
// License & terms of use: https://www.unicode.org/copyright.html
package com.ibm.icu.dev.test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* “Known issues” manager.
* Intended to be shared between ICU, CLDR, &c.
* Test frameworks can create an instance of this to manage known issues
*/
public class UnicodeKnownIssues {
/**
* From Java 1.8
*/
public interface Consumer<T> { void accept(T t); }
private Map<String, List<String>> knownIssues = new TreeMap<>();
/**
* Max number of lines to show by default (including the "more")
* unless -allKnownIssues is given. Must be at least 2.
*/
public static final int KNOWN_ISSUES_CURTAILMENT = 2;
/**
* true if all issues should be shown, false if they should
* be curtailed.
*/
private boolean allKnownIssues;
/**
* Construct a known issue manager
* @param allKnownIssues true if all known issues should be printed,
* not curtailed
*/
public UnicodeKnownIssues(boolean allKnownIssues) {
this.allKnownIssues = allKnownIssues;
}
/**
* Base URL for browsing Unicode JIRA
*/
public static final String UNICODE_JIRA_BROWSE = "https://unicode-org.atlassian.net/browse/";
static final Pattern ICU_TICKET_PATTERN = Pattern.compile(
"(?i)(?:icu-)?(\\d+)"
);
static final Pattern CLDR_TICKET_PATTERN = Pattern.compile(
"(?i)cldr(?:bug:)?(?:-)?(\\d+)"
);
/**
* Match all linkable ticket patterns
* @see {org.unicode.cldr.util.CLDRURLS#CLDR_TICKET_BROWSE}
*/
static final Pattern UNICODE_JIRA_PATTERN = Pattern.compile(
"(CLDR|ICU)-(\\d+)"
);
/**
* Log the known issue.
* Call this from the test framework when logKnownIssue() is called.
*
* @param path Path to the error, will be returned in the
* known issue list
* @param ticket A ticket number string. For an ICU ticket, use "ICU-10245".
* For a CLDR ticket, use "CLDR-12345".
* For compatibility, "1234" -> ICU-1234 and "cldrbug:456" -> CLDR-456
* @param comment Additional comment, or null
*
*/
public void logKnownIssue(String path, String ticket, String comment) {
StringBuilder descBuf = new StringBuilder(path);
if (comment != null && comment.length() > 0) {
descBuf.append(" (" + comment + ")");
}
String description = descBuf.toString();
String ticketLink = "Unknown Ticket";
if (ticket != null && ticket.length() > 0) {
Matcher matcher = ICU_TICKET_PATTERN.matcher(ticket);
if (matcher.matches()) {
ticketLink = "ICU-" + matcher.group(1);
} else {
matcher = CLDR_TICKET_PATTERN.matcher(ticket);
if (matcher.matches()) {
ticketLink = "CLDR-" + matcher.group(1);
}
}
}
List<String> lines = knownIssues.get(ticketLink);
if (lines == null) {
lines = new ArrayList<>();
knownIssues.put(ticketLink, lines);
}
if (!lines.contains(description)) {
lines.add(description);
}
}
/**
* Print out all known issues to the logFn.
* Usage: printKnownIssues(System.out::println)
* @param logFn consumer for Strings (e.g. System.out::println)
* @return true if (!allKnownIssues) and we had to curtail
*/
public boolean printKnownIssues(Consumer<String> logFn) {
boolean didCurtail = false;
if (knownIssues.isEmpty()) {
return false;
}
logFn.accept("\n " + knownIssues.size() + " Known Issues:");
for (Entry<String, List<String>> entry : knownIssues.entrySet()) {
String ticketLink = entry.getKey();
if (UNICODE_JIRA_PATTERN.matcher(ticketLink) != null) {
logFn.accept(ticketLink + " <" + UNICODE_JIRA_BROWSE + ticketLink + ">");
} else {
// Unknown or something else
logFn.accept("<" + ticketLink + ">");
}
List<String> entries = entry.getValue();
int issuesToShow = entries.size();
if (!allKnownIssues && issuesToShow > KNOWN_ISSUES_CURTAILMENT) {
issuesToShow = (KNOWN_ISSUES_CURTAILMENT - 1);
}
for (int i=0; i<issuesToShow; i++) {
logFn.accept(" - " + entries.get(i));
}
if (entries.size() > issuesToShow) {
didCurtail = true;
logFn.accept(" ... and " +
(entries.size() - issuesToShow) + " more");
}
}
return didCurtail;
}
/**
* Reset the known issues
*/
public void reset() {
knownIssues.clear();
}
}