Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best practice for delegating configurations? #272

Open
941design opened this issue Aug 10, 2020 · 3 comments
Open

Best practice for delegating configurations? #272

941design opened this issue Aug 10, 2020 · 3 comments
Labels

Comments

@941design
Copy link

Hi,

How to properly delegate a generator configuration?

Assume MyObject has two attributes of the same type whose generators need to be configured. Let's say foo and bar are both integers, and I want to configure them with different ranges. I created a configuration annotation with fields fooMin, fooMax, barMin, and barMax, and a generator MyObjectGen that can be configured with MyObjectConf. In configure I want to delegate to sub-generators. What is the proper way to do this?

My solution works but does not feel right, because I also hat to create an implementation of @InRange in order to configure the inner generators. I know I could configure the inner generators with annotations, but that does not seem to be practical either (when I have a lot of test methods each requiring a unique configuration).

On the other hand, I like the usage of my implementation, because how the parameter is configured matches that of the built-in generated parameters.

What am I missing?
Thanks a lot!

@RunWith(JUnitQuickcheck.class)
public class MyObjectPropertiesTest {

    @Target({PARAMETER, FIELD, ANNOTATION_TYPE, TYPE_USE})
    @Retention(RUNTIME)
    @From(MyObjectGen.class)
    @GeneratorConfiguration
    @interface MyObjectConf {

        int fooMin() default 0;

        int fooMax() default 10;

        int barMin() default 0;

        int barMax() default 10;

    }

    public static class MyObject {

        private final int foo;
        private final int bar;

        public MyObject(int foo, int bar) {
            this.foo = foo;
            this.bar = bar;
        }

    }

    public static class MyObjectGen extends Generator<MyObject> {

        private final IntegerGenerator fooGen = new IntegerGenerator();
        private final IntegerGenerator barGen = new IntegerGenerator();

        public MyObjectGen() {
            super(MyObject.class);
        }

        public void configure(MyObjectConf config) {
            fooGen.configure(new InRangeBase() {
                @Override
                public String min() {
                    return String.valueOf(config.fooMin());
                }

                @Override
                public String max() {
                    return String.valueOf(config.fooMax());
                }
            });
            barGen.configure(new InRangeBase() {
                @Override
                public String min() {
                    return String.valueOf(config.barMin());
                }

                @Override
                public String max() {
                    return String.valueOf(config.barMax());
                }
            });
        }

        @Override
        public MyObject generate(SourceOfRandomness random, GenerationStatus status) {
            return new MyObject(fooGen.generate(random, status),
                                barGen.generate(random, status));
        }

    }

    @Property
    public void lessThanZero(@MyObjectConf(fooMin = -10, fooMax = -1) MyObject obj) {
        assertThat(obj.foo, lessThan(0));
    }

}
@pholser
Copy link
Owner

pholser commented Aug 13, 2020

@941design Thanks for this -- sorry I'm just getting around to reading it. Will advise.

@pholser
Copy link
Owner

pholser commented Aug 21, 2020

@941design I think using the random passed to generate() directly might be your best bet:

  public static class MyObjectGen extends Generator<MyObject> {
    private int fooMin, fooMax, barMin, barMax;

    public MyObjectGen() {
      super(MyObject.class);
    }

    public void configure(MyObjectConf config) {
      this.fooMin = config.fooMin();
      this.fooMax = config.fooMax();
      this.barMin = config.barMin();
      this.barMax = config.barMax();
    }

    @Override
    public MyObject generate(
      SourceOfRandomness random,
      GenerationStatus status) {

      return new MyObject(
        random.nextInt(fooMin, fooMax),
        random.nextInt(barMin, barMax));
    }
  }

@pholser
Copy link
Owner

pholser commented Sep 24, 2020

@941design Let me know how this works for you -- if satisfactory, I'll close the issue. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants