1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 /*
  24  * @test
  25  * @bug 8177552
  26  * @summary Checks the validity of compact number patterns specified through
  27  *          CompactNumberFormat constructor
  28  * @run testng/othervm CompactPatternsValidity
  29  */
  30 
  31 import java.math.BigDecimal;
  32 import java.math.BigInteger;
  33 import java.text.CompactNumberFormat;
  34 import java.text.DecimalFormatSymbols;
  35 import java.text.ParseException;
  36 import java.util.List;
  37 import java.util.Locale;
  38 import org.testng.annotations.DataProvider;
  39 import org.testng.annotations.Test;
  40 
  41 public class CompactPatternsValidity {
  42 
  43     @DataProvider(name = "invalidPatterns")
  44     Object[][] invalidCompactPatterns() {
  45         return new Object[][]{
  46             // compact patterns
  47             // pattern containing unquoted special character '.'
  48             {new String[]{"", "", "", "0K", "0.0K"}},
  49             // a non empty pattern containing no min integer digits
  50             {new String[]{"K", "0K", "00K"}},
  51             // min integer digits exceeding for the range at index 3
  52             {new String[]{"", "", "0K", "00000K"}},};
  53     }
  54 
  55     @DataProvider(name = "validPatternsFormat")
  56     Object[][] validPatternsFormat() {
  57         return new Object[][]{
  58             // compact patterns, numbers, expected output
  59             {new String[]{"0", "0", "0", "0K", "00K"}, List.of(200, 1000, 3000, 500000),
  60             List.of("200", "1K", "3K", "500K")},
  61             {new String[]{"0", "'.'K0"}, List.of(1, 20, 3000),
  62             List.of("1", ".K2", ".K300")},
  63             {new String[]{"0", "0", "0", "0K", "00K'.'"}, List.of(100.99, 1000, 30000),
  64             List.of("101", "1K", "30K.")},
  65             // a pattern containing both prefix and suffix
  66             {new String[]{"", "", "H0H", "0K", "00K", "H0G"}, List.of(0.0, 500, -500, 30000, 5000000),
  67             List.of("0", "H5H", "-H5H", "30K", "H50G")},
  68             // inconsistency across patterns regarding prefix and suffix
  69             {new String[]{"", "", "", "0K", "K0"}, List.of(100, 1000, 30000),
  70             List.of("100", "1K", "K3")},
  71             // a pattern containing both prefix ('.') and suffix (K)
  72             {new String[]{"0", "", "", "'.'0K"}, List.of(20.99, 1000, 30000),
  73             List.of("21", ".1K", ".30K")},
  74             {new String[]{"", "0", "0", "0K','"}, List.of(100, 1000, new BigInteger("12345678987654321")),
  75             List.of("100", "1K,", "12345678987654K,")},
  76             {new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M",
  77                 "000M", "0B", "00B", "000B", "0T", "00T", "000T"},
  78             List.of(new BigInteger("223565686837667632"),
  79             new BigDecimal("12322456774334.89766"), 30000, 3456.78),
  80             List.of("223566T", "12T", "30K", "3K")},
  81             // all empty or special patterns; checking the default formatting behaviour
  82             {new String[]{"", "", "", "0", "0", "", "", "", "", "", "", "", "", "", ""},
  83             List.of(new BigInteger("223566000000000000"),
  84             new BigDecimal("12345678987654567"), 30000, 3000),
  85             List.of("223,566,000,000,000,000", "12,345,678,987,654,567", "30,000", "3,000")},
  86             // patterns beyond 10^19; divisors beyond long range
  87             {new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M", "000M",
  88                 "0B", "00B", "000B", "0T", "00T", "000T", "0L", "00L",
  89                 "000L", "0XL", "00XL"},
  90             List.of(new BigInteger("100000000000000000"),
  91             new BigInteger("10000000000000000000"),
  92             new BigDecimal("555555555555555555555.89766"), 30000),
  93             List.of("100L", "10XL", "556XL", "30K")},
  94             // patterns containing positive;negative subpatterns
  95             {new String[]{"", "", "", "elfu 0;elfu -0", "elfu 00;elfu -00",
  96                 "elfu 000;elfu -000", "milioni 0;milioni -0",
  97                 "milioni 00;milioni -00", "milioni 000;milioni -000"},
  98             List.of(20.99, -20.99, 1000, -1000, 30000, -30000,
  99             new BigInteger("12345678987654321"),
 100             new BigInteger("-12345678987654321")),
 101             List.of("21", "-21", "elfu 1", "elfu -1", "elfu 30", "elfu -30",
 102             "milioni 12345678988", "milioni -12345678988")},
 103             // patterns containing both prefix and suffix and positive;negative
 104             // subpatern
 105             {new String[]{"", "", "H0H;H-0H", "0K;0K-", "00K;-00K", "H0G;-H0G"},
 106             List.of(0, 500, -500, 30000, -3000, 5000000),
 107             List.of("0", "H5H", "H-5H", "30K", "3K-", "H50G")},};
 108     }
 109 
 110     @DataProvider(name = "validPatternsParse")
 111     Object[][] validPatternsParse() {
 112         return new Object[][]{
 113             // compact patterns, parse string, expected output
 114             {new String[]{"0", "0", "0", "0K", "00K"},
 115             List.of(".56", "200", ".1K", "3K", "500K"),
 116             List.of(0.56, 200L, 100L, 3000L, 500000L)},
 117             {new String[]{"0", "'.'K0"}, List.of("1", ".K2", ".K300"),
 118             List.of(1L, 20L, 3000L)},
 119             {new String[]{"0", "0", "0", "0K", "00K'.'"},
 120             List.of("101", "1K", "30K."), List.of(101L, 1000L, 30000L)},
 121             // a pattern containing both prefix and suffix
 122             {new String[]{"", "", "H0H", "0K", "00K", "H0G"},
 123             List.of("0", "H5H", "-H5H", "30K", "H50G"),
 124             List.of(0L, 500L, -500L, 30000L, 5000000L)},
 125             // inconsistency across patterns regarding prefix and suffix
 126             {new String[]{"", "", "", "0K", "K0"}, List.of("100", "1K", "K3"),
 127             List.of(100L, 1000L, 30000L)},
 128             // a pattern containing both prefix ('.') and suffix (K)
 129             {new String[]{"0", "", "", "'.'0K"}, List.of("21", ".1K", ".30K"),
 130             List.of(21L, 1000L, 30000L)},
 131             {new String[]{"", "0", "0", "0K','"},
 132             List.of("100", "1K,", "12345678987654K,"),
 133             List.of(100L, 1000L, 12345678987654000L)},
 134             {new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M",
 135                 "000M", "0B", "00B", "000B", "0T", "00T", "000T"},
 136             List.of("223566T", "12T", "30K", "3K"),
 137             List.of(223566000000000000L, 12000000000000L, 30000L, 3000L)},
 138             // patterns beyond 10^19; divisors beyond long range
 139             {new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M", "000M",
 140                 "0B", "00B", "000B", "0T", "00T", "000T", "0L", "00L",
 141                 "000L", "0XL", "00XL"},
 142             List.of("1L", "100L", "10XL", "556XL", "30K"),
 143             List.of(1000000000000000L, 100000000000000000L, 1.0E19, 5.56E20, 30000L)},
 144             // patterns containing positive;negative subpatterns
 145             {new String[]{"", "", "", "elfu 0;elfu -0", "elfu 00;elfu -00",
 146                 "elfu 000;elfu -000", "milioni 0;milioni -0",
 147                 "milioni 00;milioni -00", "milioni 000;milioni -000"},
 148             List.of("21", "-21", "100.90", "-100.90", "elfu 1", "elfu -1",
 149             "elfu 30", "elfu -30", "milioni 12345678988",
 150             "milioni -12345678988"),
 151             List.of(21L, -21L, 100.90, -100.90, 1000L, -1000L, 30000L, -30000L,
 152             12345678988000000L, -12345678988000000L)},
 153             // patterns containing both prefix and suffix and positive;negative
 154             // subpatern
 155             {new String[]{"", "", "H0H;H-0H", "0K;0K-", "00K;-00K", "H0G;-H0G"},
 156             List.of("0", "H5H", "H-5H", "30K", "30K-", "H50G"),
 157             List.of(0L, 500L, -500L, 30000L, -30000L, 5000000L)},};
 158     }
 159 
 160     @Test(dataProvider = "invalidPatterns",
 161             expectedExceptions = RuntimeException.class)
 162     public void testInvalidCompactPatterns(String[] compactPatterns) {
 163         new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols
 164                 .getInstance(Locale.US), compactPatterns);
 165     }
 166 
 167     @Test(dataProvider = "validPatternsFormat")
 168     public void testValidPatternsFormat(String[] compactPatterns,
 169             List<Object> numbers, List<String> expected) {
 170         CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
 171                 DecimalFormatSymbols.getInstance(Locale.US), compactPatterns);
 172         for (int index = 0; index < numbers.size(); index++) {
 173             CompactFormatAndParse.testFormat(fmt, numbers.get(index),
 174                     expected.get(index));
 175         }
 176     }
 177 
 178     @Test(dataProvider = "validPatternsParse")
 179     public void testValidPatternsParse(String[] compactPatterns,
 180             List<String> parseString, List<Number> numbers) throws ParseException {
 181         CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
 182                 DecimalFormatSymbols.getInstance(Locale.US), compactPatterns);
 183         for (int index = 0; index < parseString.size(); index++) {
 184             CompactFormatAndParse.testParse(fmt, parseString.get(index),
 185                     numbers.get(index), null, null);
 186         }
 187     }
 188 }