Skip to content

Commit

Permalink
More generative testing
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Dec 22, 2024
1 parent 5370a17 commit 45837fb
Show file tree
Hide file tree
Showing 13 changed files with 62 additions and 30 deletions.
12 changes: 12 additions & 0 deletions convex-core/src/main/java/convex/core/cvm/Ops.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,16 @@ public static <T extends ACell> AOp<T> ensureOp(ACell a) {
if (a instanceof AOp) return (AOp<T>)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 <T extends ACell> AOp<T> castOp(AOp<?> a) {
if (a==null) return Constant.nil();
if (!(a instanceof AOp)) return (AOp<T>) Constant.create(a);
return (AOp<T>)a;
}
}
7 changes: 4 additions & 3 deletions convex-core/src/main/java/convex/core/cvm/ops/Cond.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -59,23 +60,23 @@ public Context execute(Context context) {
if (ctx.isExceptional()) return (Context) ctx;

for (int i=0; i<(n-1); i+=2) {
AOp<ACell> testOp=ops.get(i);
AOp<ACell> testOp=Ops.castOp(ops.get(i));
ctx=ctx.execute(testOp);

// bail out from exceptional result in test
if (ctx.isExceptional()) return (Context) ctx;

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) {
// no default value, return null
return ctx.withResult((T)null);
} else {
// default value
return ctx.execute(ops.get(n-1));
return ctx.execute(Ops.castOp(ops.get(n-1)));
}
}

Expand Down
3 changes: 2 additions & 1 deletion convex-core/src/main/java/convex/core/cvm/ops/Def.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -62,7 +63,7 @@ public static <T extends ACell> Def<T> create(String key, AOp<T> op) {

@Override
public Context execute(Context ctx) {
AOp<T> op = this.value.getValue();
AOp<T> op = Ops.ensureOp(this.value.getValue()); // note: may be null for declare with no value
ACell symbol=code.getValue();

ACell result;
Expand Down
6 changes: 4 additions & 2 deletions convex-core/src/main/java/convex/core/cvm/ops/Do.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down
16 changes: 12 additions & 4 deletions convex-core/src/main/java/convex/core/cvm/ops/Invoke.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,7 +33,6 @@ protected Invoke(AVector<AOp<ACell>> ops) {
}

public static <T extends ACell> Invoke<T> create(ASequence<AOp<ACell>> ops) {
if (ops.count()==0) return null;
AVector<AOp<ACell>> vops = ops.toVector();
return new Invoke<T>(vops);
}
Expand Down Expand Up @@ -75,8 +77,13 @@ public static <T extends ACell> Invoke<T> 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;

Expand All @@ -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;

Expand All @@ -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);
Expand Down
7 changes: 3 additions & 4 deletions convex-core/src/main/java/convex/core/cvm/ops/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -66,12 +67,10 @@ public Context execute(Context context) {
AVector<ACell> 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);
Expand All @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions convex-core/src/main/java/convex/core/cvm/ops/Set.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions convex-core/src/test/java/convex/core/cvm/GenTestOps.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 11 additions & 4 deletions convex-core/src/test/java/convex/core/lang/OpsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -203,8 +204,14 @@ public void testQuery() throws BadFormatException {

doOpTest(op);
}



@Test
public void testBadQuery() {
// query with a null op
Query<CVMLong> op=Reader.read("#[c0bb800100]");
Context c = context();
c=step(c,op);
}

@Test
public void testSpecial() {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion convex-core/src/test/java/convex/test/generators/Gen.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
* Generator for plausible forms
*/
@SuppressWarnings("rawtypes")
public class OpsGen extends Generator<AOp> {
public OpsGen() {
public class OpGen extends Generator<AOp> {
public OpGen() {
super(AOp.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -19,7 +18,7 @@
*
*/
@SuppressWarnings("rawtypes")
public class VectorGen extends ComponentizedGenerator<AVector> {
public class VectorGen extends AGenerator<AVector> {
public VectorGen() {
super(AVector.class);
}
Expand Down

0 comments on commit 45837fb

Please sign in to comment.