From 28b12ad9cc60f03281fdf192029b9620d8da2ba9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Oct 2025 03:30:21 +0000 Subject: [PATCH] Add comprehensive integration test for inline struct handling - Add TestGenWithInlineStructs to verify end-to-end generation - Test verifies correct parameter generation, flattening of inline structs - Test verifies no incorrect Headers interfaces are generated - Test verifies correct argument counts in function calls Co-authored-by: kevwan <1918356+kevwan@users.noreply.github.com> --- tools/goctl/api/tsgen/gen_test.go | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tools/goctl/api/tsgen/gen_test.go diff --git a/tools/goctl/api/tsgen/gen_test.go b/tools/goctl/api/tsgen/gen_test.go new file mode 100644 index 000000000..b069253a2 --- /dev/null +++ b/tools/goctl/api/tsgen/gen_test.go @@ -0,0 +1,163 @@ +package tsgen + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/zeromicro/go-zero/tools/goctl/api/parser" +) + +func TestGenWithInlineStructs(t *testing.T) { + // Create a temporary directory for the test + tmpDir := t.TempDir() + apiFile := filepath.Join(tmpDir, "test.api") + + // Write the test API file + apiContent := `syntax = "v1" + +info ( + title: "Test ts generator" + desc: "Test inline struct handling" + author: "test" + version: "v1" +) + +// common pagination request +type PaginationReq { + PageNum int ` + "`form:\"pageNum\"`" + ` + PageSize int ` + "`form:\"pageSize\"`" + ` +} + +// base response +type BaseResp { + Code int64 ` + "`json:\"code\"`" + ` + Msg string ` + "`json:\"msg\"`" + ` +} + +// common req +type GetListCommonReq { + Sth string ` + "`form:\"sth\"`" + ` + PageNum int ` + "`form:\"pageNum\"`" + ` + PageSize int ` + "`form:\"pageSize\"`" + ` +} + +// bad req to ts - inline struct with form tags +type GetListBadReq { + Sth string ` + "`form:\"sth\"`" + ` + PaginationReq +} + +// bad req to ts 2 - only inline struct with form tags +type GetListBad2Req { + PaginationReq +} + +// GetListResp - inline struct with json tags +type GetListResp { + BaseResp +} + +service test-api { + @doc "common req" + @handler getListCommon + get /getListCommon (GetListCommonReq) returns (GetListResp) + + @doc "bad req" + @handler getListBad + get /getListBad (GetListBadReq) returns (GetListResp) + + @doc "bad req 2" + @handler getListBad2 + get /getListBad2 (GetListBad2Req) returns (GetListResp) + + @doc "no req" + @handler getListNoReq + get /getListNoReq returns (GetListResp) +}` + + err := os.WriteFile(apiFile, []byte(apiContent), 0644) + assert.NoError(t, err) + + // Parse the API file + api, err := parser.Parse(apiFile) + assert.NoError(t, err) + + // Generate TypeScript files + outputDir := filepath.Join(tmpDir, "output") + err = os.MkdirAll(outputDir, 0755) + assert.NoError(t, err) + + // Generate the files directly + api.Service = api.Service.JoinPrefix() + err = genRequest(outputDir) + assert.NoError(t, err) + err = genHandler(outputDir, ".", "webapi", api, false) + assert.NoError(t, err) + err = genComponents(outputDir, api) + assert.NoError(t, err) + + // Read generated handler file + handlerFile := filepath.Join(outputDir, "test.ts") + handlerContent, err := os.ReadFile(handlerFile) + assert.NoError(t, err) + handler := string(handlerContent) + + // Read generated components file + componentsFile := filepath.Join(outputDir, "testComponents.ts") + componentsContent, err := os.ReadFile(componentsFile) + assert.NoError(t, err) + components := string(componentsContent) + + // Verify getListBad function signature and call + assert.Contains(t, handler, "export function getListBad(params: components.GetListBadReqParams)") + assert.Contains(t, handler, "return webapi.get(`/getListBad`, params)") + // Should NOT contain 4 arguments + assert.NotContains(t, handler, "getListBad`, params, req, headers") + + // Verify getListBad2 function signature and call + assert.Contains(t, handler, "export function getListBad2(params: components.GetListBad2ReqParams)") + assert.Contains(t, handler, "return webapi.get(`/getListBad2`, params)") + // Should NOT reference non-existent headers + assert.NotContains(t, handler, "GetListBad2ReqHeaders") + + // Verify getListCommon function signature and call + assert.Contains(t, handler, "export function getListCommon(params: components.GetListCommonReqParams)") + assert.Contains(t, handler, "return webapi.get(`/getListCommon`, params)") + + // Verify getListNoReq function signature and call + assert.Contains(t, handler, "export function getListNoReq()") + assert.Contains(t, handler, "return webapi.get(`/getListNoReq`)") + + // Verify GetListBadReqParams contains flattened fields + assert.Contains(t, components, "export interface GetListBadReqParams") + // Count occurrences of fields in GetListBadReqParams + paramsStart := strings.Index(components, "export interface GetListBadReqParams") + paramsEnd := strings.Index(components[paramsStart:], "}") + paramsSection := components[paramsStart : paramsStart+paramsEnd] + assert.Contains(t, paramsSection, "sth: string") + assert.Contains(t, paramsSection, "pageNum: number") + assert.Contains(t, paramsSection, "pageSize: number") + + // Verify GetListBad2ReqParams contains flattened fields from inline PaginationReq + assert.Contains(t, components, "export interface GetListBad2ReqParams") + params2Start := strings.Index(components, "export interface GetListBad2ReqParams") + params2End := strings.Index(components[params2Start:], "}") + params2Section := components[params2Start : params2Start+params2End] + assert.Contains(t, params2Section, "pageNum: number") + assert.Contains(t, params2Section, "pageSize: number") + + // Verify no empty Headers interfaces are generated + assert.NotContains(t, components, "GetListBadReqHeaders") + assert.NotContains(t, components, "GetListBad2ReqHeaders") + + // Verify GetListResp contains flattened fields from BaseResp + assert.Contains(t, components, "export interface GetListResp") + respStart := strings.Index(components, "export interface GetListResp") + respEnd := strings.Index(components[respStart:], "}") + respSection := components[respStart : respStart+respEnd] + assert.Contains(t, respSection, "code: number") + assert.Contains(t, respSection, "msg: string") +}