diff --git a/src/test/java/com/esaulpaugh/headlong/abi/MonteCarloTestCase.java b/src/test/java/com/esaulpaugh/headlong/abi/MonteCarloTestCase.java index 54efda147..786c2af05 100644 --- a/src/test/java/com/esaulpaugh/headlong/abi/MonteCarloTestCase.java +++ b/src/test/java/com/esaulpaugh/headlong/abi/MonteCarloTestCase.java @@ -16,6 +16,8 @@ package com.esaulpaugh.headlong.abi; import com.esaulpaugh.headlong.TestUtils; +import com.esaulpaugh.headlong.abi.util.BizarroIntegers; +import com.esaulpaugh.headlong.util.Integers; import com.esaulpaugh.headlong.util.Strings; import com.esaulpaugh.headlong.util.SuperSerial; import com.google.gson.Gson; @@ -139,6 +141,7 @@ public class MonteCarloTestCase { this.rawSignature = sig; this.function = new Function(sig, null, md); this.argsTuple = generateTuple(function.getParamTypes(), rng); + function.getParamTypes().validate(argsTuple); } JsonElement toJsonElement(Gson gson, String name, JsonPrimitive version) { @@ -300,8 +303,8 @@ private Tuple generateTuple(TupleType tupleType, Random r) { private Object generateValue(ABIType type, Random r) { switch (type.typeCode()) { case TYPE_CODE_BOOLEAN: return r.nextBoolean(); - case TYPE_CODE_BYTE: return generateByte(r); - case TYPE_CODE_INT: return generateInt(r, (IntType) type); + case TYPE_CODE_BYTE: return (byte) r.nextInt(); + case TYPE_CODE_INT: return (int) generateLong(r, (IntType) type); case TYPE_CODE_LONG: return generateLong(r, (LongType) type); case TYPE_CODE_BIG_INTEGER: return generateBigInteger(r, (BigIntegerType) type); case TYPE_CODE_BIG_DECIMAL: return generateBigDecimal(r, (BigDecimalType) type); @@ -311,30 +314,34 @@ private Object generateValue(ABIType type, Random r) { } } - private static byte generateByte(Random r) { - return (byte) r.nextInt(); + private static long generateLong(Random r, UnitType unitType) { + return generateLong(r, unitType.bitLength, 1 + r.nextInt(unitType.bitLength / Byte.SIZE), unitType.unsigned); } - private static int generateInt(Random r, IntType intType) { - byte[] buffer = new byte[1 + r.nextInt(intType.bitLength >>> 3)]; // 1-4 - r.nextBytes(buffer); - int x = new BigInteger(buffer).intValue(); - if(intType.unsigned && x < 0) { - return (-(x + 1) << 1) + (r.nextBoolean() ? 1 : 0); + private static long generateLong(Random r, int bitLen, int len, boolean unsigned) { + long val = r.nextLong(); + switch (len) { + case 1: val &= 0xFFL; break; + case 2: val &= 0xFFFFL; break; + case 3: val &= 0xFFFFFFL; break; + case 4: val &= 0xFFFFFFFFL; break; + case 5: val &= 0xFFFFFFFFFFL; break; + case 6: val &= 0xFFFFFFFFFFFFL; break; + case 7: val &= 0xFFFFFFFFFFFFFFL; break; + case 8: break; + default: throw new Error(); } - return x; - } - - private static long generateLong(Random r, LongType longType) { - byte[] random = TestUtils.randomBytes(1 + r.nextInt(longType.bitLength / Byte.SIZE) /* 1-8 */, r); - long x = new BigInteger(random).longValue(); - if(longType.unsigned && x < 0) { - return ((-(x + 1)) << 1) + (r.nextBoolean() ? 1 : 0); + val = unsigned || r.nextBoolean() ? val : val < 0 ? -(val + 1) : (-val - 1); + if(!unsigned) { + int valBitLen = val < 0 ? BizarroIntegers.bitLen(val) : Integers.bitLen(val); + if(valBitLen >= bitLen) { + val >>= 1; + } } - return x; + return val; } - private static BigInteger generateBigInteger(Random r, UnitType type) { + private static BigInteger generateBigInteger(Random r, UnitType type) { byte[] magnitude = new byte[type.bitLength / Byte.SIZE]; r.nextBytes(magnitude); boolean zero = true; @@ -394,7 +401,7 @@ private static String generateASCIIString(final int len, Random r) { private static int[] generateIntArray(final int len, IntType intType, Random r) { int[] ints = new int[len]; for (int i = 0; i < len; i++) { - ints[i] = generateInt(r, intType); + ints[i] = (int) generateLong(r, intType); } return ints; } diff --git a/src/test/java/com/esaulpaugh/headlong/abi/TupleTest.java b/src/test/java/com/esaulpaugh/headlong/abi/TupleTest.java index ae716be33..c027a3923 100644 --- a/src/test/java/com/esaulpaugh/headlong/abi/TupleTest.java +++ b/src/test/java/com/esaulpaugh/headlong/abi/TupleTest.java @@ -16,12 +16,16 @@ package com.esaulpaugh.headlong.abi; import com.esaulpaugh.headlong.TestUtils; +import com.esaulpaugh.headlong.abi.util.BizarroIntegers; +import com.esaulpaugh.headlong.util.Integers; import com.joemelsha.crypto.hash.Keccak; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -46,6 +50,67 @@ public class TupleTest { 1.9d }; + @Disabled("meta test") + @Test + public void metaTest1() { + Random r = ThreadLocalRandom.current(); + + int bits = 24; + + final int pow = (int) Math.pow(2.0, bits); + final int powMinus1 = pow - 1; + System.out.println(Long.toHexString(powMinus1)); + + System.out.println(pow); + + boolean[] bools = new boolean[pow]; + + @SuppressWarnings("unchecked") + UnitType type = (UnitType) TupleType.parse("(int" + bits + ")").get(0); + + for (int i = 0; i < 1_579_919_999; i++) { + bools[(int) generateLong(r, type) & powMinus1] = true; + } + + int count = 0; + for (int i = 0; i < pow; i++) { + if(!bools[i]) { + count++; + System.err.println(i); + } + } + + System.out.println("missed " + count); + System.out.println(pow - count + " / " + pow + " " + (1 - ((double) count / pow))); + } + + private static long generateLong(Random r, UnitType unitType) { + return generateLong(r, unitType.bitLength, 1 + r.nextInt(unitType.bitLength / Byte.SIZE), unitType.unsigned); + } + + private static long generateLong(Random r, int bitLen, int len, boolean unsigned) { + long val = r.nextLong(); + switch (len) { + case 1: val &= 0xFFL; break; + case 2: val &= 0xFFFFL; break; + case 3: val &= 0xFFFFFFL; break; + case 4: val &= 0xFFFFFFFFL; break; + case 5: val &= 0xFFFFFFFFFFL; break; + case 6: val &= 0xFFFFFFFFFFFFL; break; + case 7: val &= 0xFFFFFFFFFFFFFFL; break; + case 8: break; + default: throw new Error(); + } + val = unsigned || r.nextBoolean() ? val : val < 0 ? -(val + 1) : (-val - 1); + if(!unsigned) { + int valBitLen = val < 0 ? BizarroIntegers.bitLen(val) : Integers.bitLen(val); + if(valBitLen >= bitLen) { + val >>= 1; + } + } + return val; + } + @Test public void testTypeSafety() throws Throwable {