package main import ( "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" ) // download 是原生「另存为 / 系统打开」真正落盘的那一段,之前零测试。 // 对话框本身要真窗口没法自动化,但下载这段是纯 HTTP + 文件 IO,必须钉住。 func TestDownloadOK(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("PK\x03\x04fake docx")) })) defer srv.Close() dst := filepath.Join(t.TempDir(), "r.docx") if err := download(srv.URL, dst); err != nil { t.Fatalf("下载应成功: %v", err) } b, err := os.ReadFile(dst) if err != nil || string(b) != "PK\x03\x04fake docx" { t.Fatalf("落盘内容不对: %q err=%v", b, err) } } func TestDownloadHTTPError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer srv.Close() dst := filepath.Join(t.TempDir(), "r.docx") err := download(srv.URL, dst) if err == nil { t.Fatal("404 应该报错") } if !strings.Contains(err.Error(), "404") { t.Errorf("错误里应带状态码,便于用户判断: %v", err) } // 失败时不该在用户选定的路径上留一个空的/半截的 .docx —— // 用户会以为导出成功,双击却打不开。 if _, statErr := os.Stat(dst); statErr == nil { t.Error("下载失败却留下了文件(用户会当成导出成功的空文档)") } } // io.Copy 中途断开:用户选定路径上不该留半截文件。 func TestDownloadTruncatedLeavesNoFile(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Length", "999999") // 声明很长,实际写一点就断 _, _ = w.Write([]byte("half")) if f, ok := w.(http.Flusher); ok { f.Flush() } panic(http.ErrAbortHandler) // 掐断连接 })) defer srv.Close() dst := filepath.Join(t.TempDir(), "r.docx") if err := download(srv.URL, dst); err == nil { t.Fatal("连接中断应该报错") } if _, statErr := os.Stat(dst); statErr == nil { t.Error("中断却留下了半截文件") } } func TestPing(t *testing.T) { if (&App{}).Ping() == "" { t.Error("Ping 是前端探活 Go 桥的唯一手段,不能返回空") } }