Files
fn-serverless/vendor/github.com/leanovate/gopter/gen/regex.go
Tom Coupland 98880b5474 Add App,Trigger,Fn Equality and Clone Testing (#1159)
Creates a test that aims to assert that the Equals and Clone functions
for our three entity structs actually work.

The bulk of the code is spent creating gopter generators for the entities. See information of generative or property based testing for
explainations on that topic, but basically it's an object that is
capable of creating a stream of unique instances of the given struct.

With the generator we then make three assertions:
 1) Entities are always equal to themselves.
 2) A .Clone() of an entity is Equal to the original entity.
 3) A .Clone() of an entity that has a field modified is not equal to the
 orignal.

The third property is the worse for implementation, as it does not
generate the field to modify, it simply loops all fields for each generated
entity, and checks Equals always breaks.

Break testing shows that this would have caught earlier bugs in Equals
due to field addition. It will add to the work to add further fields,
generators have to be manually specified for each field, but that
seems a worthy cost.
2018-08-22 11:00:04 +01:00

79 lines
2.2 KiB
Go

package gen
import (
"reflect"
"regexp"
"regexp/syntax"
"strings"
"github.com/leanovate/gopter"
)
// RegexMatch generates matches for a given regular expression
// regexStr is supposed to conform to the perl regular expression syntax
func RegexMatch(regexStr string) gopter.Gen {
regexSyntax, err1 := syntax.Parse(regexStr, syntax.Perl)
regex, err2 := regexp.Compile(regexStr)
if err1 != nil || err2 != nil {
return Fail(reflect.TypeOf(""))
}
return regexMatchGen(regexSyntax.Simplify()).SuchThat(func(v string) bool {
return regex.MatchString(v)
}).WithShrinker(StringShrinker)
}
func regexMatchGen(regex *syntax.Regexp) gopter.Gen {
switch regex.Op {
case syntax.OpLiteral:
return Const(string(regex.Rune))
case syntax.OpCharClass:
gens := make([]gopter.Gen, 0, len(regex.Rune)/2)
for i := 0; i+1 < len(regex.Rune); i += 2 {
gens = append(gens, RuneRange(regex.Rune[i], regex.Rune[i+1]).Map(runeToString))
}
return OneGenOf(gens...)
case syntax.OpAnyChar:
return Rune().Map(runeToString)
case syntax.OpAnyCharNotNL:
return RuneNoControl().Map(runeToString)
case syntax.OpCapture:
return regexMatchGen(regex.Sub[0])
case syntax.OpStar:
elementGen := regexMatchGen(regex.Sub[0])
return SliceOf(elementGen).Map(func(v []string) string {
return strings.Join(v, "")
})
case syntax.OpPlus:
elementGen := regexMatchGen(regex.Sub[0])
return gopter.CombineGens(elementGen, SliceOf(elementGen)).Map(func(vs []interface{}) string {
return vs[0].(string) + strings.Join(vs[1].([]string), "")
})
case syntax.OpQuest:
elementGen := regexMatchGen(regex.Sub[0])
return OneGenOf(Const(""), elementGen)
case syntax.OpConcat:
gens := make([]gopter.Gen, len(regex.Sub))
for i, sub := range regex.Sub {
gens[i] = regexMatchGen(sub)
}
return gopter.CombineGens(gens...).Map(func(v []interface{}) string {
result := ""
for _, str := range v {
result += str.(string)
}
return result
})
case syntax.OpAlternate:
gens := make([]gopter.Gen, len(regex.Sub))
for i, sub := range regex.Sub {
gens[i] = regexMatchGen(sub)
}
return OneGenOf(gens...)
}
return Const("")
}
func runeToString(v rune) string {
return string(v)
}