mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-26 00:11:43 +08:00
326 lines
12 KiB
Go
326 lines
12 KiB
Go
package app
|
||
|
||
import (
|
||
"encoding/json"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
|
||
"GoNavi-Wails/internal/appdata"
|
||
"GoNavi-Wails/shared/i18n"
|
||
)
|
||
|
||
func methodsDataRootFunctionSource(t *testing.T, source string, signature string) string {
|
||
t.Helper()
|
||
start := strings.Index(source, signature)
|
||
if start < 0 {
|
||
t.Fatalf("methods_data_root.go 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]
|
||
}
|
||
|
||
func TestMethodsDataRootMessagesUseLocalizedText(t *testing.T) {
|
||
sourceBytes, err := os.ReadFile("methods_data_root.go")
|
||
if err != nil {
|
||
t.Fatalf("read methods_data_root.go: %v", err)
|
||
}
|
||
source := string(sourceBytes)
|
||
|
||
checks := map[string]struct {
|
||
rawMessages []string
|
||
keys []string
|
||
}{
|
||
"func (a *App) SelectDataRootDirectory": {
|
||
rawMessages: []string{
|
||
`Title: "选择 GoNavi 数据目录"`,
|
||
},
|
||
keys: []string{
|
||
"app.data_root.backend.dialog.select_directory",
|
||
},
|
||
},
|
||
"func (a *App) ApplyDataRootDirectory": {
|
||
rawMessages: []string{
|
||
`Message: "数据目录未发生变化"`,
|
||
`message := "数据目录已更新,建议重启应用以让 AI 与其他运行态模块完全切换到新目录"`,
|
||
`message = "数据已迁移并切换到新目录,建议重启应用以完成全部模块切换"`,
|
||
},
|
||
keys: []string{
|
||
"app.data_root.backend.message.unchanged",
|
||
"app.data_root.backend.message.updated_restart",
|
||
"app.data_root.backend.message.migrated_restart",
|
||
},
|
||
},
|
||
"func dataRootLocalizeSetActiveRootError": {
|
||
rawMessages: nil,
|
||
keys: []string{
|
||
"app.data_root.backend.error.create_data_directory_failed",
|
||
"app.data_root.backend.error.create_bootstrap_directory_failed",
|
||
},
|
||
},
|
||
"func (a *App) OpenDataRootDirectory": {
|
||
rawMessages: []string{
|
||
`Message: "数据目录不存在或不可访问"`,
|
||
`fmt.Sprintf("当前平台暂不支持打开目录:%s", stdRuntime.GOOS)`,
|
||
`fmt.Sprintf("打开数据目录失败:%v", err)`,
|
||
`Message: "已打开数据目录"`,
|
||
},
|
||
keys: []string{
|
||
"app.data_root.backend.error.directory_unavailable",
|
||
"app.data_root.backend.error.open_directory_unsupported",
|
||
"app.data_root.backend.error.open_directory_failed",
|
||
"app.data_root.backend.message.opened",
|
||
},
|
||
},
|
||
"func migrateDataRootContentsWithText": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("数据目录不能为空")`,
|
||
`fmt.Errorf("解析源数据目录失败:%w", err)`,
|
||
`fmt.Errorf("解析目标数据目录失败:%w", err)`,
|
||
`fmt.Errorf("目标数据目录不能位于源目录内部")`,
|
||
`fmt.Errorf("创建目标数据目录失败:%w", err)`,
|
||
`fmt.Errorf("读取源数据目录失败:%w", err)`,
|
||
`fmt.Errorf("读取源数据失败(%s):%w", name, err)`,
|
||
`fmt.Errorf("迁移目录失败(%s):%w", name, err)`,
|
||
`fmt.Errorf("迁移文件失败(%s):%w", name, err)`,
|
||
},
|
||
keys: []string{
|
||
"app.data_root.backend.error.directory_empty",
|
||
"app.data_root.backend.error.resolve_source_failed",
|
||
"app.data_root.backend.error.resolve_target_failed",
|
||
"app.data_root.backend.error.target_inside_source",
|
||
"app.data_root.backend.error.create_target_failed",
|
||
"app.data_root.backend.error.read_source_root_failed",
|
||
"app.data_root.backend.error.read_source_failed",
|
||
"app.data_root.backend.error.migrate_directory_failed",
|
||
"app.data_root.backend.error.migrate_file_failed",
|
||
},
|
||
},
|
||
"func rewriteSecurityUpdateBackupPathsWithText": {
|
||
rawMessages: []string{
|
||
`fmt.Errorf("读取迁移后的安全更新状态失败:%w", err)`,
|
||
`fmt.Errorf("写入迁移后的安全更新状态失败:%w", err)`,
|
||
`fmt.Errorf("读取迁移后的安全更新备份清单失败:%w", err)`,
|
||
`fmt.Errorf("解析迁移后的安全更新备份清单失败:%w", err)`,
|
||
`fmt.Errorf("写入迁移后的安全更新备份清单失败:%w", err)`,
|
||
`fmt.Errorf("读取迁移后的安全更新结果失败:%w", err)`,
|
||
`fmt.Errorf("解析迁移后的安全更新结果失败:%w", err)`,
|
||
`fmt.Errorf("写入迁移后的安全更新结果失败:%w", err)`,
|
||
},
|
||
keys: []string{
|
||
"app.data_root.backend.error.read_migrated_security_update_state_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_state_failed",
|
||
"app.data_root.backend.error.read_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.parse_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.read_migrated_security_update_result_failed",
|
||
"app.data_root.backend.error.parse_migrated_security_update_result_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_result_failed",
|
||
},
|
||
},
|
||
}
|
||
|
||
for signature, check := range checks {
|
||
body := methodsDataRootFunctionSource(t, source, signature)
|
||
for _, raw := range check.rawMessages {
|
||
if strings.Contains(body, raw) {
|
||
t.Fatalf("%s still contains raw data-root text %q", signature, raw)
|
||
}
|
||
}
|
||
for _, key := range check.keys {
|
||
if !strings.Contains(body, key) {
|
||
t.Fatalf("%s should reference localized key %q", signature, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestMethodsDataRootCatalogKeysExist(t *testing.T) {
|
||
catalogs, err := i18n.LoadCatalogs()
|
||
if err != nil {
|
||
t.Fatalf("LoadCatalogs() error = %v", err)
|
||
}
|
||
|
||
keys := []string{
|
||
"app.data_root.backend.dialog.select_directory",
|
||
"app.data_root.backend.error.create_target_failed",
|
||
"app.data_root.backend.error.create_bootstrap_directory_failed",
|
||
"app.data_root.backend.error.create_data_directory_failed",
|
||
"app.data_root.backend.error.directory_empty",
|
||
"app.data_root.backend.error.directory_unavailable",
|
||
"app.data_root.backend.error.migrate_directory_failed",
|
||
"app.data_root.backend.error.migrate_file_failed",
|
||
"app.data_root.backend.error.open_directory_failed",
|
||
"app.data_root.backend.error.open_directory_unsupported",
|
||
"app.data_root.backend.error.read_source_failed",
|
||
"app.data_root.backend.error.resolve_source_failed",
|
||
"app.data_root.backend.error.resolve_target_failed",
|
||
"app.data_root.backend.error.target_inside_source",
|
||
"app.data_root.backend.error.read_source_root_failed",
|
||
"app.data_root.backend.error.read_migrated_security_update_state_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_state_failed",
|
||
"app.data_root.backend.error.read_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.parse_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_manifest_failed",
|
||
"app.data_root.backend.error.read_migrated_security_update_result_failed",
|
||
"app.data_root.backend.error.parse_migrated_security_update_result_failed",
|
||
"app.data_root.backend.error.write_migrated_security_update_result_failed",
|
||
"app.data_root.backend.message.migrated_restart",
|
||
"app.data_root.backend.message.opened",
|
||
"app.data_root.backend.message.unchanged",
|
||
"app.data_root.backend.message.updated_restart",
|
||
}
|
||
|
||
for _, language := range i18n.SupportedLanguages() {
|
||
catalog := catalogs[language]
|
||
for _, key := range keys {
|
||
if strings.TrimSpace(catalog[key]) == "" {
|
||
t.Fatalf("%s catalog missing data-root key %q", language, key)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestApplyDataRootDirectoryUsesEnglishLocalizedMessageWhenUnchanged(t *testing.T) {
|
||
homeDir := t.TempDir()
|
||
t.Setenv("HOME", homeDir)
|
||
t.Setenv("USERPROFILE", homeDir)
|
||
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
})
|
||
|
||
defaultRoot := filepath.Join(homeDir, ".gonavi")
|
||
result := app.ApplyDataRootDirectory(defaultRoot, false)
|
||
if !result.Success {
|
||
t.Fatalf("expected success for unchanged root, got %+v", result)
|
||
}
|
||
|
||
want := app.appText("app.data_root.backend.message.unchanged", nil)
|
||
if result.Message != want {
|
||
t.Fatalf("expected localized unchanged message %q, got %q", want, result.Message)
|
||
}
|
||
if strings.Contains(result.Message, "数据目录未发生变化") {
|
||
t.Fatalf("expected no raw Chinese unchanged message, got %q", result.Message)
|
||
}
|
||
}
|
||
|
||
func TestApplyDataRootDirectoryLocalizesCreateDirectoryFailure(t *testing.T) {
|
||
homeDir := t.TempDir()
|
||
t.Setenv("HOME", homeDir)
|
||
t.Setenv("USERPROFILE", homeDir)
|
||
|
||
blockingPath := filepath.Join(t.TempDir(), "blocked-root")
|
||
if err := os.WriteFile(blockingPath, []byte("blocked"), 0o644); err != nil {
|
||
t.Fatalf("write blocking path: %v", err)
|
||
}
|
||
detailErr := os.MkdirAll(blockingPath, 0o755)
|
||
if detailErr == nil {
|
||
t.Fatalf("expected MkdirAll(%q) to fail against an existing file", blockingPath)
|
||
}
|
||
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
})
|
||
|
||
result := app.ApplyDataRootDirectory(blockingPath, false)
|
||
if result.Success {
|
||
t.Fatalf("expected create-directory failure, got %+v", result)
|
||
}
|
||
|
||
want := app.appText("app.data_root.backend.error.create_data_directory_failed", map[string]any{
|
||
"detail": detailErr.Error(),
|
||
})
|
||
if result.Message != want {
|
||
t.Fatalf("expected localized create-directory message %q, got %q", want, result.Message)
|
||
}
|
||
}
|
||
|
||
func TestMigrateDataRootContentsUsesEnglishLocalizedValidationMessage(t *testing.T) {
|
||
setDefaultAppLanguage(i18n.LanguageEnUS)
|
||
|
||
err := migrateDataRootContents(" ", filepath.Join(t.TempDir(), "target"))
|
||
if err == nil {
|
||
t.Fatal("expected migrateDataRootContents to fail for empty source root")
|
||
}
|
||
|
||
want := defaultAppText("app.data_root.backend.error.directory_empty", nil)
|
||
if err.Error() != want {
|
||
t.Fatalf("expected localized empty-directory message %q, got %q", want, err.Error())
|
||
}
|
||
}
|
||
|
||
func TestRewriteSecurityUpdateBackupPathsUsesEnglishLocalizedManifestParseError(t *testing.T) {
|
||
setDefaultAppLanguage(i18n.LanguageEnUS)
|
||
|
||
targetRoot := t.TempDir()
|
||
repo := newSecurityUpdateStateRepository(targetRoot)
|
||
started, err := repo.StartRound(StartSecurityUpdateRequest{SourceType: SecurityUpdateSourceTypeCurrentAppSavedConfig})
|
||
if err != nil {
|
||
t.Fatalf("start security update round failed: %v", err)
|
||
}
|
||
if err := os.WriteFile(repo.manifestPath(started.MigrationID), []byte("{"), 0o644); err != nil {
|
||
t.Fatalf("write invalid manifest: %v", err)
|
||
}
|
||
|
||
err = rewriteSecurityUpdateBackupPaths(targetRoot)
|
||
if err == nil {
|
||
t.Fatal("expected rewriteSecurityUpdateBackupPaths to fail for invalid manifest")
|
||
}
|
||
|
||
var manifest securityUpdateBackupManifest
|
||
parseErr := json.Unmarshal([]byte("{"), &manifest)
|
||
if parseErr == nil {
|
||
t.Fatal("expected invalid manifest json to fail")
|
||
}
|
||
want := defaultAppText("app.data_root.backend.error.parse_migrated_security_update_manifest_failed", map[string]any{
|
||
"detail": parseErr.Error(),
|
||
})
|
||
if err.Error() != want {
|
||
t.Fatalf("expected localized manifest-parse message %q, got %q", want, err.Error())
|
||
}
|
||
}
|
||
|
||
func TestApplyDataRootDirectoryLocalizesBootstrapDirectoryFailure(t *testing.T) {
|
||
homeDir := t.TempDir()
|
||
t.Setenv("HOME", homeDir)
|
||
t.Setenv("USERPROFILE", homeDir)
|
||
|
||
defaultRoot := appdata.DefaultRoot()
|
||
if err := os.WriteFile(defaultRoot, []byte("blocked"), 0o644); err != nil {
|
||
t.Fatalf("write blocking default root: %v", err)
|
||
}
|
||
|
||
app := NewApp()
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
t.Cleanup(func() {
|
||
app.SetLanguage(string(i18n.LanguageEnUS))
|
||
})
|
||
|
||
targetRoot := filepath.Join(t.TempDir(), "custom-root")
|
||
result := app.ApplyDataRootDirectory(targetRoot, false)
|
||
if result.Success {
|
||
t.Fatalf("expected bootstrap-directory failure, got %+v", result)
|
||
}
|
||
|
||
detailErr := os.MkdirAll(defaultRoot, 0o755)
|
||
if detailErr == nil {
|
||
t.Fatalf("expected MkdirAll(%q) to fail against an existing file", defaultRoot)
|
||
}
|
||
want := app.appText("app.data_root.backend.error.create_bootstrap_directory_failed", map[string]any{
|
||
"detail": detailErr.Error(),
|
||
})
|
||
if result.Message != want {
|
||
t.Fatalf("expected localized bootstrap-directory message %q, got %q", want, result.Message)
|
||
}
|
||
}
|