blob: dc195ae017d647566a3a77799d0ad66e2257e235 [file] [log] [blame]
package eu.mulk.jgvariant.core;
import java.text.ParseException;
import java.util.*;
import java.util.function.Supplier;
import net.jqwik.api.*;
@SuppressWarnings("java:S2187")
class DecoderPropertyTest {
@Group
class VariantRoundtripLaw implements RoundtripLaw<Variant> {
@Override
public Decoder<Variant> decoder() {
return Decoder.ofVariant();
}
@Override
public Arbitrary<Variant> anyT() {
return anyVariant();
}
}
interface RoundtripLaw<T> {
@Property
default boolean roundtripsWell(@ForAll(value = "anyT") T entityLeft) {
var decoder = decoder();
var bytes = decoder.encode(entityLeft);
var entityRight = decoder.decode(bytes);
return Objects.equals(entityLeft, entityRight);
}
Decoder<T> decoder();
@Provide
Arbitrary<T> anyT();
}
@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));
var anyDouble = Arbitraries.doubles().map(d -> new Variant(parseSignature("d"), d));
var anyBoolean =
Arbitraries.of(Boolean.TRUE, Boolean.FALSE).map(b -> new Variant(parseSignature("b"), b));
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));
// 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) {
try {
return Signature.parse(s);
} catch (ParseException e) {
throw new AssertionError(e);
}
}
}