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 }