From 5370a1746baaf8909132fb352ab806c4d43e1c1b Mon Sep 17 00:00:00 2001 From: mikera Date: Sun, 22 Dec 2024 13:21:35 +0000 Subject: [PATCH] More generative testing enhancements --- .../main/java/convex/core/cpos/Belief.java | 5 ++-- .../main/java/convex/core/cvm/ops/Invoke.java | 1 + .../java/convex/core/data/ACAD3Record.java | 2 +- .../main/java/convex/core/data/AVector.java | 7 +++++ .../main/java/convex/core/data/MapEntry.java | 7 +++++ .../java/convex/core/data/VectorArray.java | 11 ++++++++ .../java/convex/core/data/VectorLeaf.java | 25 +++++++++++++++++ .../java/convex/core/data/VectorTree.java | 6 +++++ .../main/java/convex/core/data/Vectors.java | 6 +++++ .../test/java/convex/comms/GenTestFormat.java | 17 ++++++++---- .../test/java/convex/core/cvm/GenTestOps.java | 21 ++++++++++++++- .../java/convex/core/data/GenTestVectors.java | 27 +++++++++++++++++++ .../test/java/convex/core/lang/OpsTest.java | 11 ++++++-- .../convex/test/generators/AGenerator.java | 18 +++++++++++++ .../convex/test/generators/AddressGen.java | 3 +-- .../convex/test/generators/AnyMapGen.java | 3 +-- .../convex/test/generators/AnyRecordGen.java | 3 +-- .../java/convex/test/generators/BlobGen.java | 3 +-- .../convex/test/generators/BooleanGen.java | 3 +-- .../convex/test/generators/ByteFlagGen.java | 3 +-- .../java/convex/test/generators/CharGen.java | 3 +-- .../test/generators/DataStructureGen.java | 2 +- .../test/generators/DenseRecordGen.java | 3 +-- .../convex/test/generators/DoubleGen.java | 3 +-- .../convex/test/generators/VectorGen.java | 25 +++++++++++++++++ 25 files changed, 187 insertions(+), 31 deletions(-) create mode 100644 convex-core/src/test/java/convex/test/generators/AGenerator.java diff --git a/convex-core/src/main/java/convex/core/cpos/Belief.java b/convex-core/src/main/java/convex/core/cpos/Belief.java index f014e13db..6e380a373 100644 --- a/convex-core/src/main/java/convex/core/cpos/Belief.java +++ b/convex-core/src/main/java/convex/core/cpos/Belief.java @@ -179,9 +179,8 @@ public Index> getOrders() { @Override public boolean equals(ACell a) { - if (!(a instanceof Belief)) return false; - Belief as=(Belief)a; - return equals(as); + if (a instanceof Belief) return equals((Belief)a); + return super.equals(a); } /** diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Invoke.java b/convex-core/src/main/java/convex/core/cvm/ops/Invoke.java index 5869895b9..60b12d41f 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Invoke.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Invoke.java @@ -30,6 +30,7 @@ protected Invoke(AVector> ops) { } public static Invoke create(ASequence> ops) { + if (ops.count()==0) return null; AVector> vops = ops.toVector(); return new Invoke(vops); } diff --git a/convex-core/src/main/java/convex/core/data/ACAD3Record.java b/convex-core/src/main/java/convex/core/data/ACAD3Record.java index dd7a4248a..faf1f5c64 100644 --- a/convex-core/src/main/java/convex/core/data/ACAD3Record.java +++ b/convex-core/src/main/java/convex/core/data/ACAD3Record.java @@ -40,7 +40,7 @@ public void validateStructure() throws InvalidDataException { public boolean equals(ACell a) { if (a==null) return false; if (a.getTag()!=tag) return false; - return encoding.equals(a.getEncoding()); + return getEncoding().equals(a.getEncoding()); } @Override diff --git a/convex-core/src/main/java/convex/core/data/AVector.java b/convex-core/src/main/java/convex/core/data/AVector.java index e8ee5da19..fc8506465 100644 --- a/convex-core/src/main/java/convex/core/data/AVector.java +++ b/convex-core/src/main/java/convex/core/data/AVector.java @@ -61,6 +61,13 @@ public AType getType() { */ @Override public abstract T get(long i); + + /** + * Remove an element at the specified position in a vector. WARNING: likely to be O(n) + * @param i + * @return Shortened Vector, or null if position was invalid + */ + public abstract AVector dissocAt(long i); /** * Appends a ListVector chunk to this vector. This vector must contain a whole diff --git a/convex-core/src/main/java/convex/core/data/MapEntry.java b/convex-core/src/main/java/convex/core/data/MapEntry.java index 7eda9ea25..cb93e714a 100644 --- a/convex-core/src/main/java/convex/core/data/MapEntry.java +++ b/convex-core/src/main/java/convex/core/data/MapEntry.java @@ -290,4 +290,11 @@ protected void visitAllChildren(Consumer> visitor) { // nothing to visit } + @Override + public AVector dissocAt(long i) { + if (i==0) return Vectors.create(get(1)); + if (i==1) return Vectors.create(get(0)); + return null; + } + } diff --git a/convex-core/src/main/java/convex/core/data/VectorArray.java b/convex-core/src/main/java/convex/core/data/VectorArray.java index b62203e60..f74ae0122 100644 --- a/convex-core/src/main/java/convex/core/data/VectorArray.java +++ b/convex-core/src/main/java/convex/core/data/VectorArray.java @@ -1,5 +1,6 @@ package convex.core.data; +import java.util.Arrays; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.function.BiFunction; @@ -295,6 +296,16 @@ public Ref getRef(int i) { return getCanonical().getRef(i); } + @Override + public AVector dissocAt(long i) { + int n=(int)count; + if ((i<0)||(i>=n)) return null; + ACell[] cells=Arrays.copyOf(data, n-1); + System.arraycopy(data, (int)(i+1), cells, (int)i, (int)(n-i-1)); + + return wrap(cells); + } + diff --git a/convex-core/src/main/java/convex/core/data/VectorLeaf.java b/convex-core/src/main/java/convex/core/data/VectorLeaf.java index 9785f5c7b..f0f7ba2f8 100644 --- a/convex-core/src/main/java/convex/core/data/VectorLeaf.java +++ b/convex-core/src/main/java/convex/core/data/VectorLeaf.java @@ -1,5 +1,6 @@ package convex.core.data; +import java.util.Arrays; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.function.BiFunction; @@ -437,6 +438,10 @@ public void add(T e) { } + /** + * Get the length of the prefix vector, will be 0 if no prefix + * @return + */ public long prefixLength() { return count - items.length; } @@ -737,4 +742,24 @@ protected void visitAllChildren(Consumer> visitor) { visitor.accept(child); } } + + @Override + public AVector dissocAt(long i) { + if ((i<0)||(i>=count)) return null; + long pl=prefixLength(); + if (i >= pl) { + int cn=items.length; + if (cn==1) { + // Just return prefix, or empty vector if no prefix + return (pl==0)?Vectors.empty():prefix.getValue(); + } + + int ci=(int)(i-pl); + Ref[] newItems=Arrays.copyOf(items, cn-1); + System.arraycopy(items, ci+1, newItems, ci, cn-ci-1); + + return new VectorLeaf(newItems,prefix,count-1); + } + return slice(0,i).concat(slice(i+1,count)); + } } diff --git a/convex-core/src/main/java/convex/core/data/VectorTree.java b/convex-core/src/main/java/convex/core/data/VectorTree.java index a09518c11..f63ad1457 100644 --- a/convex-core/src/main/java/convex/core/data/VectorTree.java +++ b/convex-core/src/main/java/convex/core/data/VectorTree.java @@ -745,5 +745,11 @@ protected void visitAllChildren(Consumer> visitor) { visitor.accept(child); } } + + @Override + public AVector dissocAt(long i) { + if ((i<0)||(i>=count)) return null; + return slice(0,i).concat(slice(i+1,count)); + } } diff --git a/convex-core/src/main/java/convex/core/data/Vectors.java b/convex-core/src/main/java/convex/core/data/Vectors.java index 1272b3052..11dc5a5c0 100644 --- a/convex-core/src/main/java/convex/core/data/Vectors.java +++ b/convex-core/src/main/java/convex/core/data/Vectors.java @@ -1,6 +1,7 @@ package convex.core.data; import java.util.Collection; +import java.util.Comparator; import org.bouncycastle.util.Arrays; @@ -23,6 +24,11 @@ public class Vectors { public static final int MAX_ENCODING_LENGTH = Math.max(VectorLeaf.MAX_ENCODING_LENGTH,VectorTree.MAX_ENCODING_LENGTH); + @SuppressWarnings("rawtypes") + public static final Comparator lengthComparator = (a,b)->{ + return Utils.checkedInt(a.count()-b.count()); + }; + /** * Creates a canonical AVector with the given elements * diff --git a/convex-core/src/test/java/convex/comms/GenTestFormat.java b/convex-core/src/test/java/convex/comms/GenTestFormat.java index 9ac28733f..6471ae60c 100644 --- a/convex-core/src/test/java/convex/comms/GenTestFormat.java +++ b/convex-core/src/test/java/convex/comms/GenTestFormat.java @@ -53,12 +53,19 @@ public void primitiveRoundTrip(@From(PrimitiveGen.class) ACell prim) throws BadF public void dataRoundTrip(@From(ValueGen.class) ACell value) throws BadFormatException, IOException { Ref pref = Ref.get(Cells.persist(value)); // ensure persisted Blob b = Cells.encode(value); - ACell o = Format.read(b); + try { + ACell o = Format.read(b); + + assertEquals(value, o); + assertEquals(b, Cells.encode(o)); + assertEquals(pref.getValue(), o); + + FuzzTestFormat.doMutationTest(b); + } catch (BadFormatException e) { + System.err.println("Bad format in GenTestFromat: "+b); + throw e; + } - assertEquals(value, o); - assertEquals(b, Cells.encode(o)); - assertEquals(pref.getValue(), o); - FuzzTestFormat.doMutationTest(b); } } diff --git a/convex-core/src/test/java/convex/core/cvm/GenTestOps.java b/convex-core/src/test/java/convex/core/cvm/GenTestOps.java index c03247221..17fb06574 100644 --- a/convex-core/src/test/java/convex/core/cvm/GenTestOps.java +++ b/convex-core/src/test/java/convex/core/cvm/GenTestOps.java @@ -1,6 +1,7 @@ package convex.core.cvm; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.runner.RunWith; @@ -9,13 +10,16 @@ import com.pholser.junit.quickcheck.Property; import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; +import convex.core.data.ACell; import convex.core.init.InitTest; +import convex.core.lang.OpsTest; +import convex.test.generators.FormGen; import convex.test.generators.OpsGen; @RunWith(JUnitQuickcheck.class) public class GenTestOps { - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) @Property public void testOpExecution(@From(OpsGen.class) AOp op) { // A context should be able to execute any valid Op without throwing @@ -26,8 +30,23 @@ public void testOpExecution(@From(OpsGen.class) AOp op) { assertEquals(0,c.getDepth()); assertTrue(c.getJuiceUsed()>initialJuice); + + OpsTest.doOpTest(op); } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void testCompile(@From(FormGen.class) ACell form) { + Context c=Context.create(InitTest.STATE); + c=c.compile(form); + if (c.isExceptional()) { + // can easily happen, invalid syntax etc + } else { + AOp op=Ops.ensureOp(c.getResult()); + assertNotNull(op); + OpsTest.doOpTest(op); + } + } } diff --git a/convex-core/src/test/java/convex/core/data/GenTestVectors.java b/convex-core/src/test/java/convex/core/data/GenTestVectors.java index fb03977ea..6b59a9e7b 100644 --- a/convex-core/src/test/java/convex/core/data/GenTestVectors.java +++ b/convex-core/src/test/java/convex/core/data/GenTestVectors.java @@ -41,4 +41,31 @@ public void testConcatPrefixes(@From(VectorGen.class) AVector a, @From(VectorGen assertEquals(a.get(cp - 1), b.get(cp - 1)); } } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Property + public void testElementProperties(@From(VectorGen.class) AVector a,long index) { + long n=a.count(); + if (n==0) return; // skip for empty vector + + + long i=Math.abs(Math.floorMod(index, n)); + + // Get the element + ACell e=a.get(i); + ObjectsTest.doAnyValueTests(e); + + // dissoc the specified element + AVector d=a.dissocAt(i); + assertEquals(n-1,d.count()); + if (iFormat.read(enc)); } - public void doOpTest(AOp op) { + public static void doOpTest(AOp op) { // Executing any Op should not throw - context().execute(op); + TestState.CONTEXT.fork().execute(op); try { op.validate(); diff --git a/convex-core/src/test/java/convex/test/generators/AGenerator.java b/convex-core/src/test/java/convex/test/generators/AGenerator.java new file mode 100644 index 000000000..016ba4d13 --- /dev/null +++ b/convex-core/src/test/java/convex/test/generators/AGenerator.java @@ -0,0 +1,18 @@ +package convex.test.generators; + +import com.pholser.junit.quickcheck.generator.GenerationStatus; +import com.pholser.junit.quickcheck.generator.Generator; +import com.pholser.junit.quickcheck.random.SourceOfRandomness; + +/** + * Generator for arbitrary Addresses + */ +public abstract class AGenerator extends Generator { + + protected AGenerator(Class type) { + super(type); + } + + @Override + public abstract T generate(SourceOfRandomness r, GenerationStatus status); +} diff --git a/convex-core/src/test/java/convex/test/generators/AddressGen.java b/convex-core/src/test/java/convex/test/generators/AddressGen.java index 444f816c5..41298ca3c 100644 --- a/convex-core/src/test/java/convex/test/generators/AddressGen.java +++ b/convex-core/src/test/java/convex/test/generators/AddressGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.cvm.Address; @@ -9,7 +8,7 @@ /** * Generator for arbitrary Addresses */ -public class AddressGen extends Generator
{ +public class AddressGen extends AGenerator
{ public AddressGen() { super(Address.class); diff --git a/convex-core/src/test/java/convex/test/generators/AnyMapGen.java b/convex-core/src/test/java/convex/test/generators/AnyMapGen.java index 166c67d33..f6b3f3dac 100644 --- a/convex-core/src/test/java/convex/test/generators/AnyMapGen.java +++ b/convex-core/src/test/java/convex/test/generators/AnyMapGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.ABlob; @@ -18,7 +17,7 @@ * */ @SuppressWarnings("rawtypes") -public class AnyMapGen extends Generator { +public class AnyMapGen extends AGenerator { public AnyMapGen() { super(AMap.class); } diff --git a/convex-core/src/test/java/convex/test/generators/AnyRecordGen.java b/convex-core/src/test/java/convex/test/generators/AnyRecordGen.java index e71e4a536..2004ba0e3 100644 --- a/convex-core/src/test/java/convex/test/generators/AnyRecordGen.java +++ b/convex-core/src/test/java/convex/test/generators/AnyRecordGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.Constants; @@ -18,7 +17,7 @@ * */ @SuppressWarnings("rawtypes") -public class AnyRecordGen extends Generator { +public class AnyRecordGen extends AGenerator { public AnyRecordGen() { super(ARecord.class); } diff --git a/convex-core/src/test/java/convex/test/generators/BlobGen.java b/convex-core/src/test/java/convex/test/generators/BlobGen.java index ec965edda..27e5656db 100644 --- a/convex-core/src/test/java/convex/test/generators/BlobGen.java +++ b/convex-core/src/test/java/convex/test/generators/BlobGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.ABlob; @@ -15,7 +14,7 @@ * Generator for binary Blobs * */ -public class BlobGen extends Generator { +public class BlobGen extends AGenerator { public BlobGen() { super(ABlob.class); } diff --git a/convex-core/src/test/java/convex/test/generators/BooleanGen.java b/convex-core/src/test/java/convex/test/generators/BooleanGen.java index 77a7bee6f..1ba70bd1a 100644 --- a/convex-core/src/test/java/convex/test/generators/BooleanGen.java +++ b/convex-core/src/test/java/convex/test/generators/BooleanGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.prim.CVMBool; @@ -11,7 +10,7 @@ /** * Generator for booleans */ -public class BooleanGen extends Generator { +public class BooleanGen extends AGenerator { public BooleanGen() { super(CVMBool.class); } diff --git a/convex-core/src/test/java/convex/test/generators/ByteFlagGen.java b/convex-core/src/test/java/convex/test/generators/ByteFlagGen.java index cde9ca0a9..8c7fdd26c 100644 --- a/convex-core/src/test/java/convex/test/generators/ByteFlagGen.java +++ b/convex-core/src/test/java/convex/test/generators/ByteFlagGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.prim.AByteFlag; @@ -11,7 +10,7 @@ * Generator for CAD3 byte flags * */ -public class ByteFlagGen extends Generator { +public class ByteFlagGen extends AGenerator { public ByteFlagGen() { super(AByteFlag.class); } diff --git a/convex-core/src/test/java/convex/test/generators/CharGen.java b/convex-core/src/test/java/convex/test/generators/CharGen.java index 9a8eab4b5..f8b65b074 100644 --- a/convex-core/src/test/java/convex/test/generators/CharGen.java +++ b/convex-core/src/test/java/convex/test/generators/CharGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.prim.CVMChar; @@ -9,7 +8,7 @@ /** * Generator for primitive data values */ -public class CharGen extends Generator { +public class CharGen extends AGenerator { public final static CharGen INSTANCE = new CharGen(); // public final Generator BYTE = gen().type(byte.class); diff --git a/convex-core/src/test/java/convex/test/generators/DataStructureGen.java b/convex-core/src/test/java/convex/test/generators/DataStructureGen.java index 1bfdda8ad..f8784854c 100644 --- a/convex-core/src/test/java/convex/test/generators/DataStructureGen.java +++ b/convex-core/src/test/java/convex/test/generators/DataStructureGen.java @@ -11,7 +11,7 @@ /** * Generator for arbitrary collections */ -public class DataStructureGen extends Generator> { +public class DataStructureGen extends AGenerator> { @SuppressWarnings("rawtypes") private static final Class cls = (Class) ADataStructure.class; diff --git a/convex-core/src/test/java/convex/test/generators/DenseRecordGen.java b/convex-core/src/test/java/convex/test/generators/DenseRecordGen.java index c13c0b87a..379e08c40 100644 --- a/convex-core/src/test/java/convex/test/generators/DenseRecordGen.java +++ b/convex-core/src/test/java/convex/test/generators/DenseRecordGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.ACell; @@ -13,7 +12,7 @@ * Generator for CAD3 dense records * */ -public class DenseRecordGen extends Generator { +public class DenseRecordGen extends AGenerator { public DenseRecordGen() { super(DenseRecord.class); } diff --git a/convex-core/src/test/java/convex/test/generators/DoubleGen.java b/convex-core/src/test/java/convex/test/generators/DoubleGen.java index 9af1b7816..bbe9c33dd 100644 --- a/convex-core/src/test/java/convex/test/generators/DoubleGen.java +++ b/convex-core/src/test/java/convex/test/generators/DoubleGen.java @@ -1,7 +1,6 @@ package convex.test.generators; import com.pholser.junit.quickcheck.generator.GenerationStatus; -import com.pholser.junit.quickcheck.generator.Generator; import com.pholser.junit.quickcheck.random.SourceOfRandomness; import convex.core.data.prim.CVMDouble; @@ -10,7 +9,7 @@ * Generator for arbitrary numeric values * */ -public class DoubleGen extends Generator { +public class DoubleGen extends AGenerator { private static final CVMDouble[] ODDITIES = new CVMDouble[] {CVMDouble.NaN, CVMDouble.NEGATIVE_INFINITY, CVMDouble.NEGATIVE_ZERO, CVMDouble.POSITIVE_INFINITY}; public DoubleGen() { diff --git a/convex-core/src/test/java/convex/test/generators/VectorGen.java b/convex-core/src/test/java/convex/test/generators/VectorGen.java index d48dd5f15..dfa04e573 100644 --- a/convex-core/src/test/java/convex/test/generators/VectorGen.java +++ b/convex-core/src/test/java/convex/test/generators/VectorGen.java @@ -1,5 +1,9 @@ package convex.test.generators; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import com.pholser.junit.quickcheck.generator.ComponentizedGenerator; import com.pholser.junit.quickcheck.generator.GenerationStatus; import com.pholser.junit.quickcheck.random.SourceOfRandomness; @@ -77,6 +81,27 @@ public AVector generate(SourceOfRandomness r, GenerationStatus status) { } } } + + @SuppressWarnings("unchecked") + @Override + public List doShrink(SourceOfRandomness r, AVector v) { + long n=v.count(); + if (n==0) return (List)Collections.EMPTY_LIST; + if (n==1) return Collections.singletonList(Vectors.empty()); + ArrayList al=new ArrayList<>(); + + long split=r.nextLong(1, n-1); + al.add(v.slice(0, split)); + al.add(v.slice(split, n)); + + Collections.sort(al,Vectors.lengthComparator); + + for (int i=0; i