You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

270 lines
7.0 KiB

  1. package main
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. "testing"
  7. "github.com/golang/mock/mockgen/model"
  8. )
  9. func TestMakeArgString(t *testing.T) {
  10. testCases := []struct {
  11. argNames []string
  12. argTypes []string
  13. argString string
  14. }{
  15. {
  16. argNames: nil,
  17. argTypes: nil,
  18. argString: "",
  19. },
  20. {
  21. argNames: []string{"arg0"},
  22. argTypes: []string{"int"},
  23. argString: "arg0 int",
  24. },
  25. {
  26. argNames: []string{"arg0", "arg1"},
  27. argTypes: []string{"int", "bool"},
  28. argString: "arg0 int, arg1 bool",
  29. },
  30. {
  31. argNames: []string{"arg0", "arg1"},
  32. argTypes: []string{"int", "int"},
  33. argString: "arg0, arg1 int",
  34. },
  35. {
  36. argNames: []string{"arg0", "arg1", "arg2"},
  37. argTypes: []string{"bool", "int", "int"},
  38. argString: "arg0 bool, arg1, arg2 int",
  39. },
  40. {
  41. argNames: []string{"arg0", "arg1", "arg2"},
  42. argTypes: []string{"int", "bool", "int"},
  43. argString: "arg0 int, arg1 bool, arg2 int",
  44. },
  45. {
  46. argNames: []string{"arg0", "arg1", "arg2"},
  47. argTypes: []string{"int", "int", "bool"},
  48. argString: "arg0, arg1 int, arg2 bool",
  49. },
  50. {
  51. argNames: []string{"arg0", "arg1", "arg2"},
  52. argTypes: []string{"int", "int", "int"},
  53. argString: "arg0, arg1, arg2 int",
  54. },
  55. {
  56. argNames: []string{"arg0", "arg1", "arg2", "arg3"},
  57. argTypes: []string{"bool", "int", "int", "int"},
  58. argString: "arg0 bool, arg1, arg2, arg3 int",
  59. },
  60. {
  61. argNames: []string{"arg0", "arg1", "arg2", "arg3"},
  62. argTypes: []string{"int", "bool", "int", "int"},
  63. argString: "arg0 int, arg1 bool, arg2, arg3 int",
  64. },
  65. {
  66. argNames: []string{"arg0", "arg1", "arg2", "arg3"},
  67. argTypes: []string{"int", "int", "bool", "int"},
  68. argString: "arg0, arg1 int, arg2 bool, arg3 int",
  69. },
  70. {
  71. argNames: []string{"arg0", "arg1", "arg2", "arg3"},
  72. argTypes: []string{"int", "int", "int", "bool"},
  73. argString: "arg0, arg1, arg2 int, arg3 bool",
  74. },
  75. {
  76. argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
  77. argTypes: []string{"bool", "int", "int", "int", "bool"},
  78. argString: "arg0 bool, arg1, arg2, arg3 int, arg4 bool",
  79. },
  80. {
  81. argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
  82. argTypes: []string{"int", "bool", "int", "int", "bool"},
  83. argString: "arg0 int, arg1 bool, arg2, arg3 int, arg4 bool",
  84. },
  85. {
  86. argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
  87. argTypes: []string{"int", "int", "bool", "int", "bool"},
  88. argString: "arg0, arg1 int, arg2 bool, arg3 int, arg4 bool",
  89. },
  90. {
  91. argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
  92. argTypes: []string{"int", "int", "int", "bool", "bool"},
  93. argString: "arg0, arg1, arg2 int, arg3, arg4 bool",
  94. },
  95. {
  96. argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
  97. argTypes: []string{"int", "int", "bool", "bool", "int"},
  98. argString: "arg0, arg1 int, arg2, arg3 bool, arg4 int",
  99. },
  100. }
  101. for i, tc := range testCases {
  102. t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  103. s := makeArgString(tc.argNames, tc.argTypes)
  104. if s != tc.argString {
  105. t.Errorf("result == %q, want %q", s, tc.argString)
  106. }
  107. })
  108. }
  109. }
  110. func TestNewIdentifierAllocator(t *testing.T) {
  111. a := newIdentifierAllocator([]string{"taken1", "taken2"})
  112. if len(a) != 2 {
  113. t.Fatalf("expected 2 items, got %v", len(a))
  114. }
  115. _, ok := a["taken1"]
  116. if !ok {
  117. t.Errorf("allocator doesn't contain 'taken1': %#v", a)
  118. }
  119. _, ok = a["taken2"]
  120. if !ok {
  121. t.Errorf("allocator doesn't contain 'taken2': %#v", a)
  122. }
  123. }
  124. func allocatorContainsIdentifiers(a identifierAllocator, ids []string) bool {
  125. if len(a) != len(ids) {
  126. return false
  127. }
  128. for _, id := range ids {
  129. _, ok := a[id]
  130. if !ok {
  131. return false
  132. }
  133. }
  134. return true
  135. }
  136. func TestIdentifierAllocator_allocateIdentifier(t *testing.T) {
  137. a := newIdentifierAllocator([]string{"taken"})
  138. t2 := a.allocateIdentifier("taken_2")
  139. if t2 != "taken_2" {
  140. t.Fatalf("expected 'taken_2', got %q", t2)
  141. }
  142. expected := []string{"taken", "taken_2"}
  143. if !allocatorContainsIdentifiers(a, expected) {
  144. t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
  145. }
  146. t3 := a.allocateIdentifier("taken")
  147. if t3 != "taken_3" {
  148. t.Fatalf("expected 'taken_3', got %q", t3)
  149. }
  150. expected = []string{"taken", "taken_2", "taken_3"}
  151. if !allocatorContainsIdentifiers(a, expected) {
  152. t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
  153. }
  154. t4 := a.allocateIdentifier("taken")
  155. if t4 != "taken_4" {
  156. t.Fatalf("expected 'taken_4', got %q", t4)
  157. }
  158. expected = []string{"taken", "taken_2", "taken_3", "taken_4"}
  159. if !allocatorContainsIdentifiers(a, expected) {
  160. t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
  161. }
  162. id := a.allocateIdentifier("id")
  163. if id != "id" {
  164. t.Fatalf("expected 'id', got %q", id)
  165. }
  166. expected = []string{"taken", "taken_2", "taken_3", "taken_4", "id"}
  167. if !allocatorContainsIdentifiers(a, expected) {
  168. t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
  169. }
  170. }
  171. func TestGenerateMockInterface_Helper(t *testing.T) {
  172. for _, test := range []struct {
  173. Name string
  174. Identifier string
  175. HelperLine string
  176. Methods []*model.Method
  177. }{
  178. {Name: "mock", Identifier: "MockSomename", HelperLine: "m.ctrl.T.Helper()"},
  179. {Name: "recorder", Identifier: "MockSomenameMockRecorder", HelperLine: "mr.mock.ctrl.T.Helper()"},
  180. {
  181. Name: "mock identifier conflict",
  182. Identifier: "MockSomename",
  183. HelperLine: "m_2.ctrl.T.Helper()",
  184. Methods: []*model.Method{
  185. {
  186. Name: "MethodA",
  187. In: []*model.Parameter{
  188. {
  189. Name: "m",
  190. Type: &model.NamedType{Type: "int"},
  191. },
  192. },
  193. },
  194. },
  195. },
  196. {
  197. Name: "recorder identifier conflict",
  198. Identifier: "MockSomenameMockRecorder",
  199. HelperLine: "mr_2.mock.ctrl.T.Helper()",
  200. Methods: []*model.Method{
  201. {
  202. Name: "MethodA",
  203. In: []*model.Parameter{
  204. {
  205. Name: "mr",
  206. Type: &model.NamedType{Type: "int"},
  207. },
  208. },
  209. },
  210. },
  211. },
  212. } {
  213. t.Run(test.Name, func(t *testing.T) {
  214. g := generator{}
  215. if len(test.Methods) == 0 {
  216. test.Methods = []*model.Method{
  217. {Name: "MethodA"},
  218. {Name: "MethodB"},
  219. }
  220. }
  221. if err := g.GenerateMockInterface(&model.Interface{
  222. Name: "Somename",
  223. Methods: test.Methods,
  224. }, "somepackage"); err != nil {
  225. t.Fatal(err)
  226. }
  227. lines := strings.Split(g.buf.String(), "\n")
  228. // T.Helper() should be the first line
  229. for _, method := range test.Methods {
  230. if strings.TrimSpace(lines[findMethod(t, test.Identifier, method.Name, lines)+1]) != test.HelperLine {
  231. t.Fatalf("method %s.%s did not declare itself a Helper method", test.Identifier, method.Name)
  232. }
  233. }
  234. })
  235. }
  236. }
  237. func findMethod(t *testing.T, identifier, methodName string, lines []string) int {
  238. t.Helper()
  239. r := regexp.MustCompile(fmt.Sprintf(`func\s+\(.+%s\)\s*%s`, identifier, methodName))
  240. for i, line := range lines {
  241. if r.MatchString(line) {
  242. return i
  243. }
  244. }
  245. t.Fatalf("unable to find 'func (m %s) %s'", identifier, methodName)
  246. panic("unreachable")
  247. }