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

Generator is not used during shrinking. #273

Closed
niilohlin opened this issue Aug 24, 2018 · 2 comments
Closed

Generator is not used during shrinking. #273

niilohlin opened this issue Aug 24, 2018 · 2 comments

Comments

@niilohlin
Copy link

Version

SwiftCheck (0.10.0)

Environment

Xcode 9.4.1. iOS target.

Description

When a property fails with a custom Gen<T> the generator is not used while shrinking. And therefore calling the test block without it.

Steps To Reproduce

sample code:

func stringDoesNotContainA(_ string: String) -> Bool {
    precondition(!string.isEmpty)
    return !string.contains("a" as Character)
}

class SwiftCheckTests: XCTestCase {
    func testSwiftCheck() {
        property("string is not \"a\"") <- forAll(String.arbitrary.suchThat { !$0.isEmpty }, pf: stringDoesNotContainA)
    }
}

Expected Result

The function stringDoesNotContainA is expected to only be called with non empty strings.

Actual Result

After the test fails. The function is called with an empty String and execution halts.

@niilohlin
Copy link
Author

After looking thorough the code and the QuickCheck code I realize that what I'm asking to do is probably not possible to do automatically. But instead forAllShrink can be used with a custom shrinker that filters the values according to my predicate. Like this:

func stringDoesNotContainA(_ string: String) -> Bool {
    precondition(!string.isEmpty)
    return !string.contains("a" as Character)
}

class SwiftCheckTests: XCTestCase {
    func testSwiftCheck() {
        let predicate = { (str: String) -> Bool in
            return !str.isEmpty
        }
        let stringShrinker = { (str: String) -> [String] in
            String.shrink(str).filter(predicate)
        }

        property("string is not \"a\"") <- forAllShrink(String.arbitrary.suchThat(predicate) , shrinker: stringShrinker, f: stringDoesNotContainA)
    }
}

This code will work as expected.

@CodaFi
Copy link
Member

CodaFi commented Aug 25, 2018

Hi @niilohlin, apologies for the delay in getting to this.

This is the expected behavior. shrink is defined as a static requirement on the type that conforms to arbitrary. We do not derive shrinkers from generators as other, more recent, frameworks may try to do. Instead, you should write a modifier type for strings that pass your predicate and add your own shrinker there.

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

No branches or pull requests

2 participants