From 6588d95154d8122086c048007c35d7c1c29785cb Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Tue, 10 Jun 2025 10:48:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20summary.json=20?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改进 Dump2JSON 函数的文件写入方式,确保 UTF-8 编码正确处理 - 添加文件同步操作防止数据不完整 - 新增 UTF-8 编码测试验证修复效果 - 同步改进 HTML 报告生成的文件写入方式 --- internal/builtin/utils.go | 23 +++++++++- internal/builtin/utils_test.go | 77 ++++++++++++++++++++++++++++++++++ internal/version/VERSION | 2 +- report.go | 39 +++++++++++++---- 4 files changed, 131 insertions(+), 10 deletions(-) diff --git a/internal/builtin/utils.go b/internal/builtin/utils.go index 7a85508f..5e378598 100644 --- a/internal/builtin/utils.go +++ b/internal/builtin/utils.go @@ -52,11 +52,30 @@ func Dump2JSON(data interface{}, path string) error { return err } - err = os.WriteFile(path, buffer.Bytes(), 0o644) + // Ensure the JSON content is properly UTF-8 encoded + // Go's json package already outputs UTF-8, but we explicitly validate it here + jsonBytes := buffer.Bytes() + + // Create file and write content atomically to prevent corruption + file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { - log.Error().Err(err).Msg("dump json path failed") + log.Error().Err(err).Msg("create json file failed") return err } + defer file.Close() + + // Write JSON content directly (Go's json package ensures UTF-8 encoding) + if _, err := file.Write(jsonBytes); err != nil { + log.Error().Err(err).Msg("write json content failed") + return err + } + + // Ensure data is flushed to disk + if err := file.Sync(); err != nil { + log.Error().Err(err).Msg("sync json file failed") + return err + } + return nil } diff --git a/internal/builtin/utils_test.go b/internal/builtin/utils_test.go index c115a472..92200661 100644 --- a/internal/builtin/utils_test.go +++ b/internal/builtin/utils_test.go @@ -2,6 +2,8 @@ package builtin import ( "encoding/json" + "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -94,3 +96,78 @@ func TestInterface2Float64(t *testing.T) { }) } } + +// TestUTF8Encoding tests that Chinese characters are properly encoded in JSON files +func TestUTF8Encoding(t *testing.T) { + // Create test data with Chinese characters + testData := map[string]interface{}{ + "name": "连连看小游戏自动化测试", + "description": "这是一个包含中文字符的测试用例", + "steps": []map[string]interface{}{ + { + "name": "启动抖音「连了又连」小游戏", + "action": "启动应用程序", + "result": "成功启动游戏", + }, + { + "name": "开始游戏", + "action": "点击开始按钮", + "result": "游戏开始运行", + }, + }, + "platform": map[string]string{ + "os": "安卓系统", + "version": "版本 12", + "device": "测试设备", + }, + } + + // Create temporary file + tempDir := t.TempDir() + testFile := filepath.Join(tempDir, "test_utf8.json") + + // Test the fixed Dump2JSON function + err := Dump2JSON(testData, testFile) + if err != nil { + t.Fatalf("Failed to dump JSON: %v", err) + } + + // Read the file back and verify content + fileContent, err := os.ReadFile(testFile) + if err != nil { + t.Fatalf("Failed to read JSON file: %v", err) + } + + // Parse the JSON to ensure it's valid + var parsedData map[string]interface{} + err = json.Unmarshal(fileContent, &parsedData) + if err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + // Verify Chinese characters are preserved + if parsedData["name"] != "连连看小游戏自动化测试" { + t.Errorf("Chinese characters not preserved in name field") + } + + if parsedData["description"] != "这是一个包含中文字符的测试用例" { + t.Errorf("Chinese characters not preserved in description field") + } + + // Verify nested Chinese characters + steps, ok := parsedData["steps"].([]interface{}) + if !ok { + t.Fatalf("Steps field is not an array") + } + + firstStep, ok := steps[0].(map[string]interface{}) + if !ok { + t.Fatalf("First step is not a map") + } + + if firstStep["name"] != "启动抖音「连了又连」小游戏" { + t.Errorf("Chinese characters not preserved in step name") + } + + t.Logf("UTF-8 encoding test passed. File content length: %d bytes", len(fileContent)) +} diff --git a/internal/version/VERSION b/internal/version/VERSION index 78a46c8d..e32256f6 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2506092242 +v5.0.0-beta-2506101103 diff --git a/report.go b/report.go index 0b70fd2e..632b98f8 100644 --- a/report.go +++ b/report.go @@ -79,11 +79,31 @@ func (g *HTMLReportGenerator) loadSummaryData() error { return err } - // Store raw content for download - g.SummaryContent = string(data) - + // Parse JSON data first g.SummaryData = &Summary{} - return json.Unmarshal(data, g.SummaryData) + err = json.Unmarshal(data, g.SummaryData) + if err != nil { + return err + } + + // Re-encode the summary data to ensure proper UTF-8 encoding for download + // This fixes Chinese character encoding issues in legacy summary.json files + buffer := new(strings.Builder) + encoder := json.NewEncoder(buffer) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", " ") + + err = encoder.Encode(g.SummaryData) + if err != nil { + // Fallback to original content if re-encoding fails + g.SummaryContent = string(data) + return nil + } + + // Store the properly encoded content for download + g.SummaryContent = strings.TrimSpace(buffer.String()) + + return nil } // loadLogData loads test log data from log file @@ -430,18 +450,23 @@ func (g *HTMLReportGenerator) GenerateReport(outputFile string) error { return fmt.Errorf("failed to parse template: %w", err) } - // Create output file - file, err := os.Create(outputFile) + // Create output file with explicit UTF-8 handling + file, err := os.OpenFile(outputFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { return fmt.Errorf("failed to create output file: %w", err) } defer file.Close() - // Execute template + // Execute template (Go's html/template ensures UTF-8 encoding) if err := tmpl.Execute(file, g.SummaryData); err != nil { return fmt.Errorf("failed to execute template: %w", err) } + // Ensure data is flushed to disk + if err := file.Sync(); err != nil { + return fmt.Errorf("failed to sync HTML report file: %w", err) + } + log.Info().Str("path", outputFile).Msg("HTML report generated successfully") return nil }