]> granicus.if.org Git - icu/commitdiff
ICU-21756 icu4j: port UnicodeKnownIssues.java from CLDR
authorSteven R. Loomis <srl295@gmail.com>
Sat, 18 Sep 2021 00:51:23 +0000 (19:51 -0500)
committerSteven R. Loomis <srl295@gmail.com>
Tue, 21 Sep 2021 17:16:57 +0000 (12:16 -0500)
- port of CLDR-14588
- use a fake Consumer<String>
- currently logs after each test class, not ideal but better
- Formerly ICU-12589 but that is not as related
- add unit test

icu4j/main/tests/core/src/com/ibm/icu/dev/test/TestUnicodeKnownIssues.java [new file with mode: 0644]
icu4j/main/tests/framework/src/com/ibm/icu/dev/test/TestFmwk.java
icu4j/main/tests/framework/src/com/ibm/icu/dev/test/UnicodeKnownIssues.java [new file with mode: 0644]

diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/TestUnicodeKnownIssues.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/TestUnicodeKnownIssues.java
new file mode 100644 (file)
index 0000000..29b2588
--- /dev/null
@@ -0,0 +1,143 @@
+// © 2021 and later: Unicode, Inc. and others.
+// License & terms of use: https://www.unicode.org/copyright.html
+
+package com.ibm.icu.dev.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link UnicodeKnownIssues}
+ */
+@RunWith(JUnit4.class)
+public class TestUnicodeKnownIssues {
+    @Test
+    public void TestBasic() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "ICU-21756", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Three", 3, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/ICU-21756"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+    }
+
+    @Test
+    public void TestNotCurtailed() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "ICU-21756", "Something is working!");
+        uki.logKnownIssue("d/e/f", "ICU-21756", "Something is working!");
+        uki.logKnownIssue("g/h/i", "ICU-21756", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of 5", 5, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/ICU-21756"));
+        // Not curtailed: test shows up in a/b/c, d/e/f, and g/h/i
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+        assertTrue(l.get(3) + "#3 says d/e/f", l.get(3).contains("d/e/f"));
+        assertTrue(l.get(4) + "#4 says g/h/i", l.get(4).contains("g/h/i"));
+    }
+
+    @Test
+    public void TestCurtailed() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(false);
+        uki.logKnownIssue("a/b/c", "ICU-21756", "Something is working!");
+        uki.logKnownIssue("d/e/f", "ICU-21756", "Something is working!");
+        uki.logKnownIssue("g/h/i", "ICU-21756", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count", 4, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/ICU-21756"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+        // Curtailed: the next line has "... and 2 more"
+        assertTrue(l.get(3) + "#3 has 'and 2 more'", l.get(3).contains("and 2 more"));
+    }
+
+    @Test
+    public void TestBare() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "21756", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Three", 3, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/ICU-21756"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+    }
+
+    @Test
+    public void TestUnknown() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "zzz", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Three", 3, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has unknown ticket", l.get(1).contains("Unknown Ticket"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+    }
+
+    @Test
+    public void TestCldrLink() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "CLDR-9787", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Three", 3, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/CLDR-9787"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+    }
+
+    @Test
+    public void TestCldrBug() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        uki.logKnownIssue("a/b/c", "cldrbug:9787", "Something is working!");
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Three", 3, l.size());
+        assertTrue(l.get(0) + "#0 says Known Issues", l.get(0).contains("Known Issues"));
+        assertTrue(l.get(1) + "#1 has atlassian URL", l.get(1).contains("browse/CLDR-9787"));
+        assertTrue(l.get(2) + "#2 says a/b/c", l.get(2).contains("a/b/c"));
+    }
+
+
+    @Test
+    public void TestNoProblem() {
+        UnicodeKnownIssues uki = new UnicodeKnownIssues(true);
+        List<String> l = printToList(uki);
+        assertNotNull("no list", l);
+        assertEquals("message count Of Zero", 0, l.size());
+    }
+
+    List<String> printToList(UnicodeKnownIssues uki) {
+        // TODO: for JDK 1.8
+        // final List<String> l = new LinkedList<>();
+        // uki.printKnownIssues(s -> l.add(s));
+
+        // TODO: Pre JDK 1.8 below
+        MyConsumer m = new MyConsumer();
+        uki.printKnownIssues(m);
+        return m.l;
+    }
+
+    // TODO: remove for JDK 1.8
+    static final class MyConsumer implements UnicodeKnownIssues.Consumer<String> {
+        final List<String> l = new LinkedList<>();
+        @Override
+        public void accept(String t) {
+            l.add(t);
+        }
+    }
+}
index c22cc07dbdaa1585c17607536e1b183f0b2b8c2b..e54766f3dcaeaaceeb450b70264a7319b571ef6a 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Random;
 import java.util.TreeMap;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
 
