pholser/junit-quickcheck

Allow configuration annotations from a generator used with @From onto the parameter

SimY4 opened this issue · 4 comments

SimY4 commented

Consider a generator like this:

@MyAnnotation(value = "Some default")
class MyClassGenerator extends Generator<MyClass> {
  private MyAnnotation myAnnotation;

  ...

  public MyClass generate(SourceOfRandomness random, GenerationStatus status) {
    MyClassFieldGenerator myClassFieldGenerator = gen().make(MyClassFieldGenerator.class);
    myClassFieldGenerator.configure(myAnnotation);
    return new MyClass(myClassFieldGenerator.generate(random, status))
  }

  public void configure(MyAnnotation myAnnotation) {
    this.myAnnotation = myAnnotation;
  }
}

What's interesting about it is that by calling gen().make(MyClassFieldGenerator.class) I can put my configuration annotation on generator class itself to configure defaults on it without calling to myClassFieldGenerator.configure(myAnnotation); explicitly.

But I can't do the same for Generator that is referred from a Property method itself:

@Property
public void myProperty(@From(MyClassGenerator.class) MyClass myClass) {
  // here MyClassGenerator will not receive defaults from annotation present on Generator class.
}

In practice, this means that I have to instantiate default annotation instance myself if it's not provided by the framework which looks like something that could be easily avoided.

@SimY4 Thanks for your interest in junit-quickcheck.

You're right -- when you say gen().make(MyClassFieldGenerator.class), it will configure that generator with whatever config annotations live on MyClassFieldGenerator. On a property method, junit-quickcheck decides on generators to use in producing values for a parameter by examining annotations on the parameter itself; and if one of those annotations is From, it doesn't necessarily also scrape annotations from the generator class named in From. I suppose junit-quickcheck could be made to do that....Another possibility I want to examine in the future is pulling annotations on a prescribed path from a parameter, to its declaring method, its enclosing class(es), and so on.

Which path would better address your need? Maybe there are other options I haven't considered?

@SimY4 Checking in to see how you'd like to proceed with this issue. Let me know....thanks!

SimY4 commented

@pholser Hi, sorry I missed your message. I tried to approach this issue myself but failed to find a solution. Currently, I'm using workaround where my generators configuring themselves at the moment of creation:

@MyAnnotation(value = "Some default")
class MyClassGenerator extends Generator<MyClass> {
  private MyAnnotation myAnnotation;

  public MyClassGenerator() {
    super(MyClass.class);
    configure(getClass());
  }

  ...

  public void configure(MyAnnotation myAnnotation) {
    this.myAnnotation = myAnnotation;
  }
}

@SimY4 Thanks for getting back to me. I'm considering going ahead and scraping config annotations from generators from @From. Can't see any harm or confusion it would cause.