package infra import ( "testing" ) func makeMig(version int, name, upSQL string) Migration { return Migration{Version: version, Name: name, UpSQL: upSQL, DownSQL: "DROP TABLE IF EXISTS t;"} } func TestMigrationValidate(t *testing.T) { t.Run("secuencia valida retorna sin errores", func(t *testing.T) { migrations := []Migration{ makeMig(1, "create_users", "CREATE TABLE users (id TEXT PRIMARY KEY);"), makeMig(2, "add_email", "ALTER TABLE users ADD COLUMN email TEXT;"), makeMig(3, "create_roles", "CREATE TABLE roles (id TEXT PRIMARY KEY);"), } errs := MigrationValidate(migrations) if len(errs) != 0 { t.Errorf("expected no errors, got: %v", errs) } }) t.Run("secuencia vacia retorna sin errores", func(t *testing.T) { errs := MigrationValidate([]Migration{}) if len(errs) != 0 { t.Errorf("expected no errors for empty slice, got: %v", errs) } }) t.Run("version duplicada reporta error", func(t *testing.T) { migrations := []Migration{ makeMig(1, "create_users", "CREATE TABLE users (id TEXT PRIMARY KEY);"), makeMig(1, "create_users_dup", "CREATE TABLE users2 (id TEXT PRIMARY KEY);"), makeMig(2, "add_email", "ALTER TABLE users ADD COLUMN email TEXT;"), } errs := MigrationValidate(migrations) if len(errs) == 0 { t.Fatal("expected error for duplicate version, got none") } found := false for _, e := range errs { if containsStr(e, "duplicate") { found = true } } if !found { t.Errorf("expected 'duplicate' in errors, got: %v", errs) } }) t.Run("hueco en versiones reporta version faltante", func(t *testing.T) { migrations := []Migration{ makeMig(1, "create_users", "CREATE TABLE users (id TEXT PRIMARY KEY);"), makeMig(3, "create_roles", "CREATE TABLE roles (id TEXT PRIMARY KEY);"), } errs := MigrationValidate(migrations) if len(errs) == 0 { t.Fatal("expected error for gap in versions, got none") } found := false for _, e := range errs { if containsStr(e, "gap") || containsStr(e, "missing 2") { found = true } } if !found { t.Errorf("expected gap error in errors, got: %v", errs) } }) t.Run("up_sql vacio reporta error", func(t *testing.T) { migrations := []Migration{ {Version: 1, Name: "create_users", UpSQL: "", DownSQL: "DROP TABLE users;"}, } errs := MigrationValidate(migrations) if len(errs) == 0 { t.Fatal("expected error for empty up_sql, got none") } found := false for _, e := range errs { if containsStr(e, "empty up_sql") { found = true } } if !found { t.Errorf("expected 'empty up_sql' in errors, got: %v", errs) } }) t.Run("nombre vacio reporta error", func(t *testing.T) { migrations := []Migration{ {Version: 1, Name: "", UpSQL: "CREATE TABLE users (id TEXT PRIMARY KEY);"}, } errs := MigrationValidate(migrations) if len(errs) == 0 { t.Fatal("expected error for empty name, got none") } found := false for _, e := range errs { if containsStr(e, "empty name") { found = true } } if !found { t.Errorf("expected 'empty name' in errors, got: %v", errs) } }) t.Run("versiones que no empiezan en 1 reportan error", func(t *testing.T) { migrations := []Migration{ makeMig(2, "create_users", "CREATE TABLE users (id TEXT PRIMARY KEY);"), makeMig(3, "add_email", "ALTER TABLE users ADD COLUMN email TEXT;"), } errs := MigrationValidate(migrations) if len(errs) == 0 { t.Fatal("expected error for versions not starting at 1, got none") } found := false for _, e := range errs { if containsStr(e, "start at 1") { found = true } } if !found { t.Errorf("expected 'start at 1' error, got: %v", errs) } }) t.Run("multiple errores se reportan todos", func(t *testing.T) { migrations := []Migration{ {Version: 2, Name: "", UpSQL: ""}, {Version: 4, Name: "something", UpSQL: "CREATE TABLE x (id TEXT);"}, } errs := MigrationValidate(migrations) // Expect: not starting at 1, gap between 2 and 4, empty name for v2, empty up_sql for v2 if len(errs) < 3 { t.Errorf("expected at least 3 errors, got %d: %v", len(errs), errs) } }) } func containsStr(s, sub string) bool { return len(s) >= len(sub) && (s == sub || len(sub) == 0 || func() bool { for i := 0; i <= len(s)-len(sub); i++ { if s[i:i+len(sub)] == sub { return true } } return false }()) }