diff --git a/tools/goctl/pkg/parser/api/parser/analyzer_test.go b/tools/goctl/pkg/parser/api/parser/analyzer_test.go index 9f7976e47..7c817157f 100644 --- a/tools/goctl/pkg/parser/api/parser/analyzer_test.go +++ b/tools/goctl/pkg/parser/api/parser/analyzer_test.go @@ -14,69 +14,97 @@ import ( ) func Test_Parse(t *testing.T) { - t.Run("valid", func(t *testing.T) { - apiSpec, err := Parse("./testdata/example.api", nil) - assert.Nil(t, err) - ast := assert.New(t) - ast.Equal(spec.Info{ - Title: "type title here", - Desc: "type desc here", - Version: "type version here", - Author: "type author here", - Email: "type email here", - Properties: map[string]string{ - "title": "type title here", - "desc": "type desc here", - "version": "type version here", - "author": "type author here", - "email": "type email here", - }, - }, apiSpec.Info) - ast.True(func() bool { - for _, group := range apiSpec.Service.Groups { - value, ok := group.Annotation.Properties["summary"] - if ok { - return value == "test" - } - } - return false - }()) - }) + t.Run( + "valid", func(t *testing.T) { + apiSpec, err := Parse("./testdata/example.api", nil) + assert.Nil(t, err) + ast := assert.New(t) + ast.Equal( + spec.Info{ + Title: "type title here", + Desc: "type desc here", + Version: "type version here", + Author: "type author here", + Email: "type email here", + Properties: map[string]string{ + "title": "type title here", + "desc": "type desc here", + "version": "type version here", + "author": "type author here", + "email": "type email here", + }, + }, apiSpec.Info, + ) + ast.True( + func() bool { + for _, group := range apiSpec.Service.Groups { + value, ok := group.Annotation.Properties["summary"] + if ok { + return value == "test" + } + } + return false + }(), + ) + }, + ) - t.Run("invalid", func(t *testing.T) { - data, err := os.ReadFile("./testdata/invalid.api") - assert.NoError(t, err) - splits := bytes.Split(data, []byte("-----")) - var testFile []string - for idx, split := range splits { - replacer := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\f", "") - r := replacer.Replace(string(split)) - if len(r) == 0 { - continue - } - filename := filepath.Join(t.TempDir(), fmt.Sprintf("invalid%d.api", idx)) - err := os.WriteFile(filename, split, 0666) + t.Run( + "invalid", func(t *testing.T) { + data, err := os.ReadFile("./testdata/invalid.api") assert.NoError(t, err) - testFile = append(testFile, filename) - } - for _, v := range testFile { - _, err := Parse(v, nil) + splits := bytes.Split(data, []byte("-----")) + var testFile []string + for idx, split := range splits { + replacer := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\f", "") + r := replacer.Replace(string(split)) + if len(r) == 0 { + continue + } + filename := filepath.Join(t.TempDir(), fmt.Sprintf("invalid%d.api", idx)) + err := os.WriteFile(filename, split, 0666) + assert.NoError(t, err) + testFile = append(testFile, filename) + } + for _, v := range testFile { + _, err := Parse(v, nil) + assertx.Error(t, err) + } + }, + ) + + t.Run( + "circleImport", func(t *testing.T) { + _, err := Parse("./testdata/base.api", nil) assertx.Error(t, err) - } - }) + }, + ) - t.Run("circleImport", func(t *testing.T) { - _, err := Parse("./testdata/base.api", nil) - assertx.Error(t, err) - }) + t.Run( + "link_import", func(t *testing.T) { + _, err := Parse("./testdata/link_import.api", nil) + assert.Nil(t, err) + }, + ) - t.Run("link_import", func(t *testing.T) { - _, err := Parse("./testdata/link_import.api", nil) - assert.Nil(t, err) - }) + t.Run( + "duplicate_types", func(t *testing.T) { + _, err := Parse("./testdata/duplicate_type.api", nil) + assertx.Error(t, err) + }, + ) - t.Run("duplicate_types", func(t *testing.T) { - _, err := Parse("./testdata/duplicate_type.api", nil) - assertx.Error(t, err) - }) + t.Run( + "duplicate_path_expression", func(t *testing.T) { + _, err := Parse("./testdata/duplicate_path_expression.api", nil) + assertx.Error(t, err) + }, + ) + t.Run( + "duplicate_path_expression_different_prefix", func(t *testing.T) { + _, err := Parse("./testdata/duplicate_path_expression_different_prefix.api", nil) + + assert.Nil(t, err) + }, + ) } diff --git a/tools/goctl/pkg/parser/api/parser/api.go b/tools/goctl/pkg/parser/api/parser/api.go index aee27727a..c1db8ce9e 100644 --- a/tools/goctl/pkg/parser/api/parser/api.go +++ b/tools/goctl/pkg/parser/api/parser/api.go @@ -13,8 +13,8 @@ import ( ) const ( - atServerGroupKey = "group:" - atServerPrefixKey = "prefix:" + atServerGroupKey = "group" + atServerPrefixKey = "prefix" ) // API is the parsed api file. @@ -38,18 +38,24 @@ func convert2API(a *ast.AST, importSet map[string]lang.PlaceholderType, is *impo syntax, ok := one.(*ast.SyntaxStmt) if !ok { syntax = &ast.SyntaxStmt{ - Syntax: ast.NewTokenNode(token.Token{ - Type: token.IDENT, - Text: token.Syntax, - }), - Assign: ast.NewTokenNode(token.Token{ - Type: token.ASSIGN, - Text: "=", - }), - Value: ast.NewTokenNode(token.Token{ - Type: token.STRING, - Text: `"v1"`, - }), + Syntax: ast.NewTokenNode( + token.Token{ + Type: token.IDENT, + Text: token.Syntax, + }, + ), + Assign: ast.NewTokenNode( + token.Token{ + Type: token.ASSIGN, + Text: "=", + }, + ), + Value: ast.NewTokenNode( + token.Token{ + Type: token.STRING, + Text: `"v1"`, + }, + ), } } @@ -133,10 +139,14 @@ func (api *API) checkServiceStmt() error { for _, item := range v.Routes { handlerChecker.checkNodeWithPrefix(group, item.AtHandler.Name) path := fmt.Sprintf("[%s]:%s", prefix, item.Route.Format("")) - pathChecker.check(ast.NewTokenNode(token.Token{ - Text: path, - Position: item.Route.Pos(), - })) + pathChecker.check( + ast.NewTokenNode( + token.Token{ + Text: path, + Position: item.Route.Pos(), + }, + ), + ) } } return f.error() @@ -237,7 +247,8 @@ func (api *API) getAtServerValue(atServer *ast.AtServerStmt, key string) string func (api *API) mergeAPI(in *API) error { if api.Syntax.Value.Format() != in.Syntax.Value.Format() { - return ast.SyntaxError(in.Syntax.Value.Pos(), + return ast.SyntaxError( + in.Syntax.Value.Pos(), "multiple syntax value expression, expected <%s>, got <%s>", api.Syntax.Value.Format(), in.Syntax.Value.Format(), diff --git a/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression.api b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression.api new file mode 100644 index 000000000..4db1a50d9 --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression.api @@ -0,0 +1,21 @@ +syntax = "v1" + +@server ( + group: path2 + middleware: Path + prefix: /v1/v3 + timeout: 100ms +) +service example { + @doc ( + desc: "path demo" + ) + @handler getPath1 + get / (string) returns (string) + + @doc ( + desc: "path demo" + ) + @handler getPath2 + get / (string) returns (string) +} \ No newline at end of file diff --git a/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix.api b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix.api new file mode 100644 index 000000000..691ab0f47 --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix.api @@ -0,0 +1,2 @@ +import "duplicate_path_expression_different_prefix__prefix_1.api" +import "duplicate_path_expression_different_prefix__prefix_2.api" \ No newline at end of file diff --git a/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_1.api b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_1.api new file mode 100644 index 000000000..7c6042aa9 --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_1.api @@ -0,0 +1,16 @@ +syntax = "v1" + + +@server ( + group: group2 + middleware: Path + prefix: /v1/group2 + timeout: 100ms +) +service example { + @doc ( + desc: "path demo" + ) + @handler getPath2 + get / (string) returns (string) +} \ No newline at end of file diff --git a/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_2.api b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_2.api new file mode 100644 index 000000000..62328a7da --- /dev/null +++ b/tools/goctl/pkg/parser/api/parser/testdata/duplicate_path_expression_different_prefix__prefix_2.api @@ -0,0 +1,15 @@ +syntax = "v1" + +@server ( + group: group1 + middleware: Path + prefix: /v1/group1 + timeout: 100ms +) +service example { + @doc ( + desc: "path demo" + ) + @handler getPath1 + get / (string) returns (string) +} \ No newline at end of file