pholser / junit-quickcheck

Property-based testing, JUnit-style
MIT License
957 stars 121 forks source link

Support shrink in @Fields #239

Open vlsi opened 5 years ago

vlsi commented 5 years ago

It looks like @Fields does not support shrinking.

Use case:

public class GeneratorDescriptors {
    @From(value = KnownManifestKeyGenerator.class, frequency = 10)
    @Regex("[-_a-zA-Z0-9]+")
    @Size(min = 1, max = 70)
    @From(value = RegexStringGenerator.class, frequency = 90)
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface ManifestKey {
    }

    @Regex("([a-zA-Z0-9 -\t:@_]|नि|😃|丈)+")
    @Size(min = 0, max = 200)
    @From(value = RegexStringGenerator.class)
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface ManifestValue {
    }

    public final @Size(min = 0, max = 10) HashMap<@ManifestKey String, @ManifestValue String> manifestAttributes = null;

    public static class ManifestDto {
        @FromField(value = GeneratorDescriptors.class, field = "manifestAttributes")
        public HashMap<String, String> mainAttributes;

        @Size(min=0, max=5)
        public HashMap<@ManifestValue String,
            @FromField(value = GeneratorDescriptors.class, field = "manifestAttributes")
            HashMap<String, String>> sections;

        public DefaultManifest build() {
            DefaultManifest m = new DefaultManifest(null);
            m.attributes(mainAttributes);
            for (Map.Entry<String, HashMap<String, String>> sections : sections.entrySet()) {
                m.attributes(sections.getValue(), sections.getKey());
            }
            return m;
        }

        @Override
        public String toString() {
            return "ManifestDto{" +
                "mainAttributes=" + mainAttributes +
                ", sections=" + sections +
                '}';
        }
    }
}
@RunWith(JUnitQuickcheck.class)
class ManifestTheoryTest {
    @Property
    public void storeSuceeds(@From(Fields.class) GeneratorDescriptors.ManifestDto manifestDto) {
...

It does not seem try shrinking the values :(

pholser commented 5 years ago

@visi Thanks for this. If doable, sounds like a nice addition.

pholser commented 5 years ago

@visi I'm looking into an implementation for this issue.

Suppose the target type is:

class Foo {
    int a;
    String b;
    boolean c;
}

If asked to shrink a particular instance f of Foo, Fields.shrink() could ask each field generator for smaller values for each of f.a, f.b, and f.c; so it would have lists of each of these.

What should the list of shrinks of f be?

vlsi commented 5 years ago

That is why https://github.com/pholser/junit-quickcheck/issues/220 is important.

If you are OK to read Apache 2.0 code, then please check https://github.com/gradle/gradle/pull/10724/files#diff-24a277fc1a43b679d84443863b0cb58aR82-R88