package gogen import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/tools/goctl/internal/version" ) // TestGenerationComments verifies that all generated files have appropriate generation comments func TestGenerationComments(t *testing.T) { // Create a temporary directory for our test tempDir, err := os.MkdirTemp("", "goctl_test_") require.NoError(t, err) defer os.RemoveAll(tempDir) // Create a simple API spec for testing apiContent := ` syntax = "v1" type HelloRequest { Name string ` + "`json:\"name\"`" + ` } type HelloResponse { Message string ` + "`json:\"message\"`" + ` } service hello-api { @handler helloHandler post /hello (HelloRequest) returns (HelloResponse) }` // Write the API spec to a temporary file apiFile := filepath.Join(tempDir, "test.api") err = os.WriteFile(apiFile, []byte(apiContent), 0644) require.NoError(t, err) // Parse and generate the API files using the correct function signature err = DoGenProject(apiFile, tempDir, "gozero", false) require.NoError(t, err) // Define expected files and their comment types expectedFiles := map[string]string{ // Files that should have "DO NOT EDIT" comments (regenerated files) "internal/types/types.go": "DO NOT EDIT", // Files that should have "Safe to edit" comments (scaffolded files) "internal/handler/hellohandler.go": "Safe to edit", "internal/config/config.go": "Safe to edit", "hello.go": "Safe to edit", // main file "internal/svc/servicecontext.go": "Safe to edit", "internal/logic/hellologic.go": "Safe to edit", } // Check each file for the correct generation comment for filePath, expectedCommentType := range expectedFiles { fullPath := filepath.Join(tempDir, filePath) // Skip if file doesn't exist (some files might not be generated in all cases) if _, err := os.Stat(fullPath); os.IsNotExist(err) { t.Logf("File %s does not exist, skipping", filePath) continue } content, err := os.ReadFile(fullPath) require.NoError(t, err, "Failed to read file: %s", filePath) contentStr := string(content) lines := strings.Split(contentStr, "\n") // Check that the file starts with proper generation comments require.GreaterOrEqual(t, len(lines), 2, "File %s should have at least 2 lines", filePath) if expectedCommentType == "DO NOT EDIT" { assert.Contains(t, lines[0], "// Code generated by goctl. DO NOT EDIT.", "File %s should have 'DO NOT EDIT' comment as first line", filePath) } else if expectedCommentType == "Safe to edit" { assert.Contains(t, lines[0], "// Code scaffolded by goctl. Safe to edit.", "File %s should have 'Safe to edit' comment as first line", filePath) } // Check that the second line contains the version assert.Contains(t, lines[1], "// goctl", "File %s should have version comment as second line", filePath) assert.Contains(t, lines[1], version.BuildVersion, "File %s should contain version %s in second line", filePath, version.BuildVersion) } } // TestRoutesGenerationComment verifies routes files have "DO NOT EDIT" comment func TestRoutesGenerationComment(t *testing.T) { // Create a temporary directory for our test tempDir, err := os.MkdirTemp("", "goctl_routes_test_") require.NoError(t, err) defer os.RemoveAll(tempDir) // Create an API spec with multiple handlers to ensure routes file is generated apiContent := ` syntax = "v1" type HelloRequest { Name string ` + "`json:\"name\"`" + ` } type HelloResponse { Message string ` + "`json:\"message\"`" + ` } service hello-api { @handler helloHandler post /hello (HelloRequest) returns (HelloResponse) @handler worldHandler get /world returns (HelloResponse) }` // Write the API spec to a temporary file apiFile := filepath.Join(tempDir, "test.api") err = os.WriteFile(apiFile, []byte(apiContent), 0644) require.NoError(t, err) // Generate the API files using the correct function signature err = DoGenProject(apiFile, tempDir, "gozero", false) require.NoError(t, err) // Check the routes file specifically routesFile := filepath.Join(tempDir, "internal/handler/routes.go") if _, err := os.Stat(routesFile); os.IsNotExist(err) { t.Skip("Routes file not generated, skipping test") return } content, err := os.ReadFile(routesFile) require.NoError(t, err, "Failed to read routes.go") contentStr := string(content) lines := strings.Split(contentStr, "\n") // Check that routes.go has "DO NOT EDIT" comment require.GreaterOrEqual(t, len(lines), 2, "Routes file should have at least 2 lines") assert.Contains(t, lines[0], "// Code generated by goctl. DO NOT EDIT.", "Routes file should have 'DO NOT EDIT' comment") assert.Contains(t, lines[1], "// goctl", "Routes file should have version comment") assert.Contains(t, lines[1], version.BuildVersion, "Routes file should contain version %s", version.BuildVersion) } // TestVersionInTemplateData verifies that version is correctly passed to templates func TestVersionInTemplateData(t *testing.T) { // Test that BuildVersion is available assert.NotEmpty(t, version.BuildVersion, "BuildVersion should not be empty") } // TestCommentsFollowGoStandards verifies our comments follow Go community standards func TestCommentsFollowGoStandards(t *testing.T) { // Test the format of our generation comments doNotEditComment := "// Code generated by goctl. DO NOT EDIT." safeToEditComment := "// Code scaffolded by goctl. Safe to edit." // Both should be valid Go comments assert.True(t, strings.HasPrefix(doNotEditComment, "//"), "DO NOT EDIT comment should start with //") assert.True(t, strings.HasPrefix(safeToEditComment, "//"), "Safe to edit comment should start with //") // Should contain key information assert.Contains(t, doNotEditComment, "goctl", "DO NOT EDIT comment should mention goctl") assert.Contains(t, safeToEditComment, "goctl", "Safe to edit comment should mention goctl") assert.Contains(t, doNotEditComment, "DO NOT EDIT", "Should clearly state DO NOT EDIT") assert.Contains(t, safeToEditComment, "Safe to edit", "Should clearly state Safe to edit") }