1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 1996-2015, International Business Machines Corporation and    *
7 * others. All Rights Reserved.                                                *
8 *******************************************************************************
9 */
10package android.icu.dev.test;
11
12import java.lang.reflect.Constructor;
13import java.lang.reflect.Method;
14import java.lang.reflect.Modifier;
15import java.security.Policy;
16import java.util.ArrayList;
17import java.util.Arrays;
18import java.util.List;
19import java.util.Locale;
20import java.util.Map;
21import java.util.Properties;
22import java.util.Random;
23import java.util.TreeMap;
24
25import org.junit.After;
26import org.junit.Assert;
27import org.junit.Before;
28
29import android.icu.util.TimeZone;
30import android.icu.util.ULocale;
31
32/**
33 * TestFmwk is a base class for tests that can be run conveniently from the
34 * command line as well as under the Java test harness.
35 * <p>
36 * Sub-classes implement a set of methods named Test <something>. Each of these
37 * methods performs some test. Test methods should indicate errors by calling
38 * either err or errln. This will increment the errorCount field and may
39 * optionally print a message to the log. Debugging information may also be
40 * added to the log via the log and logln methods. These methods will add their
41 * arguments to the log only if the test is being run in verbose mode.
42 */
43abstract public class TestFmwk extends AbstractTestLog {
44    /**
45     * The default time zone for all of our tests. Used in @Before
46     */
47    private final static TimeZone defaultTimeZone = TimeZone.getTimeZone("America/Los_Angeles");
48
49    /**
50     * The default locale used for all of our tests. Used in @Before
51     */
52    private final static Locale defaultLocale = Locale.US;
53
54    private static final String EXHAUSTIVENESS = "ICU.exhaustive";
55    private static final int DEFAULT_EXHAUSTIVENESS = 0;
56    private static final int MAX_EXHAUSTIVENESS = 10;
57
58    private static final String LOGGING_LEVEL = "ICU.logging";
59    private static final int DEFAULT_LOGGING_LEVEL = 0;
60    private static final int MAX_LOGGING_LEVEL = 3;
61
62    public static final int LOGGING_NONE = 0;
63    public static final int LOGGING_WARN = 1;
64    public static final int LOGGING_INFO = 2;
65    public static final int LOGGING_DEBUG = 3;
66
67    private static final String SEED = "ICU.seed";
68    private static final String SECURITY_POLICY = "ICU.securitypolicy";
69
70    private static final TestParams testParams;
71    static {
72        testParams = TestParams.create();
73    }
74
75    protected TestFmwk() {
76    }
77
78    @Before
79    public void testInitialize() {
80        Locale.setDefault(defaultLocale);
81        TimeZone.setDefault(defaultTimeZone);
82
83        if (getParams().testSecurityManager != null) {
84            System.setSecurityManager(getParams().testSecurityManager);
85        }
86    }
87
88    @After
89    public void testTeardown() {
90        if (getParams().testSecurityManager != null) {
91            System.setSecurityManager(getParams().originalSecurityManager);
92        }
93    }
94
95    private static TestParams getParams() {
96        //return paramsReference.get();
97        return testParams;
98    }
99
100    protected static boolean isVerbose() {
101        return getParams().getLoggingLevel() >= LOGGING_INFO;
102    }
103
104    /**
105     * 0 = fewest tests, 5 is normal build, 10 is most tests
106     */
107    protected static int getExhaustiveness() {
108        return getParams().inclusion;
109    }
110
111    protected static boolean isQuick() {
112        return getParams().getInclusion() == 0;
113    }
114
115    // use this instead of new random so we get a consistent seed
116    // for our tests
117    protected Random createRandom() {
118        return new Random(getParams().getSeed());
119    }
120
121    /**
122     * Integer Random number generator, produces positive int values.
123     * Similar to C++ std::minstd_rand, with the same algorithm & constants.
124     * Provided for compatibility with ICU4C.
125     * Get & set of the seed allows for reproducible monkey tests.
126     */
127    protected class ICU_Rand {
128        private int fLast;
129
130        public ICU_Rand(int seed) {
131            seed(seed);
132        }
133
134        public int next() {
135            fLast = (int)((fLast * 48271L) % 2147483647L);
136            return fLast;
137        }
138
139        public void seed(int seed) {
140            if (seed <= 0) {
141                seed = 1;
142            }
143            seed %= 2147483647;   // = 0x7FFFFFFF
144            fLast = seed > 0 ? seed : 1;
145        }
146
147        public int getSeed() {
148            return fLast;
149        }
150
151    }
152
153    static final String ICU_TRAC_URL = "http://bugs.icu-project.org/trac/ticket/";
154    static final String CLDR_TRAC_URL = "http://unicode.org/cldr/trac/ticket/";
155    static final String CLDR_TICKET_PREFIX = "cldrbug:";
156
157    /**
158     * Log the known issue.
159     * This method returns true unless -prop:logKnownIssue=no is specified
160     * in the argument list.
161     *
162     * @param ticket A ticket number string. For an ICU ticket, use numeric characters only,
163     * such as "10245". For a CLDR ticket, use prefix "cldrbug:" followed by ticket number,
164     * such as "cldrbug:5013".
165     * @param comment Additional comment, or null
166     * @return true unless -prop:logKnownIssue=no is specified in the test command line argument.
167     */
168    protected static boolean logKnownIssue(String ticket, String comment) {
169        if (!getBooleanProperty("logKnownIssue", true)) {
170            return false;
171        }
172
173        StringBuffer descBuf = new StringBuffer();
174        // TODO(junit) : what to do about this?
175        //getParams().stack.appendPath(descBuf);
176        if (comment != null && comment.length() > 0) {
177            descBuf.append(" (" + comment + ")");
178        }
179        String description = descBuf.toString();
180
181        String ticketLink = "Unknown Ticket";
182        if (ticket != null && ticket.length() > 0) {
183            boolean isCldr = false;
184            ticket = ticket.toLowerCase(Locale.ENGLISH);
185            if (ticket.startsWith(CLDR_TICKET_PREFIX)) {
186                isCldr = true;
187                ticket = ticket.substring(CLDR_TICKET_PREFIX.length());
188            }
189            ticketLink = (isCldr ? CLDR_TRAC_URL : ICU_TRAC_URL) + ticket;
190        }
191
192        if (getParams().knownIssues == null) {
193            getParams().knownIssues = new TreeMap<String, List<String>>();
194        }
195        List<String> lines = getParams().knownIssues.get(ticketLink);
196        if (lines == null) {
197            lines = new ArrayList<String>();
198            getParams().knownIssues.put(ticketLink, lines);
199        }
200        if (!lines.contains(description)) {
201            lines.add(description);
202        }
203
204        return true;
205    }
206
207    protected static String getProperty(String key) {
208        return getParams().getProperty(key);
209    }
210
211    protected static boolean getBooleanProperty(String key) {
212        return getParams().getBooleanProperty(key);
213    }
214
215    protected static boolean getBooleanProperty(String key, boolean defVal) {
216        return getParams().getBooleanProperty(key, defVal);
217    }
218
219    protected static int getIntProperty(String key, int defVal) {
220        return getParams().getIntProperty(key, defVal);
221    }
222
223    protected static int getIntProperty(String key, int defVal, int maxVal) {
224        return getParams().getIntProperty(key, defVal, maxVal);
225    }
226
227    protected static TimeZone safeGetTimeZone(String id) {
228        TimeZone tz = TimeZone.getTimeZone(id);
229        if (tz == null) {
230            // should never happen
231            errln("FAIL: TimeZone.getTimeZone(" + id + ") => null");
232        }
233        if (!tz.getID().equals(id)) {
234            warnln("FAIL: TimeZone.getTimeZone(" + id + ") => " + tz.getID());
235        }
236        return tz;
237    }
238
239
240    // Utility Methods
241
242    protected static String hex(char[] s){
243        StringBuffer result = new StringBuffer();
244        for (int i = 0; i < s.length; ++i) {
245            if (i != 0) result.append(',');
246            result.append(hex(s[i]));
247        }
248        return result.toString();
249    }
250
251    protected static String hex(byte[] s){
252        StringBuffer result = new StringBuffer();
253        for (int i = 0; i < s.length; ++i) {
254            if (i != 0) result.append(',');
255            result.append(hex(s[i]));
256        }
257        return result.toString();
258    }
259
260    protected static String hex(char ch) {
261        StringBuffer result = new StringBuffer();
262        String foo = Integer.toString(ch, 16).toUpperCase();
263        for (int i = foo.length(); i < 4; ++i) {
264            result.append('0');
265        }
266        return result + foo;
267    }
268
269    protected static String hex(int ch) {
270        StringBuffer result = new StringBuffer();
271        String foo = Integer.toString(ch, 16).toUpperCase();
272        for (int i = foo.length(); i < 4; ++i) {
273            result.append('0');
274        }
275        return result + foo;
276    }
277
278    protected static String hex(CharSequence s) {
279        StringBuilder result = new StringBuilder();
280        for (int i = 0; i < s.length(); ++i) {
281            if (i != 0)
282                result.append(',');
283            result.append(hex(s.charAt(i)));
284        }
285        return result.toString();
286    }
287
288    protected static String prettify(CharSequence s) {
289        StringBuilder result = new StringBuilder();
290        int ch;
291        for (int i = 0; i < s.length(); i += Character.charCount(ch)) {
292            ch = Character.codePointAt(s, i);
293            if (ch > 0xfffff) {
294                result.append("\\U00");
295                result.append(hex(ch));
296            } else if (ch > 0xffff) {
297                result.append("\\U000");
298                result.append(hex(ch));
299            } else if (ch < 0x20 || 0x7e < ch) {
300                result.append("\\u");
301                result.append(hex(ch));
302            } else {
303                result.append((char) ch);
304            }
305
306        }
307        return result.toString();
308    }
309
310    private static java.util.GregorianCalendar cal;
311
312    /**
313     * Return a Date given a year, month, and day of month. This is similar to
314     * new Date(y-1900, m, d). It uses the default time zone at the time this
315     * method is first called.
316     *
317     * @param year
318     *            use 2000 for 2000, unlike new Date()
319     * @param month
320     *            use Calendar.JANUARY etc.
321     * @param dom
322     *            day of month, 1-based
323     * @return a Date object for the given y/m/d
324     */
325    protected static synchronized java.util.Date getDate(int year, int month,
326            int dom) {
327        if (cal == null) {
328            cal = new java.util.GregorianCalendar();
329        }
330        cal.clear();
331        cal.set(year, month, dom);
332        return cal.getTime();
333    }
334
335    private static class TestParams {
336
337        private int inclusion;
338        private long seed;
339        private int loggingLevel;
340
341        private String policyFileName;
342        private SecurityManager testSecurityManager;
343        private SecurityManager originalSecurityManager;
344
345        private Map<String, List<String>> knownIssues;
346
347        private Properties props;
348
349
350        private TestParams() {
351        }
352
353        static TestParams create() {
354            TestParams params = new TestParams();
355            Properties props = System.getProperties();
356            params.parseProperties(props);
357            return params;
358        }
359
360        private void parseProperties(Properties props) {
361            this.props = props;
362
363            inclusion = getIntProperty(EXHAUSTIVENESS, DEFAULT_EXHAUSTIVENESS, MAX_EXHAUSTIVENESS);
364            seed = getLongProperty(SEED, System.currentTimeMillis());
365            loggingLevel = getIntProperty(LOGGING_LEVEL, DEFAULT_LOGGING_LEVEL, MAX_LOGGING_LEVEL);
366
367            policyFileName = getProperty(SECURITY_POLICY);
368            if (policyFileName != null) {
369                String originalPolicyFileName = System.getProperty("java.security.policy");
370                originalSecurityManager = System.getSecurityManager();
371                System.setProperty("java.security.policy", policyFileName);
372                Policy.getPolicy().refresh();
373                testSecurityManager = new SecurityManager();
374                System.setProperty("java.security.policy", originalPolicyFileName==null ? "" : originalPolicyFileName);
375            }
376        }
377
378        public String getProperty(String key) {
379            String val = null;
380            if (key != null && key.length() > 0) {
381                val = props.getProperty(key);
382            }
383            return val;
384        }
385
386        public boolean getBooleanProperty(String key) {
387            return getBooleanProperty(key, false);
388        }
389
390        public boolean getBooleanProperty(String key, boolean defVal) {
391            String s = getProperty(key);
392            if (s == null) {
393                return defVal;
394            }
395            if (s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("true") || s.equals("1")) {
396                return true;
397            }
398            return false;
399        }
400
401        public int getIntProperty(String key, int defVal) {
402            return getIntProperty(key, defVal, -1);
403        }
404
405        public int getIntProperty(String key, int defVal, int maxVal) {
406            String s = getProperty(key);
407            if (s == null) {
408                return defVal;
409            }
410            return (maxVal == -1) ? Integer.valueOf(s) : Math.max(Integer.valueOf(s), maxVal);
411        }
412
413        public long getLongProperty(String key, long defVal) {
414            String s = getProperty(key);
415            if (s == null) {
416                return defVal;
417            }
418            return Long.valueOf(s);
419        }
420
421        public int getInclusion() {
422            return inclusion;
423        }
424
425        public long getSeed() {
426            return seed;
427        }
428
429        public int getLoggingLevel() {
430            return loggingLevel;
431        }
432    }
433
434    /**
435     * Check the given array to see that all the strings in the expected array
436     * are present.
437     *
438     * @param msg
439     *            string message, for log output
440     * @param array
441     *            array of strings to check
442     * @param expected
443     *            array of strings we expect to see, or null
444     * @return the length of 'array', or -1 on error
445     */
446    protected static int checkArray(String msg, String array[], String expected[]) {
447        int explen = (expected != null) ? expected.length : 0;
448        if (!(explen >= 0 && explen < 31)) { // [sic] 31 not 32
449            errln("Internal error");
450            return -1;
451        }
452        int i = 0;
453        StringBuffer buf = new StringBuffer();
454        int seenMask = 0;
455        for (; i < array.length; ++i) {
456            String s = array[i];
457            if (i != 0)
458                buf.append(", ");
459            buf.append(s);
460            // check expected list
461            for (int j = 0, bit = 1; j < explen; ++j, bit <<= 1) {
462                if ((seenMask & bit) == 0) {
463                    if (s.equals(expected[j])) {
464                        seenMask |= bit;
465                        logln("Ok: \"" + s + "\" seen");
466                    }
467                }
468            }
469        }
470        logln(msg + " = [" + buf + "] (" + i + ")");
471        // did we see all expected strings?
472        if (((1 << explen) - 1) != seenMask) {
473            for (int j = 0, bit = 1; j < expected.length; ++j, bit <<= 1) {
474                if ((seenMask & bit) == 0) {
475                    errln("\"" + expected[j] + "\" not seen");
476                }
477            }
478        }
479        return array.length;
480    }
481
482    /**
483     * Check the given array to see that all the locales in the expected array
484     * are present.
485     *
486     * @param msg
487     *            string message, for log output
488     * @param array
489     *            array of locales to check
490     * @param expected
491     *            array of locales names we expect to see, or null
492     * @return the length of 'array'
493     */
494    protected static int checkArray(String msg, Locale array[], String expected[]) {
495        String strs[] = new String[array.length];
496        for (int i = 0; i < array.length; ++i) {
497            strs[i] = array[i].toString();
498        }
499        return checkArray(msg, strs, expected);
500    }
501
502    /**
503     * Check the given array to see that all the locales in the expected array
504     * are present.
505     *
506     * @param msg
507     *            string message, for log output
508     * @param array
509     *            array of locales to check
510     * @param expected
511     *            array of locales names we expect to see, or null
512     * @return the length of 'array'
513     */
514    protected static int checkArray(String msg, ULocale array[], String expected[]) {
515        String strs[] = new String[array.length];
516        for (int i = 0; i < array.length; ++i) {
517            strs[i] = array[i].toString();
518        }
519        return checkArray(msg, strs, expected);
520    }
521
522    // JUnit-like assertions.
523
524    protected static boolean assertTrue(String message, boolean condition) {
525        return handleAssert(condition, message, "true", null);
526    }
527
528    protected static boolean assertFalse(String message, boolean condition) {
529        return handleAssert(!condition, message, "false", null);
530    }
531
532    protected static boolean assertEquals(String message, boolean expected,
533            boolean actual) {
534        return handleAssert(expected == actual, message, String
535                .valueOf(expected), String.valueOf(actual));
536    }
537
538    protected static boolean assertEquals(String message, long expected, long actual) {
539        return handleAssert(expected == actual, message, String
540                .valueOf(expected), String.valueOf(actual));
541    }
542
543    // do NaN and range calculations to precision of float, don't rely on
544    // promotion to double
545    protected static boolean assertEquals(String message, float expected,
546            float actual, double error) {
547        boolean result = Float.isInfinite(expected)
548                ? expected == actual
549                : !(Math.abs(expected - actual) > error); // handles NaN
550        return handleAssert(result, message, String.valueOf(expected)
551                + (error == 0 ? "" : " (within " + error + ")"), String
552                .valueOf(actual));
553    }
554
555    protected static boolean assertEquals(String message, double expected,
556            double actual, double error) {
557        boolean result = Double.isInfinite(expected)
558                ? expected == actual
559                : !(Math.abs(expected - actual) > error); // handles NaN
560        return handleAssert(result, message, String.valueOf(expected)
561                + (error == 0 ? "" : " (within " + error + ")"), String
562                .valueOf(actual));
563    }
564
565    protected static <T> boolean assertEquals(String message, T[] expected, T[] actual) {
566        // Use toString on a List to get useful, readable messages
567        String expectedString = expected == null ? "null" : Arrays.asList(expected).toString();
568        String actualString = actual == null ? "null" : Arrays.asList(actual).toString();
569        return assertEquals(message, expectedString, actualString);
570    }
571
572    protected static boolean assertEquals(String message, Object expected,
573            Object actual) {
574        boolean result = expected == null ? actual == null : expected
575                .equals(actual);
576        return handleAssert(result, message, stringFor(expected),
577                stringFor(actual));
578    }
579
580    protected static boolean assertNotEquals(String message, Object expected,
581            Object actual) {
582        boolean result = !(expected == null ? actual == null : expected
583                .equals(actual));
584        return handleAssert(result, message, stringFor(expected),
585                stringFor(actual), "not equal to", true);
586    }
587
588    protected boolean assertSame(String message, Object expected, Object actual) {
589        return handleAssert(expected == actual, message, stringFor(expected),
590                stringFor(actual), "==", false);
591    }
592
593    protected static boolean assertNotSame(String message, Object expected,
594            Object actual) {
595        return handleAssert(expected != actual, message, stringFor(expected),
596                stringFor(actual), "!=", true);
597    }
598
599    protected static boolean assertNull(String message, Object actual) {
600        return handleAssert(actual == null, message, null, stringFor(actual));
601    }
602
603    protected static boolean assertNotNull(String message, Object actual) {
604        return handleAssert(actual != null, message, null, stringFor(actual),
605                "!=", true);
606    }
607
608    protected static void fail() {
609        fail("");
610    }
611
612    protected static void fail(String message) {
613        if (message == null) {
614            message = "";
615        }
616        if (!message.equals("")) {
617            message = ": " + message;
618        }
619        errln(sourceLocation() + message);
620    }
621
622    private static boolean handleAssert(boolean result, String message,
623            String expected, String actual) {
624        return handleAssert(result, message, expected, actual, null, false);
625    }
626
627    public static boolean handleAssert(boolean result, String message,
628            Object expected, Object actual, String relation, boolean flip) {
629        if (!result || isVerbose()) {
630            if (message == null) {
631                message = "";
632            }
633            if (!message.equals("")) {
634                message = ": " + message;
635            }
636            relation = relation == null ? ", got " : " " + relation + " ";
637            if (result) {
638                logln("OK " + message + ": "
639                        + (flip ? expected + relation + actual : expected));
640            } else {
641                // assert must assume errors are true errors and not just warnings
642                // so cannot warnln here
643                errln(  message
644                        + ": expected"
645                        + (flip ? relation + expected : " " + expected
646                                + (actual != null ? relation + actual : "")));
647            }
648        }
649        return result;
650    }
651
652    private static final String stringFor(Object obj) {
653        if (obj == null) {
654            return "null";
655        }
656        if (obj instanceof String) {
657            return "\"" + obj + '"';
658        }
659        return obj.getClass().getName() + "<" + obj + ">";
660    }
661
662    // Return the source code location of the caller located callDepth frames up the stack.
663    protected static String sourceLocation() {
664        // Walk up the stack to the first call site outside this file
665        for (StackTraceElement st : new Throwable().getStackTrace()) {
666            String source = st.getFileName();
667            if (source != null && !source.equals("TestFmwk.java") && !source.equals("AbstractTestLog.java")) {
668                String methodName = st.getMethodName();
669                if (methodName != null &&
670                       (methodName.startsWith("Test") || methodName.startsWith("test") || methodName.equals("main"))) {
671                    return "(" + source + ":" + st.getLineNumber() + ") ";
672                }
673            }
674        }
675        throw new InternalError();
676    }
677
678    protected static boolean checkDefaultPrivateConstructor(String fullyQualifiedClassName) throws Exception {
679        return checkDefaultPrivateConstructor(Class.forName(fullyQualifiedClassName));
680    }
681
682    protected static boolean checkDefaultPrivateConstructor(Class<?> classToBeTested) throws Exception {
683        Constructor<?> constructor = classToBeTested.getDeclaredConstructor();
684
685        // Check that the constructor is private.
686        boolean isPrivate = Modifier.isPrivate(constructor.getModifiers());
687
688        // Call the constructor for coverage.
689        constructor.setAccessible(true);
690        constructor.newInstance();
691
692        if (!isPrivate) {
693            errln("Default private constructor for class: " + classToBeTested.getName() + " is not private.");
694        }
695        return isPrivate;
696    }
697
698    /**
699     * Tests the toString method on a private or hard-to-reach class.  Assumes constructor of the class does not
700     * take any arguments.
701     * @param fullyQualifiedClassName
702     * @return The output of the toString method.
703     * @throws Exception
704     */
705    protected static String invokeToString(String fullyQualifiedClassName) throws Exception {
706        return invokeToString(fullyQualifiedClassName, new Class<?>[]{}, new Object[]{});
707    }
708
709    /**
710     * Tests the toString method on a private or hard-to-reach class.  Assumes constructor of the class does not
711     * take any arguments.
712     * @param classToBeTested
713     * @return The output of the toString method.
714     * @throws Exception
715     */
716    protected static String invokeToString(Class<?> classToBeTested) throws Exception {
717        return invokeToString(classToBeTested, new Class<?>[]{}, new Object[]{});
718    }
719
720    /**
721     * Tests the toString method on a private or hard-to-reach class.  Allows you to specify the argument types for
722     * the constructor.
723     * @param fullyQualifiedClassName
724     * @return The output of the toString method.
725     * @throws Exception
726     */
727    protected static String invokeToString(String fullyQualifiedClassName,
728            Class<?>[] constructorParamTypes, Object[] constructorParams) throws Exception {
729        return invokeToString(Class.forName(fullyQualifiedClassName), constructorParamTypes, constructorParams);
730    }
731
732    /**
733     * Tests the toString method on a private or hard-to-reach class.  Allows you to specify the argument types for
734     * the constructor.
735     * @param classToBeTested
736     * @return The output of the toString method.
737     * @throws Exception
738     */
739    protected static String invokeToString(Class<?> classToBeTested,
740            Class<?>[] constructorParamTypes, Object[] constructorParams) throws Exception {
741        Constructor<?> constructor = classToBeTested.getDeclaredConstructor(constructorParamTypes);
742        constructor.setAccessible(true);
743        Object obj = constructor.newInstance(constructorParams);
744        Method toStringMethod = classToBeTested.getDeclaredMethod("toString");
745        toStringMethod.setAccessible(true);
746        return (String) toStringMethod.invoke(obj);
747    }
748
749
750    // End JUnit-like assertions
751
752    // TODO (sgill): added to keep errors away
753    /* (non-Javadoc)
754     * @see android.icu.dev.test.TestLog#msg(java.lang.String, int, boolean, boolean)
755     */
756    //@Override
757    protected static void msg(String message, int level, boolean incCount, boolean newln) {
758        if (level == TestLog.WARN || level == TestLog.ERR) {
759            Assert.fail(message);
760        }
761        // TODO(stuartg): turned off - causing OOM running under ant
762//        while (level > 0) {
763//            System.out.print(" ");
764//            level--;
765//        }
766//        System.out.print(message);
767//        if (newln) {
768//            System.out.println();
769//        }
770    }
771
772}
773