package config import ( "os" "testing" "time" ) func TestLoad_EmbeddedConfig(t *testing.T) { clearEnvVars(t) setRequiredEnvVars(t) defer clearEnvVars(t) cfg, err := Load() if err != nil { t.Fatalf("Load() 失败: %v", err) } if cfg.Server.Address != ":3000" { t.Errorf("server.address 期望 :3000, 实际 %s", cfg.Server.Address) } if cfg.Server.ReadTimeout != 30*time.Second { t.Errorf("server.read_timeout 期望 30s, 实际 %v", cfg.Server.ReadTimeout) } if cfg.Logging.Level != "info" { t.Errorf("logging.level 期望 info, 实际 %s", cfg.Logging.Level) } } func TestLoad_EnvOverride(t *testing.T) { clearEnvVars(t) setRequiredEnvVars(t) defer clearEnvVars(t) os.Setenv("JUNHONG_SERVER_ADDRESS", ":8080") os.Setenv("JUNHONG_LOGGING_LEVEL", "debug") defer func() { os.Unsetenv("JUNHONG_SERVER_ADDRESS") os.Unsetenv("JUNHONG_LOGGING_LEVEL") }() cfg, err := Load() if err != nil { t.Fatalf("Load() 失败: %v", err) } if cfg.Server.Address != ":8080" { t.Errorf("server.address 期望 :8080, 实际 %s", cfg.Server.Address) } if cfg.Logging.Level != "debug" { t.Errorf("logging.level 期望 debug, 实际 %s", cfg.Logging.Level) } } func TestLoad_MissingRequired(t *testing.T) { clearEnvVars(t) defer clearEnvVars(t) _, err := Load() if err == nil { t.Fatal("Load() 缺少必填配置时应返回错误") } expectedFields := []string{"database.host", "database.user", "database.password", "database.dbname", "redis.address", "jwt.secret_key"} for _, field := range expectedFields { if !containsString(err.Error(), field) { t.Errorf("错误信息应包含 %q, 实际: %s", field, err.Error()) } } } func TestLoad_PartialRequired(t *testing.T) { clearEnvVars(t) defer clearEnvVars(t) os.Setenv("JUNHONG_DATABASE_HOST", "localhost") os.Setenv("JUNHONG_DATABASE_USER", "user") _, err := Load() if err == nil { t.Fatal("Load() 部分必填配置缺失时应返回错误") } if containsString(err.Error(), "database.host") { t.Error("database.host 已设置,不应在错误信息中") } if containsString(err.Error(), "database.user") { t.Error("database.user 已设置,不应在错误信息中") } if !containsString(err.Error(), "database.password") { t.Error("database.password 未设置,应在错误信息中") } } func TestLoad_GlobalConfig(t *testing.T) { clearEnvVars(t) setRequiredEnvVars(t) defer clearEnvVars(t) cfg, err := Load() if err != nil { t.Fatalf("Load() 失败: %v", err) } globalCfg := Get() if globalCfg == nil { t.Fatal("Get() 返回 nil") } if globalCfg.Server.Address != cfg.Server.Address { t.Errorf("全局配置与返回配置不一致") } } func TestValidateRequired(t *testing.T) { tests := []struct { name string cfg *Config wantErr bool }{ { name: "all required set", cfg: &Config{ Database: DatabaseConfig{ Host: "localhost", User: "user", Password: "pass", DBName: "db", }, Redis: RedisConfig{Address: "localhost"}, JWT: JWTConfig{SecretKey: "12345678901234567890123456789012"}, }, wantErr: false, }, { name: "missing database host", cfg: &Config{ Database: DatabaseConfig{ User: "user", Password: "pass", DBName: "db", }, Redis: RedisConfig{Address: "localhost"}, JWT: JWTConfig{SecretKey: "12345678901234567890123456789012"}, }, wantErr: true, }, { name: "missing redis address", cfg: &Config{ Database: DatabaseConfig{ Host: "localhost", User: "user", Password: "pass", DBName: "db", }, Redis: RedisConfig{}, JWT: JWTConfig{SecretKey: "12345678901234567890123456789012"}, }, wantErr: true, }, { name: "missing jwt secret", cfg: &Config{ Database: DatabaseConfig{ Host: "localhost", User: "user", Password: "pass", DBName: "db", }, Redis: RedisConfig{Address: "localhost"}, JWT: JWTConfig{}, }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.cfg.ValidateRequired() if (err != nil) != tt.wantErr { t.Errorf("ValidateRequired() error = %v, wantErr %v", err, tt.wantErr) } }) } } func setRequiredEnvVars(t *testing.T) { t.Helper() os.Setenv("JUNHONG_DATABASE_HOST", "localhost") os.Setenv("JUNHONG_DATABASE_USER", "testuser") os.Setenv("JUNHONG_DATABASE_PASSWORD", "testpass") os.Setenv("JUNHONG_DATABASE_DBNAME", "testdb") os.Setenv("JUNHONG_REDIS_ADDRESS", "localhost") os.Setenv("JUNHONG_JWT_SECRET_KEY", "12345678901234567890123456789012") } func clearEnvVars(t *testing.T) { t.Helper() envVars := []string{ "JUNHONG_DATABASE_HOST", "JUNHONG_DATABASE_PORT", "JUNHONG_DATABASE_USER", "JUNHONG_DATABASE_PASSWORD", "JUNHONG_DATABASE_DBNAME", "JUNHONG_REDIS_ADDRESS", "JUNHONG_REDIS_PORT", "JUNHONG_REDIS_PASSWORD", "JUNHONG_JWT_SECRET_KEY", "JUNHONG_SERVER_ADDRESS", "JUNHONG_LOGGING_LEVEL", } for _, v := range envVars { os.Unsetenv(v) } } func containsString(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > 0 && (s[:len(substr)] == substr || containsString(s[1:], substr))) }