Files

1 line
16 KiB
JSON

{"repo": "851235550/gita", "files": {"internal/config/config_test.go": {"8477465f26674ecae112651cc9ed89a69b0a0c6e": {"t": 1785746097.5699494, "n": 6239, "h": "340d2feecffcfeb3", "c": "package config\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\n// setupConfigDir 在临时目录下创建 ~/.gita/config.yaml 结构并设置 HOME 环境变量。\n// 返回临时目录路径和清理函数。\nfunc setupConfigDir(t *testing.T, yamlContent string) string {\n\tt.Helper()\n\n\ttmpDir := t.TempDir()\n\tconfigDir := filepath.Join(tmpDir, \".gita\")\n\tif err := os.MkdirAll(configDir, 0755); err != nil {\n\t\tt.Fatalf(\"创建测试配置目录失败: %v\", err)\n\t}\n\n\tif yamlContent != \"\" {\n\t\tconfigFile := filepath.Join(configDir, \"config.yaml\")\n\t\tif err := os.WriteFile(configFile, []byte(yamlContent), 0644); err != nil {\n\t\t\tt.Fatalf(\"写入测试配置文件失败: %v\", err)\n\t\t}\n\t}\n\n\tt.Setenv(\"HOME\", tmpDir)\n\treturn tmpDir\n}\n\n// ============================================================================\n// TC-T0.2-01: 配置文件不存在时使用内置默认值,不报错\n// ============================================================================\nfunc TestLoad_NoConfigFile_UsesDefaults(t *testing.T) {\n\t// Arrange: 不创建任何配置文件,仅设置 HOME。\n\ttmpDir := t.TempDir()\n\tt.Setenv(\"HOME\", tmpDir)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"配置文件不存在时不应报错,但返回了 error: %v\", err)\n\t}\n\tif cfg == nil {\n\t\tt.Fatal(\"返回的 Config 不应为 nil\")\n\t}\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider 默认值应为 deepseek,实际: %s\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"zh-CN\" {\n\t\tt.Errorf(\"Language 默认值应为 zh-CN,实际: %s\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle 默认值应为 conventional,实际: %s\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines 默认值应为 5000,实际: %d\", cfg.MaxDiffLines)\n\t}\n\tif len(cfg.Providers) == 0 {\n\t\tt.Error(\"Providers 默认值不应为空\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-02: 完整配置文件,所有字段均正确解析\n// ============================================================================\nfunc TestLoad_FullConfig_ParsesCorrectly(t *testing.T) {\n\t// Arrange: 构造一份包含全部字段的合法 YAML。\n\tsetupConfigDir(t, `\ndefault_provider: openai\nlanguage: en\ncommit_style: plain\nmax_diff_lines: 3000\nproviders:\n openai:\n model: gpt-4o-mini\n base_url: https://api.openai.com/v1\n api_key_env: GITA_OPENAI_API_KEY\n deepseek:\n model: deepseek-chat\n base_url: https://api.deepseek.com/v1\n api_key_env: GITA_DEEPSEEK_API_KEY\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"合法配置文件解析失败: %v\", err)\n\t}\n\tif cfg.DefaultProvider != \"openai\" {\n\t\tt.Errorf(\"DefaultProvider = %s, want openai\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"en\" {\n\t\tt.Errorf(\"Language = %s, want en\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"plain\" {\n\t\tt.Errorf(\"CommitStyle = %s, want plain\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 3000 {\n\t\tt.Errorf(\"MaxDiffLines = %d, want 3000\", cfg.MaxDiffLines)\n\t}\n\tif len(cfg.Providers) != 2 {\n\t\tt.Fatalf(\"Providers 数量 = %d, want 2\", len(cfg.Providers))\n\t}\n\tif cfg.Providers[\"openai\"].Model != \"gpt-4o-mini\" {\n\t\tt.Errorf(\"openai model = %s, want gpt-4o-mini\", cfg.Providers[\"openai\"].Model)\n\t}\n\tif cfg.Providers[\"deepseek\"].APIKeyEnv != \"GITA_DEEPSEEK_API_KEY\" {\n\t\tt.Errorf(\"deepseek api_key_env = %s, want GITA_DEEPSEEK_API_KEY\", cfg.Providers[\"deepseek\"].APIKeyEnv)\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-03: 部分字段缺失 —— 缺失字段使用默认值\n// ============================================================================\nfunc TestLoad_PartialConfig_FillsDefaults(t *testing.T) {\n\t// Arrange: 只配置 language,其余字段留空。\n\tsetupConfigDir(t, `\nlanguage: en\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"部分字段缺失的配置解析失败: %v\", err)\n\t}\n\t// 明确配置的字段应生效。\n\tif cfg.Language != \"en\" {\n\t\tt.Errorf(\"Language = %s, want en\", cfg.Language)\n\t}\n\t// 未配置的字段应使用默认值。\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider 应使用默认值 deepseek,实际: %s\", cfg.DefaultProvider)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle 应使用默认值 conventional,实际: %s\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines 应使用默认值 5000,实际: %d\", cfg.MaxDiffLines)\n\t}\n\t// Providers 未配置时也应使用内置默认值。\n\tif len(cfg.Providers) == 0 {\n\t\tt.Error(\"Providers 未配置时应使用内置默认值\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-04: 空配置文件(文件存在但内容为空)\n// ============================================================================\nfunc TestLoad_EmptyConfigFile(t *testing.T) {\n\t// Arrange: 创建空配置文件。\n\tsetupConfigDir(t, \"\")\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"空配置文件解析不应报错: %v\", err)\n\t}\n\t// 空文件解析后所有字段均为零值,mergeConfig 不会覆盖,应全部为默认值。\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider = %s, want deepseek\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"zh-CN\" {\n\t\tt.Errorf(\"Language = %s, want zh-CN\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle = %s, want conventional\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines = %d, want 5000\", cfg.MaxDiffLines)\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-05: 非法 YAML 格式 —— 应返回错误\n// ============================================================================\nfunc TestLoad_InvalidYAML_ReturnsError(t *testing.T) {\n\t// Arrange: 写入非法的 YAML 内容(缩进混乱)。\n\tsetupConfigDir(t, `default_provider: [unclosed bracket`)\n\n\t// Act\n\t_, err := Load()\n\n\t// Assert\n\tif err == nil {\n\t\tt.Error(\"非法 YAML 应返回错误,但返回了 nil\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-06: Provider 配置覆盖 —— 用户自定义 provider 完全替换默认值\n// ============================================================================\nfunc TestLoad_CustomProviders_ReplacesDefaults(t *testing.T) {\n\t// Arrange: 只配置自定义 provider,不包含内置的三个。\n\tsetupConfigDir(t, `\nproviders:\n custom_llm:\n model: my-model\n base_url: https://custom.api.com/v1\n api_key_env: CUSTOM_KEY\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"自定义 provider 配置解析失败: %v\", err)\n\t}\n\t// 用户配置的 provider 表完全覆盖默认表(需求:让用户有完全控制权)。\n\tif len(cfg.Providers) != 1 {\n\t\tt.Fatalf(\"Providers 数量 = %d, want 1(用户配置应完全覆盖默认值)\", len(cfg.Providers))\n\t}\n\tif _, ok := cfg.Providers[\"custom_llm\"]; !ok {\n\t\tt.Error(\"应包含用户自定义的 custom_llm provider\")\n\t}\n\tif _, ok := cfg.Providers[\"deepseek\"]; ok {\n\t\tt.Error(\"用户未配置 deepseek 时不应出现在结果中\")\n\t}\n}\n"}, "bb0fd40c82a7421d2f72958133d91589efc29958": {"t": 1785759840.2375772, "n": 6239, "h": "340d2feecffcfeb3", "c": "package config\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\n// setupConfigDir 在临时目录下创建 ~/.gita/config.yaml 结构并设置 HOME 环境变量。\n// 返回临时目录路径和清理函数。\nfunc setupConfigDir(t *testing.T, yamlContent string) string {\n\tt.Helper()\n\n\ttmpDir := t.TempDir()\n\tconfigDir := filepath.Join(tmpDir, \".gita\")\n\tif err := os.MkdirAll(configDir, 0755); err != nil {\n\t\tt.Fatalf(\"创建测试配置目录失败: %v\", err)\n\t}\n\n\tif yamlContent != \"\" {\n\t\tconfigFile := filepath.Join(configDir, \"config.yaml\")\n\t\tif err := os.WriteFile(configFile, []byte(yamlContent), 0644); err != nil {\n\t\t\tt.Fatalf(\"写入测试配置文件失败: %v\", err)\n\t\t}\n\t}\n\n\tt.Setenv(\"HOME\", tmpDir)\n\treturn tmpDir\n}\n\n// ============================================================================\n// TC-T0.2-01: 配置文件不存在时使用内置默认值,不报错\n// ============================================================================\nfunc TestLoad_NoConfigFile_UsesDefaults(t *testing.T) {\n\t// Arrange: 不创建任何配置文件,仅设置 HOME。\n\ttmpDir := t.TempDir()\n\tt.Setenv(\"HOME\", tmpDir)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"配置文件不存在时不应报错,但返回了 error: %v\", err)\n\t}\n\tif cfg == nil {\n\t\tt.Fatal(\"返回的 Config 不应为 nil\")\n\t}\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider 默认值应为 deepseek,实际: %s\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"zh-CN\" {\n\t\tt.Errorf(\"Language 默认值应为 zh-CN,实际: %s\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle 默认值应为 conventional,实际: %s\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines 默认值应为 5000,实际: %d\", cfg.MaxDiffLines)\n\t}\n\tif len(cfg.Providers) == 0 {\n\t\tt.Error(\"Providers 默认值不应为空\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-02: 完整配置文件,所有字段均正确解析\n// ============================================================================\nfunc TestLoad_FullConfig_ParsesCorrectly(t *testing.T) {\n\t// Arrange: 构造一份包含全部字段的合法 YAML。\n\tsetupConfigDir(t, `\ndefault_provider: openai\nlanguage: en\ncommit_style: plain\nmax_diff_lines: 3000\nproviders:\n openai:\n model: gpt-4o-mini\n base_url: https://api.openai.com/v1\n api_key_env: GITA_OPENAI_API_KEY\n deepseek:\n model: deepseek-chat\n base_url: https://api.deepseek.com/v1\n api_key_env: GITA_DEEPSEEK_API_KEY\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"合法配置文件解析失败: %v\", err)\n\t}\n\tif cfg.DefaultProvider != \"openai\" {\n\t\tt.Errorf(\"DefaultProvider = %s, want openai\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"en\" {\n\t\tt.Errorf(\"Language = %s, want en\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"plain\" {\n\t\tt.Errorf(\"CommitStyle = %s, want plain\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 3000 {\n\t\tt.Errorf(\"MaxDiffLines = %d, want 3000\", cfg.MaxDiffLines)\n\t}\n\tif len(cfg.Providers) != 2 {\n\t\tt.Fatalf(\"Providers 数量 = %d, want 2\", len(cfg.Providers))\n\t}\n\tif cfg.Providers[\"openai\"].Model != \"gpt-4o-mini\" {\n\t\tt.Errorf(\"openai model = %s, want gpt-4o-mini\", cfg.Providers[\"openai\"].Model)\n\t}\n\tif cfg.Providers[\"deepseek\"].APIKeyEnv != \"GITA_DEEPSEEK_API_KEY\" {\n\t\tt.Errorf(\"deepseek api_key_env = %s, want GITA_DEEPSEEK_API_KEY\", cfg.Providers[\"deepseek\"].APIKeyEnv)\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-03: 部分字段缺失 —— 缺失字段使用默认值\n// ============================================================================\nfunc TestLoad_PartialConfig_FillsDefaults(t *testing.T) {\n\t// Arrange: 只配置 language,其余字段留空。\n\tsetupConfigDir(t, `\nlanguage: en\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"部分字段缺失的配置解析失败: %v\", err)\n\t}\n\t// 明确配置的字段应生效。\n\tif cfg.Language != \"en\" {\n\t\tt.Errorf(\"Language = %s, want en\", cfg.Language)\n\t}\n\t// 未配置的字段应使用默认值。\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider 应使用默认值 deepseek,实际: %s\", cfg.DefaultProvider)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle 应使用默认值 conventional,实际: %s\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines 应使用默认值 5000,实际: %d\", cfg.MaxDiffLines)\n\t}\n\t// Providers 未配置时也应使用内置默认值。\n\tif len(cfg.Providers) == 0 {\n\t\tt.Error(\"Providers 未配置时应使用内置默认值\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-04: 空配置文件(文件存在但内容为空)\n// ============================================================================\nfunc TestLoad_EmptyConfigFile(t *testing.T) {\n\t// Arrange: 创建空配置文件。\n\tsetupConfigDir(t, \"\")\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"空配置文件解析不应报错: %v\", err)\n\t}\n\t// 空文件解析后所有字段均为零值,mergeConfig 不会覆盖,应全部为默认值。\n\tif cfg.DefaultProvider != \"deepseek\" {\n\t\tt.Errorf(\"DefaultProvider = %s, want deepseek\", cfg.DefaultProvider)\n\t}\n\tif cfg.Language != \"zh-CN\" {\n\t\tt.Errorf(\"Language = %s, want zh-CN\", cfg.Language)\n\t}\n\tif cfg.CommitStyle != \"conventional\" {\n\t\tt.Errorf(\"CommitStyle = %s, want conventional\", cfg.CommitStyle)\n\t}\n\tif cfg.MaxDiffLines != 5000 {\n\t\tt.Errorf(\"MaxDiffLines = %d, want 5000\", cfg.MaxDiffLines)\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-05: 非法 YAML 格式 —— 应返回错误\n// ============================================================================\nfunc TestLoad_InvalidYAML_ReturnsError(t *testing.T) {\n\t// Arrange: 写入非法的 YAML 内容(缩进混乱)。\n\tsetupConfigDir(t, `default_provider: [unclosed bracket`)\n\n\t// Act\n\t_, err := Load()\n\n\t// Assert\n\tif err == nil {\n\t\tt.Error(\"非法 YAML 应返回错误,但返回了 nil\")\n\t}\n}\n\n// ============================================================================\n// TC-T0.2-06: Provider 配置覆盖 —— 用户自定义 provider 完全替换默认值\n// ============================================================================\nfunc TestLoad_CustomProviders_ReplacesDefaults(t *testing.T) {\n\t// Arrange: 只配置自定义 provider,不包含内置的三个。\n\tsetupConfigDir(t, `\nproviders:\n custom_llm:\n model: my-model\n base_url: https://custom.api.com/v1\n api_key_env: CUSTOM_KEY\n`)\n\n\t// Act\n\tcfg, err := Load()\n\n\t// Assert\n\tif err != nil {\n\t\tt.Fatalf(\"自定义 provider 配置解析失败: %v\", err)\n\t}\n\t// 用户配置的 provider 表完全覆盖默认表(需求:让用户有完全控制权)。\n\tif len(cfg.Providers) != 1 {\n\t\tt.Fatalf(\"Providers 数量 = %d, want 1(用户配置应完全覆盖默认值)\", len(cfg.Providers))\n\t}\n\tif _, ok := cfg.Providers[\"custom_llm\"]; !ok {\n\t\tt.Error(\"应包含用户自定义的 custom_llm provider\")\n\t}\n\tif _, ok := cfg.Providers[\"deepseek\"]; ok {\n\t\tt.Error(\"用户未配置 deepseek 时不应出现在结果中\")\n\t}\n}\n"}}}}