github.com/moitias/moq@v0.0.0-20240223074357-5eb0f0ba4054/internal/template/template.go (about)

     1  package template
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  	"text/template"
     7  
     8  	"github.com/moitias/moq/internal/registry"
     9  )
    10  
    11  // Template is the Moq template. It is capable of generating the Moq
    12  // implementation for the given template.Data.
    13  type Template struct {
    14  	tmpl *template.Template
    15  }
    16  
    17  // New returns a new instance of Template.
    18  func New() (Template, error) {
    19  	tmpl, err := template.New("moq").Funcs(templateFuncs).Parse(moqTemplate)
    20  	if err != nil {
    21  		return Template{}, err
    22  	}
    23  
    24  	return Template{tmpl: tmpl}, nil
    25  }
    26  
    27  // Execute generates and writes the Moq implementation for the given
    28  // data.
    29  func (t Template) Execute(w io.Writer, data Data) error {
    30  	return t.tmpl.Execute(w, data)
    31  }
    32  
    33  // moqTemplate is the template for mocked code.
    34  // language=GoTemplate
    35  var moqTemplate = `// Code generated by moq; DO NOT EDIT.
    36  // github.com/matryer/moq
    37  
    38  package {{.PkgName}}
    39  
    40  import (
    41  {{- range .Imports}}
    42  	{{. | ImportStatement}}
    43  {{- end}}
    44  )
    45  
    46  {{range $i, $mock := .Mocks -}}
    47  
    48  {{- if not $.SkipEnsure -}}
    49  // Ensure, that {{.MockName}} does implement {{$.SrcPkgQualifier}}{{.InterfaceName}}.
    50  // If this is not the case, regenerate this file with moq.
    51  var _ {{$.SrcPkgQualifier}}{{.InterfaceName -}} 
    52  	{{- if .TypeParams }}[
    53  		{{- range $index, $param := .TypeParams}}
    54  			{{- if $index}}, {{end -}}
    55  			{{if $param.Constraint}}{{$param.Constraint.String}}{{else}}{{$param.TypeString}}{{end}}
    56  		{{- end -}}
    57  		]
    58  	{{- end }} = &{{.MockName}}
    59  	 {{- if .TypeParams }}[
    60  		{{- range $index, $param := .TypeParams}}
    61  			{{- if $index}}, {{end -}}
    62  			{{if $param.Constraint}}{{$param.Constraint.String}}{{else}}{{$param.TypeString}}{{end}}
    63  		{{- end -}}
    64  		]
    65  	{{- end -}}
    66  {}
    67  {{- end}}
    68  
    69  // {{.MockName}} is a mock implementation of {{$.SrcPkgQualifier}}{{.InterfaceName}}.
    70  //
    71  //	func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
    72  //
    73  //		// make and configure a mocked {{$.SrcPkgQualifier}}{{.InterfaceName}}
    74  //		mocked{{.InterfaceName}} := &{{.MockName}}{
    75  			{{- range .Methods}}
    76  //			{{.Name}}Func: func({{.ArgList}}) {{.ReturnArgTypeList}} {
    77  //				panic("mock out the {{.Name}} method")
    78  //			},
    79  			{{- end}}
    80  //		}
    81  //
    82  //		// use mocked{{.InterfaceName}} in code that requires {{$.SrcPkgQualifier}}{{.InterfaceName}}
    83  //		// and then make assertions.
    84  //
    85  //	}
    86  type {{.MockName}} 
    87  {{- if .TypeParams -}}
    88  	[{{- range $index, $param := .TypeParams}}
    89  			{{- if $index}}, {{end}}{{$param.Name | Exported}} {{$param.TypeString}}
    90  	{{- end -}}]
    91  {{- end }} struct {
    92  {{- range .Methods}}
    93  	// {{.Name}}Func mocks the {{.Name}} method.
    94  	{{.Name}}Func func({{.ArgList}}) {{.ReturnArgTypeList}}
    95  {{end}}
    96  	// calls tracks calls to the methods.
    97  	calls struct {
    98  {{- range .Methods}}
    99  		// {{.Name}} holds details about calls to the {{.Name}} method.
   100  		{{.Name}} []struct {
   101  			{{- range .Params}}
   102  			// {{.Name | Exported}} is the {{.Name}} argument value.
   103  			{{.Name | Exported}} {{.TypeString}}
   104  			{{- end}}
   105  		}
   106  {{- end}}
   107  	}
   108  {{- range .Methods}}
   109  	lock{{.Name}} {{$.Imports | SyncPkgQualifier}}.RWMutex
   110  {{- end}}
   111  }
   112  {{range .Methods}}
   113  // {{.Name}} calls {{.Name}}Func.
   114  func (mock *{{$mock.MockName}}
   115  {{- if $mock.TypeParams -}}
   116  	[{{- range $index, $param := $mock.TypeParams}}
   117  		{{- if $index}}, {{end}}{{$param.Name | Exported}}
   118  	{{- end -}}]
   119  {{- end -}}	
   120  ) {{.Name}}({{.ArgList}}) {{.ReturnArgTypeList}} {
   121  {{- if not $.StubImpl}}
   122  	if mock.{{.Name}}Func == nil {
   123  		panic("{{$mock.MockName}}.{{.Name}}Func: method is nil but {{$mock.InterfaceName}}.{{.Name}} was just called")
   124  	}
   125  {{- end}}
   126  	callInfo := struct {
   127  		{{- range .Params}}
   128  		{{.Name | Exported}} {{.TypeString}}
   129  		{{- end}}
   130  	}{
   131  		{{- range .Params}}
   132  		{{.Name | Exported}}: {{.Name}},
   133  		{{- end}}
   134  	}
   135  	mock.lock{{.Name}}.Lock()
   136  	mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo)
   137  	mock.lock{{.Name}}.Unlock()
   138  {{- if .Returns}}
   139  	{{- if $.StubImpl}}
   140  	if mock.{{.Name}}Func == nil {
   141  		var (
   142  		{{- range .Returns}}
   143  			{{.Name}} {{.TypeString}}
   144  		{{- end}}
   145  		)
   146  		return {{.ReturnArgNameList}}
   147  	}
   148  	{{- end}}
   149  	return mock.{{.Name}}Func({{.ArgCallList}})
   150  {{- else}}
   151  	{{- if $.StubImpl}}
   152  	if mock.{{.Name}}Func == nil {
   153  		return
   154  	}
   155  	{{- end}}
   156  	mock.{{.Name}}Func({{.ArgCallList}})
   157  {{- end}}
   158  }
   159  
   160  // {{.Name}}Calls gets all the calls that were made to {{.Name}}.
   161  // Check the length with:
   162  //
   163  //	len(mocked{{$mock.InterfaceName}}.{{.Name}}Calls())
   164  func (mock *{{$mock.MockName}}
   165  {{- if $mock.TypeParams -}}
   166  	[{{- range $index, $param := $mock.TypeParams}}
   167  		{{- if $index}}, {{end}}{{$param.Name | Exported}}
   168  	{{- end -}}]
   169  {{- end -}}	
   170  ) {{.Name}}Calls() []struct {
   171  		{{- range .Params}}
   172  		{{.Name | Exported}} {{.TypeString}}
   173  		{{- end}}
   174  	} {
   175  	var calls []struct {
   176  		{{- range .Params}}
   177  		{{.Name | Exported}} {{.TypeString}}
   178  		{{- end}}
   179  	}
   180  	mock.lock{{.Name}}.RLock()
   181  	calls = mock.calls.{{.Name}}
   182  	mock.lock{{.Name}}.RUnlock()
   183  	return calls
   184  }
   185  {{- if $.WithResets}}
   186  // Reset{{.Name}}Calls reset all the calls that were made to {{.Name}}.
   187  func (mock *{{$mock.MockName}}) Reset{{.Name}}Calls() {
   188  	mock.lock{{.Name}}.Lock()
   189  	mock.calls.{{.Name}} = nil
   190  	mock.lock{{.Name}}.Unlock()
   191  }
   192  {{end}}
   193  {{end -}}
   194  {{- if $.WithResets}}
   195  // ResetCalls reset all the calls that were made to all mocked methods.
   196  func (mock *{{$mock.MockName}}) ResetCalls() {
   197  	{{- range .Methods}}
   198  	mock.lock{{.Name}}.Lock()
   199  	mock.calls.{{.Name}} = nil
   200  	mock.lock{{.Name}}.Unlock()
   201  	{{end -}}
   202  }
   203  {{end -}}
   204  {{end -}}
   205  `
   206  
   207  // This list comes from the golint codebase. Golint will complain about any of
   208  // these being mixed-case, like "Id" instead of "ID".
   209  var golintInitialisms = []string{
   210  	"ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS",
   211  	"QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "UID", "UUID", "URI",
   212  	"URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS",
   213  }
   214  
   215  var templateFuncs = template.FuncMap{
   216  	"ImportStatement": func(imprt *registry.Package) string {
   217  		if imprt.Alias == "" {
   218  			return `"` + imprt.Path() + `"`
   219  		}
   220  		return imprt.Alias + ` "` + imprt.Path() + `"`
   221  	},
   222  	"SyncPkgQualifier": func(imports []*registry.Package) string {
   223  		for _, imprt := range imports {
   224  			if imprt.Path() == "sync" {
   225  				return imprt.Qualifier()
   226  			}
   227  		}
   228  
   229  		return "sync"
   230  	},
   231  	"Exported": func(s string) string {
   232  		if s == "" {
   233  			return ""
   234  		}
   235  		for _, initialism := range golintInitialisms {
   236  			if strings.ToUpper(s) == initialism {
   237  				return initialism
   238  			}
   239  		}
   240  		return strings.ToUpper(s[0:1]) + s[1:]
   241  	},
   242  }