jgvariant-core: Property tests for some maps and lists.

Change-Id: I1edb66339290f02bf147582f9541b7fd2f3533ce
diff --git a/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderPropertyTest.java b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderPropertyTest.java
index 5e07ea0..dc195ae 100644
--- a/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderPropertyTest.java
+++ b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderPropertyTest.java
@@ -1,7 +1,8 @@
 package eu.mulk.jgvariant.core;
 
 import java.text.ParseException;
-import java.util.Optional;
+import java.util.*;
+import java.util.function.Supplier;
 import net.jqwik.api.*;
 
 @SuppressWarnings("java:S2187")
@@ -28,7 +29,7 @@
       var decoder = decoder();
       var bytes = decoder.encode(entityLeft);
       var entityRight = decoder.decode(bytes);
-      return entityLeft.equals(entityRight);
+      return Objects.equals(entityLeft, entityRight);
     }
 
     Decoder<T> decoder();
@@ -39,6 +40,7 @@
 
   @Provide
   Arbitrary<Variant> anyVariant() {
+    // Base cases
     var anyString = Arbitraries.strings().map(s -> new Variant(parseSignature("s"), s));
     var anyInt = Arbitraries.integers().map(i -> new Variant(parseSignature("i"), i));
     var anyLong = Arbitraries.longs().map(l -> new Variant(parseSignature("x"), l));
@@ -48,35 +50,76 @@
     var anyByte = Arbitraries.bytes().map(b -> new Variant(parseSignature("y"), b));
     var anyShort = Arbitraries.shorts().map(s -> new Variant(parseSignature("n"), s));
     var anyByteArray = Arbitraries.bytes().list().map(b -> new Variant(parseSignature("ay"), b));
-    var anySome =
-        Arbitraries.lazyOf(
-            () ->
-                anyVariant()
-                    .map(
-                        x ->
-                            new Variant(
-                                parseSignature("m" + x.signature().toString()),
-                                Optional.of(x.value()))));
-    var anyNone =
-        Arbitraries.lazyOf(
-            () ->
-                anyVariant()
-                    .map(
-                        x ->
-                            new Variant(
-                                parseSignature("m" + x.signature().toString()), Optional.empty())));
-    // FIXME missing: list, tuple, dictionary, variant
-    return Arbitraries.oneOf(
-        anyString,
-        anyInt,
-        anyLong,
-        anyDouble,
-        anyBoolean,
-        anyByte,
-        anyShort,
-        anyByteArray,
-        anySome,
-        anyNone);
+
+    // Singly recursive cases
+    Supplier<Arbitrary<Variant>> anySome =
+        () ->
+            anyVariant()
+                .map(
+                    x ->
+                        new Variant(
+                            parseSignature("m" + x.signature().toString()),
+                            Optional.of(x.value())));
+    Supplier<Arbitrary<Variant>> anyNone =
+        () ->
+            anyVariant()
+                .map(
+                    x ->
+                        new Variant(
+                            parseSignature("m" + x.signature().toString()), Optional.empty()));
+    Supplier<Arbitrary<Variant>> anyNestedVariant =
+        () -> anyVariant().map(v -> new Variant(parseSignature("v"), v));
+
+    // Fixed-multiplicity recursive cases
+    /* fixme: Object[] does not work for comparison by Object#equals() */
+    Supplier<Arbitrary<Variant>> anyPair =
+        () ->
+            Combinators.combine(anyVariant(), anyVariant())
+                .as(
+                    (v1, v2) ->
+                        new Variant(
+                            parseSignature("(%s%s)".formatted(v1.signature(), v2.signature())),
+                            new Object[] {v1.value(), v2.value()}));
+    Supplier<Arbitrary<Variant>> anyTriple =
+        () ->
+            Combinators.combine(anyVariant(), anyVariant(), anyVariant())
+                .as(
+                    (v1, v2, v3) ->
+                        new Variant(
+                            parseSignature(
+                                "(%s%s%s)"
+                                    .formatted(v1.signature(), v2.signature(), v3.signature())),
+                            new Object[] {v1.value(), v2.value(), v3.value()}));
+
+    // Indefinite-multiplicity recursive cases
+    Supplier<Arbitrary<Variant>> anyVariantList =
+        () ->
+            anyVariant().list().map(ArrayList::new).map(l -> new Variant(parseSignature("av"), l));
+    Supplier<Arbitrary<Variant>> anyStringVariantMap =
+        () ->
+            Arbitraries.maps(Arbitraries.strings(), anyVariant())
+                .map(LinkedHashMap::new)
+                .map(m -> new Variant(parseSignature("a{sv}"), m));
+
+    // fixme: anyPair, anyTriple (see above)
+    return Arbitraries.frequencyOf(
+        Tuple.of(10, anyString),
+        Tuple.of(10, anyInt),
+        Tuple.of(10, anyLong),
+        Tuple.of(10, anyDouble),
+        Tuple.of(10, anyBoolean),
+        Tuple.of(10, anyByte),
+        Tuple.of(10, anyShort),
+        Tuple.of(10, anyByteArray),
+        Tuple.of(10, Arbitraries.lazy(anySome)),
+        Tuple.of(10, Arbitraries.lazy(anyNone)),
+        Tuple.of(10, Arbitraries.lazy(anyNestedVariant)),
+        Tuple.of(1, Arbitraries.lazy(anyStringVariantMap)),
+        Tuple.of(1, Arbitraries.lazy(anyVariantList))
+        /*,
+        anyPair,
+        anyTriple
+        */ );
   }
 
   private Signature parseSignature(String s) {