-
Notifications
You must be signed in to change notification settings - Fork 1
/
gen.go
136 lines (115 loc) · 3.19 KB
/
gen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package gomocker
import (
"fmt"
"io"
"strings"
"github.com/dave/jennifer/jen"
"github.com/jauhararifin/gotype"
)
type generateMockerOption struct {
outputPackagePath string
}
type GenerateMockerOption func(option *generateMockerOption)
func WithOutputPackagePath(outputPackagePath string) GenerateMockerOption {
return func(option *generateMockerOption) {
option.outputPackagePath = outputPackagePath
}
}
type mockerGenerator struct {
funcMockerGenerator interface {
GenerateFunctionMocker(
name string,
funcType gotype.FuncType,
withConstructor bool,
) jen.Code
}
interfaceMockerGenerator interface {
GenerateInterfaceMocker(
name string,
interfaceType gotype.InterfaceType,
) jen.Code
}
}
func (m *mockerGenerator) GenerateMocker(
specs []gotype.TypeSpec,
w io.Writer,
options ...GenerateMockerOption,
) error {
option := m.initOption(options...)
file := m.createCodeGenFile(option)
types, err := gotype.GenerateTypesFromSpecs(specs...)
if err != nil {
return err
}
for i, typ := range types {
file.Add(m.generateEntityMockerByName(option, typ, specs[i].Name)).Line().Line()
}
return file.Render(w)
}
func (m *mockerGenerator) initOption(options ...GenerateMockerOption) *generateMockerOption {
option := &generateMockerOption{}
for _, opt := range options {
opt(option)
}
return option
}
func (m *mockerGenerator) createCodeGenFile(option *generateMockerOption) *jen.File {
outputPackagePath := "mock"
if option.outputPackagePath != "" {
outputPackagePath = option.outputPackagePath
}
packageName := m.generatePackageName(outputPackagePath)
file := jen.NewFilePathName(outputPackagePath, packageName)
file.HeaderComment("Code generated by gomocker " + gomockerPath + ". DO NOT EDIT.")
return file
}
func (m *mockerGenerator) generatePackageName(packagePath string) string {
name := packagePath
if strings.HasSuffix(name, "/") {
name = name[:len(name)-1]
}
if strings.Contains(name, "/") {
name = name[strings.LastIndex(name, "/")+1:]
}
return name
}
func (m *mockerGenerator) generateEntityMockerByName(
option *generateMockerOption,
typ gotype.Type,
name string,
) jen.Code {
if typ.FuncType != nil {
return m.funcMockerGenerator.GenerateFunctionMocker(name, *typ.FuncType, true)
}
if typ.InterfaceType != nil {
return m.interfaceMockerGenerator.GenerateInterfaceMocker(name, *typ.InterfaceType)
}
panic(fmt.Errorf("only supported interface and function"))
}
func (m *mockerGenerator) generateFunctionMocker(
funcName string,
funcType gotype.FuncType,
mockerNamer FuncMockerNamer,
) jen.Code {
funcMockerGenerator := funcMockerGeneratorHelper{
funcName: funcName,
funcType: funcType,
mockerNamer: mockerNamer,
withConstructor: true,
}
return funcMockerGenerator.generate()
}
func (m *mockerGenerator) generateInterfaceMocker(
interfaceName string,
interfaceType gotype.InterfaceType,
funcMockerNamer FuncMockerNamer,
interfaceMockerNamer InterfaceMockerNamer,
) jen.Code {
generator := &interfaceMockerGeneratorHelper{
interfaceName: interfaceName,
interfaceType: interfaceType,
funcMockerNamer: funcMockerNamer,
interfaceMockerNamer: interfaceMockerNamer,
}
return generator.generate()
}