From 45837fb85dd10fbf872a6cb0c59a39712dd25376 Mon Sep 17 00:00:00 2001 From: mikera Date: Sun, 22 Dec 2024 15:00:07 +0000 Subject: [PATCH] More generative testing --- .../src/main/java/convex/core/cvm/Ops.java | 12 ++++++++++++ .../src/main/java/convex/core/cvm/ops/Cond.java | 7 ++++--- .../src/main/java/convex/core/cvm/ops/Def.java | 3 ++- .../src/main/java/convex/core/cvm/ops/Do.java | 6 ++++-- .../main/java/convex/core/cvm/ops/Invoke.java | 16 ++++++++++++---- .../src/main/java/convex/core/cvm/ops/Query.java | 7 +++---- .../src/main/java/convex/core/cvm/ops/Set.java | 6 ++++-- .../convex/core/data/prim/CVMBigInteger.java | 7 ++++--- .../test/java/convex/core/cvm/GenTestOps.java | 4 ++-- .../src/test/java/convex/core/lang/OpsTest.java | 15 +++++++++++---- .../test/java/convex/test/generators/Gen.java | 2 +- .../test/generators/{OpsGen.java => OpGen.java} | 4 ++-- .../java/convex/test/generators/VectorGen.java | 3 +-- 13 files changed, 62 insertions(+), 30 deletions(-) rename convex-core/src/test/java/convex/test/generators/{OpsGen.java => OpGen.java} (95%) diff --git a/convex-core/src/main/java/convex/core/cvm/Ops.java b/convex-core/src/main/java/convex/core/cvm/Ops.java index 908884fa4..1337e3acf 100644 --- a/convex-core/src/main/java/convex/core/cvm/Ops.java +++ b/convex-core/src/main/java/convex/core/cvm/Ops.java @@ -63,4 +63,16 @@ public static AOp ensureOp(ACell a) { if (a instanceof AOp) return (AOp)a; return null; } + + /** + * Cast any value to an Op. Returns value as a Constant op if not an Op + * @param aOp + * @return + */ + @SuppressWarnings("unchecked") + public static AOp castOp(AOp a) { + if (a==null) return Constant.nil(); + if (!(a instanceof AOp)) return (AOp) Constant.create(a); + return (AOp)a; + } } diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Cond.java b/convex-core/src/main/java/convex/core/cvm/ops/Cond.java index 1fcaa5bf1..cc4f970a0 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Cond.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Cond.java @@ -4,6 +4,7 @@ import convex.core.cvm.CVMTag; import convex.core.cvm.Context; import convex.core.cvm.Juice; +import convex.core.cvm.Ops; import convex.core.data.ACell; import convex.core.data.ASequence; import convex.core.data.AVector; @@ -59,7 +60,7 @@ public Context execute(Context context) { if (ctx.isExceptional()) return (Context) ctx; for (int i=0; i<(n-1); i+=2) { - AOp testOp=ops.get(i); + AOp testOp=Ops.castOp(ops.get(i)); ctx=ctx.execute(testOp); // bail out from exceptional result in test @@ -67,7 +68,7 @@ public Context execute(Context context) { ACell test=ctx.getResult(); if (RT.bool(test)) { - return ctx.execute(ops.get(i+1)); + return ctx.execute(Ops.castOp(ops.get(i+1))); } } if ((n&1)==0) { @@ -75,7 +76,7 @@ public Context execute(Context context) { return ctx.withResult((T)null); } else { // default value - return ctx.execute(ops.get(n-1)); + return ctx.execute(Ops.castOp(ops.get(n-1))); } } diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Def.java b/convex-core/src/main/java/convex/core/cvm/ops/Def.java index 9b37292d0..dfa63b90b 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Def.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Def.java @@ -4,6 +4,7 @@ import convex.core.cvm.CVMTag; import convex.core.cvm.Context; import convex.core.cvm.Juice; +import convex.core.cvm.Ops; import convex.core.cvm.Syntax; import convex.core.data.ACell; import convex.core.data.Blob; @@ -62,7 +63,7 @@ public static Def create(String key, AOp op) { @Override public Context execute(Context ctx) { - AOp op = this.value.getValue(); + AOp op = Ops.ensureOp(this.value.getValue()); // note: may be null for declare with no value ACell symbol=code.getValue(); ACell result; diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Do.java b/convex-core/src/main/java/convex/core/cvm/ops/Do.java index b07bbd72f..9eceecb3a 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Do.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Do.java @@ -4,6 +4,7 @@ import convex.core.cvm.CVMTag; import convex.core.cvm.Context; import convex.core.cvm.Juice; +import convex.core.cvm.Ops; import convex.core.data.ACell; import convex.core.data.ASequence; import convex.core.data.AVector; @@ -12,6 +13,7 @@ import convex.core.data.Vectors; import convex.core.data.util.BlobBuilder; import convex.core.exceptions.BadFormatException; +import convex.core.lang.RT; /** * Op for executing a sequence of child operations in order @@ -48,7 +50,7 @@ public Context execute(Context context) { // execute each operation in turn for (int i = 0; i < n; i++) { - AOp op = ops.get(i); + AOp op = Ops.castOp(ops.get(i)); ctx = ctx.execute(op); if (ctx.isExceptional()) break; } @@ -61,7 +63,7 @@ public boolean print(BlobBuilder bb, long limit) { int len = ops.size(); for (int i = 0; i < len; i++) { bb.append(' '); - if (!ops.get(i).print(bb,limit)) return false; + if (!RT.print(bb,ops.get(i),limit)) return false; } bb.append(')'); return bb.check(limit); 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 60b12d41f..f5da234d8 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 @@ -4,11 +4,14 @@ import convex.core.cvm.AOp; import convex.core.cvm.CVMTag; import convex.core.cvm.Context; +import convex.core.cvm.Juice; +import convex.core.cvm.Ops; import convex.core.data.ACell; import convex.core.data.ASequence; import convex.core.data.AVector; import convex.core.data.Blob; import convex.core.data.Cells; +import convex.core.data.Lists; import convex.core.data.Vectors; import convex.core.data.type.Types; import convex.core.data.util.BlobBuilder; @@ -30,7 +33,6 @@ protected Invoke(AVector> ops) { } public static Invoke create(ASequence> ops) { - if (ops.count()==0) return null; AVector> vops = ops.toVector(); return new Invoke(vops); } @@ -75,8 +77,13 @@ public static Invoke create(String string, AOp... args) @Override public Context execute(Context context) { + long n=ops.count(); + if (n==0) { + return context.withResult(Juice.APPLY, Lists.empty()); + } + // execute first op to obtain function value - AOp fnOp=ops.get(0); + AOp fnOp=Ops.castOp(ops.get(0)); Context ctx = context.execute(fnOp); if (ctx.isExceptional()) return ctx; @@ -92,7 +99,7 @@ public Context execute(Context context) { ACell[] args = new ACell[arity]; for (int i = 0; i < arity; i++) { // Compute the op for each argument in order - AOp argOp=ops.get(i + 1); + AOp argOp=Ops.castOp(ops.get(i + 1)); ctx = ctx.execute(argOp); if (ctx.isExceptional()) return ctx; @@ -119,7 +126,8 @@ public boolean print(BlobBuilder bb, long limit) { int len = ops.size(); for (int i = 0; i < len; i++) { if (i > 0) bb.append(' '); - if (!ops.get(i).print(bb,limit)) return false; + AOp op=Ops.castOp(ops.get(i)); + if (!op.print(bb,limit)) return false; } bb.append(')'); return bb.check(limit); diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Query.java b/convex-core/src/main/java/convex/core/cvm/ops/Query.java index 569dd4dd5..445f72472 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Query.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Query.java @@ -16,6 +16,7 @@ import convex.core.data.prim.ByteFlag; import convex.core.data.util.BlobBuilder; import convex.core.exceptions.BadFormatException; +import convex.core.lang.RT; /** * Op for executing a sequence of child operations in order in query mode (no state changes) @@ -66,12 +67,10 @@ public Context execute(Context context) { AVector savedBindings=context.getLocalBindings(); // execute each operation in turn - // TODO: early return for (int i = 0; i < n; i++) { - AOp op = ops.get(i); + AOp op = Ops.castOp(ops.get(i)); ctx = ctx.execute(op); if (ctx.isExceptional()) break; - } // restore state unconditionally. ctx=ctx.withState(savedState); @@ -86,7 +85,7 @@ public boolean print(BlobBuilder bb, long limit) { int len = ops.size(); for (int i = 0; i < len; i++) { bb.append(' '); - if (!ops.get(i).print(bb,limit)) return false; + if (!RT.print(bb,ops.get(i),limit)) return false; } bb.append(')'); return bb.check(limit); diff --git a/convex-core/src/main/java/convex/core/cvm/ops/Set.java b/convex-core/src/main/java/convex/core/cvm/ops/Set.java index 704c72416..d76f47166 100644 --- a/convex-core/src/main/java/convex/core/cvm/ops/Set.java +++ b/convex-core/src/main/java/convex/core/cvm/ops/Set.java @@ -5,6 +5,7 @@ import convex.core.cvm.CVMTag; import convex.core.cvm.Context; import convex.core.cvm.Juice; +import convex.core.cvm.Ops; import convex.core.data.ACell; import convex.core.data.AVector; import convex.core.data.Blob; @@ -56,7 +57,7 @@ public Context execute(Context ctx) { return ctx.withError(ErrorCodes.BOUNDS, "Bad position for set!: " + position); } - ctx = ctx.execute(value.getValue()); + ctx = ctx.execute(Ops.castOp(value.getValue())); if (ctx.isExceptional()) return ctx; ACell value = ctx.getResult(); @@ -100,7 +101,8 @@ public boolean print(BlobBuilder sb, long limit) { sb.append("(set! %"); sb.append(Long.toString(position)); sb.append(' '); - if (!value.getValue().print(sb, limit)) return false; + AOp op=Ops.castOp(value.getValue()); + if (!op.print(sb, limit)) return false; sb.append(')'); return sb.check(limit); } diff --git a/convex-core/src/main/java/convex/core/data/prim/CVMBigInteger.java b/convex-core/src/main/java/convex/core/data/prim/CVMBigInteger.java index f8a1ef718..0ff751472 100644 --- a/convex-core/src/main/java/convex/core/data/prim/CVMBigInteger.java +++ b/convex-core/src/main/java/convex/core/data/prim/CVMBigInteger.java @@ -189,11 +189,12 @@ public int encodeRaw(byte[] bs, int pos) { @Override public boolean print(BlobBuilder sb, long limit) { + long space=limit-sb.count(); long blen=byteLength(); - if (blen>limit*2) return false; + if (blen>space*2) return false; // defintely too long, since each byte is at least 2 chars AString s=Strings.create(big().toString()); - if (s.count()>limit) { - sb.append(s.slice(0, limit)); + if (s.count()>space) { + sb.append(s.slice(0, space)); return false; } sb.append(s); 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 17fb06574..024c0f4a2 100644 --- a/convex-core/src/test/java/convex/core/cvm/GenTestOps.java +++ b/convex-core/src/test/java/convex/core/cvm/GenTestOps.java @@ -14,14 +14,14 @@ import convex.core.init.InitTest; import convex.core.lang.OpsTest; import convex.test.generators.FormGen; -import convex.test.generators.OpsGen; +import convex.test.generators.OpGen; @RunWith(JUnitQuickcheck.class) public class GenTestOps { @SuppressWarnings({ "rawtypes", "unchecked" }) @Property - public void testOpExecution(@From(OpsGen.class) AOp op) { + public void testOpExecution(@From(OpGen.class) AOp op) { // A context should be able to execute any valid Op without throwing Context c=Context.create(InitTest.STATE); long initialJuice=c.getJuiceUsed(); diff --git a/convex-core/src/test/java/convex/core/lang/OpsTest.java b/convex-core/src/test/java/convex/core/lang/OpsTest.java index bc4f052ec..0f0dbdb8e 100644 --- a/convex-core/src/test/java/convex/core/lang/OpsTest.java +++ b/convex-core/src/test/java/convex/core/lang/OpsTest.java @@ -39,6 +39,7 @@ import convex.core.data.DenseRecord; import convex.core.data.ExtensionValue; import convex.core.data.Format; +import convex.core.data.List; import convex.core.data.ObjectsTest; import convex.core.data.Symbol; import convex.core.data.Tag; @@ -203,8 +204,14 @@ public void testQuery() throws BadFormatException { doOpTest(op); } - - + + @Test + public void testBadQuery() { + // query with a null op + Query op=Reader.read("#[c0bb800100]"); + Context c = context(); + c=step(c,op); + } @Test public void testSpecial() { @@ -376,10 +383,10 @@ public void testLambda() { } @Test - public void testBadInvokeOp() { + public void testEnptyInvokeOp() { Context c = context(); c=step(c,"(eval #[db00])"); // Dense record that looks like an Invoke op with no values - assertEquals(DenseRecord.create(0xdb, Vectors.empty()),c.getResult()); + assertEquals(List.EMPTY,c.getResult()); } @Test diff --git a/convex-core/src/test/java/convex/test/generators/Gen.java b/convex-core/src/test/java/convex/test/generators/Gen.java index 17c0d3d3d..19e4d7179 100644 --- a/convex-core/src/test/java/convex/test/generators/Gen.java +++ b/convex-core/src/test/java/convex/test/generators/Gen.java @@ -46,5 +46,5 @@ public class Gen { public static final DenseRecordGen DENSE_RECORD = new DenseRecordGen(); - public static final OpsGen OP = new OpsGen(); + public static final OpGen OP = new OpGen(); } diff --git a/convex-core/src/test/java/convex/test/generators/OpsGen.java b/convex-core/src/test/java/convex/test/generators/OpGen.java similarity index 95% rename from convex-core/src/test/java/convex/test/generators/OpsGen.java rename to convex-core/src/test/java/convex/test/generators/OpGen.java index 1416194f6..dfad5991a 100644 --- a/convex-core/src/test/java/convex/test/generators/OpsGen.java +++ b/convex-core/src/test/java/convex/test/generators/OpGen.java @@ -17,8 +17,8 @@ * Generator for plausible forms */ @SuppressWarnings("rawtypes") -public class OpsGen extends Generator { - public OpsGen() { +public class OpGen extends Generator { + public OpGen() { super(AOp.class); } 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 dfa04e573..deaa92caa 100644 --- a/convex-core/src/test/java/convex/test/generators/VectorGen.java +++ b/convex-core/src/test/java/convex/test/generators/VectorGen.java @@ -4,7 +4,6 @@ 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; @@ -19,7 +18,7 @@ * */ @SuppressWarnings("rawtypes") -public class VectorGen extends ComponentizedGenerator { +public class VectorGen extends AGenerator { public VectorGen() { super(AVector.class); }