package config import ( "os" "path/filepath" "testing" ) func TestLoad_Defaults(t *testing.T) { // Clear env to test defaults envVars := []string{"APP_PORT", "APP_ENV", "DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASS", "ADMIN_API_KEY", "ADMIN_PASSWORD", "SESSION_SECRET", "RSA_PRIVATE_KEY_PATH", "RATE_LIMIT_ACTIVATE", "RATE_LIMIT_VALIDATE", "LOG_LEVEL"} saved := make(map[string]string) for _, v := range envVars { saved[v] = os.Getenv(v) os.Unsetenv(v) } defer func() { for k, v := range saved { if v != "" { os.Setenv(k, v) } } }() cfg := Load() if cfg.Port != "8090" { t.Errorf("Port default: ocekivano '8090', dobijeno %q", cfg.Port) } if cfg.Env != "development" { t.Errorf("Env default: ocekivano 'development', dobijeno %q", cfg.Env) } if cfg.DBHost != "localhost" { t.Errorf("DBHost default: ocekivano 'localhost', dobijeno %q", cfg.DBHost) } if cfg.DBPort != "3306" { t.Errorf("DBPort default: ocekivano '3306', dobijeno %q", cfg.DBPort) } if cfg.DBName != "dal_license_db" { t.Errorf("DBName default: ocekivano 'dal_license_db', dobijeno %q", cfg.DBName) } if cfg.DBUser != "license" { t.Errorf("DBUser default: ocekivano 'license', dobijeno %q", cfg.DBUser) } if cfg.RSAPrivateKey != "./crypto/private.pem" { t.Errorf("RSAPrivateKey default: ocekivano './crypto/private.pem', dobijeno %q", cfg.RSAPrivateKey) } if cfg.RateLimitActivate != "10" { t.Errorf("RateLimitActivate default: ocekivano '10', dobijeno %q", cfg.RateLimitActivate) } if cfg.RateLimitValidate != "60" { t.Errorf("RateLimitValidate default: ocekivano '60', dobijeno %q", cfg.RateLimitValidate) } if cfg.LogLevel != "info" { t.Errorf("LogLevel default: ocekivano 'info', dobijeno %q", cfg.LogLevel) } } func TestLoad_EnvOverrides(t *testing.T) { os.Setenv("APP_PORT", "9999") os.Setenv("APP_ENV", "production") os.Setenv("DB_HOST", "db.example.com") defer func() { os.Unsetenv("APP_PORT") os.Unsetenv("APP_ENV") os.Unsetenv("DB_HOST") }() cfg := Load() if cfg.Port != "9999" { t.Errorf("Port override: ocekivano '9999', dobijeno %q", cfg.Port) } if cfg.Env != "production" { t.Errorf("Env override: ocekivano 'production', dobijeno %q", cfg.Env) } if cfg.DBHost != "db.example.com" { t.Errorf("DBHost override: ocekivano 'db.example.com', dobijeno %q", cfg.DBHost) } } func TestDSN(t *testing.T) { cfg := &Config{ DBUser: "testuser", DBPass: "testpass", DBHost: "localhost", DBPort: "3306", DBName: "testdb", } dsn := cfg.DSN() expected := "testuser:testpass@tcp(localhost:3306)/testdb?parseTime=true&charset=utf8mb4&multiStatements=true" if dsn != expected { t.Errorf("DSN:\nocekivano: %q\ndobijeno: %q", expected, dsn) } } func TestDSN_SpecialChars(t *testing.T) { cfg := &Config{ DBUser: "user", DBPass: "p@ss:w0rd", DBHost: "192.168.1.1", DBPort: "3307", DBName: "my_db", } dsn := cfg.DSN() if dsn == "" { t.Error("DSN ne sme biti prazan") } // Mora sadrzati sve parametre if !contains(dsn, "parseTime=true") { t.Error("DSN mora sadrzati parseTime=true") } if !contains(dsn, "multiStatements=true") { t.Error("DSN mora sadrzati multiStatements=true") } if !contains(dsn, "charset=utf8mb4") { t.Error("DSN mora sadrzati charset=utf8mb4") } } func TestLoadEnvFile(t *testing.T) { dir := t.TempDir() envPath := filepath.Join(dir, ".env") content := `# Comment TEST_CONFIG_VAR=hello_world TEST_CONFIG_NUM=42 ` os.WriteFile(envPath, []byte(content), 0644) os.Unsetenv("TEST_CONFIG_VAR") os.Unsetenv("TEST_CONFIG_NUM") loadEnvFile(envPath) if v := os.Getenv("TEST_CONFIG_VAR"); v != "hello_world" { t.Errorf("TEST_CONFIG_VAR: ocekivano 'hello_world', dobijeno %q", v) } if v := os.Getenv("TEST_CONFIG_NUM"); v != "42" { t.Errorf("TEST_CONFIG_NUM: ocekivano '42', dobijeno %q", v) } os.Unsetenv("TEST_CONFIG_VAR") os.Unsetenv("TEST_CONFIG_NUM") } func TestLoadEnvFile_ExistingEnvNotOverwritten(t *testing.T) { dir := t.TempDir() envPath := filepath.Join(dir, ".env") os.WriteFile(envPath, []byte("TEST_EXISTING=from_file\n"), 0644) os.Setenv("TEST_EXISTING", "from_env") defer os.Unsetenv("TEST_EXISTING") loadEnvFile(envPath) if v := os.Getenv("TEST_EXISTING"); v != "from_env" { t.Errorf("env varijabla ne sme biti prepisana iz fajla: ocekivano 'from_env', dobijeno %q", v) } } func TestLoadEnvFile_SkipsComments(t *testing.T) { dir := t.TempDir() envPath := filepath.Join(dir, ".env") os.WriteFile(envPath, []byte("# COMMENTED_VAR=should_not_set\nACTUAL_VAR=set_this\n"), 0644) os.Unsetenv("COMMENTED_VAR") os.Unsetenv("ACTUAL_VAR") loadEnvFile(envPath) if v := os.Getenv("COMMENTED_VAR"); v != "" { t.Errorf("komentarisana varijabla ne sme biti setovana: dobijeno %q", v) } if v := os.Getenv("ACTUAL_VAR"); v != "set_this" { t.Errorf("ACTUAL_VAR: ocekivano 'set_this', dobijeno %q", v) } os.Unsetenv("ACTUAL_VAR") } func TestLoadEnvFile_EmptyLines(t *testing.T) { dir := t.TempDir() envPath := filepath.Join(dir, ".env") os.WriteFile(envPath, []byte("\n\nVAR_AFTER_EMPTY=works\n\n"), 0644) os.Unsetenv("VAR_AFTER_EMPTY") loadEnvFile(envPath) if v := os.Getenv("VAR_AFTER_EMPTY"); v != "works" { t.Errorf("ocekivano 'works', dobijeno %q", v) } os.Unsetenv("VAR_AFTER_EMPTY") } func TestLoadEnvFile_NonexistentFile(t *testing.T) { // Ne sme pasti loadEnvFile("/nonexistent/path/.env") } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr)) } func containsStr(s, sub string) bool { for i := 0; i <= len(s)-len(sub); i++ { if s[i:i+len(sub)] == sub { return true } } return false }