github.com/Capventis/moq@v0.2.6-0.20220316100624-05dd47497214/internal/template/template.go (about)

     1  package template
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  	"text/template"
     7  
     8  	"github.com/Capventis/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}} = &{{.MockName}}{}
    52  {{- end}}
    53  
    54  // {{.MockName}} is a mock implementation of {{$.SrcPkgQualifier}}{{.InterfaceName}}.
    55  //
    56  // 	func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) {
    57  //
    58  // 		// make and configure a mocked {{$.SrcPkgQualifier}}{{.InterfaceName}}
    59  // 		mocked{{.InterfaceName}} := &{{.MockName}}{ 
    60  			{{- range .Methods}}
    61  // 			{{.Name}}Func: func({{.ArgList}}) {{.ReturnArgTypeList}} {
    62  // 				panic("mock out the {{.Name}} method")
    63  // 			},
    64  			{{- end}}
    65  // 		}
    66  //
    67  // 		// use mocked{{.InterfaceName}} in code that requires {{$.SrcPkgQualifier}}{{.InterfaceName}}
    68  // 		// and then make assertions.
    69  //
    70  // 	}
    71  type {{.MockName}} struct {
    72  {{- range .Methods}}
    73  	// {{.Name}}Func mocks the {{.Name}} method.
    74  	{{.Name}}Func func({{.ArgList}}) {{.ReturnArgTypeList}}
    75  {{end}}
    76  	// calls tracks calls to the methods.
    77  	calls struct {
    78  {{- range .Methods}}
    79  		// {{.Name}} holds details about calls to the {{.Name}} method.
    80  		{{.Name}} []struct {
    81  			{{- range .Params}}
    82  			// {{.Name | Exported}} is the {{.Name}} argument value.
    83  			{{.Name | Exported}} {{.TypeString}}
    84  			{{- end}}
    85  		}
    86  {{- end}}
    87  	}
    88  {{- range .Methods}}
    89  	lock{{.Name}} {{$.Imports | SyncPkgQualifier}}.RWMutex
    90  {{- end}}
    91  }
    92  {{range .Methods}}
    93  // {{.Name}} calls {{.Name}}Func.
    94  func (mock *{{$mock.MockName}}) {{.Name}}({{.ArgList}}) {{.ReturnArgTypeList}} {
    95  {{- if not $.StubImpl}}
    96  	if mock.{{.Name}}Func == nil {
    97  		panic("{{$mock.MockName}}.{{.Name}}Func: method is nil but {{$mock.InterfaceName}}.{{.Name}} was just called")
    98  	}
    99  {{- end}}
   100  	callInfo := struct {
   101  		{{- range .Params}}
   102  		{{.Name | Exported}} {{.TypeString}}
   103  		{{- end}}
   104  	}{
   105  		{{- range .Params}}
   106  		{{.Name | Exported}}: {{.Name}},
   107  		{{- end}}
   108  	}
   109  	mock.lock{{.Name}}.Lock()
   110  	mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo)
   111  	mock.lock{{.Name}}.Unlock()
   112  {{- if .Returns}}
   113  	{{- if $.StubImpl}}
   114  	if mock.{{.Name}}Func == nil {
   115  		var (
   116  		{{- range .Returns}}
   117  			{{.Name}} {{.TypeString}}
   118  		{{- end}}
   119  		)
   120  		return {{.ReturnArgNameList}}
   121  	}
   122  	{{- end}}
   123  	return mock.{{.Name}}Func({{.ArgCallList}})
   124  {{- else}}
   125  	{{- if $.StubImpl}}
   126  	if mock.{{.Name}}Func == nil {
   127  		return
   128  	}
   129  	{{- end}}
   130  	mock.{{.Name}}Func({{.ArgCallList}})
   131  {{- end}}
   132  }
   133  
   134  // {{.Name}}Calls gets all the calls that were made to {{.Name}}.
   135  // Check the length with:
   136  //     len(mocked{{$mock.InterfaceName}}.{{.Name}}Calls())
   137  func (mock *{{$mock.MockName}}) {{.Name}}Calls() []struct {
   138  		{{- range .Params}}
   139  		{{.Name | Exported}} {{.TypeString}}
   140  		{{- end}}
   141  	} {
   142  	var calls []struct {
   143  		{{- range .Params}}
   144  		{{.Name | Exported}} {{.TypeString}}
   145  		{{- end}}
   146  	}
   147  	mock.lock{{.Name}}.RLock()
   148  	calls = mock.calls.{{.Name}}
   149  	mock.lock{{.Name}}.RUnlock()
   150  	return calls
   151  }
   152  {{end -}}
   153  {{end -}}`
   154  
   155  // This list comes from the golint codebase. Golint will complain about any of
   156  // these being mixed-case, like "Id" instead of "ID".
   157  var golintInitialisms = []string{
   158  	"ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS",
   159  	"QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "UID", "UUID", "URI",
   160  	"URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS",
   161  }
   162  
   163  var templateFuncs = template.FuncMap{
   164  	"ImportStatement": func(imprt *registry.Package) string {
   165  		if imprt.Alias == "" {
   166  			return `"` + imprt.Path() + `"`
   167  		}
   168  		return imprt.Alias + ` "` + imprt.Path() + `"`
   169  	},
   170  	"SyncPkgQualifier": func(imports []*registry.Package) string {
   171  		for _, imprt := range imports {
   172  			if imprt.Path() == "sync" {
   173  				return imprt.Qualifier()
   174  			}
   175  		}
   176  
   177  		return "sync"
   178  	},
   179  	"Exported": func(s string) string {
   180  		if s == "" {
   181  			return ""
   182  		}
   183  		for _, initialism := range golintInitialisms {
   184  			if strings.ToUpper(s) == initialism {
   185  				return initialism
   186  			}
   187  		}
   188  		return strings.ToUpper(s[0:1]) + s[1:]
   189  	},
   190  }