-
Notifications
You must be signed in to change notification settings - Fork 257
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
Allow for user-defined entity creation in test generation #4574
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why wouldn't you just write
method {:test} Test0() {
var bool0 : bool := M.flipCoin();
M.m(bool0);
}
Instead of
{:testGenerators "b", "M.CoinFlip"}
?
I think the motivation behind the corresponding issue has a lot to do with how these tests end up being compiled and run. The goal is to not modify the code under test and at the same time to preserve |
A wrapper test method such as
does not modify the code under test
Why do want |
If I'm following correctly, the motivation is clearer once you have more than one input parameter and want to allow test generation to control what other arguments are passed in. Runnin module M {
method {:extern} CoinFlip() returns (b:bool)
method {:testEntry} {:testGenerators "b", "M.CoinFlip"} ToTest(b: bool, c: bool) {
// Do Something Here
}
} Would produce something like: method {:test} Test0() {
var bool0 : bool := M.flipCoin();
M.m(bool0, true);
}
method {:test} Test1() {
var bool0 : bool := M.flipCoin();
M.m(bool0, false);
} In other words, |
Why not write the following, for your example? module M {
method {:extern} CoinFlip() returns (b:bool)
method {:testEntry} ToTestWrapper(c: bool) {
var bool0 : bool := M.flipCoin();
ToTest(bool0, c);
}
method ToTest(b: bool, c: bool) {
// Do Something Here
}
} |
Fair point, it seems like the extra wrapper shouldn't change the coverage of the generated tests - @Dargones or @codyroux? |
Using a wrapper method in this way makes sense to me when the goal is to test the Dafny code directly. That said, I do see a potential issue when the goal is to perform model-based testing, i.e. when we want to generate tests from the Dafny model to run on another implementation written in a different language. Ideally, we would want to (1) generate the tests, (2) switch the call to the method from which we generated the tests to the method that will be tested at runtime, and (3) run the tests. The use of a wrapper method complicates things in this scenario because now the switch has to happen within the wrapper method itself meaning that the user has to constantly modify the wrapper method between generating tests and running them. I do like the wrapper solution more because it does not require any new features but I am wondering to what extent it is feasible in practice in the model-based testing scenario. @codyroux, do you have a take on this? |
Closing in favor of #5226 |
Fixes #4543
This PR lets users specify how to generate a given argument for the test entry method using a
:testGenerators
attribute. Here is the description of the attribute I propose to put in the Reference Manual:This attribute instructs Dafny test generation to override an input parameter with a value obtained by calling the specified generator function or method. A method annotated with
{:testGenerators}
must always be a test entry method.For example, consider the following Dafny code:
In the code snippet above, method
ToTest
is annotated with{:testGenerators "b", "M.CoinFlip"}
which means that Dafny test generation will produce a test that calls theM.CoinFlip
method to obtain a value for the input parameterb
. In particular, runningdafny generate-tests Block FILE.dfy
on the file above, will produce the following:By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.