diff --git a/internal/store/migrations/embed_test.go b/internal/store/migrations/embed_test.go new file mode 100644 index 00000000..c8735051 --- /dev/null +++ b/internal/store/migrations/embed_test.go @@ -0,0 +1,171 @@ +package migrations + +import ( + "testing" +) + +func TestFilesEmbedded(t *testing.T) { + // Test that migration files are properly embedded + entries, err := Files.ReadDir(".") + if err != nil { + t.Fatalf("Failed to read embedded migrations: %v", err) + } + + if len(entries) == 0 { + t.Fatal("No migration files embedded") + } + + // Verify we have SQL files + hasSQL := false + for _, entry := range entries { + if !entry.IsDir() && len(entry.Name()) > 4 && entry.Name()[len(entry.Name())-4:] == ".sql" { + hasSQL = true + break + } + } + + if !hasSQL { + t.Fatal("No .sql files found in embedded migrations") + } +} + +func TestMigrationFilesReadable(t *testing.T) { + // Test that all embedded migration files can be read + entries, err := Files.ReadDir(".") + if err != nil { + t.Fatalf("Failed to read embedded migrations: %v", err) + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + + // Skip non-SQL files + name := entry.Name() + if len(name) < 4 || name[len(name)-4:] != ".sql" { + continue + } + + content, err := Files.ReadFile(name) + if err != nil { + t.Errorf("Failed to read migration file %s: %v", name, err) + continue + } + + if len(content) == 0 { + t.Errorf("Migration file %s is empty", name) + } + + // Verify content looks like SQL + contentStr := string(content) + if len(contentStr) < 10 { + t.Errorf("Migration file %s content too short", name) + } + } +} + +func TestMigrationFileNaming(t *testing.T) { + // Test that migration files follow naming convention (NNNN_description.sql) + entries, err := Files.ReadDir(".") + if err != nil { + t.Fatalf("Failed to read embedded migrations: %v", err) + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + + name := entry.Name() + if len(name) < 4 || name[len(name)-4:] != ".sql" { + continue + } + + // Check naming pattern: should start with digits followed by underscore + if len(name) < 5 { + t.Errorf("Migration file %s name too short", name) + continue + } + + // Should start with at least 4 digits + hasPrefix := false + for i := 0; i < 4 && i < len(name); i++ { + if name[i] >= '0' && name[i] <= '9' { + if i == 3 { + hasPrefix = true + } + } else { + break + } + } + + if !hasPrefix { + t.Errorf("Migration file %s does not follow naming convention (should start with 4 digits)", name) + } + } +} + +func TestMigrationFilesSorted(t *testing.T) { + // Test that migration files can be sorted consistently + entries, err := Files.ReadDir(".") + if err != nil { + t.Fatalf("Failed to read embedded migrations: %v", err) + } + + var sqlFiles []string + for _, entry := range entries { + if entry.IsDir() { + continue + } + name := entry.Name() + if len(name) > 4 && name[len(name)-4:] == ".sql" { + sqlFiles = append(sqlFiles, name) + } + } + + if len(sqlFiles) < 2 { + t.Skip("Not enough SQL files to test sorting") + } + + // Verify files can be compared + for i := 1; i < len(sqlFiles); i++ { + if sqlFiles[i] < sqlFiles[i-1] { + t.Errorf("Files not sorted: %s should come before %s", sqlFiles[i-1], sqlFiles[i]) + } + } +} + +func TestInitialMigrationContent(t *testing.T) { + // Test that the initial migration file exists and has expected content + content, err := Files.ReadFile("0001_init.sql") + if err != nil { + t.Skipf("0001_init.sql not found: %v", err) + } + + contentStr := string(content) + + // Initial migration should contain CREATE TABLE statements + if len(contentStr) < 50 { + t.Error("Initial migration file seems too short") + } + + // Should contain typical SQL keywords + hasCreate := containsAny(contentStr, []string{"CREATE", "create"}) + hasTable := containsAny(contentStr, []string{"TABLE", "table"}) + + if !hasCreate || !hasTable { + t.Error("Initial migration should contain CREATE TABLE statements") + } +} + +func containsAny(s string, substrs []string) bool { + for _, substr := range substrs { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + } + return false +}