feature: refactor api parse to g4 (#365)
* feature: refactor api parse to g4 * new g4 parser * add CHANGE_LOG.MD * refactor * fix byte bug * refactor * optimized * optimized * revert * update readme.md * update readme.md * update readme.md * update readme.md * remove no need * fix java gen * add upgrade * resolve confilits Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
This commit is contained in:
369
tools/goctl/api/parser/g4/test/apiparser_test.go
Normal file
369
tools/goctl/api/parser/g4/test/apiparser_test.go
Normal file
@@ -0,0 +1,369 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
)
|
||||
|
||||
var (
|
||||
normalApi = `
|
||||
syntax="v1"
|
||||
|
||||
info (
|
||||
foo: bar
|
||||
)
|
||||
|
||||
type Foo {
|
||||
Bar int
|
||||
}
|
||||
|
||||
@server(
|
||||
foo: bar
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
@handler foo
|
||||
post /foo (Foo) returns ([]int)
|
||||
}
|
||||
`
|
||||
missDeclarationApi = `
|
||||
@server(
|
||||
foo: bar
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
@handler foo
|
||||
post /foo (Foo) returns (Foo)
|
||||
}
|
||||
`
|
||||
|
||||
missDeclarationInArrayApi = `
|
||||
@server(
|
||||
foo: bar
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
@handler foo
|
||||
post /foo returns ([]Foo)
|
||||
}
|
||||
`
|
||||
|
||||
missDeclarationInArrayApi2 = `
|
||||
@server(
|
||||
foo: bar
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
@handler foo
|
||||
post /foo returns ([]*Foo)
|
||||
}
|
||||
`
|
||||
|
||||
nestedApiImport = `
|
||||
import "foo.api"
|
||||
`
|
||||
|
||||
ambiguousSyntax = `
|
||||
syntax = "v2"
|
||||
`
|
||||
|
||||
ambiguousService = `
|
||||
service bar-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
}
|
||||
`
|
||||
duplicateHandler = `
|
||||
service bar-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
}
|
||||
`
|
||||
|
||||
duplicateRoute = `
|
||||
service bar-api{
|
||||
@handler bar
|
||||
post /foo
|
||||
}
|
||||
`
|
||||
|
||||
duplicateType = `
|
||||
type Foo int
|
||||
`
|
||||
)
|
||||
|
||||
func TestApiParser(t *testing.T) {
|
||||
t.Run("missDeclarationApi", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(missDeclarationApi)
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("missDeclarationApi", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(missDeclarationInArrayApi)
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("missDeclarationApi", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(missDeclarationInArrayApi2)
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("nestedImport", func(t *testing.T) {
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err := ioutil.WriteFile(file, []byte(nestedApiImport), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`import "%s"`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("duplicateImport", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(`
|
||||
import "foo.api"
|
||||
import "foo.api"
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("duplicateKey", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(`
|
||||
info (
|
||||
foo: bar
|
||||
foo: bar
|
||||
)
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("ambiguousSyntax", func(t *testing.T) {
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
syntax = "v1"
|
||||
import "%s"`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("ambiguousSyntax", func(t *testing.T) {
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
syntax = "v1"
|
||||
import "%s"`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("ambiguousService", func(t *testing.T) {
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err := ioutil.WriteFile(file, []byte(ambiguousService), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
import "%s"
|
||||
|
||||
service foo-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
}
|
||||
`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("duplicateHandler", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(`
|
||||
service foo-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
|
||||
@handler foo
|
||||
post /bar
|
||||
}
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err = ioutil.WriteFile(file, []byte(duplicateHandler), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
import "%s"
|
||||
service bar-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
}
|
||||
`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("duplicateRoute", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(`
|
||||
service foo-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
|
||||
@handler bar
|
||||
post /foo
|
||||
}
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err = ioutil.WriteFile(file, []byte(duplicateRoute), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
import "%s"
|
||||
service bar-api{
|
||||
@handler foo
|
||||
post /foo
|
||||
}
|
||||
`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("duplicateType", func(t *testing.T) {
|
||||
_, err := parser.ParseContent(`
|
||||
type Foo int
|
||||
type Foo bool
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
file := filepath.Join(t.TempDir(), "foo.api")
|
||||
err = ioutil.WriteFile(file, []byte(duplicateType), os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(fmt.Sprintf(`
|
||||
import "%s"
|
||||
|
||||
type Foo bool
|
||||
`, file))
|
||||
assert.Error(t, err)
|
||||
fmt.Printf("%+v\n", err)
|
||||
})
|
||||
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.ParseContent(normalApi)
|
||||
assert.Nil(t, err)
|
||||
body := &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
}
|
||||
|
||||
assert.True(t, v.Equal(&ast.Api{
|
||||
Syntax: &ast.SyntaxExpr{
|
||||
Syntax: ast.NewTextExpr("syntax"),
|
||||
Assign: ast.NewTextExpr("="),
|
||||
Version: ast.NewTextExpr(`"v1"`),
|
||||
},
|
||||
Info: &ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: []ast.TypeExpr{
|
||||
&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Service: []*ast.Service{
|
||||
{
|
||||
AtServer: &ast.AtServer{
|
||||
AtServerToken: ast.NewTextExpr("@server"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
ServiceApi: &ast.ServiceApi{
|
||||
ServiceToken: ast.NewTextExpr("service"),
|
||||
Name: ast.NewTextExpr("foo-api"),
|
||||
Lbrace: ast.NewTextExpr("{"),
|
||||
Rbrace: ast.NewTextExpr("}"),
|
||||
ServiceRoute: []*ast.ServiceRoute{
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: body,
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]int"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
0
tools/goctl/api/parser/g4/test/apis/empty.api
Normal file
0
tools/goctl/api/parser/g4/test/apis/empty.api
Normal file
72
tools/goctl/api/parser/g4/test/apis/example.api
Normal file
72
tools/goctl/api/parser/g4/test/apis/example.api
Normal file
@@ -0,0 +1,72 @@
|
||||
// syntax: specify the api syntax version,
|
||||
// through this version can be a good control
|
||||
// api syntax upgrade incompatibility issues
|
||||
syntax = "v1"
|
||||
|
||||
// Info block is a key-value pair description body,
|
||||
// you can add some descriptions of the current api
|
||||
// file through this description body, you can add
|
||||
// any key-value pair, which does not participate in the api generation
|
||||
info(
|
||||
title: sample of api
|
||||
desc: "you can add a newline
|
||||
description by quotes"
|
||||
author: songmeizi
|
||||
anyAnotherKey: anyTnotherValue
|
||||
)
|
||||
|
||||
// The structure in the api evolved from the structure of golang,
|
||||
// and it is also reserved to support the structure of golang.
|
||||
|
||||
// a golang structure
|
||||
type Foo struct{
|
||||
Foo int
|
||||
}
|
||||
|
||||
// api structure
|
||||
type Bar {
|
||||
Bar int
|
||||
}
|
||||
|
||||
// structure group
|
||||
type (
|
||||
FooBar {
|
||||
Foo int
|
||||
Bar bool
|
||||
}
|
||||
)
|
||||
|
||||
// Like the info block, @server can define any key-value pair.
|
||||
// The difference is that @server is a description of the service
|
||||
// block or route, which will participate in the api file generation.
|
||||
// There are several important keys that need to be understood,
|
||||
// which have special meanings. The jwt key is to declare that code
|
||||
// generation needs to include jwt authentication logic. The group key
|
||||
// is to declare that the files generated by the code need to be grouped
|
||||
// according to the value corresponding to the group. The handler key
|
||||
// determines the handler in golang. Layer file logic generation
|
||||
@server(
|
||||
jwt: Auth
|
||||
group: foo
|
||||
anyAnotherKey: anyTnotherValue
|
||||
)
|
||||
|
||||
// service block is the description of the api service,
|
||||
// including @doc block, @handler and api routing information
|
||||
service foo-api {
|
||||
// shortening doc declaration
|
||||
@doc("foo")
|
||||
// shortening handler declaration
|
||||
@handler foo
|
||||
// route
|
||||
get /foo (Foo) returns (Bar)
|
||||
|
||||
|
||||
@doc(
|
||||
summary: foo
|
||||
)
|
||||
@server(
|
||||
handler: bar
|
||||
)
|
||||
post /bar (Foo)
|
||||
}
|
||||
6
tools/goctl/api/parser/g4/test/apis/info.api
Normal file
6
tools/goctl/api/parser/g4/test/apis/info.api
Normal file
@@ -0,0 +1,6 @@
|
||||
info(
|
||||
author: songmeizi
|
||||
desc: "the sample of
|
||||
info"
|
||||
date: "2020-01-06"
|
||||
)
|
||||
29
tools/goctl/api/parser/g4/test/apis/service.api
Normal file
29
tools/goctl/api/parser/g4/test/apis/service.api
Normal file
@@ -0,0 +1,29 @@
|
||||
type Foo {}
|
||||
|
||||
@server(
|
||||
foo: foo
|
||||
bar: "bar"
|
||||
fooBar: "foo
|
||||
bar"
|
||||
)
|
||||
service foo-api {
|
||||
@doc("foo")
|
||||
@handler foo
|
||||
get /foo (Foo) returns (Foo)
|
||||
@handler bar
|
||||
post /foo (Foo)
|
||||
@handler fooBar
|
||||
post /foo/bar
|
||||
@server(
|
||||
handler: getFoo
|
||||
)
|
||||
post /foo/:id returns(Foo)
|
||||
}
|
||||
|
||||
service foo-api {
|
||||
@doc(
|
||||
summary:"post foo"
|
||||
)
|
||||
@handler postFoo
|
||||
post /foo/bar/post (Foo)
|
||||
}
|
||||
1
tools/goctl/api/parser/g4/test/apis/syntax.api
Normal file
1
tools/goctl/api/parser/g4/test/apis/syntax.api
Normal file
@@ -0,0 +1 @@
|
||||
syntax = "v1"
|
||||
111
tools/goctl/api/parser/g4/test/apis/test.api
Normal file
111
tools/goctl/api/parser/g4/test/apis/test.api
Normal file
@@ -0,0 +1,111 @@
|
||||
// syntax doc
|
||||
syntax = "v1" // syntax comment
|
||||
|
||||
// import doc
|
||||
import "foo.api" // import comment
|
||||
|
||||
import(
|
||||
// import group doc
|
||||
"bar.api" // import group comment
|
||||
)
|
||||
|
||||
// info doc
|
||||
info(// info comment
|
||||
// author doc
|
||||
author: "songmeizi" // author comment
|
||||
// date doc
|
||||
date: 2020-01-04 // date comment
|
||||
// desc doc
|
||||
desc: "break line
|
||||
desc" // desc comment
|
||||
)
|
||||
|
||||
|
||||
type (
|
||||
FooBar struct{
|
||||
Foo int
|
||||
}
|
||||
// remove struct
|
||||
Bar {
|
||||
// vString
|
||||
VString string `json:"vString"`
|
||||
// vBool
|
||||
VBool bool `json:"vBool"`
|
||||
// vInt8
|
||||
VInt8 int8 `json:"vInt8"`
|
||||
// vInt16
|
||||
VInt16 int16 `json:"vInt16"`
|
||||
// vInt32
|
||||
VInt32 int32 `json:"vInt32"`
|
||||
// vInt64
|
||||
VInt64 int64 `json:"vInt64"`
|
||||
// vInt
|
||||
VInt int `json:"vInt"`
|
||||
// vUInt8
|
||||
VUInt8 uint8 `json:"vUInt8"`
|
||||
// vUInt16
|
||||
VUInt16 uint16 `json:"vUInt16"`
|
||||
// vUInt32
|
||||
VUInt32 uint32 `json:"vUInt32"`
|
||||
// vUInt64
|
||||
VUInt64 uint64 `json:"vUInt64"`
|
||||
// vFloat32
|
||||
VFloat32 float32 `json:"vFloat32"`
|
||||
// vFloat64
|
||||
VFloat64 float64 `json:"vFloat64"`
|
||||
// vByte
|
||||
VByte byte `json:"vByte"`
|
||||
// vRune
|
||||
VRune rune `json:"vRune"`
|
||||
// vMap
|
||||
VMap map[string]int `json:"vMap"`
|
||||
// vArray
|
||||
VArray []int `json:"vArray"`
|
||||
// vStruct
|
||||
VStruct FooBar `json:"vStruct"`
|
||||
// vStructPointer
|
||||
VStructPointer *FooBar `json:"vStructPointer"`
|
||||
// vInterface
|
||||
VInterface interface{} `json:"vInterface"`
|
||||
// inline
|
||||
FooBar
|
||||
}
|
||||
)
|
||||
|
||||
@server(
|
||||
host: 0.0.0.0
|
||||
port: 8080
|
||||
annotation: "break line
|
||||
desc"
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
@handler postFoo
|
||||
// foo
|
||||
post /foo (FooBar) returns (FooBar)
|
||||
|
||||
@doc(
|
||||
summary: bar
|
||||
)
|
||||
@server(
|
||||
handler: postBar
|
||||
)
|
||||
post /bar (FooBar)
|
||||
|
||||
@doc("foobar")
|
||||
@handler postFooBar
|
||||
/**
|
||||
* httpmethod: post
|
||||
* path: /foo/bar
|
||||
* reply: FooBar
|
||||
*/
|
||||
post /foo/bar returns (FooBar)
|
||||
|
||||
@doc("barfoo")
|
||||
@handler postBarFoo
|
||||
post /bar/foo // post:/bar/foo
|
||||
|
||||
@doc("barfoo")
|
||||
@handler getBarFoo
|
||||
get /bar/foo returns (FooBar)
|
||||
}
|
||||
23
tools/goctl/api/parser/g4/test/apis/types.api
Normal file
23
tools/goctl/api/parser/g4/test/apis/types.api
Normal file
@@ -0,0 +1,23 @@
|
||||
type Foo{
|
||||
}
|
||||
|
||||
type Bar struct{
|
||||
}
|
||||
|
||||
type FooBar {
|
||||
Foo int
|
||||
Bar bool
|
||||
Map map[string]int
|
||||
Map1 map[string]Bar
|
||||
Map2 map[string]*Bar
|
||||
Map3 map[string][]int
|
||||
Map4 map[string][]Bar
|
||||
Map5 map[string][]*Bar
|
||||
Map6 map[string]map[string]int
|
||||
Array []int
|
||||
Array1 []*Bar
|
||||
Array2 []Bar
|
||||
Pointer *Bar
|
||||
Bar
|
||||
}
|
||||
|
||||
457
tools/goctl/api/parser/g4/test/ast_test.go
Normal file
457
tools/goctl/api/parser/g4/test/ast_test.go
Normal file
@@ -0,0 +1,457 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
var parser = ast.NewParser(ast.WithParserPrefix("test.api"), ast.WithParserDebug())
|
||||
|
||||
func TestApi(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.Api().Accept(visitor)
|
||||
}
|
||||
content, err := ioutil.ReadFile("./apis/test.api")
|
||||
assert.Nil(t, err)
|
||||
|
||||
v, err := parser.Accept(fn, string(content))
|
||||
assert.Nil(t, err)
|
||||
api := v.(*ast.Api)
|
||||
body := &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
|
||||
}
|
||||
|
||||
returns := ast.NewTextExpr("returns")
|
||||
assert.True(t, api.Equal(&ast.Api{
|
||||
Syntax: &ast.SyntaxExpr{
|
||||
Syntax: ast.NewTextExpr("syntax"),
|
||||
Assign: ast.NewTextExpr("="),
|
||||
Version: ast.NewTextExpr(`"v1"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// syntax doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// syntax comment"),
|
||||
},
|
||||
Import: []*ast.ImportExpr{
|
||||
{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// import doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// import comment"),
|
||||
},
|
||||
{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"bar.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// import group doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// import group comment"),
|
||||
},
|
||||
},
|
||||
Info: &ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("author"),
|
||||
Value: ast.NewTextExpr(`"songmeizi"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// author doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// author comment"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("date"),
|
||||
Value: ast.NewTextExpr(`2020-01-04`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// date doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// date comment"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("desc"),
|
||||
Value: ast.NewTextExpr(`"break line
|
||||
desc"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// desc doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// desc comment"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: []ast.TypeExpr{
|
||||
&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("FooBar"),
|
||||
Struct: ast.NewTextExpr("struct"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
},
|
||||
},
|
||||
&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// remove struct"),
|
||||
},
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("VString"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("string")},
|
||||
Tag: ast.NewTextExpr("`json:\"vString\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vString"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VBool"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("bool")},
|
||||
Tag: ast.NewTextExpr("`json:\"vBool\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vBool"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInt8"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int8")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInt8\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInt8"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInt16"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int16")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInt16\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInt16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInt32"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int32")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInt32\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInt32"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInt64"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int64")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInt64\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInt64"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInt"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInt\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInt"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VUInt8"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("uint8")},
|
||||
Tag: ast.NewTextExpr("`json:\"vUInt8\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vUInt8"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VUInt16"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("uint16")},
|
||||
Tag: ast.NewTextExpr("`json:\"vUInt16\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vUInt16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VUInt32"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("uint32")},
|
||||
Tag: ast.NewTextExpr("`json:\"vUInt32\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vUInt32"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VUInt64"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("uint64")},
|
||||
Tag: ast.NewTextExpr("`json:\"vUInt64\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vUInt64"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VFloat32"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("float32")},
|
||||
Tag: ast.NewTextExpr("`json:\"vFloat32\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vFloat32"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VFloat64"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("float64")},
|
||||
Tag: ast.NewTextExpr("`json:\"vFloat64\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vFloat64"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VByte"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("byte")},
|
||||
Tag: ast.NewTextExpr("`json:\"vByte\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vByte"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VRune"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("rune")},
|
||||
Tag: ast.NewTextExpr("`json:\"vRune\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vRune"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VMap"),
|
||||
DataType: &ast.Map{
|
||||
MapExpr: ast.NewTextExpr("map[string]int"),
|
||||
Map: ast.NewTextExpr("map"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Key: ast.NewTextExpr("string"),
|
||||
Value: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
Tag: ast.NewTextExpr("`json:\"vMap\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vMap"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VArray"),
|
||||
DataType: &ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]int"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
Tag: ast.NewTextExpr("`json:\"vArray\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vArray"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VStruct"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
|
||||
Tag: ast.NewTextExpr("`json:\"vStruct\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vStruct"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VStructPointer"),
|
||||
DataType: &ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*FooBar"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("FooBar"),
|
||||
},
|
||||
Tag: ast.NewTextExpr("`json:\"vStructPointer\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vStructPointer"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("VInterface"),
|
||||
DataType: &ast.Interface{Literal: ast.NewTextExpr("interface{}")},
|
||||
Tag: ast.NewTextExpr("`json:\"vInterface\"`"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// vInterface"),
|
||||
},
|
||||
},
|
||||
{
|
||||
IsAnonymous: true,
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("FooBar")},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// inline"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Service: []*ast.Service{
|
||||
{
|
||||
AtServer: &ast.AtServer{
|
||||
AtServerToken: ast.NewTextExpr("@server"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("host"),
|
||||
Value: ast.NewTextExpr("0.0.0.0"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("port"),
|
||||
Value: ast.NewTextExpr("8080"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("annotation"),
|
||||
Value: ast.NewTextExpr(`"break line
|
||||
desc"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
ServiceApi: &ast.ServiceApi{
|
||||
ServiceToken: ast.NewTextExpr("service"),
|
||||
Name: ast.NewTextExpr("foo-api"),
|
||||
Lbrace: ast.NewTextExpr("{"),
|
||||
Rbrace: ast.NewTextExpr("}"),
|
||||
ServiceRoute: []*ast.ServiceRoute{
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("postFoo"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: body,
|
||||
ReturnToken: returns,
|
||||
Reply: body,
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("summary"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
AtServer: &ast.AtServer{
|
||||
AtServerToken: ast.NewTextExpr("@server"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("handler"),
|
||||
Value: ast.NewTextExpr("postBar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/bar"),
|
||||
Req: body,
|
||||
},
|
||||
},
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foobar"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("postFooBar"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/bar"),
|
||||
ReturnToken: returns,
|
||||
Reply: body,
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr(`/**
|
||||
* httpmethod: post
|
||||
* path: /foo/bar
|
||||
* reply: FooBar
|
||||
*/`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"barfoo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("postBarFoo"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/bar/foo"),
|
||||
ReturnToken: returns,
|
||||
Reply: body,
|
||||
CommentExpr: ast.NewTextExpr("// post:/bar/foo"),
|
||||
},
|
||||
},
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"barfoo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("getBarFoo"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("get"),
|
||||
Path: ast.NewTextExpr("/bar/foo"),
|
||||
ReturnToken: returns,
|
||||
Reply: body,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
func TestApiSyntax(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.Api().Accept(visitor)
|
||||
}
|
||||
parser.Accept(fn, `
|
||||
// doc 1
|
||||
// doc 2
|
||||
syntax = "v1" // comment 1
|
||||
// comment 2
|
||||
import "foo.api"
|
||||
`)
|
||||
}
|
||||
25
tools/goctl/api/parser/g4/test/grammar_test.go
Normal file
25
tools/goctl/api/parser/g4/test/grammar_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var files = []string{
|
||||
"example",
|
||||
"empty",
|
||||
"syntax",
|
||||
"info",
|
||||
"types",
|
||||
"service",
|
||||
}
|
||||
|
||||
func TestGrammar(t *testing.T) {
|
||||
for _, file := range files {
|
||||
t.Run(file, func(t *testing.T) {
|
||||
_, err := parser.Parse("./apis/" + file + ".api")
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
143
tools/goctl/api/parser/g4/test/import_test.go
Normal file
143
tools/goctl/api/parser/g4/test/import_test.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
var importAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.ImportSpec().Accept(visitor)
|
||||
}
|
||||
|
||||
func TestImport(t *testing.T) {
|
||||
t.Run("matched", func(t *testing.T) {
|
||||
v, err := parser.Accept(importAccept, `import "foo.api"`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
list := v.([]*ast.ImportExpr)
|
||||
for _, each := range list {
|
||||
assert.True(t, each.Equal(&ast.ImportExpr{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo.api"`),
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("matched block", func(t *testing.T) {
|
||||
v, err := parser.Accept(importAccept, `
|
||||
import (
|
||||
/**foo*/
|
||||
"foo.api"
|
||||
/**bar*/
|
||||
"bar.api"
|
||||
/**foobar*/
|
||||
"foo/bar.api"/**foobar*/
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
list := v.([]*ast.ImportExpr)
|
||||
expected := []*ast.ImportExpr{
|
||||
{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**foo*/"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"bar.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**bar*/"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo/bar.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**foobar*/"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("/**foobar*/"),
|
||||
},
|
||||
}
|
||||
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return list[i].Value.Line() < list[j].Value.Line()
|
||||
})
|
||||
sort.Slice(expected, func(i, j int) bool {
|
||||
return expected[i].Value.Line() < expected[j].Value.Line()
|
||||
})
|
||||
|
||||
assert.True(t, len(list) == len(expected))
|
||||
for index, each := range list {
|
||||
assert.True(t, each.Equal(expected[index]))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("matched doc", func(t *testing.T) {
|
||||
v, err := parser.Accept(importAccept, `
|
||||
/**doc*/
|
||||
import "foo.api" /**line doc*/`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
list := v.([]*ast.ImportExpr)
|
||||
for _, each := range list {
|
||||
assert.True(t, each.Equal(&ast.ImportExpr{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**doc*/"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("/**line doc*/"),
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("matched comment", func(t *testing.T) {
|
||||
v, err := parser.Accept(importAccept, `
|
||||
// comment block
|
||||
import "foo.api" // line comment`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
list := v.([]*ast.ImportExpr)
|
||||
for _, each := range list {
|
||||
assert.True(t, each.Equal(&ast.ImportExpr{
|
||||
Import: ast.NewTextExpr("import"),
|
||||
Value: ast.NewTextExpr(`"foo.api"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// comment block"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// line comment"),
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("mismatched import", func(t *testing.T) {
|
||||
_, err := parser.Accept(importAccept, `
|
||||
"foo.api"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(importAccept, `
|
||||
impor "foo.api"`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("mismatched value", func(t *testing.T) {
|
||||
_, err := parser.Accept(importAccept, `
|
||||
import "foo"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(importAccept, `
|
||||
import ""`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(importAccept, `
|
||||
import `)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
186
tools/goctl/api/parser/g4/test/info_test.go
Normal file
186
tools/goctl/api/parser/g4/test/info_test.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
var infoAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.InfoSpec().Accept(visitor)
|
||||
}
|
||||
|
||||
func TestInfo(t *testing.T) {
|
||||
t.Run("matched", func(t *testing.T) {
|
||||
v, err := parser.Accept(infoAccept, `
|
||||
info(
|
||||
title: foo
|
||||
)
|
||||
`)
|
||||
|
||||
assert.Nil(t, err)
|
||||
info := v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("title"),
|
||||
Value: ast.NewTextExpr("foo"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
title: 中文(bar)
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
info = v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("title"),
|
||||
Value: ast.NewTextExpr("中文(bar)"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
foo: "new
|
||||
line"
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
info = v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo"),
|
||||
Value: ast.NewTextExpr(`"new
|
||||
line"`),
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("matched doc", func(t *testing.T) {
|
||||
v, err := parser.Accept(infoAccept, `
|
||||
// doc
|
||||
info( // comment
|
||||
// foo
|
||||
title: foo // bar
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
info := v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("title"),
|
||||
Value: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(infoAccept, `
|
||||
/**doc block*/
|
||||
info( /**line block*/
|
||||
/**foo*/
|
||||
title: foo /*bar**/
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
info = v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("title"),
|
||||
Value: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**foo*/"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("/*bar**/"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
// doc
|
||||
title: foo
|
||||
// doc
|
||||
author: bar
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
info = v.(*ast.InfoExpr)
|
||||
assert.True(t, info.Equal(&ast.InfoExpr{
|
||||
Info: ast.NewTextExpr("info"),
|
||||
Kvs: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("title"),
|
||||
Value: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("author"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
})
|
||||
|
||||
t.Run("mismatched", func(t *testing.T) {
|
||||
_, err := parser.Accept(infoAccept, `
|
||||
info(
|
||||
title
|
||||
)
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
:title
|
||||
)
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
foo bar
|
||||
)
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(infoAccept, `
|
||||
info(
|
||||
foo : new
|
||||
line
|
||||
)
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(infoAccept, `
|
||||
info()
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
686
tools/goctl/api/parser/g4/test/service_test.go
Normal file
686
tools/goctl/api/parser/g4/test/service_test.go
Normal file
@@ -0,0 +1,686 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
func TestBody(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.Body().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `(Foo)`)
|
||||
assert.Nil(t, err)
|
||||
body := v.(*ast.Body)
|
||||
assert.True(t, body.Equal(&ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `(var)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `()`)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoute(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.Route().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `post /foo/foo-bar/:bar (Foo) returns (Bar)`)
|
||||
assert.Nil(t, err)
|
||||
route := v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `post /foo/foo-bar/:bar (Foo)`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `post /foo/foo-bar/:bar returns (Bar)`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `post /foo/foo-bar/:bar returns ([]Bar)`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]Bar"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `post /foo/foo-bar/:bar returns ([]*Bar)`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]*Bar"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*Bar"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
}},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `post /foo/foo-bar/:bar`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `
|
||||
// foo
|
||||
post /foo/foo-bar/:bar // bar`)
|
||||
assert.Nil(t, err)
|
||||
route = v.(*ast.Route)
|
||||
assert.True(t, route.Equal(&ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo/foo-bar/:bar"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `posts /foo`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `gets /foo`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `post /foo/:`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `post /foo/`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `post foo/bar`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `post /foo/bar return (Bar)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` /foo/bar returns (Bar)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` post returns (Bar)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` post /foo/bar returns (int)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` post /foo/bar returns (*int)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` post /foo/bar returns ([]var)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, ` post /foo/bar returns (const)`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAtHandler(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.AtHandler().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `@handler foo`)
|
||||
assert.Nil(t, err)
|
||||
atHandler := v.(*ast.AtHandler)
|
||||
assert.True(t, atHandler.Equal(&ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `
|
||||
// foo
|
||||
@handler foo // bar`)
|
||||
assert.Nil(t, err)
|
||||
atHandler = v.(*ast.AtHandler)
|
||||
assert.True(t, atHandler.Equal(&ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, ``)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@handler`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@handler "foo"`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestAtDoc(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.AtDoc().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `@doc "foo"`)
|
||||
assert.Nil(t, err)
|
||||
atDoc := v.(*ast.AtDoc)
|
||||
assert.True(t, atDoc.Equal(&ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `@doc("foo")`)
|
||||
assert.Nil(t, err)
|
||||
atDoc = v.(*ast.AtDoc)
|
||||
assert.True(t, atDoc.Equal(&ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `@doc(
|
||||
foo: bar
|
||||
)`)
|
||||
assert.Nil(t, err)
|
||||
atDoc = v.(*ast.AtDoc)
|
||||
assert.True(t, atDoc.Equal(&ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `@doc(
|
||||
// foo
|
||||
foo: bar // bar
|
||||
)`)
|
||||
assert.Nil(t, err)
|
||||
atDoc = v.(*ast.AtDoc)
|
||||
assert.True(t, atDoc.Equal(&ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo"),
|
||||
Value: ast.NewTextExpr("bar"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `@doc("foo"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@doc "foo")`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServiceRoute(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.ServiceRoute().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `
|
||||
@doc("foo")
|
||||
// foo/bar
|
||||
// foo
|
||||
@handler foo // bar
|
||||
// foo/bar
|
||||
// foo
|
||||
post /foo (Foo) returns (Bar) // bar
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
sr := v.(*ast.ServiceRoute)
|
||||
assert.True(t, sr.Equal(&ast.ServiceRoute{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `post /foo (Foo) returns (Bar) // bar`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@handler foo`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServiceApi(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.ServiceApi().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
// foo/bar
|
||||
// foo
|
||||
@handler foo // bar
|
||||
// foo/bar
|
||||
// foo
|
||||
post /foo (Foo) returns (Bar) // bar
|
||||
}
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
api := v.(*ast.ServiceApi)
|
||||
assert.True(t, api.Equal(&ast.ServiceApi{
|
||||
ServiceToken: ast.NewTextExpr("service"),
|
||||
Name: ast.NewTextExpr("foo-api"),
|
||||
Lbrace: ast.NewTextExpr("{"),
|
||||
Rbrace: ast.NewTextExpr("}"),
|
||||
ServiceRoute: []*ast.ServiceRoute{
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `services foo-api{}`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `service foo-api{`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `service foo-api{
|
||||
post /foo
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `service foo-api{
|
||||
@handler foo
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAtServer(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.AtServer().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `
|
||||
@server(
|
||||
// foo
|
||||
foo1: bar1 // bar
|
||||
// foo
|
||||
foo2: "bar2" // bar
|
||||
/**foo*/
|
||||
foo3: "foo
|
||||
bar" /**bar*/
|
||||
)
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
as := v.(*ast.AtServer)
|
||||
assert.True(t, as.Equal(&ast.AtServer{
|
||||
AtServerToken: ast.NewTextExpr("@server"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo1"),
|
||||
Value: ast.NewTextExpr("bar1"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("foo2"),
|
||||
Value: ast.NewTextExpr(`"bar2"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("foo3"),
|
||||
Value: ast.NewTextExpr(`"foo
|
||||
bar"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**foo*/"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("/**bar*/"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `server (
|
||||
foo:bar
|
||||
)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@server ()`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `@server (
|
||||
foo: bar
|
||||
`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServiceSpec(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, v *ast.ApiVisitor) interface{} {
|
||||
return p.ServiceSpec().Accept(v)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `
|
||||
service foo-api{
|
||||
@handler foo
|
||||
post /foo returns ([]int)
|
||||
}
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
v, err := parser.Accept(fn, `
|
||||
@server(
|
||||
// foo
|
||||
foo1: bar1 // bar
|
||||
// foo
|
||||
foo2: "bar2" // bar
|
||||
/**foo*/
|
||||
foo3: "foo
|
||||
bar" /**bar*/
|
||||
)
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
// foo/bar
|
||||
// foo
|
||||
@handler foo // bar
|
||||
// foo/bar
|
||||
// foo
|
||||
post /foo (Foo) returns (Bar) // bar
|
||||
}
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
service := v.(*ast.Service)
|
||||
assert.True(t, service.Equal(&ast.Service{
|
||||
AtServer: &ast.AtServer{
|
||||
AtServerToken: ast.NewTextExpr("@server"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Kv: []*ast.KvExpr{
|
||||
{
|
||||
Key: ast.NewTextExpr("foo1"),
|
||||
Value: ast.NewTextExpr("bar1"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("foo2"),
|
||||
Value: ast.NewTextExpr(`"bar2"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
{
|
||||
Key: ast.NewTextExpr("foo3"),
|
||||
Value: ast.NewTextExpr(`"foo
|
||||
bar"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("/**foo*/"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("/**bar*/"),
|
||||
},
|
||||
},
|
||||
},
|
||||
ServiceApi: &ast.ServiceApi{
|
||||
ServiceToken: ast.NewTextExpr("service"),
|
||||
Name: ast.NewTextExpr("foo-api"),
|
||||
Lbrace: ast.NewTextExpr("{"),
|
||||
Rbrace: ast.NewTextExpr("}"),
|
||||
ServiceRoute: []*ast.ServiceRoute{
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `
|
||||
service foo-api{
|
||||
@doc("foo")
|
||||
// foo/bar
|
||||
// foo
|
||||
@handler foo // bar
|
||||
// foo/bar
|
||||
// foo
|
||||
post /foo (Foo) returns (Bar) // bar
|
||||
}
|
||||
`)
|
||||
assert.Nil(t, err)
|
||||
service = v.(*ast.Service)
|
||||
assert.True(t, service.Equal(&ast.Service{
|
||||
ServiceApi: &ast.ServiceApi{
|
||||
ServiceToken: ast.NewTextExpr("service"),
|
||||
Name: ast.NewTextExpr("foo-api"),
|
||||
Lbrace: ast.NewTextExpr("{"),
|
||||
Rbrace: ast.NewTextExpr("}"),
|
||||
ServiceRoute: []*ast.ServiceRoute{
|
||||
{
|
||||
AtDoc: &ast.AtDoc{
|
||||
AtDocToken: ast.NewTextExpr("@doc"),
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
LineDoc: ast.NewTextExpr(`"foo"`),
|
||||
},
|
||||
AtHandler: &ast.AtHandler{
|
||||
AtHandlerToken: ast.NewTextExpr("@handler"),
|
||||
Name: ast.NewTextExpr("foo"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
Route: &ast.Route{
|
||||
Method: ast.NewTextExpr("post"),
|
||||
Path: ast.NewTextExpr("/foo"),
|
||||
Req: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Foo")},
|
||||
},
|
||||
ReturnToken: ast.NewTextExpr("returns"),
|
||||
Reply: &ast.Body{
|
||||
Lp: ast.NewTextExpr("("),
|
||||
Rp: ast.NewTextExpr(")"),
|
||||
Name: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// foo"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
75
tools/goctl/api/parser/g4/test/syntax_test.go
Normal file
75
tools/goctl/api/parser/g4/test/syntax_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
var syntaxAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.SyntaxLit().Accept(visitor)
|
||||
}
|
||||
|
||||
func TestSyntax(t *testing.T) {
|
||||
t.Run("matched", func(t *testing.T) {
|
||||
v, err := parser.Accept(syntaxAccept, `syntax = "v1"`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
syntax := v.(*ast.SyntaxExpr)
|
||||
assert.True(t, syntax.Equal(&ast.SyntaxExpr{
|
||||
Syntax: ast.NewTextExpr("syntax"),
|
||||
Assign: ast.NewTextExpr("="),
|
||||
Version: ast.NewTextExpr(`"v1"`),
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("expecting syntax", func(t *testing.T) {
|
||||
_, err := parser.Accept(syntaxAccept, `= "v1"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(syntaxAccept, `syn = "v1"`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("missing assign", func(t *testing.T) {
|
||||
_, err := parser.Accept(syntaxAccept, `syntax "v1"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(syntaxAccept, `syntax + "v1"`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("mismatched version", func(t *testing.T) {
|
||||
_, err := parser.Accept(syntaxAccept, `syntax="v0"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(syntaxAccept, `syntax = "v1a"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(syntaxAccept, `syntax = "vv1"`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(syntaxAccept, `syntax = "1"`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("with comment", func(t *testing.T) {
|
||||
v, err := parser.Accept(syntaxAccept, `
|
||||
// doc
|
||||
syntax="v1" // line comment`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
syntax := v.(*ast.SyntaxExpr)
|
||||
assert.True(t, syntax.Equal(&ast.SyntaxExpr{
|
||||
Syntax: ast.NewTextExpr("syntax"),
|
||||
Assign: ast.NewTextExpr("="),
|
||||
Version: ast.NewTextExpr(`"v1"`),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// line comment"),
|
||||
}))
|
||||
})
|
||||
}
|
||||
467
tools/goctl/api/parser/g4/test/type_test.go
Normal file
467
tools/goctl/api/parser/g4/test/type_test.go
Normal file
@@ -0,0 +1,467 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
|
||||
)
|
||||
|
||||
var fieldAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.Field().Accept(visitor)
|
||||
}
|
||||
|
||||
func TestField(t *testing.T) {
|
||||
t.Run("anonymous", func(t *testing.T) {
|
||||
v, err := parser.Accept(fieldAccept, `User`)
|
||||
assert.Nil(t, err)
|
||||
f := v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
IsAnonymous: true,
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("User")},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fieldAccept, `*User`)
|
||||
assert.Nil(t, err)
|
||||
f = v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
IsAnonymous: true,
|
||||
DataType: &ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*User"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("User"),
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fieldAccept, `
|
||||
// anonymous user
|
||||
*User // pointer type`)
|
||||
assert.Nil(t, err)
|
||||
f = v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
IsAnonymous: true,
|
||||
DataType: &ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*User"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("User"),
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// anonymous user"),
|
||||
},
|
||||
CommentExpr: ast.NewTextExpr("// pointer type"),
|
||||
}))
|
||||
|
||||
_, err = parser.Accept(fieldAccept, `interface`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fieldAccept, `map`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fieldAccept, `User int`)
|
||||
assert.Nil(t, err)
|
||||
f := v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
Name: ast.NewTextExpr("User"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
}))
|
||||
v, err = parser.Accept(fieldAccept, `Foo Bar`)
|
||||
assert.Nil(t, err)
|
||||
f = v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fieldAccept, `Foo map[int]Bar`)
|
||||
assert.Nil(t, err)
|
||||
f = v.(*ast.TypeField)
|
||||
assert.True(t, f.Equal(&ast.TypeField{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
DataType: &ast.Map{
|
||||
MapExpr: ast.NewTextExpr("map[int]Bar"),
|
||||
Map: ast.NewTextExpr("map"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Key: ast.NewTextExpr("int"),
|
||||
Value: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_ID(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.DataType().Accept(visitor)
|
||||
}
|
||||
t.Run("Struct", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `Foo`)
|
||||
assert.Nil(t, err)
|
||||
id := v.(ast.DataType)
|
||||
assert.True(t, id.Equal(&ast.Literal{Literal: ast.NewTextExpr("Foo")}))
|
||||
})
|
||||
|
||||
t.Run("basic", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `int`)
|
||||
assert.Nil(t, err)
|
||||
id := v.(ast.DataType)
|
||||
assert.True(t, id.Equal(&ast.Literal{Literal: ast.NewTextExpr("int")}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `map`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_Map(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.MapType().Accept(visitor)
|
||||
}
|
||||
t.Run("basicKey", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `map[int]Bar`)
|
||||
assert.Nil(t, err)
|
||||
m := v.(ast.DataType)
|
||||
assert.True(t, m.Equal(&ast.Map{
|
||||
MapExpr: ast.NewTextExpr("map[int]Bar"),
|
||||
Map: ast.NewTextExpr("map"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Key: ast.NewTextExpr("int"),
|
||||
Value: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `map[var]Bar`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(dt, `map[*User]Bar`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(dt, `map[User]Bar`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_Array(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.ArrayType().Accept(visitor)
|
||||
}
|
||||
t.Run("basic", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `[]int`)
|
||||
assert.Nil(t, err)
|
||||
array := v.(ast.DataType)
|
||||
assert.True(t, array.Equal(&ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]int"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("pointer", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `[]*User`)
|
||||
assert.Nil(t, err)
|
||||
array := v.(ast.DataType)
|
||||
assert.True(t, array.Equal(&ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]*User"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*User"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("User"),
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("interface{}", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `[]interface{}`)
|
||||
assert.Nil(t, err)
|
||||
array := v.(ast.DataType)
|
||||
assert.True(t, array.Equal(&ast.Array{
|
||||
ArrayExpr: ast.NewTextExpr("[]interface{}"),
|
||||
LBrack: ast.NewTextExpr("["),
|
||||
RBrack: ast.NewTextExpr("]"),
|
||||
Literal: &ast.Interface{Literal: ast.NewTextExpr("interface{}")},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `[]var`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(dt, `[]interface`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_Interface(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.DataType().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `interface{}`)
|
||||
assert.Nil(t, err)
|
||||
inter := v.(ast.DataType)
|
||||
assert.True(t, inter.Equal(&ast.Interface{Literal: ast.NewTextExpr("interface{}")}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `interface`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `interface{`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_Time(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.DataType().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `time.Time`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataType_Pointer(t *testing.T) {
|
||||
dt := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.PointerType().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(dt, `*int`)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, v.(ast.DataType).Equal(&ast.Pointer{
|
||||
PointerExpr: ast.NewTextExpr("*int"),
|
||||
Star: ast.NewTextExpr("*"),
|
||||
Name: ast.NewTextExpr("int"),
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(dt, `int`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAlias(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.TypeAlias().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `Foo int`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `Foo=int`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `
|
||||
Foo int // comment`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `
|
||||
Foo int /**comment*/`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `Foo var`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `Foo 2`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypeStruct(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.TypeStruct().Accept(visitor)
|
||||
}
|
||||
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, "Foo {\n\t\t\tFoo string\n\t\t\tBar int `json:\"bar\"``\n\t\t}")
|
||||
assert.Nil(t, err)
|
||||
s := v.(*ast.TypeStruct)
|
||||
assert.True(t, s.Equal(&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("string")},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
Tag: ast.NewTextExpr("`json:\"bar\"`"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, "Foo struct{\n\t\t\tFoo string\n\t\t\tBar int `json:\"bar\"``\n\t\t}")
|
||||
assert.Nil(t, err)
|
||||
s = v.(*ast.TypeStruct)
|
||||
assert.True(t, s.Equal(&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
Struct: ast.NewTextExpr("struct"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("string")},
|
||||
},
|
||||
{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
Tag: ast.NewTextExpr("`json:\"bar\"`"),
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypeBlock(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.TypeBlock().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
v, err := parser.Accept(fn, `type(
|
||||
// doc
|
||||
Foo int
|
||||
)`)
|
||||
assert.Error(t, err)
|
||||
|
||||
v, err = parser.Accept(fn, `type (
|
||||
// doc
|
||||
Foo {
|
||||
Bar int
|
||||
}
|
||||
)`)
|
||||
assert.Nil(t, err)
|
||||
st := v.([]ast.TypeExpr)
|
||||
assert.True(t, st[0].Equal(&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
LBrace: ast.NewTextExpr("{"),
|
||||
RBrace: ast.NewTextExpr("}"),
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypeLit(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.TypeLit().Accept(visitor)
|
||||
}
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `type Foo int`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `type Foo = int`)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `
|
||||
// doc
|
||||
type Foo = int // comment`)
|
||||
assert.Error(t, err)
|
||||
|
||||
v, err := parser.Accept(fn, `
|
||||
// doc
|
||||
type Foo {// comment
|
||||
Bar int
|
||||
}`)
|
||||
assert.Nil(t, err)
|
||||
st := v.(*ast.TypeStruct)
|
||||
assert.True(t, st.Equal(&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
Name: ast.NewTextExpr("Bar"),
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("int")},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// comment"),
|
||||
},
|
||||
},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
}))
|
||||
|
||||
v, err = parser.Accept(fn, `
|
||||
// doc
|
||||
type Foo {// comment
|
||||
Bar
|
||||
}`)
|
||||
assert.Nil(t, err)
|
||||
st = v.(*ast.TypeStruct)
|
||||
assert.True(t, st.Equal(&ast.TypeStruct{
|
||||
Name: ast.NewTextExpr("Foo"),
|
||||
Fields: []*ast.TypeField{
|
||||
{
|
||||
IsAnonymous: true,
|
||||
DataType: &ast.Literal{Literal: ast.NewTextExpr("Bar")},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// comment"),
|
||||
},
|
||||
},
|
||||
},
|
||||
DocExpr: []ast.Expr{
|
||||
ast.NewTextExpr("// doc"),
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("wrong", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `type Foo`)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypeUnExported(t *testing.T) {
|
||||
fn := func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {
|
||||
return p.TypeSpec().Accept(visitor)
|
||||
}
|
||||
|
||||
t.Run("type", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `type foo {}`)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("field", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `type Foo {
|
||||
name int
|
||||
}`)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = parser.Accept(fn, `type Foo {
|
||||
Name int
|
||||
}`)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("filedDataType", func(t *testing.T) {
|
||||
_, err := parser.Accept(fn, `type Foo {
|
||||
Foo *foo
|
||||
Bar []bar
|
||||
FooBar map[int]fooBar
|
||||
}`)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user