1/*
2 * Copyright (c) 2012, 2013, 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
24import org.testng.annotations.DataProvider;
25import org.testng.annotations.Test;
26
27import java.math.BigInteger;
28import java.util.ArrayList;
29import java.util.Iterator;
30import java.util.Arrays;
31import java.util.List;
32import java.util.function.LongFunction;
33import java.util.function.Function;
34
35import 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 */
43public 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}
195