mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-13 00:13:33 +08:00
1698 lines
60 KiB
Go
1698 lines
60 KiB
Go
package app
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"net"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
|
||
"GoNavi-Wails/internal/db"
|
||
"GoNavi-Wails/internal/logger"
|
||
"GoNavi-Wails/shared/i18n"
|
||
)
|
||
|
||
func methodsDriverFunctionSource(t *testing.T, source string, signature string) string {
|
||
t.Helper()
|
||
start := strings.Index(source, signature)
|
||
if start < 0 {
|
||
t.Fatalf("methods driver source missing function signature %q", signature)
|
||
}
|
||
rest := source[start+len(signature):]
|
||
end := strings.Index(rest, "\nfunc ")
|
||
if end < 0 {
|
||
return source[start:]
|
||
}
|
||
return source[start : start+len(signature)+end]
|
||
}
|
||
|
||
type timeoutDriverNetworkError struct{}
|
||
|
||
func (timeoutDriverNetworkError) Error() string { return "dial timeout" }
|
||
func (timeoutDriverNetworkError) Timeout() bool { return true }
|
||
func (timeoutDriverNetworkError) Temporary() bool { return true }
|
||
|
||
var _ net.Error = timeoutDriverNetworkError{}
|
||
|
||
func TestMethodsDriverNetworkBackendMessagesUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func probeDriverNetworkEndpoint": {
|
||
rawMessages: []string{`probed.Error = "检测地址为空"`},
|
||
keys: []string{"driver_manager.backend.network.error.probe_url_empty"},
|
||
},
|
||
"func resolveDriverProbeDialAddress": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("检测地址为空")`,
|
||
`fmt.Errorf("检测地址缺少主机")`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.network.error.probe_url_empty",
|
||
"driver_manager.backend.network.error.probe_host_missing",
|
||
},
|
||
},
|
||
"func normalizeDriverNetworkError": {
|
||
rawMessages: []string{`return "网络连接超时"`},
|
||
keys: []string{"driver_manager.backend.network.error.timeout"},
|
||
},
|
||
"func driverLogHint": {
|
||
rawMessages: []string{`fmt.Sprintf("(详细日志:%s)", path)`},
|
||
keys: []string{"driver_manager.backend.message.log_hint"},
|
||
},
|
||
"func logDriverOperationError": {
|
||
rawMessages: []string{`message = "未知错误"`},
|
||
keys: []string{"driver_manager.backend.error.unknown"},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw driver network text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference driver network i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverNetworkBackendCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.network.error.probe_url_empty",
|
||
"driver_manager.backend.network.error.probe_host_missing",
|
||
"driver_manager.backend.network.error.timeout",
|
||
"driver_manager.backend.message.log_hint",
|
||
"driver_manager.backend.error.unknown",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing driver network key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverReleaseHelpersUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func loadReleaseAssetSizesCached": {
|
||
rawMessages: []string{`fmt.Errorf("缓存 key 为空")`},
|
||
keys: []string{"driver_manager.backend.error.cache_key_empty"},
|
||
},
|
||
"func fetchDriverReleaseList": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("拉取驱动版本列表失败:HTTP %d", resp.StatusCode)`,
|
||
`fmt.Errorf("解析驱动版本列表失败:%w", err)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.driver_version_list_fetch_failed",
|
||
"driver_manager.backend.error.driver_version_list_parse_failed",
|
||
},
|
||
},
|
||
"func fetchDriverBundleAssetSizeIndex": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("release 为空")`,
|
||
`fmt.Errorf("未找到驱动总包索引资产")`,
|
||
`fmt.Errorf("拉取驱动总包索引失败:HTTP %d")`,
|
||
`fmt.Errorf("解析驱动总包索引失败:%w")`,
|
||
`fmt.Errorf("驱动总包索引为空")`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.release_empty",
|
||
"driver_manager.backend.error.bundle_index_asset_missing",
|
||
"driver_manager.backend.error.bundle_index_fetch_failed",
|
||
"driver_manager.backend.error.bundle_index_parse_failed",
|
||
"driver_manager.backend.error.bundle_index_empty",
|
||
},
|
||
},
|
||
"func fetchReleaseByTag": {
|
||
rawMessages: []string{`fmt.Errorf("Tag 为空")`},
|
||
keys: []string{"driver_manager.backend.error.tag_empty"},
|
||
},
|
||
"func fetchDriverReleaseByURL": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("API 地址为空")`,
|
||
`fmt.Errorf("拉取 Release 信息失败:HTTP %d")`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.api_url_empty",
|
||
"driver_manager.backend.error.release_info_fetch_failed",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw release helper text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference release helper i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverInstallActionDetailsUseEnglishInternalWrappers(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
internalDetails []string
|
||
}{
|
||
"func (a *App) InstallLocalDriverPackage": {
|
||
rawMessages: []string{
|
||
`"导入本地驱动包失败,driver=%s file=%s"`,
|
||
`"写入本地驱动元数据失败,driver=%s"`,
|
||
},
|
||
internalDetails: []string{
|
||
`"failed to import local driver package, driver=%s file=%s"`,
|
||
`"failed to write local driver metadata, driver=%s"`,
|
||
},
|
||
},
|
||
"func (a *App) DownloadDriverPackage": {
|
||
rawMessages: []string{
|
||
`"驱动下载安装失败,driver=%s version=%s url=%s"`,
|
||
`"写入驱动元数据失败,driver=%s version=%s"`,
|
||
},
|
||
internalDetails: []string{
|
||
`"failed to download and install driver, driver=%s version=%s url=%s"`,
|
||
`"failed to write driver metadata, driver=%s version=%s"`,
|
||
},
|
||
},
|
||
"func (a *App) RemoveDriverPackage": {
|
||
rawMessages: []string{
|
||
`"移除驱动包失败,driver=%s path=%s"`,
|
||
},
|
||
internalDetails: []string{
|
||
`"failed to remove driver package, driver=%s path=%s"`,
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw install action detail wrapper %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, internalDetail := range check.internalDetails {
|
||
if !strings.Contains(functionSource, internalDetail) {
|
||
t.Fatalf("%s does not contain English internal detail wrapper %q", signature, internalDetail)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverReleaseHelperCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.cache_key_empty",
|
||
"driver_manager.backend.error.driver_version_list_fetch_failed",
|
||
"driver_manager.backend.error.driver_version_list_parse_failed",
|
||
"driver_manager.backend.error.release_empty",
|
||
"driver_manager.backend.error.bundle_index_asset_missing",
|
||
"driver_manager.backend.error.bundle_index_fetch_failed",
|
||
"driver_manager.backend.error.bundle_index_parse_failed",
|
||
"driver_manager.backend.error.bundle_index_empty",
|
||
"driver_manager.backend.error.tag_empty",
|
||
"driver_manager.backend.error.api_url_empty",
|
||
"driver_manager.backend.error.release_info_fetch_failed",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing release helper key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestResolveDriverDownloadDirectoryUsesCurrentLanguageForCreateDirectoryFailure(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
blocker := filepath.Join(t.TempDir(), "driver-root-blocker")
|
||
if err := os.WriteFile(blocker, []byte("blocker"), 0o644); err != nil {
|
||
t.Fatalf("write blocker file: %v", err)
|
||
}
|
||
|
||
result := app.ResolveDriverDownloadDirectory(filepath.Join(blocker, "nested"))
|
||
if result.Success {
|
||
t.Fatalf("expected resolve driver directory failure, got %+v", result)
|
||
}
|
||
if !strings.Contains(result.Message, "Failed to create driver directory:") {
|
||
t.Fatalf("expected English create-directory wrapper, got %q", result.Message)
|
||
}
|
||
if strings.Contains(result.Message, "\u521b\u5efa\u9a71\u52a8\u76ee\u5f55\u5931\u8d25") {
|
||
t.Fatalf("expected no Chinese create-directory wrapper in en-US mode, got %q", result.Message)
|
||
}
|
||
}
|
||
|
||
func TestProbeDriverNetworkEndpointUsesCurrentLanguageForEmptyURL(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
probed := probeDriverNetworkEndpoint(nil, driverNetworkProbeItem{URL: " "})
|
||
if probed.Error != "Probe URL is empty" {
|
||
t.Fatalf("expected English probe URL message, got %q", probed.Error)
|
||
}
|
||
if strings.Contains(probed.Error, "检测地址为空") {
|
||
t.Fatalf("expected no Chinese probe URL message in en-US mode, got %q", probed.Error)
|
||
}
|
||
}
|
||
|
||
func TestResolveDriverProbeDialAddressUsesCurrentLanguageForMissingHost(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
_, err := resolveDriverProbeDialAddress("https:///driver")
|
||
if err == nil {
|
||
t.Fatal("expected probe host validation error")
|
||
}
|
||
if err.Error() != "Probe URL is missing a host" {
|
||
t.Fatalf("expected English probe host message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "检测地址缺少主机") {
|
||
t.Fatalf("expected no Chinese probe host message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestNormalizeDriverNetworkErrorUsesCurrentLanguageForTimeout(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
text := normalizeDriverNetworkError(timeoutDriverNetworkError{})
|
||
if text != "Network connection timed out" {
|
||
t.Fatalf("expected English network timeout message, got %q", text)
|
||
}
|
||
if strings.Contains(text, "网络连接超时") {
|
||
t.Fatalf("expected no Chinese timeout message in en-US mode, got %q", text)
|
||
}
|
||
}
|
||
|
||
func TestDriverOperationLegacyHelpersUseCurrentLanguageForUnknownAndLogHint(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
if strings.TrimSpace(logger.Path()) == "" {
|
||
t.Skip("logger path unavailable")
|
||
}
|
||
|
||
hint := driverLogHint()
|
||
if !strings.Contains(hint, "detail log:") {
|
||
t.Fatalf("expected English driver log hint, got %q", hint)
|
||
}
|
||
if strings.Contains(hint, "详细日志") {
|
||
t.Fatalf("expected no Chinese driver log hint in en-US mode, got %q", hint)
|
||
}
|
||
|
||
text := logDriverOperationError(errors.New(""), "test driver error")
|
||
if !strings.Contains(text, "Unknown error") {
|
||
t.Fatalf("expected English unknown driver error fallback, got %q", text)
|
||
}
|
||
if !strings.Contains(text, "detail log:") {
|
||
t.Fatalf("expected English detail log hint in legacy driver error text, got %q", text)
|
||
}
|
||
if strings.Contains(text, "未知错误") || strings.Contains(text, "详细日志") {
|
||
t.Fatalf("expected no Chinese legacy driver error text in en-US mode, got %q", text)
|
||
}
|
||
}
|
||
|
||
func TestLoadReleaseAssetSizesCachedUsesCurrentLanguageForEmptyCacheKey(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
_, _, err := loadReleaseAssetSizesCached(" ", func() (*githubRelease, error) {
|
||
t.Fatal("fetch should not be called for empty cache key")
|
||
return nil, nil
|
||
})
|
||
if err == nil {
|
||
t.Fatal("expected empty cache key error")
|
||
}
|
||
if err.Error() != "Cache key is empty" {
|
||
t.Fatalf("expected English cache key message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "缓存 key 为空") {
|
||
t.Fatalf("expected no Chinese cache key message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestFetchDriverBundleAssetSizeIndexUsesCurrentLanguageForStructuredErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
disableGlobalProxyForTest(t)
|
||
|
||
makeRelease := func(downloadURL string) *githubRelease {
|
||
return &githubRelease{
|
||
Assets: []githubAsset{{
|
||
Name: optionalDriverBundleIndexAssetName,
|
||
BrowserDownloadURL: downloadURL,
|
||
}},
|
||
}
|
||
}
|
||
|
||
server500 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||
http.Error(w, "nope", http.StatusInternalServerError)
|
||
}))
|
||
defer server500.Close()
|
||
|
||
serverInvalidJSON := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||
_, _ = w.Write([]byte("{invalid"))
|
||
}))
|
||
defer serverInvalidJSON.Close()
|
||
|
||
serverEmptyIndex := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||
_, _ = w.Write([]byte(`{"assets":{}}`))
|
||
}))
|
||
defer serverEmptyIndex.Close()
|
||
|
||
cases := []struct {
|
||
name string
|
||
release *githubRelease
|
||
want string
|
||
avoid string
|
||
}{
|
||
{
|
||
name: "nil release",
|
||
release: nil,
|
||
want: "Release is empty",
|
||
avoid: "release 为空",
|
||
},
|
||
{
|
||
name: "missing bundle index asset",
|
||
release: &githubRelease{},
|
||
want: "Driver bundle index asset was not found",
|
||
avoid: "未找到驱动总包索引资产",
|
||
},
|
||
{
|
||
name: "http status failure",
|
||
release: makeRelease(server500.URL),
|
||
want: "Failed to fetch driver bundle index: HTTP 500",
|
||
avoid: "拉取驱动总包索引失败",
|
||
},
|
||
{
|
||
name: "parse failure",
|
||
release: makeRelease(serverInvalidJSON.URL),
|
||
want: "Failed to parse driver bundle index:",
|
||
avoid: "解析驱动总包索引失败",
|
||
},
|
||
{
|
||
name: "empty index",
|
||
release: makeRelease(serverEmptyIndex.URL),
|
||
want: "Driver bundle index is empty",
|
||
avoid: "驱动总包索引为空",
|
||
},
|
||
}
|
||
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
_, err := fetchDriverBundleAssetSizeIndex(tc.release)
|
||
if err == nil {
|
||
t.Fatal("expected structured release index error")
|
||
}
|
||
if !strings.Contains(err.Error(), tc.want) {
|
||
t.Fatalf("expected %q in English release index error, got %q", tc.want, err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), tc.avoid) {
|
||
t.Fatalf("expected no Chinese release index error in en-US mode, got %q", err.Error())
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestFetchReleaseByTagUsesCurrentLanguageForEmptyTag(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
|
||
_, err := fetchReleaseByTag(" ")
|
||
if err == nil {
|
||
t.Fatal("expected empty tag error")
|
||
}
|
||
if err.Error() != "Tag is empty" {
|
||
t.Fatalf("expected English empty tag message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "Tag 为空") {
|
||
t.Fatalf("expected no Chinese empty tag message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestFetchDriverReleaseByURLUsesCurrentLanguageForStructuredErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
disableGlobalProxyForTest(t)
|
||
|
||
_, err := fetchDriverReleaseByURL(" ")
|
||
if err == nil {
|
||
t.Fatal("expected empty API URL error")
|
||
}
|
||
if err.Error() != "API URL is empty" {
|
||
t.Fatalf("expected English API URL message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "API 地址为空") {
|
||
t.Fatalf("expected no Chinese API URL message in en-US mode, got %q", err.Error())
|
||
}
|
||
|
||
server500 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||
http.Error(w, "nope", http.StatusInternalServerError)
|
||
}))
|
||
defer server500.Close()
|
||
|
||
_, err = fetchDriverReleaseByURL(server500.URL)
|
||
if err == nil {
|
||
t.Fatal("expected Release information fetch failure")
|
||
}
|
||
want := fmt.Sprintf("Failed to fetch Release information: HTTP %d", http.StatusInternalServerError)
|
||
if err.Error() != want {
|
||
t.Fatalf("expected English Release information fetch message %q, got %q", want, err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "拉取 Release 信息失败") {
|
||
t.Fatalf("expected no Chinese Release information fetch message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverVersionOptionErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
functionSource := methodsDriverFunctionSource(t, source, "func resolveDriverVersionOptions")
|
||
for _, rawMessage := range []string{
|
||
`fmt.Errorf("驱动类型为空")`,
|
||
`fmt.Errorf("未找到可用驱动版本")`,
|
||
} {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("resolveDriverVersionOptions still contains raw version option text %q", rawMessage)
|
||
}
|
||
}
|
||
for _, key := range []string{
|
||
"driver_manager.backend.error.driver_type_empty",
|
||
"driver_manager.backend.error.no_driver_versions",
|
||
} {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("resolveDriverVersionOptions does not reference version option i18n key %q", key)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverVersionOptionErrorCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.driver_type_empty",
|
||
"driver_manager.backend.error.no_driver_versions",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing version option error key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestResolveDriverVersionOptionsUsesCurrentLanguageForStructuredErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := resolveDriverVersionOptions(driverDefinition{}, "", app.appText)
|
||
if err == nil {
|
||
t.Fatal("expected empty driver type error")
|
||
}
|
||
if err.Error() != "Driver type is empty" {
|
||
t.Fatalf("expected English driver type message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "驱动类型为空") {
|
||
t.Fatalf("expected no Chinese driver type message in en-US mode, got %q", err.Error())
|
||
}
|
||
|
||
originalModulePath, hadModulePath := driverGoModulePathMap["mongodb"]
|
||
originalAliasPaths, hadAliasPaths := driverGoModuleAliasPathMap["mongodb"]
|
||
originalFallbackVersions, hadFallbackVersions := fallbackRecentDriverVersionsMap["mongodb"]
|
||
originalLatestVersion, hadLatestVersion := latestDriverVersionMap["mongodb"]
|
||
delete(driverGoModulePathMap, "mongodb")
|
||
delete(driverGoModuleAliasPathMap, "mongodb")
|
||
delete(fallbackRecentDriverVersionsMap, "mongodb")
|
||
delete(latestDriverVersionMap, "mongodb")
|
||
t.Cleanup(func() {
|
||
if hadModulePath {
|
||
driverGoModulePathMap["mongodb"] = originalModulePath
|
||
} else {
|
||
delete(driverGoModulePathMap, "mongodb")
|
||
}
|
||
if hadAliasPaths {
|
||
driverGoModuleAliasPathMap["mongodb"] = originalAliasPaths
|
||
} else {
|
||
delete(driverGoModuleAliasPathMap, "mongodb")
|
||
}
|
||
if hadFallbackVersions {
|
||
fallbackRecentDriverVersionsMap["mongodb"] = originalFallbackVersions
|
||
} else {
|
||
delete(fallbackRecentDriverVersionsMap, "mongodb")
|
||
}
|
||
if hadLatestVersion {
|
||
latestDriverVersionMap["mongodb"] = originalLatestVersion
|
||
} else {
|
||
delete(latestDriverVersionMap, "mongodb")
|
||
}
|
||
})
|
||
|
||
_, err = resolveDriverVersionOptions(
|
||
driverDefinition{Type: "mongodb", Name: "MongoDB"},
|
||
"unsupported://manifest",
|
||
app.appText,
|
||
)
|
||
if err == nil {
|
||
t.Fatal("expected missing driver version options error")
|
||
}
|
||
if err.Error() != "No available driver versions were found" {
|
||
t.Fatalf("expected English version options message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未找到可用驱动版本") {
|
||
t.Fatalf("expected no Chinese version options message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverModuleVersionFetchErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
functionSource := methodsDriverFunctionSource(t, source, "func fetchGoModuleVersionMetas(modulePath string)")
|
||
for _, rawMessage := range []string{
|
||
`fmt.Errorf("模块路径为空")`,
|
||
`fmt.Errorf("拉取模块版本列表失败:HTTP %d", resp.StatusCode)`,
|
||
`fmt.Errorf("读取模块版本列表失败:%w", err)`,
|
||
`fmt.Errorf("模块版本列表为空")`,
|
||
} {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("fetchGoModuleVersionMetas still contains raw module-version text %q", rawMessage)
|
||
}
|
||
}
|
||
for _, key := range []string{
|
||
"driver_manager.backend.error.module_path_empty",
|
||
"driver_manager.backend.error.module_version_list_fetch_failed",
|
||
"driver_manager.backend.error.module_version_list_read_failed",
|
||
"driver_manager.backend.error.module_version_list_empty",
|
||
} {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("fetchGoModuleVersionMetas does not reference module-version i18n key %q", key)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverModuleVersionFetchErrorCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.module_path_empty",
|
||
"driver_manager.backend.error.module_version_list_fetch_failed",
|
||
"driver_manager.backend.error.module_version_list_read_failed",
|
||
"driver_manager.backend.error.module_version_list_empty",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing module-version fetch key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestFetchGoModuleVersionMetasUsesCurrentLanguageForEmptyModulePath(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := fetchGoModuleVersionMetas(" ")
|
||
if err == nil {
|
||
t.Fatal("expected empty module path error")
|
||
}
|
||
if err.Error() != "Module path is empty" {
|
||
t.Fatalf("expected English module path message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "模块路径为空") {
|
||
t.Fatalf("expected no Chinese module path message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverBundleAcquireErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
functionSource := methodsDriverFunctionSource(t, source, "func acquireOptionalDriverBundlePath(bundleURL string, onProgress func(downloaded, total int64), onWaiting func()) (string, error)")
|
||
if strings.Contains(functionSource, `fmt.Errorf("驱动总包下载地址为空")`) {
|
||
t.Fatalf("acquireOptionalDriverBundlePath still contains raw bundle URL text")
|
||
}
|
||
if !strings.Contains(functionSource, "driver_manager.backend.error.bundle_url_empty") {
|
||
t.Fatalf("acquireOptionalDriverBundlePath does not reference bundle URL i18n key")
|
||
}
|
||
}
|
||
|
||
func TestAcquireOptionalDriverBundlePathUsesCurrentLanguageForEmptyURL(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := acquireOptionalDriverBundlePath(" ", nil, nil)
|
||
if err == nil {
|
||
t.Fatal("expected empty bundle URL error")
|
||
}
|
||
if err.Error() != "Driver bundle download URL is empty" {
|
||
t.Fatalf("expected English bundle URL message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "驱动总包下载地址为空") {
|
||
t.Fatalf("expected no Chinese bundle URL message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverManifestErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func resolveDriverRepositoryURL": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("无效的文件清单地址")`,
|
||
`fmt.Errorf("不支持的内置清单地址:%s", parsed.String())`,
|
||
`fmt.Errorf("不支持的清单地址协议:%s", parsed.Scheme)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.file_manifest_url_invalid",
|
||
"driver_manager.backend.message.unsupported_builtin_manifest_url",
|
||
"driver_manager.backend.error.manifest_scheme_unsupported",
|
||
},
|
||
},
|
||
"func loadManifestPackageAndVersions": {
|
||
rawMessages: []string{`fmt.Errorf("解析驱动清单失败:%w", err)`},
|
||
keys: []string{"driver_manager.backend.error.manifest_parse_failed"},
|
||
},
|
||
"func loadManifestContent": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("驱动清单地址为空")`,
|
||
`fmt.Errorf("拉取驱动清单失败:HTTP %d", resp.StatusCode)`,
|
||
`fmt.Errorf("驱动清单超过大小限制")`,
|
||
`fmt.Errorf("无效的本地驱动清单地址")`,
|
||
`fmt.Errorf("不支持的内置清单地址:%s", parsed.String())`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.manifest_url_empty",
|
||
"driver_manager.backend.error.manifest_fetch_failed",
|
||
"driver_manager.backend.error.manifest_too_large",
|
||
"driver_manager.backend.error.local_manifest_url_invalid",
|
||
"driver_manager.backend.message.unsupported_builtin_manifest_url",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw manifest text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference manifest i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverManifestErrorCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.file_manifest_url_invalid",
|
||
"driver_manager.backend.message.unsupported_builtin_manifest_url",
|
||
"driver_manager.backend.error.manifest_scheme_unsupported",
|
||
"driver_manager.backend.error.manifest_parse_failed",
|
||
"driver_manager.backend.error.manifest_url_empty",
|
||
"driver_manager.backend.error.manifest_fetch_failed",
|
||
"driver_manager.backend.error.manifest_too_large",
|
||
"driver_manager.backend.error.local_manifest_url_invalid",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing manifest key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestResolveDriverRepositoryURLUsesCurrentLanguageForStructuredErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
invalidFile := app.ResolveDriverRepositoryURL("file://")
|
||
if invalidFile.Success {
|
||
t.Fatal("expected invalid file manifest URL error")
|
||
}
|
||
if invalidFile.Message != "Invalid file driver manifest URL" {
|
||
t.Fatalf("expected English invalid file manifest URL message, got %q", invalidFile.Message)
|
||
}
|
||
if strings.Contains(invalidFile.Message, "无效的文件清单地址") {
|
||
t.Fatalf("expected no Chinese invalid file manifest URL text in en-US mode, got %q", invalidFile.Message)
|
||
}
|
||
|
||
unsupportedScheme := app.ResolveDriverRepositoryURL("unsupported://manifest")
|
||
if unsupportedScheme.Success {
|
||
t.Fatal("expected unsupported manifest scheme error")
|
||
}
|
||
if unsupportedScheme.Message != "Unsupported driver manifest URL scheme: unsupported" {
|
||
t.Fatalf("expected English unsupported scheme message, got %q", unsupportedScheme.Message)
|
||
}
|
||
if strings.Contains(unsupportedScheme.Message, "不支持的清单地址协议") {
|
||
t.Fatalf("expected no Chinese unsupported scheme text in en-US mode, got %q", unsupportedScheme.Message)
|
||
}
|
||
}
|
||
|
||
func TestGetDriverStatusListUsesCurrentLanguageForManifestErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
disableGlobalProxyForTest(t)
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
fetchServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.WriteHeader(http.StatusServiceUnavailable)
|
||
_, _ = w.Write([]byte("busy"))
|
||
}))
|
||
defer fetchServer.Close()
|
||
driverManifestCacheMu.Lock()
|
||
delete(driverManifestCache, fetchServer.URL)
|
||
driverManifestCacheMu.Unlock()
|
||
t.Cleanup(func() {
|
||
driverManifestCacheMu.Lock()
|
||
delete(driverManifestCache, fetchServer.URL)
|
||
driverManifestCacheMu.Unlock()
|
||
})
|
||
|
||
fetchRes := app.GetDriverStatusList(t.TempDir(), fetchServer.URL)
|
||
if !fetchRes.Success {
|
||
t.Fatalf("expected status list success with manifest warning, got %+v", fetchRes)
|
||
}
|
||
fetchData, ok := fetchRes.Data.(map[string]interface{})
|
||
if !ok {
|
||
t.Fatalf("expected status list data map, got %T", fetchRes.Data)
|
||
}
|
||
fetchManifestError := strings.TrimSpace(fmt.Sprint(fetchData["manifestError"]))
|
||
if fetchManifestError != "Failed to fetch driver manifest: HTTP 503" {
|
||
t.Fatalf("expected English manifest fetch warning, got %q", fetchManifestError)
|
||
}
|
||
if strings.Contains(fetchManifestError, "拉取驱动清单失败") {
|
||
t.Fatalf("expected no Chinese manifest fetch warning in en-US mode, got %q", fetchManifestError)
|
||
}
|
||
fetchResCached := app.GetDriverStatusList(t.TempDir(), fetchServer.URL)
|
||
if !fetchResCached.Success {
|
||
t.Fatalf("expected cached status list success with manifest warning, got %+v", fetchResCached)
|
||
}
|
||
fetchDataCached, ok := fetchResCached.Data.(map[string]interface{})
|
||
if !ok {
|
||
t.Fatalf("expected cached status list data map, got %T", fetchResCached.Data)
|
||
}
|
||
fetchManifestErrorCached := strings.TrimSpace(fmt.Sprint(fetchDataCached["manifestError"]))
|
||
if fetchManifestErrorCached != "Failed to fetch driver manifest: HTTP 503" {
|
||
t.Fatalf("expected cached English manifest fetch warning, got %q", fetchManifestErrorCached)
|
||
}
|
||
if strings.Contains(fetchManifestErrorCached, "拉取驱动清单失败") {
|
||
t.Fatalf("expected no Chinese cached manifest fetch warning in en-US mode, got %q", fetchManifestErrorCached)
|
||
}
|
||
|
||
parseServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_, _ = w.Write([]byte("{not-json"))
|
||
}))
|
||
defer parseServer.Close()
|
||
driverManifestCacheMu.Lock()
|
||
delete(driverManifestCache, parseServer.URL)
|
||
driverManifestCacheMu.Unlock()
|
||
t.Cleanup(func() {
|
||
driverManifestCacheMu.Lock()
|
||
delete(driverManifestCache, parseServer.URL)
|
||
driverManifestCacheMu.Unlock()
|
||
})
|
||
|
||
parseRes := app.GetDriverStatusList(t.TempDir(), parseServer.URL)
|
||
if !parseRes.Success {
|
||
t.Fatalf("expected status list success with manifest parse warning, got %+v", parseRes)
|
||
}
|
||
parseData, ok := parseRes.Data.(map[string]interface{})
|
||
if !ok {
|
||
t.Fatalf("expected status list data map, got %T", parseRes.Data)
|
||
}
|
||
parseManifestError := strings.TrimSpace(fmt.Sprint(parseData["manifestError"]))
|
||
if !strings.HasPrefix(parseManifestError, "Failed to parse driver manifest:") {
|
||
t.Fatalf("expected English manifest parse warning, got %q", parseManifestError)
|
||
}
|
||
if strings.Contains(parseManifestError, "解析驱动清单失败") {
|
||
t.Fatalf("expected no Chinese manifest parse warning in en-US mode, got %q", parseManifestError)
|
||
}
|
||
parseResCached := app.GetDriverStatusList(t.TempDir(), parseServer.URL)
|
||
if !parseResCached.Success {
|
||
t.Fatalf("expected cached status list success with manifest parse warning, got %+v", parseResCached)
|
||
}
|
||
parseDataCached, ok := parseResCached.Data.(map[string]interface{})
|
||
if !ok {
|
||
t.Fatalf("expected cached status list data map, got %T", parseResCached.Data)
|
||
}
|
||
parseManifestErrorCached := strings.TrimSpace(fmt.Sprint(parseDataCached["manifestError"]))
|
||
if !strings.HasPrefix(parseManifestErrorCached, "Failed to parse driver manifest:") {
|
||
t.Fatalf("expected cached English manifest parse warning, got %q", parseManifestErrorCached)
|
||
}
|
||
if strings.Contains(parseManifestErrorCached, "解析驱动清单失败") {
|
||
t.Fatalf("expected no Chinese cached manifest parse warning in en-US mode, got %q", parseManifestErrorCached)
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverUnsupportedVersionErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
functionSource := methodsDriverFunctionSource(t, source, "func (a *App) localizeDriverSelectionError")
|
||
for _, key := range []string{
|
||
"driver_manager.backend.error.mongo_version_unsupported",
|
||
"driver_manager.backend.error.driver_version_unsupported",
|
||
} {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("localizeDriverSelectionError does not reference unsupported-version i18n key %q", key)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverUnsupportedVersionErrorTypesUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func (e *driverBuildUnavailableError) Error() string": {
|
||
rawMessages: []string{
|
||
`fmt.Sprintf("%s 当前发行包为精简构建,未内置该驱动;如需使用请安装 Full 版", strings.TrimSpace(e.Name))`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.status.slim_build_required",
|
||
},
|
||
},
|
||
"func (e *driverVersionValidationError) Error() string": {
|
||
rawMessages: []string{
|
||
`fmt.Sprintf("MongoDB 版本 %s 当前不受支持;仅支持 1.17.x 和 2.x", versionText)`,
|
||
`fmt.Sprintf("%s 版本 %s 当前不受支持", driverType, versionText)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.mongo_version_unsupported",
|
||
"driver_manager.backend.error.driver_version_unsupported",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw unsupported-version error text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference unsupported-version error i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverUnsupportedVersionErrorCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.mongo_version_unsupported",
|
||
"driver_manager.backend.error.driver_version_unsupported",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing unsupported-version key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestDriverSelectionErrorTypesUseCurrentLanguageDirectly(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
cases := []struct {
|
||
name string
|
||
err error
|
||
want string
|
||
avoid string
|
||
}{
|
||
{
|
||
name: "slim build required",
|
||
err: &driverBuildUnavailableError{Name: "ClickHouse"},
|
||
want: "ClickHouse is not included in the current slim build. Install the Full edition to use this driver.",
|
||
avoid: "当前发行包为精简构建",
|
||
},
|
||
{
|
||
name: "mongodb version unsupported",
|
||
err: &driverVersionValidationError{
|
||
DriverType: "mongodb",
|
||
Version: "1.16.9",
|
||
},
|
||
want: "MongoDB version 1.16.9 is not supported; only 1.17.x and 2.x are supported",
|
||
avoid: "当前不受支持;仅支持 1.17.x 和 2.x",
|
||
},
|
||
{
|
||
name: "generic driver version unsupported",
|
||
err: &driverVersionValidationError{
|
||
DriverType: "clickhouse",
|
||
Version: " 24.3.1 ",
|
||
},
|
||
want: "ClickHouse version 24.3.1 is not supported",
|
||
avoid: "当前不受支持",
|
||
},
|
||
}
|
||
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
got := tc.err.Error()
|
||
if got != tc.want {
|
||
t.Fatalf("expected direct English driver error %q, got %q", tc.want, got)
|
||
}
|
||
if strings.Contains(got, tc.avoid) {
|
||
t.Fatalf("expected no Chinese direct driver error in en-US mode, got %q", got)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestLocalizeDriverSelectionErrorUsesCurrentLanguageForUnsupportedVersions(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
cases := []struct {
|
||
name string
|
||
definition driverDefinition
|
||
err error
|
||
want string
|
||
avoid string
|
||
}{
|
||
{
|
||
name: "mongodb compatibility pin",
|
||
definition: driverDefinition{Type: "mongodb", Name: "MongoDB"},
|
||
err: &driverVersionValidationError{
|
||
DriverType: "mongodb",
|
||
Version: "1.16.9",
|
||
},
|
||
want: "MongoDB version 1.16.9 is not supported; only 1.17.x and 2.x are supported",
|
||
avoid: "当前不受支持;仅支持 1.17.x 和 2.x",
|
||
},
|
||
{
|
||
name: "generic optional driver version",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
err: &driverVersionValidationError{
|
||
DriverType: "clickhouse",
|
||
Version: " 24.3.1 ",
|
||
},
|
||
want: "ClickHouse version 24.3.1 is not supported",
|
||
avoid: "当前不受支持",
|
||
},
|
||
}
|
||
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
err := app.localizeDriverSelectionError(tc.definition, tc.err)
|
||
if err == nil {
|
||
t.Fatal("expected unsupported version error")
|
||
}
|
||
if err.Error() != tc.want {
|
||
t.Fatalf("expected English unsupported-version message %q, got %q", tc.want, err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), tc.avoid) {
|
||
t.Fatalf("expected no Chinese unsupported-version message in en-US mode, got %q", err.Error())
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverRuntimeReasonCompatibilityUsesLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func parseDriverAgentArchIncompatibleDetail": {
|
||
rawMessages: []string{
|
||
`"可执行文件架构不兼容(文件="`,
|
||
`",当前进程="`,
|
||
},
|
||
},
|
||
"func parseDriverAgentUnavailableDetail": {
|
||
rawMessages: []string{
|
||
`" 驱动代理不可用:"`,
|
||
`";请在驱动管理中重新安装启用"`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.status.agent_unavailable_reinstall",
|
||
},
|
||
},
|
||
"func (a *App) localizeDriverRuntimeReason": {
|
||
rawMessages: []string{
|
||
`"未识别的数据源类型"`,
|
||
`fmt.Sprintf("%s 当前发行包为精简构建,未内置该驱动;如需使用请安装 Full 版", name)`,
|
||
`fmt.Sprintf("%s 驱动代理路径解析失败,请在驱动管理中重新安装启用", name)`,
|
||
`fmt.Sprintf("%s 驱动代理路径为空;请在驱动管理中重新安装启用", name)`,
|
||
`fmt.Sprintf("%s 驱动代理缺失,请在驱动管理中重新安装启用", name)`,
|
||
`fmt.Sprintf("%s 纯 Go 驱动未启用,请先在驱动管理中点击“安装启用”", name)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.status.unrecognized_driver_type",
|
||
"driver_manager.backend.status.slim_build_required",
|
||
"driver_manager.backend.status.agent_path_failed",
|
||
"driver_manager.backend.status.agent_missing",
|
||
"driver_manager.backend.status.optional_disabled",
|
||
"driver_manager.backend.status.agent_unavailable_reinstall",
|
||
"driver_manager.backend.status.agent_arch_incompatible_detail",
|
||
},
|
||
},
|
||
"func resolveDriverDisplayName": {
|
||
rawMessages: []string{
|
||
`return "未知"`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.driver_fallback_name",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw runtime-reason text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference runtime-reason i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestLocalizeDriverRuntimeReasonUsesCurrentLanguageForLegacyZhCNReasons(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
zhLocalizer, err := i18n.NewLocalizer(i18n.LanguageZhCN)
|
||
if err != nil {
|
||
t.Fatalf("NewLocalizer(zh-CN): %v", err)
|
||
}
|
||
|
||
buildLegacyAgentUnavailableReason := func(name string, detail string) string {
|
||
current := zhLocalizer.T("driver_manager.backend.status.agent_unavailable_reinstall", map[string]any{
|
||
"name": name,
|
||
"detail": detail,
|
||
})
|
||
return strings.Replace(current, detail+"。", detail+";", 1)
|
||
}
|
||
|
||
cases := []struct {
|
||
name string
|
||
definition driverDefinition
|
||
reason string
|
||
want string
|
||
avoid string
|
||
}{
|
||
{
|
||
name: "unrecognized driver type",
|
||
definition: driverDefinition{},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.unrecognized_driver_type", nil),
|
||
want: "Unrecognized data source type",
|
||
avoid: "未识别的数据源类型",
|
||
},
|
||
{
|
||
name: "slim build required",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.slim_build_required", map[string]any{
|
||
"name": "ClickHouse",
|
||
}),
|
||
want: "ClickHouse is not included in the current slim build. Install the Full edition to use this driver.",
|
||
avoid: "当前发行包为精简构建",
|
||
},
|
||
{
|
||
name: "agent path failed",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.agent_path_failed", map[string]any{
|
||
"name": "ClickHouse",
|
||
}),
|
||
want: "ClickHouse driver agent path could not be resolved; reinstall and enable it in Driver Manager.",
|
||
avoid: "驱动代理路径解析失败",
|
||
},
|
||
{
|
||
name: "agent missing",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.agent_missing", map[string]any{
|
||
"name": "ClickHouse",
|
||
}),
|
||
want: "ClickHouse driver agent is missing; reinstall and enable it in Driver Manager.",
|
||
avoid: "驱动代理缺失",
|
||
},
|
||
{
|
||
name: "optional driver disabled",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.optional_disabled", map[string]any{
|
||
"name": "ClickHouse",
|
||
}),
|
||
want: "ClickHouse Go driver is not enabled; install and enable it in Driver Manager.",
|
||
avoid: "纯 Go 驱动未启用",
|
||
},
|
||
{
|
||
name: "agent arch incompatible current zh-CN template",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: zhLocalizer.T("driver_manager.backend.status.agent_arch_incompatible_detail", map[string]any{
|
||
"name": "ClickHouse",
|
||
"file": "arm64",
|
||
"process": "amd64",
|
||
}),
|
||
want: "ClickHouse driver agent architecture is incompatible: file=arm64, current process=amd64; reinstall and enable it in Driver Manager.",
|
||
avoid: "驱动代理架构不兼容",
|
||
},
|
||
{
|
||
name: "legacy unavailable wrapper with english arch detail",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: buildLegacyAgentUnavailableReason(
|
||
"ClickHouse",
|
||
"driver agent architecture is incompatible (file=arm64, current process=amd64)",
|
||
),
|
||
want: "ClickHouse driver agent architecture is incompatible: file=arm64, current process=amd64; reinstall and enable it in Driver Manager.",
|
||
avoid: "驱动代理不可用",
|
||
},
|
||
{
|
||
name: "legacy unavailable wrapper keeps raw detail",
|
||
definition: driverDefinition{Type: "clickhouse", Name: "ClickHouse"},
|
||
reason: buildLegacyAgentUnavailableReason("ClickHouse", "permission denied"),
|
||
want: "ClickHouse driver agent is unavailable: permission denied; reinstall and enable it in Driver Manager.",
|
||
avoid: "驱动代理不可用",
|
||
},
|
||
}
|
||
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
got := app.localizeDriverRuntimeReason(tc.definition, tc.reason)
|
||
if got != tc.want {
|
||
t.Fatalf("expected localized runtime reason %q, got %q", tc.want, got)
|
||
}
|
||
if strings.Contains(got, tc.avoid) {
|
||
t.Fatalf("expected no Chinese runtime reason fragment %q in %q", tc.avoid, got)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestResolveDriverDisplayNameUsesCurrentLanguageFallbackName(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
got := resolveDriverDisplayName(driverDefinition{})
|
||
if got != "driver" {
|
||
t.Fatalf("expected English fallback driver display name %q, got %q", "driver", got)
|
||
}
|
||
if strings.Contains(got, "未知") {
|
||
t.Fatalf("expected no Chinese fallback driver display name, got %q", got)
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverUpdateStatusUsesLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func optionalDriverAgentRevisionStatus": {
|
||
rawMessages: []string{
|
||
`fmt.Sprintf("当前 GoNavi 版本要求更新后的 %s driver-agent(revision: %s)", displayName, expected)`,
|
||
`impact := "driver-agent 是独立二进制,不会随主程序自动更新;如果不重装,会继续使用旧 agent 逻辑,驱动侧已修复或优化的行为不会生效,可能继续出现旧版本问题。强烈建议重装对应驱动代理"`,
|
||
`fmt.Sprintf("原因:%s。影响:%s", updateReason, impact)`,
|
||
`fmt.Sprintf("原因:%s。影响:%s(已安装标记:%s,当前需要:%s)", updateReason, impact, actual, expected)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.status.agent_revision_update_detail",
|
||
"driver_manager.backend.status.agent_revision_update_detail_with_actual",
|
||
},
|
||
},
|
||
"func optionalDriverPackageUpdateStatus": {
|
||
rawMessages: []string{
|
||
`fmt.Sprintf("原因:当前推荐 MongoDB 兼容驱动版本为 %s,已安装版本为 %s。影响:MongoDB 2.x driver-agent 使用官方 v2 驱动,要求服务端 MongoDB 4.2+;连接 MongoDB 4.0 会出现 wire version 7 不兼容。强烈建议重装对应驱动代理", pinned, installed)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.status.mongodb_compatibility_update_detail",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw update status text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference update status i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverUpdateStatusCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.status.agent_revision_update_detail",
|
||
"driver_manager.backend.status.agent_revision_update_detail_with_actual",
|
||
"driver_manager.backend.status.mongodb_compatibility_update_detail",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing update status key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestOptionalDriverAgentRevisionStatusUsesCurrentLanguageForUpdateReason(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
needsUpdate, reason, expected := optionalDriverAgentRevisionStatus("clickhouse", installedDriverPackage{}, true)
|
||
if !needsUpdate {
|
||
t.Fatal("expected ClickHouse revision mismatch to require update")
|
||
}
|
||
if expected == "" {
|
||
t.Fatal("expected ClickHouse to define an expected revision")
|
||
}
|
||
if !strings.Contains(reason, "Reason:") || !strings.Contains(reason, "Impact:") {
|
||
t.Fatalf("expected English reason/impact wrapper, got %q", reason)
|
||
}
|
||
if !strings.Contains(reason, "ClickHouse driver-agent") || !strings.Contains(reason, expected) {
|
||
t.Fatalf("expected English ClickHouse revision detail with expected revision, got %q", reason)
|
||
}
|
||
if strings.Contains(reason, "原因:") || strings.Contains(reason, "影响:") || strings.Contains(reason, "强烈建议重装") {
|
||
t.Fatalf("expected no Chinese revision update reason in en-US mode, got %q", reason)
|
||
}
|
||
}
|
||
|
||
func TestOptionalDriverPackageUpdateStatusUsesCurrentLanguageForMongoCompatibility(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
definition, ok := resolveDriverDefinition("mongodb")
|
||
if !ok {
|
||
t.Fatal("expected mongodb driver definition")
|
||
}
|
||
meta := installedDriverPackage{
|
||
Version: "2.5.0",
|
||
AgentRevision: db.OptionalDriverAgentRevision("mongodb"),
|
||
}
|
||
|
||
needsUpdate, reason, _ := optionalDriverPackageUpdateStatus(definition, meta, true)
|
||
if !needsUpdate {
|
||
t.Fatal("expected MongoDB legacy compatibility prompt")
|
||
}
|
||
if !strings.Contains(reason, "Reason:") || !strings.Contains(reason, "Impact:") {
|
||
t.Fatalf("expected English reason/impact wrapper, got %q", reason)
|
||
}
|
||
if !strings.Contains(reason, "recommended MongoDB compatibility driver version") || !strings.Contains(reason, "wire version 7") {
|
||
t.Fatalf("expected English MongoDB compatibility detail, got %q", reason)
|
||
}
|
||
if strings.Contains(reason, "原因:") || strings.Contains(reason, "影响:") || strings.Contains(reason, "当前推荐 MongoDB 兼容驱动版本") {
|
||
t.Fatalf("expected no Chinese MongoDB compatibility reason in en-US mode, got %q", reason)
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverSourceBuildHelperErrorsUseLocalizedText(t *testing.T) {
|
||
source := methodsDriverSource(t)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func optionalDriverBuildTag": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("未配置驱动构建标签:%s", driverType)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_tag_unconfigured",
|
||
},
|
||
},
|
||
"func locateProjectRootForAgentBuild": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("获取当前目录失败:%w", err)`,
|
||
`fmt.Errorf("未找到通用驱动代理源码,无法自动构建;请使用已发布版本")`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_workdir_unavailable",
|
||
"driver_manager.backend.error.source_build_project_root_missing",
|
||
},
|
||
},
|
||
"func buildVersionedDriverModOverride": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("读取 go.mod 失败:%w", err)`,
|
||
`fmt.Errorf("未在 go.mod 中找到驱动依赖:%s", modulePath)`,
|
||
`fmt.Errorf("创建驱动构建临时目录失败:%w", err)`,
|
||
`fmt.Errorf("写入临时 go.mod 失败:%w", err)`,
|
||
`fmt.Errorf("写入临时 go.sum 失败:%w", writeErr)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_go_mod_read_failed",
|
||
"driver_manager.backend.error.source_build_module_dependency_missing",
|
||
"driver_manager.backend.error.source_build_temp_directory_create_failed",
|
||
"driver_manager.backend.error.source_build_temp_go_mod_write_failed",
|
||
"driver_manager.backend.error.source_build_temp_go_sum_write_failed",
|
||
},
|
||
},
|
||
"func rewriteRequiredModuleVersion": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("驱动模块或版本为空")`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_module_or_version_empty",
|
||
},
|
||
},
|
||
"func buildOptionalDriverAgentFromSource": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("准备 DuckDB Windows CGO 编译器失败:%w", toolchainErr)`,
|
||
`fmt.Errorf("准备 DuckDB Windows 动态库失败:%w", prepErr)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_duckdb_windows_cgo_toolchain_prepare_failed",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dynamic_library_prepare_failed",
|
||
},
|
||
},
|
||
"func resolveDuckDBWindowsCGOToolchainBinFromCandidates": {
|
||
rawMessages: []string{
|
||
`请先安装 MSYS2 UCRT64 工具链:winget install --id MSYS2.MSYS2 -e;然后执行 C:\msys64\usr\bin\bash.exe -lc "pacman -S --needed --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-binutils"`,
|
||
`fmt.Errorf("未找到可用的 gcc.exe/g++.exe;%s", installHint)`,
|
||
`fmt.Errorf("未找到可用的 gcc.exe/g++.exe,已检查:%s;%s", strings.Join(checked, ", "), installHint)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_duckdb_windows_toolchain_install_hint",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_gcc_not_found",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_gcc_not_found_with_checked",
|
||
},
|
||
},
|
||
"func prepareDuckDBWindowsDynamicLibraryForBuild": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("DuckDB 官方动态库包缺少文件:%s", strings.Join(missing, ", "))`,
|
||
`fmt.Errorf("定位 DuckDB Windows dlltool 失败:%w", err)`,
|
||
},
|
||
keys: []string{
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dynamic_library_missing_files",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dlltool_resolve_failed",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
functionSource := methodsDriverFunctionSource(t, source, signature)
|
||
for _, rawMessage := range check.rawMessages {
|
||
if strings.Contains(functionSource, rawMessage) {
|
||
t.Fatalf("%s still contains raw source-build text %q", signature, rawMessage)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(functionSource, key) {
|
||
t.Fatalf("%s does not reference source-build i18n key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDriverSourceBuildHelperCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"driver_manager.backend.error.source_build_tag_unconfigured",
|
||
"driver_manager.backend.error.source_build_workdir_unavailable",
|
||
"driver_manager.backend.error.source_build_project_root_missing",
|
||
"driver_manager.backend.error.source_build_go_mod_read_failed",
|
||
"driver_manager.backend.error.source_build_module_dependency_missing",
|
||
"driver_manager.backend.error.source_build_temp_directory_create_failed",
|
||
"driver_manager.backend.error.source_build_temp_go_mod_write_failed",
|
||
"driver_manager.backend.error.source_build_temp_go_sum_write_failed",
|
||
"driver_manager.backend.error.source_build_module_or_version_empty",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_cgo_toolchain_prepare_failed",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dynamic_library_prepare_failed",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_toolchain_install_hint",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_gcc_not_found",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_gcc_not_found_with_checked",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dynamic_library_missing_files",
|
||
"driver_manager.backend.error.source_build_duckdb_windows_dlltool_resolve_failed",
|
||
}
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing source-build key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestOptionalDriverBuildTagUsesCurrentLanguageForUnconfiguredDriver(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := optionalDriverBuildTag("unsupported", "")
|
||
if err == nil {
|
||
t.Fatal("expected missing build-tag error")
|
||
}
|
||
if err.Error() != "No build tags are configured for driver type: unsupported" {
|
||
t.Fatalf("expected English source-build tag message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未配置驱动构建标签") {
|
||
t.Fatalf("expected no Chinese source-build tag message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestLocateProjectRootForAgentBuildUsesCurrentLanguageWhenSourceMissing(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
originalWD, err := os.Getwd()
|
||
if err != nil {
|
||
t.Fatalf("Getwd() error = %v", err)
|
||
}
|
||
tempDir := t.TempDir()
|
||
if err := os.Chdir(tempDir); err != nil {
|
||
t.Fatalf("Chdir(%q) error = %v", tempDir, err)
|
||
}
|
||
t.Cleanup(func() {
|
||
_ = os.Chdir(originalWD)
|
||
})
|
||
|
||
_, err = locateProjectRootForAgentBuild()
|
||
if err == nil {
|
||
t.Fatal("expected missing project-root error")
|
||
}
|
||
if err.Error() != "Optional driver agent source was not found in the project; please use a published build" {
|
||
t.Fatalf("expected English source-build project-root message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未找到通用驱动代理源码") {
|
||
t.Fatalf("expected no Chinese source-build project-root message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestBuildVersionedDriverModOverrideUsesCurrentLanguageForStructuredErrors(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
missingGoModDir := t.TempDir()
|
||
_, err := buildVersionedDriverModOverride(missingGoModDir, "github.com/example/driver", "1.2.3")
|
||
if err == nil {
|
||
t.Fatal("expected go.mod read failure")
|
||
}
|
||
if !strings.HasPrefix(err.Error(), "Failed to read go.mod:") {
|
||
t.Fatalf("expected English go.mod read prefix, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "读取 go.mod 失败") {
|
||
t.Fatalf("expected no Chinese go.mod read message in en-US mode, got %q", err.Error())
|
||
}
|
||
|
||
projectDir := t.TempDir()
|
||
goMod := "module example.com/test\n\ngo 1.24.0\n\nrequire github.com/example/other v1.0.0\n"
|
||
if writeErr := os.WriteFile(filepath.Join(projectDir, "go.mod"), []byte(goMod), 0o644); writeErr != nil {
|
||
t.Fatalf("WriteFile(go.mod) error = %v", writeErr)
|
||
}
|
||
|
||
_, err = buildVersionedDriverModOverride(projectDir, "github.com/example/missing", "1.2.3")
|
||
if err == nil {
|
||
t.Fatal("expected missing driver dependency error")
|
||
}
|
||
if err.Error() != "Driver dependency was not found in go.mod: github.com/example/missing" {
|
||
t.Fatalf("expected English missing dependency message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未在 go.mod 中找到驱动依赖") {
|
||
t.Fatalf("expected no Chinese missing dependency message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestRewriteRequiredModuleVersionUsesCurrentLanguageForEmptyInput(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, _, err := rewriteRequiredModuleVersion(nil, " ", " ")
|
||
if err == nil {
|
||
t.Fatal("expected empty module/version error")
|
||
}
|
||
if err.Error() != "Driver module path or version is empty" {
|
||
t.Fatalf("expected English empty module/version message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "驱动模块或版本为空") {
|
||
t.Fatalf("expected no Chinese empty module/version message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestResolveDuckDBWindowsCGOToolchainBinFromCandidatesUsesCurrentLanguageWhenNoneFound(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := resolveDuckDBWindowsCGOToolchainBinFromCandidates(nil)
|
||
if err == nil {
|
||
t.Fatal("expected missing DuckDB Windows toolchain error")
|
||
}
|
||
expected := `No usable gcc.exe/g++.exe was found; Please install the MSYS2 UCRT64 toolchain first: winget install --id MSYS2.MSYS2 -e; then run C:\msys64\usr\bin\bash.exe -lc "pacman -S --needed --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-binutils"`
|
||
if err.Error() != expected {
|
||
t.Fatalf("expected English DuckDB Windows toolchain message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未找到可用的 gcc.exe/g++.exe") || strings.Contains(err.Error(), "请先安装 MSYS2 UCRT64 工具链") {
|
||
t.Fatalf("expected no Chinese DuckDB Windows toolchain message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|
||
|
||
func TestResolveDuckDBWindowsCGOToolchainBinFromCandidatesUsesCurrentLanguageWhenCheckedPathsMissing(t *testing.T) {
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageZhCN))
|
||
})
|
||
|
||
_, err := resolveDuckDBWindowsCGOToolchainBinFromCandidates([]string{`C:\missing1`, `C:\missing2`})
|
||
if err == nil {
|
||
t.Fatal("expected missing DuckDB Windows toolchain error after checking candidates")
|
||
}
|
||
expected := `No usable gcc.exe/g++.exe was found. Checked: C:\missing1, C:\missing2; Please install the MSYS2 UCRT64 toolchain first: winget install --id MSYS2.MSYS2 -e; then run C:\msys64\usr\bin\bash.exe -lc "pacman -S --needed --noconfirm mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-binutils"`
|
||
if err.Error() != expected {
|
||
t.Fatalf("expected English DuckDB Windows checked-path message, got %q", err.Error())
|
||
}
|
||
if strings.Contains(err.Error(), "未找到可用的 gcc.exe/g++.exe") || strings.Contains(err.Error(), "请先安装 MSYS2 UCRT64 工具链") {
|
||
t.Fatalf("expected no Chinese DuckDB Windows checked-path message in en-US mode, got %q", err.Error())
|
||
}
|
||
}
|