apiparser_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. package test
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
  10. )
  11. var (
  12. normalAPI = `
  13. syntax="v1"
  14. info (
  15. foo: bar
  16. )
  17. type Foo {
  18. Bar int
  19. }
  20. @server(
  21. foo: bar
  22. )
  23. service foo-api{
  24. @doc("foo")
  25. @handler foo
  26. post /foo (Foo) returns ([]int)
  27. }
  28. `
  29. missDeclarationAPI = `
  30. @server(
  31. foo: bar
  32. )
  33. service foo-api{
  34. @doc("foo")
  35. @handler foo
  36. post /foo (Foo) returns (Foo)
  37. }
  38. `
  39. missDeclarationInArrayAPI = `
  40. @server(
  41. foo: bar
  42. )
  43. service foo-api{
  44. @doc("foo")
  45. @handler foo
  46. post /foo returns ([]Foo)
  47. }
  48. `
  49. missDeclarationInArrayAPI2 = `
  50. @server(
  51. foo: bar
  52. )
  53. service foo-api{
  54. @doc("foo")
  55. @handler foo
  56. post /foo returns ([]*Foo)
  57. }
  58. `
  59. nestedAPIImport = `
  60. import "foo.api"
  61. `
  62. ambiguousSyntax = `
  63. syntax = "v2"
  64. `
  65. ambiguousService = `
  66. service bar-api{
  67. @handler foo
  68. post /foo
  69. }
  70. `
  71. duplicateHandler = `
  72. service bar-api{
  73. @handler foo
  74. post /foo
  75. }
  76. `
  77. duplicateRoute = `
  78. service bar-api{
  79. @handler bar
  80. post /foo
  81. }
  82. `
  83. duplicateType = `
  84. type Foo int
  85. `
  86. )
  87. func TestApiParser(t *testing.T) {
  88. t.Run("missDeclarationAPI", func(t *testing.T) {
  89. _, err := parser.ParseContent(missDeclarationAPI)
  90. assert.Error(t, err)
  91. fmt.Printf("%+v\n", err)
  92. })
  93. t.Run("missDeclarationAPI", func(t *testing.T) {
  94. _, err := parser.ParseContent(missDeclarationInArrayAPI)
  95. assert.Error(t, err)
  96. fmt.Printf("%+v\n", err)
  97. })
  98. t.Run("missDeclarationAPI", func(t *testing.T) {
  99. _, err := parser.ParseContent(missDeclarationInArrayAPI2)
  100. assert.Error(t, err)
  101. fmt.Printf("%+v\n", err)
  102. })
  103. t.Run("nestedImport", func(t *testing.T) {
  104. file := filepath.Join(t.TempDir(), "foo.api")
  105. err := ioutil.WriteFile(file, []byte(nestedAPIImport), os.ModePerm)
  106. if err != nil {
  107. return
  108. }
  109. _, err = parser.ParseContent(fmt.Sprintf(`import "%s"`, file))
  110. assert.Error(t, err)
  111. fmt.Printf("%+v\n", err)
  112. })
  113. t.Run("duplicateImport", func(t *testing.T) {
  114. _, err := parser.ParseContent(`
  115. import "foo.api"
  116. import "foo.api"
  117. `)
  118. assert.Error(t, err)
  119. })
  120. t.Run("duplicateKey", func(t *testing.T) {
  121. _, err := parser.ParseContent(`
  122. info (
  123. foo: bar
  124. foo: bar
  125. )
  126. `)
  127. assert.Error(t, err)
  128. })
  129. t.Run("ambiguousSyntax", func(t *testing.T) {
  130. file := filepath.Join(t.TempDir(), "foo.api")
  131. err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
  132. if err != nil {
  133. return
  134. }
  135. _, err = parser.ParseContent(fmt.Sprintf(`
  136. syntax = "v1"
  137. import "%s"`, file))
  138. assert.Error(t, err)
  139. fmt.Printf("%+v\n", err)
  140. })
  141. t.Run("ambiguousSyntax", func(t *testing.T) {
  142. file := filepath.Join(t.TempDir(), "foo.api")
  143. err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
  144. if err != nil {
  145. return
  146. }
  147. _, err = parser.ParseContent(fmt.Sprintf(`
  148. syntax = "v1"
  149. import "%s"`, file))
  150. assert.Error(t, err)
  151. fmt.Printf("%+v\n", err)
  152. })
  153. t.Run("ambiguousService", func(t *testing.T) {
  154. file := filepath.Join(t.TempDir(), "foo.api")
  155. err := ioutil.WriteFile(file, []byte(ambiguousService), os.ModePerm)
  156. if err != nil {
  157. return
  158. }
  159. _, err = parser.ParseContent(fmt.Sprintf(`
  160. import "%s"
  161. service foo-api{
  162. @handler foo
  163. post /foo
  164. }
  165. `, file))
  166. assert.Error(t, err)
  167. fmt.Printf("%+v\n", err)
  168. })
  169. t.Run("duplicateHandler", func(t *testing.T) {
  170. _, err := parser.ParseContent(`
  171. service foo-api{
  172. @handler foo
  173. post /foo
  174. @handler foo
  175. post /bar
  176. }
  177. `)
  178. assert.Error(t, err)
  179. file := filepath.Join(t.TempDir(), "foo.api")
  180. err = ioutil.WriteFile(file, []byte(duplicateHandler), os.ModePerm)
  181. if err != nil {
  182. return
  183. }
  184. _, err = parser.ParseContent(fmt.Sprintf(`
  185. import "%s"
  186. service bar-api{
  187. @handler foo
  188. post /foo
  189. }
  190. `, file))
  191. assert.Error(t, err)
  192. fmt.Printf("%+v\n", err)
  193. })
  194. t.Run("duplicateRoute", func(t *testing.T) {
  195. _, err := parser.ParseContent(`
  196. service foo-api{
  197. @handler foo
  198. post /foo
  199. @handler bar
  200. post /foo
  201. }
  202. `)
  203. assert.Error(t, err)
  204. file := filepath.Join(t.TempDir(), "foo.api")
  205. err = ioutil.WriteFile(file, []byte(duplicateRoute), os.ModePerm)
  206. if err != nil {
  207. return
  208. }
  209. _, err = parser.ParseContent(fmt.Sprintf(`
  210. import "%s"
  211. service bar-api{
  212. @handler foo
  213. post /foo
  214. }
  215. `, file))
  216. assert.Error(t, err)
  217. fmt.Printf("%+v\n", err)
  218. })
  219. t.Run("duplicateType", func(t *testing.T) {
  220. _, err := parser.ParseContent(`
  221. type Foo int
  222. type Foo bool
  223. `)
  224. assert.Error(t, err)
  225. file := filepath.Join(t.TempDir(), "foo.api")
  226. err = ioutil.WriteFile(file, []byte(duplicateType), os.ModePerm)
  227. if err != nil {
  228. return
  229. }
  230. _, err = parser.ParseContent(fmt.Sprintf(`
  231. import "%s"
  232. type Foo bool
  233. `, file))
  234. assert.Error(t, err)
  235. fmt.Printf("%+v\n", err)
  236. })
  237. t.Run("normal", func(t *testing.T) {
  238. v, err := parser.ParseContent(normalAPI)
  239. assert.Nil(t, err)
  240. body := &ast.Body{
  241. Lp: ast.NewTextExpr("("),
  242. Rp: ast.NewTextExpr(")"),
  243. Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
  244. }
  245. assert.True(t, v.Equal(&ast.Api{
  246. Syntax: &ast.SyntaxExpr{
  247. Syntax: ast.NewTextExpr("syntax"),
  248. Assign: ast.NewTextExpr("="),
  249. Version: ast.NewTextExpr(`"v1"`),
  250. },
  251. Info: &ast.InfoExpr{
  252. Info: ast.NewTextExpr("info"),
  253. Lp: ast.NewTextExpr("("),
  254. Rp: ast.NewTextExpr(")"),
  255. Kvs: []*ast.KvExpr{
  256. {
  257. Key: ast.NewTextExpr("foo"),
  258. Value: ast.NewTextExpr("bar"),
  259. },
  260. },
  261. },
  262. Type: []ast.TypeExpr{
  263. &ast.TypeStruct{
  264. Name: ast.NewTextExpr("Foo"),
  265. LBrace: ast.NewTextExpr("{"),
  266. RBrace: ast.NewTextExpr("}"),
  267. Fields: []*ast.TypeField{
  268. {
  269. Name: ast.NewTextExpr("Bar"),
  270. DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
  271. },
  272. },
  273. },
  274. },
  275. Service: []*ast.Service{
  276. {
  277. AtServer: &ast.AtServer{
  278. AtServerToken: ast.NewTextExpr("@server"),
  279. Lp: ast.NewTextExpr("("),
  280. Rp: ast.NewTextExpr(")"),
  281. Kv: []*ast.KvExpr{
  282. {
  283. Key: ast.NewTextExpr("foo"),
  284. Value: ast.NewTextExpr("bar"),
  285. },
  286. },
  287. },
  288. ServiceApi: &ast.ServiceApi{
  289. ServiceToken: ast.NewTextExpr("service"),
  290. Name: ast.NewTextExpr("foo-api"),
  291. Lbrace: ast.NewTextExpr("{"),
  292. Rbrace: ast.NewTextExpr("}"),
  293. ServiceRoute: []*ast.ServiceRoute{
  294. {
  295. AtDoc: &ast.AtDoc{
  296. AtDocToken: ast.NewTextExpr("@doc"),
  297. Lp: ast.NewTextExpr("("),
  298. Rp: ast.NewTextExpr(")"),
  299. LineDoc: ast.NewTextExpr(`"foo"`),
  300. },
  301. AtHandler: &ast.AtHandler{
  302. AtHandlerToken: ast.NewTextExpr("@handler"),
  303. Name: ast.NewTextExpr("foo"),
  304. },
  305. Route: &ast.Route{
  306. Method: ast.NewTextExpr("post"),
  307. Path: ast.NewTextExpr("/foo"),
  308. Req: body,
  309. ReturnToken: ast.NewTextExpr("returns"),
  310. Reply: &ast.Body{
  311. Lp: ast.NewTextExpr("("),
  312. Rp: ast.NewTextExpr(")"),
  313. Name: &ast.Array{
  314. ArrayExpr: ast.NewTextExpr("[]int"),
  315. LBrack: ast.NewTextExpr("["),
  316. RBrack: ast.NewTextExpr("]"),
  317. Literal: &ast.Literal{Literal: ast.NewTextExpr("int")},
  318. },
  319. },
  320. },
  321. },
  322. },
  323. },
  324. },
  325. },
  326. }))
  327. })
  328. }