pholser/junit-quickcheck

Can Generator<...> be injected into Generator's constructor?

vlsi opened this issue · 1 comments

vlsi commented

Use case: I want to generate test data for java.util.jar.Manifest.

Manifest contains Attributes that is Attributes implements Map<Object,Object>.
Technically speaking attribute keys and values are strings, however the restrictions on keys and values are different.

For instance, keys should match [a-zA-z0-9_-]{1,70}, however keys can contain almost everything except newlines.
However I want not just random strings as keys, but I want the generator to produce well-known key names like Manifest-Version.

So far so good, I think behind the lines of implementing AttributesGenerator extends Generator<Attributes>.

    DefaultAttributes generate(SourceOfRandomness random, GenerationStatus status) {
        def map = gen().make(
            HashMapGenerator.class,
            Gen.frequency(
                Gen.freq(0.4, gen().make(KnownManifestKeyGenerator.class))
                Generator.freq(0.6, gen().make(AsciiStringGenerator.class)),
            ),
            gen().type(String.class))
            .generate(random, status))
        def res = new DefaultAttributes()
        res.putAll(map)
        return res
    }

Frankly speaking, I do not like how gen.make is instantiated at each and every generation attempt.

I wonder if I could "inject" Generator instance with constructor or another configuration-like method.

For instance:

class AttributesGenerator extends Generator<Attributes> {
  private Generator<Map<String, String>> mapGen;
  AttributesGenerator(Generator<Map<@From(KnownManifestKeyGenerator.class, frequency=0.4) 
 @From(AsciiStringGenerator.class, frequency=0.6), String, String>> mapGen) {
    this.mapGen = mapGen;
  }
  // then I could reuse mapGen to produce maps.
}
vlsi commented

Note: Gen.frequency dos not support shrink