Skip to content

Commit 1318d23

Browse files
committed
Misc tests and metadata edits
1 parent 2a46a02 commit 1318d23

File tree

4 files changed

+48
-13
lines changed

4 files changed

+48
-13
lines changed

convex-core/src/main/cvx/convex/core/metadata.cvx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@
352352
:return Any}]}}
353353

354354
callable?
355-
{:doc {:description "Returns true if the target is callable. If symbol is provided, also checks that this symbol references a callable function in the specified account. See `call`."
355+
{:doc {:description "Returns true if the target can be called. If symbol is provided, checks that this symbol references a callable function in the specified account. See `call`."
356356
:errors {:CAST "If the symbol argument is not a Symbol."}
357357
:examples [{:code "(callable? actor-address 'function-name)"}]
358358
:signature [{:params [target]}
@@ -374,21 +374,21 @@
374374
:return Character}]}}
375375

376376
coll?
377-
{:doc {:description "Returns `true` if and only if the argument is a collection: List, Map, Set, or Vector. Returns false otherwise."
377+
{:doc {:description "Tests if the argument is a data struture."
378378
:examples [{:code "(coll? [1 2 3])"}]
379379
:signature [{:params [x]
380380
:return Boolean}]}}
381381

382382
cond
383-
{:doc {:description ["Performs conditional tests on successive pairs of `test` -> `result`, returning the `result` for the first `test` that succeeds."
384-
"Performs short-circuit evaluation: result expressions that are not used and any test expressions after the first success will not be executed."
385-
"In the case that no test succeeds, a single aditional argument may be added as a fallback value. If no fallback value is available, nil will be returned."]
383+
{:doc {:description ["Performs conditional tests on successive (test, result) pairs, computing the result for the first test that succeeds."
384+
"Result expressions that are not used and any test expressions after the first success will not be executed."
385+
"If no test succeeds, a final expression may be added as a fallback. If no fallback value is available, nil will be returned."]
386386
:examples [{:code "(cond test-1 result-1 else-value)"}
387387
{:code "(cond test-1 result-1 test-2 result-2 test-3 result--3)"}]
388388
:signature [{:params []}
389389
{:params [test]}
390390
{:params [test result]}
391-
{:params [test result fallback-value]}
391+
{:params [test result fallback]}
392392
{:params [test-1 result-1 test-2 result-2 & more]}]}
393393
:special true}
394394

convex-core/src/main/java/convex/core/lang/Core.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,9 +670,12 @@ public Context invoke(Context context, ACell[] args) {
670670

671671
@Override
672672
public Context invoke(Context context, ACell[] args) {
673+
// When used as a predicate
673674
if (args.length==1) {
674675
Address addr = RT.callableAddress(args[0]);
675-
return context.withResult(Juice.LOOKUP,CVMBool.create(addr!=null));
676+
if (addr==null) return context.withResult(Juice.LOOKUP,CVMBool.FALSE);
677+
AccountStatus as = context.getState().getAccount(addr);
678+
return context.withResult(Juice.LOOKUP,CVMBool.create(as!=null));
676679
}
677680

678681
if (args.length != 2) return context.withArityError(rangeArityMessage(1,2, args.length));

convex-core/src/test/java/convex/core/data/prim/DoubleTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
56
import static org.junit.jupiter.api.Assertions.assertSame;
67
import static org.junit.jupiter.api.Assertions.assertThrows;
78
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -12,6 +13,7 @@
1213
import convex.core.data.Format;
1314
import convex.core.data.ObjectsTest;
1415
import convex.core.exceptions.BadFormatException;
16+
import convex.core.exceptions.InvalidDataException;
1517

1618
public class DoubleTest {
1719

@@ -20,14 +22,19 @@ public class DoubleTest {
2022

2123
assertSame(CVMDouble.NaN,CVMDouble.create(Double.NaN));
2224

23-
// Canonical NaN encoding has just high bit set
25+
// Canonical NaN encoding has just zeros as payload
2426
assertEquals(Blob.fromHex("1d7ff8000000000000"),nan.getEncoding());
2527

2628
// create coerces to correct NaN
2729
assertSame(CVMDouble.NaN,CVMDouble.create(Double.longBitsToDouble(0x7ff8000000ffffffL)));
2830

2931
Blob BAD_NAN=Blob.fromHex("1d7ff8000000ffffff");
3032
assertThrows(BadFormatException.class,()->Format.read(BAD_NAN));
33+
34+
// We can artificially create a bad NaN, but it is invalid
35+
CVMDouble badNaN=CVMDouble.unsafeCreate(Double.longBitsToDouble(0x7ff8000000ffffffL));
36+
assertNotEquals(nan,badNaN);
37+
assertThrows(InvalidDataException.class,()->badNaN.validate());
3138
}
3239

3340
@Test public void testCompares() {
@@ -44,6 +51,7 @@ public class DoubleTest {
4451
}
4552

4653
@Test public void testEquality() {
54+
// Regular object equality
4755
ObjectsTest.doEqualityTests(CVMDouble.ONE, CVMDouble.create(1.0));
4856
ObjectsTest.doEqualityTests(CVMDouble.create(12345.0),CVMDouble.create(12345.0));
4957

convex-core/src/test/java/convex/core/lang/CoreTest.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@
101101
*/
102102
public class CoreTest extends ACVMTest {
103103

104-
105104
protected CoreTest() throws IOException {
106105
super(BaseTest.STATE);
107106
}
@@ -654,6 +653,7 @@ public void testEquals() {
654653
assertFalse(evalB("(= 1 2)"));
655654
assertFalse(evalB("(= 1 nil)"));
656655
assertFalse(evalB("(= 1 1.0)"));
656+
assertFalse(evalB("(= false nil)"));
657657
assertFalse(evalB("(= \\a \\b)"));
658658
assertFalse(evalB("(= :foo :baz)"));
659659
assertFalse(evalB("(= :foo 'foo)"));
@@ -3904,13 +3904,23 @@ public void testMapPred() {
39043904
assertFalse(evalB("(map? '(3 4 5))"));
39053905
assertTrue(evalB("(map? {1 2 3 4})"));
39063906
assertFalse(evalB("(map? #{1 2})"));
3907+
3908+
// This is technically a map since it is a record
3909+
assertTrue(evalB("(map? (account #0))")); // this is a record
3910+
3911+
// This is technically a map since it is Index
3912+
assertTrue(evalB("(map? (index))")); // this is a record
3913+
39073914
}
39083915

39093916
@Test
39103917
public void testCollPred() {
3918+
// Like Clojure coll?, returns true for any data structure
39113919
assertFalse(evalB("(coll? nil)"));
39123920
assertFalse(evalB("(coll? 1)"));
39133921
assertFalse(evalB("(coll? :foo)"));
3922+
3923+
39143924
assertTrue(evalB("(coll? {})"));
39153925
assertTrue(evalB("(coll? [])"));
39163926
assertTrue(evalB("(coll? ())"));
@@ -3921,6 +3931,7 @@ public void testCollPred() {
39213931
assertTrue(evalB("(coll? {1 2 3 4})"));
39223932
assertTrue(evalB("(coll? #{1 2})"));
39233933
assertTrue(evalB("(coll? (index))"));
3934+
assertTrue(evalB("(coll? (account #0))")); // this is a record
39243935
assertTrue(evalB("(coll? (index 0x 0x))"));
39253936
}
39263937

@@ -3942,13 +3953,15 @@ public void testEmptyPred() {
39423953
assertFalse(evalB("(empty? #{[]})"));
39433954

39443955
assertFalse(evalB("(empty? 0)"));
3956+
assertFalse(evalB("(empty? false)"));
39453957
assertFalse(evalB("(empty? :foo)"));
39463958
assertFalse(evalB("(empty? 'bar)"));
39473959
}
39483960

39493961
@Test
39503962
public void testSymbolPred() {
39513963
assertTrue(evalB("(symbol? 'foo)"));
3964+
assertTrue(evalB("(symbol? (quote .))"));
39523965
assertTrue(evalB("(symbol? (symbol :bar))"));
39533966

39543967
assertFalse(evalB("(symbol? (str 1))"));
@@ -3963,6 +3976,7 @@ public void testKeywordPred() {
39633976
assertTrue(evalB("(keyword? (keyword 'bar))"));
39643977

39653978
assertFalse(evalB("(keyword? nil)"));
3979+
assertFalse(evalB("(keyword? 'zzz)"));
39663980
assertFalse(evalB("(keyword? 1)"));
39673981
assertFalse(evalB("(keyword? [:foo])"));
39683982
}
@@ -3975,6 +3989,7 @@ public void testAddressPred() {
39753989

39763990
assertFalse(evalB("(address? nil)"));
39773991
assertFalse(evalB("(address? 1)"));
3992+
assertFalse(evalB("(address? [#1 #2])"));
39783993
assertFalse(evalB("(address? \"0a1b2c3d\")"));
39793994
assertFalse(evalB("(address? (blob *origin*))"));
39803995
}
@@ -4002,7 +4017,7 @@ public void testLongPred() {
40024017
assertFalse(evalB("(long? nil)"));
40034018
assertFalse(evalB("(long? 0xFF)"));
40044019
assertFalse(evalB("(long? [1 2])"));
4005-
assertFalse(evalB("(long? 7.0)"));
4020+
assertFalse(evalB("(long? 7.0)")); // not a long, even though numerically equivalent to one
40064021

40074022
// big integer boundaries
40084023
assertTrue(evalB("(long? 9223372036854775807)"));
@@ -4018,8 +4033,10 @@ public void testStrPred() {
40184033
assertTrue(evalB("(str? (str :foo))"));
40194034
assertTrue(evalB("(str? (str nil))"));
40204035
assertTrue(evalB("(str? \"\")"));
4036+
assertTrue(evalB("(str? \"Hello World\")"));
40214037

40224038
// These are not strings
4039+
assertFalse(evalB("(str? \\Q)")); // character is not itself a string
40234040
assertFalse(evalB("(str? 1)"));
40244041
assertFalse(evalB("(str? :foo)"));
40254042
assertFalse(evalB("(str? nil)"));
@@ -4724,7 +4741,7 @@ public void testExpand() {
47244741
assertEquals(Strings.create("foo"), eval("(expand (name :foo) (fn [x e] x))"));
47254742
assertEquals(CVMLong.create(3), eval("(expand '[1 2 3] (fn [x e] (nth x 2)))"));
47264743

4727-
assertNull(Syntax.unwrap(eval("(expand nil)")));
4744+
assertNull(eval("(expand nil)"));
47284745

47294746
assertCastError(step("(expand 1 :foo)"));
47304747
assertCastError(step("(expand { 888 227 723 560} [75 561 258 833])"));
@@ -4747,7 +4764,7 @@ public void testExpand_1() {
47474764

47484765
@Test
47494766
public void testExpandEdgeCases() {
4750-
// BAd functions
4767+
// Bad functions
47514768
assertCastError(step("(expand 123 #0 :foo)"));
47524769
assertCastError(step("(expand 123 #0)"));
47534770

@@ -4778,6 +4795,7 @@ public void testExpandOnce() {
47784795
public void testMacro() {
47794796
Context c=step("(defmacro foo [] :foo)");
47804797
assertEquals(Keywords.FOO,eval(c,"(foo)"));
4798+
assertEquals(Keywords.FOO,eval(c,"(expand '(foo))"));
47814799
}
47824800

47834801
@Test
@@ -4790,6 +4808,9 @@ public void testQuote() {
47904808

47914809
// interior macros shouldn't get expanded
47924810
assertEquals(Vectors.of(1,Lists.of(Symbols.IF,4,7),3),eval("(quote [1 (if 4 7) 3])"));
4811+
4812+
assertArityError(step ("(quote foo bar)"));
4813+
assertArityError(step ("(quote)"));
47934814
}
47944815

47954816
@Test
@@ -4878,7 +4899,10 @@ public void testCallableQ() {
48784899
assertFalse(evalB(ctx, "(callable? nil)"));
48794900
assertFalse(evalB(ctx, "(callable? :foo)"));
48804901
assertFalse(evalB(ctx, "(callable? [])"));
4881-
4902+
4903+
// Missing accounts definitely not callable
4904+
assertFalse(evalB(ctx, "(callable? #6666666)"));
4905+
assertFalse(evalB(ctx, "(callable? #6666666 'something)"));
48824906

48834907
assertCastError(step(ctx, "(callable? caddr :public)")); // not a Symbol
48844908
assertCastError(step(ctx, "(callable? caddr :random-name)"));

0 commit comments

Comments
 (0)