parse_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. package parser_test
  2. import (
  3. "bytes"
  4. "path"
  5. "path/filepath"
  6. "reflect"
  7. "testing"
  8. "text/template"
  9. "go-common/app/tool/gengo/args"
  10. "go-common/app/tool/gengo/namer"
  11. "go-common/app/tool/gengo/parser"
  12. "go-common/app/tool/gengo/types"
  13. )
  14. func TestRecursive(t *testing.T) {
  15. d := args.Default()
  16. d.InputDirs = []string{"go-common/app/tool/gengo/testdata/a/..."}
  17. b, err := d.NewBuilder()
  18. if err != nil {
  19. t.Fatalf("Fail making builder: %v", err)
  20. }
  21. _, err = b.FindTypes()
  22. if err != nil {
  23. t.Fatalf("Fail finding types: %v", err)
  24. }
  25. foundB := false
  26. for _, p := range b.FindPackages() {
  27. t.Logf("Package: %v", p)
  28. if p == "go-common/app/tool/gengo/testdata/a/b" {
  29. foundB = true
  30. }
  31. }
  32. if !foundB {
  33. t.Errorf("Expected to find packages a and b")
  34. }
  35. }
  36. type file struct {
  37. path string
  38. contents string
  39. }
  40. // Pass files in topological order - deps first!
  41. func construct(t *testing.T, files []file, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) {
  42. b := parser.New()
  43. for _, f := range files {
  44. if err := b.AddFileForTest(path.Dir(f.path), filepath.FromSlash(f.path), []byte(f.contents)); err != nil {
  45. t.Fatal(err)
  46. }
  47. }
  48. u, err := b.FindTypes()
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. orderer := namer.Orderer{Namer: testNamer}
  53. o := orderer.OrderUniverse(u)
  54. return b, u, o
  55. }
  56. func TestBuilder(t *testing.T) {
  57. var testFiles = []file{
  58. {
  59. path: "base/common/proto/common.go", contents: `
  60. package common
  61. type Object struct {
  62. ID int64
  63. }
  64. `,
  65. }, {
  66. path: "base/foo/proto/foo.go", contents: `
  67. package foo
  68. import (
  69. "base/common/proto"
  70. )
  71. type Blah struct {
  72. common.Object
  73. Count int64
  74. Frobbers map[string]*Frobber
  75. Baz []Object
  76. Nickname *string
  77. NumberIsAFavorite map[int]bool
  78. }
  79. type Frobber struct {
  80. Name string
  81. Amount int64
  82. }
  83. type Object struct {
  84. common.Object
  85. }
  86. func AFunc(obj1 common.Object, obj2 Object) Frobber {
  87. }
  88. var AVar Frobber
  89. var (
  90. AnotherVar = Frobber{}
  91. )
  92. `,
  93. },
  94. }
  95. var tmplText = `
  96. package o
  97. {{define "Struct"}}type {{Name .}} interface { {{range $m := .Members}}{{$n := Name $m.Type}}
  98. {{if $m.Embedded}}{{$n}}{{else}}{{$m.Name}}() {{$n}}{{if $m.Type.Elem}}{{else}}
  99. Set{{$m.Name}}({{$n}}){{end}}{{end}}{{end}}
  100. }
  101. {{end}}
  102. {{define "Func"}}{{$s := .Underlying.Signature}}var {{Name .}} func({{range $index,$elem := $s.Parameters}}{{if $index}}, {{end}}{{Raw $elem}}{{end}}) {{if $s.Results|len |gt 1}}({{end}}{{range $index,$elem := $s.Results}}{{if $index}}, {{end}}{{Raw .}}{{end}}{{if $s.Results|len |gt 1}}){{end}} = {{Raw .}}
  103. {{end}}
  104. {{define "Var"}}{{$t := .Underlying}}var {{Name .}} {{Raw $t}} = {{Raw .}}
  105. {{end}}
  106. {{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{end}}
  107. {{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if eq $t.Underlying.Kind "Func"}}{{template "Func" $t}}{{end}}{{end}}{{end}}
  108. {{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if ne $t.Underlying.Kind "Func"}}{{template "Var" $t}}{{end}}{{end}}{{end}}`
  109. var expect = `
  110. package o
  111. type CommonObject interface {
  112. ID() Int64
  113. SetID(Int64)
  114. }
  115. type FooBlah interface {
  116. CommonObject
  117. Count() Int64
  118. SetCount(Int64)
  119. Frobbers() MapStringToPointerFooFrobber
  120. Baz() SliceFooObject
  121. Nickname() PointerString
  122. NumberIsAFavorite() MapIntToBool
  123. }
  124. type FooFrobber interface {
  125. Name() String
  126. SetName(String)
  127. Amount() Int64
  128. SetAmount(Int64)
  129. }
  130. type FooObject interface {
  131. CommonObject
  132. }
  133. var FooAFunc func(proto.Object, proto.Object) proto.Frobber = proto.AFunc
  134. var FooAVar proto.Frobber = proto.AVar
  135. var FooAnotherVar proto.Frobber = proto.AnotherVar
  136. `
  137. testNamer := namer.NewPublicNamer(1, "proto")
  138. rawNamer := namer.NewRawNamer("o", nil)
  139. _, u, o := construct(t, testFiles, testNamer)
  140. t.Logf("\n%v\n\n", o)
  141. args := map[string]interface{}{
  142. "Name": testNamer.Name,
  143. "Raw": rawNamer.Name,
  144. }
  145. tmpl := template.Must(
  146. template.New("").
  147. Funcs(args).
  148. Parse(tmplText),
  149. )
  150. buf := &bytes.Buffer{}
  151. tmpl.Execute(buf, o)
  152. if e, a := expect, buf.String(); e != a {
  153. t.Errorf("Wanted, got:\n%v\n-----\n%v\n", e, a)
  154. }
  155. if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") {
  156. t.Errorf("Unexpected lack of import line: %s", p.Imports)
  157. }
  158. }
  159. func TestStructParse(t *testing.T) {
  160. var structTest = file{
  161. path: "base/foo/proto/foo.go",
  162. contents: `
  163. package foo
  164. // Blah is a test.
  165. // A test, I tell you.
  166. type Blah struct {
  167. // A is the first field.
  168. A int64 ` + "`" + `json:"a"` + "`" + `
  169. // B is the second field.
  170. // Multiline comments work.
  171. B string ` + "`" + `json:"b"` + "`" + `
  172. }
  173. `,
  174. }
  175. _, u, o := construct(t, []file{structTest}, namer.NewPublicNamer(0))
  176. t.Logf("%#v", o)
  177. blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"})
  178. if blahT == nil {
  179. t.Fatal("type not found")
  180. }
  181. if e, a := types.Struct, blahT.Kind; e != a {
  182. t.Errorf("struct kind wrong, wanted %v, got %v", e, a)
  183. }
  184. if e, a := []string{"Blah is a test.", "A test, I tell you."}, blahT.CommentLines; !reflect.DeepEqual(e, a) {
  185. t.Errorf("struct comment wrong, wanted %q, got %q", e, a)
  186. }
  187. m := types.Member{
  188. Name: "B",
  189. Embedded: false,
  190. CommentLines: []string{"B is the second field.", "Multiline comments work."},
  191. Tags: `json:"b"`,
  192. Type: types.String,
  193. }
  194. if e, a := m, blahT.Members[1]; !reflect.DeepEqual(e, a) {
  195. t.Errorf("wanted, got:\n%#v\n%#v", e, a)
  196. }
  197. }
  198. func TestParseSecondClosestCommentLines(t *testing.T) {
  199. const fileName = "base/foo/proto/foo.go"
  200. testCases := []struct {
  201. testFile file
  202. expected []string
  203. }{
  204. {
  205. testFile: file{
  206. path: fileName, contents: `
  207. package foo
  208. // Blah's SecondClosestCommentLines.
  209. // Another line.
  210. // Blah is a test.
  211. // A test, I tell you.
  212. type Blah struct {
  213. a int
  214. }
  215. `},
  216. expected: []string{"Blah's SecondClosestCommentLines.", "Another line."},
  217. },
  218. {
  219. testFile: file{
  220. path: fileName, contents: `
  221. package foo
  222. // Blah's SecondClosestCommentLines.
  223. // Another line.
  224. type Blah struct {
  225. a int
  226. }
  227. `},
  228. expected: []string{"Blah's SecondClosestCommentLines.", "Another line."},
  229. },
  230. }
  231. for _, test := range testCases {
  232. _, u, o := construct(t, []file{test.testFile}, namer.NewPublicNamer(0))
  233. t.Logf("%#v", o)
  234. blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"})
  235. if e, a := test.expected, blahT.SecondClosestCommentLines; !reflect.DeepEqual(e, a) {
  236. t.Errorf("struct second closest comment wrong, wanted %q, got %q", e, a)
  237. }
  238. }
  239. }
  240. func TestTypeKindParse(t *testing.T) {
  241. var testFiles = []file{
  242. {path: "a/foo.go", contents: "package a\ntype Test string\n"},
  243. {path: "b/foo.go", contents: "package b\ntype Test map[int]string\n"},
  244. {path: "c/foo.go", contents: "package c\ntype Test []string\n"},
  245. {path: "d/foo.go", contents: "package d\ntype Test struct{a int; b struct{a int}; c map[int]string; d *string}\n"},
  246. {path: "e/foo.go", contents: "package e\ntype Test *string\n"},
  247. {path: "f/foo.go", contents: `
  248. package f
  249. import (
  250. "a"
  251. "b"
  252. )
  253. type Test []a.Test
  254. type Test2 *a.Test
  255. type Test3 map[a.Test]b.Test
  256. type Test4 struct {
  257. a struct {a a.Test; b b.Test}
  258. b map[a.Test]b.Test
  259. c *a.Test
  260. d []a.Test
  261. e []string
  262. }
  263. `},
  264. {path: "g/foo.go", contents: `
  265. package g
  266. type Test func(a, b string) (c, d string)
  267. func (t Test) Method(a, b string) (c, d string) { return t(a, b) }
  268. type Interface interface{Method(a, b string) (c, d string)}
  269. `},
  270. }
  271. // Check that the right types are found, and the namers give the expected names.
  272. assertions := []struct {
  273. Package, Name string
  274. k types.Kind
  275. names []string
  276. }{
  277. {
  278. Package: "a", Name: "Test", k: types.Alias,
  279. names: []string{"Test", "ATest", "test", "aTest", "a.Test"},
  280. },
  281. {
  282. Package: "b", Name: "Test", k: types.Map,
  283. names: []string{"Test", "BTest", "test", "bTest", "b.Test"},
  284. },
  285. {
  286. Package: "c", Name: "Test", k: types.Slice,
  287. names: []string{"Test", "CTest", "test", "cTest", "c.Test"},
  288. },
  289. {
  290. Package: "d", Name: "Test", k: types.Struct,
  291. names: []string{"Test", "DTest", "test", "dTest", "d.Test"},
  292. },
  293. {
  294. Package: "e", Name: "Test", k: types.Pointer,
  295. names: []string{"Test", "ETest", "test", "eTest", "e.Test"},
  296. },
  297. {
  298. Package: "f", Name: "Test", k: types.Slice,
  299. names: []string{"Test", "FTest", "test", "fTest", "f.Test"},
  300. },
  301. {
  302. Package: "g", Name: "Test", k: types.Func,
  303. names: []string{"Test", "GTest", "test", "gTest", "g.Test"},
  304. },
  305. {
  306. Package: "g", Name: "Interface", k: types.Interface,
  307. names: []string{"Interface", "GInterface", "interface", "gInterface", "g.Interface"},
  308. },
  309. {
  310. Package: "", Name: "string", k: types.Builtin,
  311. names: []string{"String", "String", "string", "string", "string"},
  312. },
  313. {
  314. Package: "", Name: "int", k: types.Builtin,
  315. names: []string{"Int", "Int", "int", "int", "int"},
  316. },
  317. {
  318. Package: "", Name: "struct{a int}", k: types.Struct,
  319. names: []string{"StructInt", "StructInt", "structInt", "structInt", "struct{a int}"},
  320. },
  321. {
  322. Package: "", Name: "struct{a a.Test; b b.Test}", k: types.Struct,
  323. names: []string{"StructTestTest", "StructATestBTest", "structTestTest", "structATestBTest", "struct{a a.Test; b b.Test}"},
  324. },
  325. {
  326. Package: "", Name: "map[int]string", k: types.Map,
  327. names: []string{"MapIntToString", "MapIntToString", "mapIntToString", "mapIntToString", "map[int]string"},
  328. },
  329. {
  330. Package: "", Name: "map[a.Test]b.Test", k: types.Map,
  331. names: []string{"MapTestToTest", "MapATestToBTest", "mapTestToTest", "mapATestToBTest", "map[a.Test]b.Test"},
  332. },
  333. {
  334. Package: "", Name: "[]string", k: types.Slice,
  335. names: []string{"SliceString", "SliceString", "sliceString", "sliceString", "[]string"},
  336. },
  337. {
  338. Package: "", Name: "[]a.Test", k: types.Slice,
  339. names: []string{"SliceTest", "SliceATest", "sliceTest", "sliceATest", "[]a.Test"},
  340. },
  341. {
  342. Package: "", Name: "*string", k: types.Pointer,
  343. names: []string{"PointerString", "PointerString", "pointerString", "pointerString", "*string"},
  344. },
  345. {
  346. Package: "", Name: "*a.Test", k: types.Pointer,
  347. names: []string{"PointerTest", "PointerATest", "pointerTest", "pointerATest", "*a.Test"},
  348. },
  349. }
  350. namers := []namer.Namer{
  351. namer.NewPublicNamer(0),
  352. namer.NewPublicNamer(1),
  353. namer.NewPrivateNamer(0),
  354. namer.NewPrivateNamer(1),
  355. namer.NewRawNamer("", nil),
  356. }
  357. for nameIndex, namer := range namers {
  358. _, u, _ := construct(t, testFiles, namer)
  359. t.Logf("Found types:\n")
  360. for pkgName, pkg := range u {
  361. for typeName, cur := range pkg.Types {
  362. t.Logf("%q-%q: %s %s", pkgName, typeName, cur.Name, cur.Kind)
  363. }
  364. }
  365. t.Logf("\n\n")
  366. for _, item := range assertions {
  367. n := types.Name{Package: item.Package, Name: item.Name}
  368. thisType := u.Type(n)
  369. if thisType == nil {
  370. t.Errorf("type %s not found", n)
  371. continue
  372. }
  373. underlyingType := thisType
  374. if item.k != types.Alias && thisType.Kind == types.Alias {
  375. underlyingType = thisType.Underlying
  376. if underlyingType == nil {
  377. t.Errorf("underlying type %s not found", n)
  378. continue
  379. }
  380. }
  381. if e, a := item.k, underlyingType.Kind; e != a {
  382. t.Errorf("%v-%s: type kind wrong, wanted %v, got %v (%#v)", nameIndex, n, e, a, underlyingType)
  383. }
  384. if e, a := item.names[nameIndex], namer.Name(thisType); e != a {
  385. t.Errorf("%v-%s: Expected %q, got %q", nameIndex, n, e, a)
  386. }
  387. }
  388. // Also do some one-off checks
  389. gtest := u.Type(types.Name{Package: "g", Name: "Test"})
  390. if e, a := 1, len(gtest.Methods); e != a {
  391. t.Errorf("expected %v but found %v methods: %#v", e, a, gtest)
  392. }
  393. iface := u.Type(types.Name{Package: "g", Name: "Interface"})
  394. if e, a := 1, len(iface.Methods); e != a {
  395. t.Errorf("expected %v but found %v methods: %#v", e, a, iface)
  396. }
  397. }
  398. }