diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2023-12-10 20:54:33 +0100 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2023-12-10 21:05:54 +0100 |
commit | 147a1c19c1f7bfe8d0939618d3c8dc2bb4e59fb7 (patch) | |
tree | 59068e90abb014e29901f7bcf91be2a8b08f79ef /jgvariant-ostree | |
parent | df853ef46a9c12d319bf824ac106a411f5eddabd (diff) |
Add more property-based tests and fix more bugs.
Change-Id: I8deb1a7d75078c037714541d8f6f656052c2476c
Diffstat (limited to 'jgvariant-ostree')
-rw-r--r-- | jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaOperation.java | 4 | ||||
-rw-r--r-- | jgvariant-ostree/src/test/java/eu/mulk/jgvariant/ostree/OstreeDecoderPropertyTest.java | 225 |
2 files changed, 225 insertions, 4 deletions
diff --git a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaOperation.java b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaOperation.java index 42b7056..bb31e50 100644 --- a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaOperation.java +++ b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaOperation.java @@ -130,6 +130,7 @@ public sealed interface DeltaOperation { * @see #readVarint64 */ private static void writeVarint64(ByteArrayOutputStream output, long value) { + int n = 0; do { byte b = (byte) (value & 0x7F); value >>= 7; @@ -137,6 +138,7 @@ public sealed interface DeltaOperation { b |= (byte) 0x80; } output.write(b); - } while (value != 0); + ++n; + } while (value != 0 && n < 10); } } diff --git a/jgvariant-ostree/src/test/java/eu/mulk/jgvariant/ostree/OstreeDecoderPropertyTest.java b/jgvariant-ostree/src/test/java/eu/mulk/jgvariant/ostree/OstreeDecoderPropertyTest.java index acd11c4..da15ff2 100644 --- a/jgvariant-ostree/src/test/java/eu/mulk/jgvariant/ostree/OstreeDecoderPropertyTest.java +++ b/jgvariant-ostree/src/test/java/eu/mulk/jgvariant/ostree/OstreeDecoderPropertyTest.java @@ -1,6 +1,9 @@ package eu.mulk.jgvariant.ostree; +import static org.junit.jupiter.api.Assertions.assertEquals; + import eu.mulk.jgvariant.core.Decoder; +import java.util.List; import java.util.Map; import net.jqwik.api.*; @@ -21,14 +24,88 @@ class OstreeDecoderPropertyTest { } } + @Group + class DeltaSuperblockRoundtripLaw implements RoundtripLaw<DeltaSuperblock> { + + @Override + public Decoder<DeltaSuperblock> decoder() { + return DeltaSuperblock.decoder(); + } + + @Override + public Arbitrary<DeltaSuperblock> anyT() { + return anyDeltaSuperblock(); + } + } + + @Group + @Disabled( + "Not implemented correctly: Requires enough file entries to parse all the delta operations.") + class DeltaPartPayloadRoundtripLaw implements RoundtripLaw<DeltaPartPayload> { + + @Override + public Decoder<DeltaPartPayload> decoder() { + // FIXME + var deltaMetaEntry = new DeltaMetaEntry(0, Checksum.zero(), 0, 0, List.of()); + return DeltaPartPayload.decoder(deltaMetaEntry); + } + + @Override + public Arbitrary<DeltaPartPayload> anyT() { + return anyDeltaPartPayload(); + } + } + + @Group + class DirTreeRoundtripLaw implements RoundtripLaw<DirTree> { + + @Override + public Decoder<DirTree> decoder() { + return DirTree.decoder(); + } + + @Override + public Arbitrary<DirTree> anyT() { + return anyDirTree(); + } + } + + @Group + class DirMetaRoundtripLaw implements RoundtripLaw<DirMeta> { + + @Override + public Decoder<DirMeta> decoder() { + return DirMeta.decoder(); + } + + @Override + public Arbitrary<DirMeta> anyT() { + return anyDirMeta(); + } + } + + @Group + class CommitRoundtripLaw implements RoundtripLaw<Commit> { + + @Override + public Decoder<Commit> decoder() { + return Commit.decoder(); + } + + @Override + public Arbitrary<Commit> anyT() { + return anyCommit(); + } + } + interface RoundtripLaw<T> { @Property - default boolean roundtripsWell(@ForAll(value = "anyT") T entityLeft) { + default void roundtripsWell(@ForAll(value = "anyT") T entityLeft) { var decoder = decoder(); var bytes = decoder.encode(entityLeft); var entityRight = decoder.decode(bytes); - return entityLeft.equals(entityRight); + assertEquals(entityLeft, entityRight); } Decoder<T> decoder(); @@ -61,6 +138,148 @@ class OstreeDecoderPropertyTest { @Provide Arbitrary<Checksum> anyChecksum() { - return Arbitraries.of(new Checksum(new ByteString(new byte[32]))); + return Arbitraries.bytes() + .array(byte[].class) + .ofSize(32) + .map(ByteString::new) + .map(Checksum::new); + } + + @Provide + Arbitrary<DeltaSuperblock> anyDeltaSuperblock() { + return Combinators.combine( + anyMetadata(), + Arbitraries.longs(), + anyChecksum(), + anyChecksum(), + anyCommit(), + anyDeltaName().list(), + anyDeltaMetaEntry().list(), + anyDeltaFallback().list()) + .as(DeltaSuperblock::new); + } + + @Provide + Arbitrary<DeltaPartPayload> anyDeltaPartPayload() { + return Combinators.combine( + anyFileMode().list(), + anyXattr().list().list(), + anyByteString(), + anyDeltaOperation().list()) + .as(DeltaPartPayload::new); + } + + @Provide + Arbitrary<DeltaOperation> anyDeltaOperation() { + return Arbitraries.oneOf( + Combinators.combine(Arbitraries.longs(), Arbitraries.longs()) + .as(DeltaOperation.OpenSpliceAndCloseMeta::new), + Combinators.combine( + Arbitraries.longs(), Arbitraries.longs(), Arbitraries.longs(), Arbitraries.longs()) + .as(DeltaOperation.OpenSpliceAndCloseReal::new), + Combinators.combine(Arbitraries.longs(), Arbitraries.longs(), Arbitraries.longs()) + .as(DeltaOperation.Open::new), + Combinators.combine(Arbitraries.longs(), Arbitraries.longs()).as(DeltaOperation.Write::new), + Arbitraries.longs().map(DeltaOperation.SetReadSource::new), + Arbitraries.of(new DeltaOperation.UnsetReadSource()), + Arbitraries.of(new DeltaOperation.Close()), + Combinators.combine(Arbitraries.longs(), Arbitraries.longs()) + .as(DeltaOperation.BsPatch::new)); + } + + @Provide + Arbitrary<DeltaPartPayload.FileMode> anyFileMode() { + return Combinators.combine( + Arbitraries.integers(), Arbitraries.integers(), Arbitraries.integers()) + .as(DeltaPartPayload.FileMode::new); + } + + @Provide + Arbitrary<Xattr> anyXattr() { + return Combinators.combine(anyByteString(), anyByteString()).as(Xattr::new); + } + + @Provide + Arbitrary<ByteString> anyByteString() { + return Arbitraries.bytes().array(byte[].class).map(ByteString::new); + } + + @Provide + Arbitrary<DirTree> anyDirTree() { + return Combinators.combine(anyDirTreeFile().list(), anyDirTreeDirectory().list()) + .as(DirTree::new); + } + + @Provide + Arbitrary<DirMeta> anyDirMeta() { + return Combinators.combine( + Arbitraries.integers(), + Arbitraries.integers(), + Arbitraries.integers(), + anyXattr().list()) + .as(DirMeta::new); + } + + @Provide + Arbitrary<Commit> anyCommit() { + return Combinators.combine( + anyMetadata(), + anyChecksum(), + anyRelatedObject().list(), + Arbitraries.strings(), + Arbitraries.strings(), + Arbitraries.longs(), + anyChecksum(), + anyChecksum()) + .as(Commit::new); + } + + @Provide + Arbitrary<Commit.RelatedObject> anyRelatedObject() { + return Combinators.combine(Arbitraries.strings(), anyChecksum()).as(Commit.RelatedObject::new); + } + + @Provide + Arbitrary<DeltaSuperblock.DeltaName> anyDeltaName() { + return Combinators.combine(anyChecksum(), anyChecksum()).as(DeltaSuperblock.DeltaName::new); + } + + @Provide + Arbitrary<DeltaMetaEntry> anyDeltaMetaEntry() { + return Combinators.combine( + Arbitraries.integers(), + anyChecksum(), + Arbitraries.longs(), + Arbitraries.longs(), + anyDeltaObject().list()) + .as(DeltaMetaEntry::new); + } + + @Provide + Arbitrary<DeltaMetaEntry.DeltaObject> anyDeltaObject() { + return Combinators.combine(anyObjectType(), anyChecksum()).as(DeltaMetaEntry.DeltaObject::new); + } + + @Provide + Arbitrary<ObjectType> anyObjectType() { + return Arbitraries.of(ObjectType.values()); + } + + @Provide + Arbitrary<DeltaFallback> anyDeltaFallback() { + return Combinators.combine( + anyObjectType(), anyChecksum(), Arbitraries.longs(), Arbitraries.longs()) + .as(DeltaFallback::new); + } + + @Provide + Arbitrary<DirTree.Directory> anyDirTreeDirectory() { + return Combinators.combine(Arbitraries.strings(), anyChecksum(), anyChecksum()) + .as(DirTree.Directory::new); + } + + @Provide + Arbitrary<DirTree.File> anyDirTreeFile() { + return Combinators.combine(Arbitraries.strings(), anyChecksum()).as(DirTree.File::new); } } |