1
0

apiparser_test.go 7.3 KB

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