github.com/joomcode/pegomock@v2.9.2-0.20220414140958-14f53b6b2a6c+incompatible/internal/generate_matchers/matcher_generation.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"reflect"
     7  	"strings"
     8  )
     9  
    10  // Generate matchers:
    11  //
    12  //     go generate github.com/petergtz/pegomock/internal/generate_matchers
    13  
    14  //go:generate go run matcher_generation.go
    15  //go:generate go fmt ../../matcher_factories.go
    16  //go:generate go fmt ../../ginkgo_compatible/matchers.go
    17  
    18  func main() {
    19  	mustWriteFile("../../matcher_factories.go", GenerateDefaultMatchersFile())
    20  	mustWriteFile("../../ginkgo_compatible/matchers.go", GenerateGinkgoMatchersFile())
    21  }
    22  
    23  func mustWriteFile(path string, contents string) {
    24  	err := ioutil.WriteFile(path, []byte(contents), 0644)
    25  	if err != nil {
    26  		panic(err)
    27  	}
    28  }
    29  
    30  func GenerateDefaultMatchersFile() string {
    31  	contents := `package pegomock
    32  
    33  import (
    34  	"reflect"
    35  )
    36  `
    37  
    38  	for _, kind := range primitiveKinds {
    39  		contents += fmt.Sprintf(`
    40  func Eq%[1]s(value %[2]s) %[2]s {
    41  	RegisterMatcher(&EqMatcher{Value: value})
    42  	return %[4]s
    43  }
    44  
    45  func NotEq%[1]s(value %[2]s) %[2]s {
    46  	RegisterMatcher(&NotEqMatcher{Value: value})
    47  	return %[4]s
    48  }
    49  
    50  func Any%[1]s() %[2]s {
    51  	RegisterMatcher(NewAnyMatcher(reflect.TypeOf(%[3]s)))
    52  	return %[4]s
    53  }
    54  
    55  func %[1]sThat(matcher ArgumentMatcher) %[2]s {
    56  	RegisterMatcher(matcher)
    57  	return %[4]s
    58  }
    59  
    60  func Eq%[1]sSlice(value []%[2]s) []%[2]s {
    61  	RegisterMatcher(&EqMatcher{Value: value})
    62  	return nil
    63  }
    64  
    65  func NotEq%[1]sSlice(value []%[2]s) []%[2]s {
    66  	RegisterMatcher(&NotEqMatcher{Value: value})
    67  	return nil
    68  }
    69  
    70  func Any%[1]sSlice() []%[2]s {
    71  	RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf(%[3]s))))
    72  	return nil
    73  }
    74  
    75  func %[1]sSliceThat(matcher ArgumentMatcher) []%[2]s {
    76  	RegisterMatcher(matcher)
    77  	return nil
    78  }
    79  `, strings.Title(kind.String()), kind.String(), exampleValue(kind), zeroValue(kind))
    80  	}
    81  
    82  	// hard-coding this for now as interface{} overall works slightly different than other types.
    83  	return contents + `
    84  func EqInterface(value interface{}) interface{} {
    85  	RegisterMatcher(&EqMatcher{Value: value})
    86  	return nil
    87  }
    88  
    89  func NotEqInterface(value interface{}) interface{} {
    90  	RegisterMatcher(&NotEqMatcher{Value: value})
    91  	return nil
    92  }
    93  
    94  func AnyInterface() interface{} {
    95  	RegisterMatcher(NewAnyMatcher(reflect.TypeOf((*interface{})(nil)).Elem()))
    96  	return nil
    97  }
    98  
    99  func InterfaceThat(matcher ArgumentMatcher) interface{} {
   100  	RegisterMatcher(matcher)
   101  	return nil
   102  }
   103  
   104  func EqInterfaceSlice(value []interface{}) []interface{} {
   105  	RegisterMatcher(&EqMatcher{Value: value})
   106  	return nil
   107  }
   108  
   109  func NotEqInterfaceSlice(value []interface{}) []interface{} {
   110  	RegisterMatcher(&NotEqMatcher{Value: value})
   111  	return nil
   112  }
   113  
   114  func AnyInterfaceSlice() []interface{} {
   115  	RegisterMatcher(NewAnyMatcher(reflect.SliceOf(reflect.TypeOf((*interface{})(nil)).Elem())))
   116  	return nil
   117  }
   118  
   119  func InterfaceSliceThat(matcher ArgumentMatcher) []interface{} {
   120  	RegisterMatcher(matcher)
   121  	return nil
   122  }
   123  `
   124  }
   125  
   126  func GenerateGinkgoMatchersFile() string {
   127  	contents := `package mock
   128  
   129  import (
   130  	"github.com/petergtz/pegomock"
   131  )
   132  
   133  var (`
   134  
   135  	for _, kind := range append(primitiveKinds, reflect.Interface) {
   136  		contents += fmt.Sprintf(`
   137  	Eq%[1]s = pegomock.Eq%[1]s
   138  	NotEq%[1]s = pegomock.NotEq%[1]s
   139  	Any%[1]s = pegomock.Any%[1]s
   140  	%[1]sThat = pegomock.%[1]sThat
   141  	Eq%[1]sSlice = pegomock.Eq%[1]sSlice
   142  	NotEq%[1]sSlice = pegomock.NotEq%[1]sSlice
   143  	Any%[1]sSlice = pegomock.Any%[1]sSlice
   144  	%[1]sSliceThat = pegomock.%[1]sSliceThat
   145  `, strings.Title(kind.String()))
   146  	}
   147  
   148  	return contents + `
   149  	Times   = pegomock.Times
   150  	AtLeast = pegomock.AtLeast
   151  	AtMost  = pegomock.AtMost
   152  	Never   = pegomock.Never
   153  	Once    = pegomock.Once
   154  	Twice   = pegomock.Twice
   155  )
   156  `
   157  }
   158  
   159  var primitiveKinds = []reflect.Kind{
   160  	reflect.Bool,
   161  	reflect.Int,
   162  	reflect.Int8,
   163  	reflect.Int16,
   164  	reflect.Int32,
   165  	reflect.Int64,
   166  	reflect.Uint,
   167  	reflect.Uint8,
   168  	reflect.Uint16,
   169  	reflect.Uint32,
   170  	reflect.Uint64,
   171  	reflect.Uintptr,
   172  	reflect.Float32,
   173  	reflect.Float64,
   174  	reflect.Complex64,
   175  	reflect.Complex128,
   176  	reflect.String,
   177  }
   178  
   179  // TODO generate: chan, func matchers
   180  
   181  func zeroValue(kind reflect.Kind) string {
   182  	switch {
   183  	case kind == reflect.Bool:
   184  		return `false`
   185  	case reflect.Int <= kind && kind <= reflect.Complex128:
   186  		return `0`
   187  	case kind == reflect.String:
   188  		return `""`
   189  	default:
   190  		return `nil`
   191  	}
   192  }
   193  
   194  func exampleValue(kind reflect.Kind) string {
   195  	if kind == reflect.Bool || kind == reflect.Int || kind == reflect.String {
   196  		return zeroValue(kind)
   197  	}
   198  	return fmt.Sprintf("(%s)(%s)", kind.String(), zeroValue(kind))
   199  }