@@ -112,6 +113,17 @@ abstract public class TestFmwk extends AbstractTestLog {
         }
     }
 
+    @AfterClass
+    public final static void testClassTeardown() {
+        getParams().knownIssues.printKnownIssues(new UnicodeKnownIssues.Consumer<String>() {
+            // TODO: make this a Lambda once JDK 1.8 ships
+            public void accept(String t) {
+                System.out.println(t);
+            }
+        });
+        getParams().knownIssues.reset();
+    }
+
     private static TestParams getParams() {
         //return paramsReference.get();
         return testParams;
@@ -170,10 +182,6 @@ abstract public class TestFmwk extends AbstractTestLog {
 
     }
 
-    static final String ICU_TRAC_URL = "http://bugs.icu-project.org/trac/ticket/";
-    static final String CLDR_TRAC_URL = "http://unicode.org/cldr/trac/ticket/";
-    static final String CLDR_TICKET_PREFIX = "cldrbug:";
-
     /**
      * Log the known issue.
      * This method returns true unless -prop:logKnownIssue=no is specified
@@ -189,41 +197,12 @@ abstract public class TestFmwk extends AbstractTestLog {
         if (!getBooleanProperty("logKnownIssue", true)) {
             return false;
         }
-
         // TODO: This method currently does not do very much.
         // See http://bugs.icu-project.org/trac/ticket/12589
-
-        StringBuffer descBuf = new StringBuffer();
         // TODO(junit) : what to do about this?
+        final String path = "";
         //getParams().stack.appendPath(descBuf);
-        if (comment != null && comment.length() > 0) {
-            descBuf.append(" (" + comment + ")");
-        }
-        String description = descBuf.toString();
-
-        String ticketLink = "Unknown Ticket";
-        if (ticket != null && ticket.length() > 0) {
-            boolean isCldr = false;
-            ticket = ticket.toLowerCase(Locale.ENGLISH);
-            if (ticket.startsWith(CLDR_TICKET_PREFIX)) {
-                isCldr = true;
-                ticket = ticket.substring(CLDR_TICKET_PREFIX.length());
-            }
-            ticketLink = (isCldr ? CLDR_TRAC_URL : ICU_TRAC_URL) + ticket;
-        }
-
-        if (getParams().knownIssues == null) {
-            getParams().knownIssues = new TreeMap<String, List<String>>();
-        }
-        List<String> lines = getParams().knownIssues.get(ticketLink);
-        if (lines == null) {
-            lines = new ArrayList<String>();
-            getParams().knownIssues.put(ticketLink, lines);
-        }
-        if (!lines.contains(description)) {
-            lines.add(description);
-        }
-
+        getParams().knownIssues.logKnownIssue(path, ticket, comment);
         return true;
     }
 
@@ -365,7 +344,7 @@ abstract public class TestFmwk extends AbstractTestLog {
         private SecurityManager testSecurityManager;
         private SecurityManager originalSecurityManager;
 
-        private Map<String, List<String>> knownIssues;
+        private UnicodeKnownIssues knownIssues = null;
 
         private Properties props;
 
@@ -377,6 +356,7 @@ abstract public class TestFmwk extends AbstractTestLog {
             TestParams params = new TestParams();
             Properties props = System.getProperties();
             params.parseProperties(props);
+            params.knownIssues = new UnicodeKnownIssues(params.getBooleanProperty("allKnownIssues", false));
             return params;
         }
 
diff --git a/icu4j/main/tests/framework/src/com/ibm/icu/dev/test/UnicodeKnownIssues.java b/icu4j/main/tests/framework/src/com/ibm/icu/dev/test/UnicodeKnownIssues.java
new file mode 100644 (file)
index 0000000..30b1d5b
--- /dev/null
@@ -0,0 +1,154 @@
+// © 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.TreeMap;
+import java.util.Map.Entry;
+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();
+    }
+}