a64fc48e2d
Reviewed-by: rriggs, darcy
149 lines
5.0 KiB
Java
149 lines
5.0 KiB
Java
/*
|
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
import jdk.test.lib.RandomFactory;
|
|
import org.junit.jupiter.api.BeforeAll;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import java.math.Accessor;
|
|
import java.math.BigInteger;
|
|
import java.util.Random;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8319174
|
|
* @summary Exercises minimality of BigInteger.mag field (use -Dseed=X to set PRANDOM seed)
|
|
* @library /test/lib
|
|
* @build jdk.test.lib.RandomFactory
|
|
* @build java.base/java.math.Accessor
|
|
* @key randomness
|
|
* @run junit/othervm -DmaxDurationMillis=3000 ByteArrayConstructorTest
|
|
*/
|
|
public class ByteArrayConstructorTest {
|
|
|
|
private static final int DEFAULT_MAX_DURATION_MILLIS = 3_000;
|
|
|
|
public static final int N = 1_024;
|
|
|
|
private static int maxDurationMillis;
|
|
private static final Random rnd = RandomFactory.getRandom();
|
|
private volatile boolean stop = false;
|
|
|
|
@BeforeAll
|
|
static void setMaxDurationMillis() {
|
|
maxDurationMillis = Math.max(maxDurationMillis(), 0);
|
|
}
|
|
|
|
@Test
|
|
public void testNonNegative() throws InterruptedException {
|
|
byte[] ba = nonNegativeBytes();
|
|
doBigIntegers(ba, ba[0]); // a mask to flip to 0 and back to ba[0]
|
|
}
|
|
|
|
@Test
|
|
public void testNegative() throws InterruptedException {
|
|
byte[] ba = negativeBytes();
|
|
doBigIntegers(ba, (byte) ~ba[0]); // a mask to flip to -1 and back to ba[0]
|
|
}
|
|
|
|
/*
|
|
* Starts a thread th that keeps flipping the "sign" byte in the array ba
|
|
* from the original value to 0 or -1 and back, depending on ba[0] being
|
|
* non-negative or negative, resp.
|
|
* (ba is "big endian", the least significant byte is the one with the
|
|
* highest index.)
|
|
*
|
|
* In the meantime, the current thread keeps creating BigInteger instances
|
|
* with ba and checks that the internal invariant holds, despite the
|
|
* attempts by thread th to racily modify ba.
|
|
* It does so at least as indicated by maxDurationMillis.
|
|
*
|
|
* Finally, this thread requests th to stop and joins with it, either
|
|
* because maxDurationMillis has expired, or because of an invalid invariant.
|
|
*/
|
|
private void doBigIntegers(byte[] ba, byte mask) throws InterruptedException {
|
|
Thread th = new Thread(() -> {
|
|
while (!stop) {
|
|
ba[0] ^= mask;
|
|
}
|
|
});
|
|
th.start();
|
|
|
|
try {
|
|
createBigIntegers(maxDurationMillis, ba);
|
|
} finally {
|
|
stop = true;
|
|
th.join(1_000);
|
|
}
|
|
}
|
|
|
|
private void createBigIntegers(int maxDurationMillis, byte[] ba) {
|
|
long start = System.currentTimeMillis();
|
|
while (System.currentTimeMillis() - start < maxDurationMillis) {
|
|
BigInteger bi = new BigInteger(ba);
|
|
int[] mag = Accessor.mag(bi);
|
|
assertTrue(mag.length == 0 || mag[0] != 0,
|
|
String.format("inconsistent BigInteger: mag.length=%d, mag[0]=%d",
|
|
mag.length, mag[0]));
|
|
}
|
|
}
|
|
|
|
private byte[] nonNegativeBytes() {
|
|
byte[] ba = new byte[1 + N];
|
|
byte b0;
|
|
while ((b0 = (byte) rnd.nextInt()) < 0); // empty body
|
|
rnd.nextBytes(ba);
|
|
ba[0] = b0;
|
|
/* Except for ba[0], fill most significant half with zeros. */
|
|
for (int i = 1; i <= N / 2; ++i) {
|
|
ba[i] = 0;
|
|
}
|
|
return ba;
|
|
}
|
|
|
|
private byte[] negativeBytes() {
|
|
byte[] ba = new byte[1 + N];
|
|
byte b0;
|
|
while ((b0 = (byte) rnd.nextInt()) >= 0); // empty body
|
|
rnd.nextBytes(ba);
|
|
ba[0] = b0;
|
|
/* Except for ba[0], fill most significant half with -1 bytes. */
|
|
for (int i = 1; i <= N / 2; ++i) {
|
|
ba[i] = -1;
|
|
}
|
|
return ba;
|
|
}
|
|
|
|
private static int maxDurationMillis() {
|
|
try {
|
|
return Integer.parseInt(System.getProperty("maxDurationMillis",
|
|
Integer.toString(DEFAULT_MAX_DURATION_MILLIS)));
|
|
} catch (NumberFormatException ignore) {
|
|
}
|
|
return DEFAULT_MAX_DURATION_MILLIS;
|
|
}
|
|
|
|
}
|