leanovate / gopter

GOlang Property TestER
MIT License
598 stars 40 forks source link

Generating unique values #73

Open jonaslagoni opened 3 years ago

jonaslagoni commented 3 years ago

Hey!

I am trying to generate unique ids however I am having some troubles with it. I have tried adding a list to which ids have already been generated and then discard any that matches. questionIdGenOptions.alreadyGeneratedQuestions is an array of strings. Utils.Contains is a function which returns true if the given array contains the corresponding string otherwise false.

func QuestionIdGen(questionIdGenOptions *QuestionIdGenOptions) gopter.Gen{
    if questionIdGenOptions != nil && questionIdGenOptions.alreadyGeneratedQuestions == nil {
        var newAlreadyGeneratedQuestions = []string{}
        questionIdGenOptions.alreadyGeneratedQuestions = &newAlreadyGeneratedQuestions
    }
    pgen := gen.PtrOf(gen.AnyString())
    if questionIdGenOptions != nil {
        pgen = pgen.SuchThat(
            func(generatedId *string) bool {
                //Some characters look the same however their bytes are not i.e. it is therefore unique.
                if questionIdGenOptions.GenUniqueId != nil && *questionIdGenOptions.GenUniqueId == true && (generatedId == nil || Utils.Contains(*questionIdGenOptions.alreadyGeneratedQuestions, *generatedId)) {
                    return false
                }

                newAlreadyGeneratedQuestions := append(*questionIdGenOptions.alreadyGeneratedQuestions, *generatedId)
                questionIdGenOptions.alreadyGeneratedQuestions = &newAlreadyGeneratedQuestions
                return true
            })
    }
    return pgen
}

However atm. with this if statement, the wrapper generator which uses this function fails to generate anything... And I am unsure why almost like something internal error is happening. If I remove it everything works fine except the ids are not unique. Is there another way of doing it or?

jonaslagoni commented 3 years ago

Soo I test simply give up after (fixed any underlying problems), however the usecase are still relevant, do you want any functionality which can do this in a reproducing manner? Or should I find external libraries for this?

untoldwind commented 3 years ago

Sorry for the long wait ... (I guess the situation is kind of messed up all around the world).

Obviously you are doing a sort of stateful testing, i.e. the function under test is not a pure-function since the outcome depends on the previous calls to it. As a rule of thumb one should use command-based tests for this kind of situation.

Maybe there is a somewhat "simple" example that could be added to the library reflecting a use-case like this.