1 /*
   2  * Copyright (c) 2012, 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 import org.testng.annotations.DataProvider;
  25 import org.testng.annotations.Test;
  26 
  27 import java.math.BigInteger;
  28 import java.util.ArrayList;
  29 import java.util.Iterator;
  30 import java.util.Arrays;
  31 import java.util.List;
  32 import java.util.function.LongFunction;
  33 import java.util.function.Function;
  34 
  35 import static org.testng.Assert.assertEquals;
  36 
  37 /**
  38  * @test
  39  * @run testng IntegralPrimitiveToString
  40  * @summary test string conversions for primitive integral types.
  41  * @author Mike Duigou
  42  */
  43 public class IntegralPrimitiveToString {
  44 
  45     @Test(dataProvider="numbers")
  46     public <N extends Number> void testToString(String description,
  47         Function<N, BigInteger> converter,
  48         Function<N, BigInteger> unsignedConverter,
  49         N[] values,
  50         Stringifier<N>[] stringifiers) {
  51         System.out.printf("%s : conversions: %d values: %d\n", description, stringifiers.length, values.length);
  52         for( N value : values) {
  53             BigInteger asBigInt = converter.apply(value);
  54             BigInteger asUnsignedBigInt = unsignedConverter.apply(value);
  55             for(Stringifier<N> stringifier : stringifiers) {
  56                 stringifier.assertMatchingToString(value, asBigInt, asUnsignedBigInt, description);
  57             }
  58         }
  59     }
  60 
  61     static class Stringifier<N extends Number> {
  62         final boolean signed;
  63         final int  radix;
  64         final Function<N,String> toString;
  65         Stringifier(boolean signed, int radix, Function<N,String> toString) {
  66             this.signed = signed;
  67             this.radix = radix;
  68             this.toString = toString;
  69         }
  70 
  71         public void assertMatchingToString(N value, BigInteger asSigned, BigInteger asUnsigned, String description) {
  72             String expected = signed
  73                 ? asSigned.toString(radix)
  74                 : asUnsigned.toString(radix);
  75 
  76             String actual = toString.apply(value);
  77 
  78             assertEquals(actual, expected, description + " conversion should be the same");
  79         }
  80     }
  81 
  82     @DataProvider(name="numbers", parallel=true)
  83     public Iterator<Object[]> testSetProvider() {
  84 
  85     return Arrays.asList(
  86         new Object[] { "Byte",
  87             (Function<Byte,BigInteger>) b -> BigInteger.valueOf((long) b),
  88             (Function<Byte,BigInteger>) b -> BigInteger.valueOf(Integer.toUnsignedLong((byte) b)),
  89             numberProvider((LongFunction<Byte>) l -> Byte.valueOf((byte) l), Byte.SIZE),
  90             new Stringifier[] {
  91                 new Stringifier<Byte>(true, 10, b -> b.toString()),
  92                 new Stringifier<Byte>(true, 10, b -> Byte.toString(b))
  93             }
  94         },
  95         new Object[] { "Short",
  96             (Function<Short,BigInteger>) s -> BigInteger.valueOf((long) s),
  97             (Function<Short,BigInteger>) s -> BigInteger.valueOf(Integer.toUnsignedLong((short) s)),
  98             numberProvider((LongFunction<Short>) l -> Short.valueOf((short) l), Short.SIZE),
  99             new Stringifier[] {
 100                 new Stringifier<Short>(true, 10, s -> s.toString()),
 101                 new Stringifier<Short>(true, 10, s -> Short.toString( s))
 102             }
 103         },
 104         new Object[] { "Integer",
 105             (Function<Integer,BigInteger>) i -> BigInteger.valueOf((long) i),
 106             (Function<Integer,BigInteger>) i -> BigInteger.valueOf(Integer.toUnsignedLong(i)),
 107             numberProvider((LongFunction<Integer>) l -> Integer.valueOf((int) l), Integer.SIZE),
 108             new Stringifier[] {
 109                 new Stringifier<Integer>(true, 10, i -> i.toString()),
 110                 new Stringifier<Integer>(true, 10, i -> Integer.toString(i)),
 111                 new Stringifier<Integer>(false, 2, Integer::toBinaryString),
 112                 new Stringifier<Integer>(false, 16, Integer::toHexString),
 113                 new Stringifier<Integer>(false, 8, Integer::toOctalString),
 114                 new Stringifier<Integer>(true, 2, i -> Integer.toString(i, 2)),
 115                 new Stringifier<Integer>(true, 8, i -> Integer.toString(i, 8)),
 116                 new Stringifier<Integer>(true, 10, i -> Integer.toString(i, 10)),
 117                 new Stringifier<Integer>(true, 16, i -> Integer.toString(i, 16)),
 118                 new Stringifier<Integer>(true, Character.MAX_RADIX, i -> Integer.toString(i, Character.MAX_RADIX)),
 119                 new Stringifier<Integer>(false, 10, i -> Integer.toUnsignedString(i)),
 120                 new Stringifier<Integer>(false, 2, i -> Integer.toUnsignedString(i, 2)),
 121                 new Stringifier<Integer>(false, 8, i -> Integer.toUnsignedString(i, 8)),
 122                 new Stringifier<Integer>(false, 10, i -> Integer.toUnsignedString(i, 10)),
 123                 new Stringifier<Integer>(false, 16, i -> Integer.toUnsignedString(i, 16)),
 124                 new Stringifier<Integer>(false, Character.MAX_RADIX, i -> Integer.toUnsignedString(i, Character.MAX_RADIX))
 125             }
 126         },
 127         new Object[] { "Long",
 128             (Function<Long, BigInteger>) BigInteger::valueOf,
 129             (Function<Long, BigInteger>) l -> {
 130                 if (l >= 0) {
 131                     return BigInteger.valueOf((long) l);
 132                 } else {
 133                     int upper = (int)(l >>> 32);
 134                     int lower = (int) (long) l;
 135 
 136                     // return (upper << 32) + lower
 137                     return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
 138                     add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
 139                 }
 140             },
 141             numberProvider((LongFunction<Long>) Long::valueOf, Long.SIZE),
 142             new Stringifier[] {
 143                 new Stringifier<Long>(true, 10, l -> l.toString()),
 144                 new Stringifier<Long>(true, 10, l -> Long.toString(l)),
 145                 new Stringifier<Long>(false, 2, Long::toBinaryString),
 146                 new Stringifier<Long>(false, 16, Long::toHexString),
 147                 new Stringifier<Long>(false, 8, Long::toOctalString),
 148                 new Stringifier<Long>(true, 2, l -> Long.toString(l, 2)),
 149                 new Stringifier<Long>(true, 8, l -> Long.toString(l, 8)),
 150                 new Stringifier<Long>(true, 10, l -> Long.toString(l, 10)),
 151                 new Stringifier<Long>(true, 16, l -> Long.toString(l, 16)),
 152                 new Stringifier<Long>(true, Character.MAX_RADIX, l -> Long.toString(l, Character.MAX_RADIX)),
 153                 new Stringifier<Long>(false, 10, Long::toUnsignedString),
 154                 new Stringifier<Long>(false, 2, l -> Long.toUnsignedString(l, 2)),
 155                 new Stringifier<Long>(false, 8, l-> Long.toUnsignedString(l, 8)),
 156                 new Stringifier<Long>(false, 10, l -> Long.toUnsignedString(l, 10)),
 157                 new Stringifier<Long>(false, 16, l -> Long.toUnsignedString(l, 16)),
 158                 new Stringifier<Long>(false, Character.MAX_RADIX, l -> Long.toUnsignedString(l, Character.MAX_RADIX))
 159             }
 160         }
 161         ).iterator();
 162     }
 163     private static final long[] SOME_PRIMES = {
 164         3L, 5L, 7L, 11L, 13L, 17L, 19L, 23L, 29L, 31L, 37L, 41L, 43L, 47L, 53L,
 165         59L, 61L, 71L, 73L, 79L, 83L, 89L, 97L, 101L, 103L, 107L, 109L, 113L,
 166         5953L, 5981L, 5987L, 6007L, 6011L, 6029L, 6037L, 6043L, 6047L, 6053L,
 167         16369L, 16381L, 16411L, 32749L, 32771L, 65521L, 65537L,
 168         (long) Integer.MAX_VALUE };
 169 
 170     public <N extends Number> N[] numberProvider(LongFunction<N> boxer, int bits, N... extras) {
 171         List<N> numbers = new ArrayList<>();
 172 
 173         for(int bitmag = 0; bitmag < bits; bitmag++) {
 174             long value = 1L << bitmag;
 175             numbers.add(boxer.apply(value));
 176             numbers.add(boxer.apply(value - 1));
 177             numbers.add(boxer.apply(value + 1));
 178             numbers.add(boxer.apply(-value));
 179             for(int divisor = 0; divisor < SOME_PRIMES.length && value < SOME_PRIMES[divisor]; divisor++) {
 180                 numbers.add(boxer.apply(value - SOME_PRIMES[divisor]));
 181                 numbers.add(boxer.apply(value + SOME_PRIMES[divisor]));
 182                 numbers.add(boxer.apply(value * SOME_PRIMES[divisor]));
 183                 numbers.add(boxer.apply(value / SOME_PRIMES[divisor]));
 184                 numbers.add(boxer.apply(value | SOME_PRIMES[divisor]));
 185                 numbers.add(boxer.apply(value & SOME_PRIMES[divisor]));
 186                 numbers.add(boxer.apply(value ^ SOME_PRIMES[divisor]));
 187             }
 188         }
 189 
 190         numbers.addAll(Arrays.asList(extras));
 191 
 192         return (N[]) numbers.toArray(new Number[numbers.size()]);
 193     }
 194 }