1 /*
   2  * Copyright (c) 2019, 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 /**
  25  * @test
  26  * @bug 8220309
  27  * @library /java/text/testlib
  28  * @summary Test String representation of MinusSign/Percent/PerMill symbols.
  29  *          This test assumes CLDR has numbering systems for "arab" and
  30  *          "arabext", and their minus/percent representations include
  31  *          BiDi formatting control characters.
  32  * @run testng/othervm DFSMinusPerCentMill
  33  */
  34 
  35 import java.io.*;
  36 import java.util.*;
  37 import java.text.*;
  38 
  39 import static org.testng.Assert.*;
  40 import org.testng.annotations.DataProvider;
  41 import org.testng.annotations.Test;
  42 
  43 public class DFSMinusPerCentMill {
  44     private enum Type {
  45         NUMBER, PERCENT, CURRENCY, INTEGER, COMPACT, PERMILL
  46     }
  47 
  48     private static final Locale US_ARAB = Locale.forLanguageTag("en-US-u-nu-arab");
  49     private static final Locale US_ARABEXT = Locale.forLanguageTag("en-US-u-nu-arabext");
  50     private static final double SRC_NUM = -1234.56;
  51 
  52     @DataProvider
  53     Object[][] formatData() {
  54         return new Object[][] {
  55             // Locale, FormatStyle, expected format, expected single char symbol
  56             {US_ARAB, Type.NUMBER, "\u061c-\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
  57             {US_ARAB, Type.PERCENT, "\u061c-\u0661\u0662\u0663\u066c\u0664\u0665\u0666\u066a\u061c"},
  58             {US_ARAB, Type.CURRENCY, "\u061c-$\u0661\u066c\u0662\u0663\u0664\u066b\u0665\u0666"},
  59             {US_ARAB, Type.INTEGER, "\u061c-\u0661\u066c\u0662\u0663\u0665"},
  60             {US_ARAB, Type.COMPACT, "\u061c-\u0661K"},
  61             {US_ARAB, Type.PERMILL, "\u061c-\u0661\u0662\u0663\u0664\u0665\u0666\u0660\u0609"},
  62 
  63             {US_ARABEXT, Type.NUMBER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
  64             {US_ARABEXT, Type.PERCENT, "\u200e-\u200e\u06f1\u06f2\u06f3\u066c\u06f4\u06f5\u06f6\u066a"},
  65             {US_ARABEXT, Type.CURRENCY, "\u200e-\u200e$\u06f1\u066c\u06f2\u06f3\u06f4\u066b\u06f5\u06f6"},
  66             {US_ARABEXT, Type.INTEGER, "\u200e-\u200e\u06f1\u066c\u06f2\u06f3\u06f5"},
  67             {US_ARABEXT, Type.COMPACT, "\u200e-\u200e\u06f1K"},
  68             {US_ARABEXT, Type.PERMILL, "\u200e-\u200e\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f0\u0609"},
  69         };
  70     }
  71 
  72     @DataProvider
  73     Object[][] charSymbols() {
  74         return new Object[][]{
  75             // Locale, percent, per mille, minus sign
  76             {US_ARAB, '\u066a', '\u0609', '-'},
  77             {US_ARABEXT, '\u066a', '\u0609', '-'},
  78         };
  79     }
  80 
  81     @Test(dataProvider="formatData")
  82     public void testFormatData(Locale l, Type style, String expected) {
  83         NumberFormat nf = null;
  84         switch (style) {
  85             case NUMBER:
  86                 nf = NumberFormat.getNumberInstance(l);
  87                 break;
  88             case PERCENT:
  89                 nf = NumberFormat.getPercentInstance(l);
  90                 break;
  91             case CURRENCY:
  92                 nf = NumberFormat.getCurrencyInstance(l);
  93                 break;
  94             case INTEGER:
  95                 nf = NumberFormat.getIntegerInstance(l);
  96                 break;
  97             case COMPACT:
  98                 nf = NumberFormat.getCompactNumberInstance(l, NumberFormat.Style.SHORT);
  99                 break;
 100             case PERMILL:
 101                 nf = new DecimalFormat("#.#\u2030", DecimalFormatSymbols.getInstance(l));
 102                 break;
 103         }
 104 
 105         assertEquals(nf.format(SRC_NUM), expected);
 106     }
 107 
 108     @Test(dataProvider="charSymbols")
 109     public void testCharSymbols(Locale l, char percent, char permill, char minus) {
 110         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
 111         assertEquals(dfs.getPercent(), percent);
 112         assertEquals(dfs.getPerMill(), permill);
 113         assertEquals(dfs.getMinusSign(), minus);
 114     }
 115 
 116     @Test
 117     public void testSerialization() throws Exception {
 118         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance();
 119         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 120         new ObjectOutputStream(bos).writeObject(dfs);
 121         DecimalFormatSymbols dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
 122                 new ByteArrayInputStream(bos.toByteArray())
 123         ).readObject();
 124 
 125         assertEquals(dfs, dfsSerialized);
 126 
 127         // set minus/percent/permille
 128         dfs.setMinusSign('a');
 129         dfs.setPercent('b');
 130         dfs.setPerMill('c');
 131         bos = new ByteArrayOutputStream();
 132         new ObjectOutputStream(bos).writeObject(dfs);
 133         dfsSerialized = (DecimalFormatSymbols)new ObjectInputStream(
 134                 new ByteArrayInputStream(bos.toByteArray())
 135         ).readObject();
 136 
 137         assertEquals(dfs, dfsSerialized);
 138     }
 139 }