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 }