376 lines
10 KiB
Go
376 lines
10 KiB
Go
package sqldir
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
|
)
|
|
|
|
func TestReader_ReadDatabase(t *testing.T) {
|
|
// Create temporary test directory
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create test SQL files with both underscore and hyphen separators
|
|
testFiles := map[string]string{
|
|
"1_001_create_users.sql": "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);",
|
|
"1_002_create_posts.sql": "CREATE TABLE posts (id SERIAL PRIMARY KEY, user_id INT);",
|
|
"2_001_add_indexes.sql": "CREATE INDEX idx_posts_user_id ON posts(user_id);",
|
|
"1_003_seed_data.pgsql": "INSERT INTO users (name) VALUES ('Alice'), ('Bob');",
|
|
"10-10-create-newid.pgsql": "CREATE TABLE newid (id SERIAL PRIMARY KEY);",
|
|
"2-005-add-column.sql": "ALTER TABLE users ADD COLUMN email TEXT;",
|
|
}
|
|
|
|
for filename, content := range testFiles {
|
|
filePath := filepath.Join(tempDir, filename)
|
|
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
|
}
|
|
}
|
|
|
|
// Create subdirectory with additional script
|
|
subDir := filepath.Join(tempDir, "migrations")
|
|
if err := os.MkdirAll(subDir, 0755); err != nil {
|
|
t.Fatalf("Failed to create subdirectory: %v", err)
|
|
}
|
|
subFile := filepath.Join(subDir, "3_001_add_column.sql")
|
|
if err := os.WriteFile(subFile, []byte("ALTER TABLE users ADD COLUMN email TEXT;"), 0644); err != nil {
|
|
t.Fatalf("Failed to create subdirectory file: %v", err)
|
|
}
|
|
|
|
// Create reader
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
Metadata: map[string]any{
|
|
"schema_name": "test_schema",
|
|
"database_name": "test_db",
|
|
},
|
|
})
|
|
|
|
// Read database
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase failed: %v", err)
|
|
}
|
|
|
|
// Verify database
|
|
if db.Name != "test_db" {
|
|
t.Errorf("Expected database name 'test_db', got '%s'", db.Name)
|
|
}
|
|
|
|
if len(db.Schemas) != 1 {
|
|
t.Fatalf("Expected 1 schema, got %d", len(db.Schemas))
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
if schema.Name != "test_schema" {
|
|
t.Errorf("Expected schema name 'test_schema', got '%s'", schema.Name)
|
|
}
|
|
|
|
// Verify scripts (should be 7 total: 4 underscore + 2 hyphen + 1 subdirectory)
|
|
if len(schema.Scripts) != 7 {
|
|
t.Fatalf("Expected 7 scripts, got %d", len(schema.Scripts))
|
|
}
|
|
|
|
// Verify script details
|
|
expectedScripts := []struct {
|
|
name string
|
|
priority int
|
|
sequence uint
|
|
}{
|
|
{"create_users", 1, 1},
|
|
{"create_posts", 1, 2},
|
|
{"seed_data", 1, 3},
|
|
{"add_indexes", 2, 1},
|
|
{"add-column", 2, 5},
|
|
{"add_column", 3, 1},
|
|
{"create-newid", 10, 10},
|
|
}
|
|
|
|
scriptMap := make(map[string]*struct {
|
|
priority int
|
|
sequence uint
|
|
sql string
|
|
})
|
|
for _, script := range schema.Scripts {
|
|
scriptMap[script.Name] = &struct {
|
|
priority int
|
|
sequence uint
|
|
sql string
|
|
}{
|
|
priority: script.Priority,
|
|
sequence: script.Sequence,
|
|
sql: script.SQL,
|
|
}
|
|
}
|
|
|
|
for _, expected := range expectedScripts {
|
|
script, exists := scriptMap[expected.name]
|
|
if !exists {
|
|
t.Errorf("Expected script '%s' not found", expected.name)
|
|
continue
|
|
}
|
|
if script.priority != expected.priority {
|
|
t.Errorf("Script '%s': expected priority %d, got %d",
|
|
expected.name, expected.priority, script.priority)
|
|
}
|
|
if script.sequence != expected.sequence {
|
|
t.Errorf("Script '%s': expected sequence %d, got %d",
|
|
expected.name, expected.sequence, script.sequence)
|
|
}
|
|
if script.sql == "" {
|
|
t.Errorf("Script '%s': SQL content is empty", expected.name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadSchema(t *testing.T) {
|
|
// Create temporary test directory
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create test SQL file
|
|
testFile := filepath.Join(tempDir, "1_001_test.sql")
|
|
if err := os.WriteFile(testFile, []byte("SELECT 1;"), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file: %v", err)
|
|
}
|
|
|
|
// Create reader
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
})
|
|
|
|
// Read schema
|
|
schema, err := reader.ReadSchema()
|
|
if err != nil {
|
|
t.Fatalf("ReadSchema failed: %v", err)
|
|
}
|
|
|
|
// Verify schema
|
|
if schema.Name != "public" {
|
|
t.Errorf("Expected default schema name 'public', got '%s'", schema.Name)
|
|
}
|
|
|
|
if len(schema.Scripts) != 1 {
|
|
t.Fatalf("Expected 1 script, got %d", len(schema.Scripts))
|
|
}
|
|
}
|
|
|
|
func TestReader_InvalidDirectory(t *testing.T) {
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: "/nonexistent/directory",
|
|
})
|
|
|
|
_, err := reader.ReadDatabase()
|
|
if err == nil {
|
|
t.Error("Expected error for nonexistent directory, got nil")
|
|
}
|
|
}
|
|
|
|
func TestReader_EmptyDirectory(t *testing.T) {
|
|
// Create temporary empty directory
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
})
|
|
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase failed: %v", err)
|
|
}
|
|
|
|
if len(db.Schemas[0].Scripts) != 0 {
|
|
t.Errorf("Expected 0 scripts in empty directory, got %d", len(db.Schemas[0].Scripts))
|
|
}
|
|
}
|
|
|
|
func TestReader_InvalidFilename(t *testing.T) {
|
|
// Create temporary test directory
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create files with various invalid patterns
|
|
invalidFiles := []string{
|
|
"invalid.sql", // No priority/sequence
|
|
"1_test.sql", // Missing sequence
|
|
"test_1_2.sql", // Wrong order
|
|
"a_001_test.sql", // Non-numeric priority
|
|
"1_abc_test.sql", // Non-numeric sequence
|
|
"1_001_test.txt", // Wrong extension
|
|
"1_001_test.sql.backup", // Wrong extension
|
|
}
|
|
|
|
for _, filename := range invalidFiles {
|
|
filePath := filepath.Join(tempDir, filename)
|
|
if err := os.WriteFile(filePath, []byte("SELECT 1;"), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
|
}
|
|
}
|
|
|
|
// Create one valid file
|
|
validFile := filepath.Join(tempDir, "1_001_valid.sql")
|
|
if err := os.WriteFile(validFile, []byte("SELECT 1;"), 0644); err != nil {
|
|
t.Fatalf("Failed to create valid file: %v", err)
|
|
}
|
|
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
})
|
|
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase failed: %v", err)
|
|
}
|
|
|
|
// Should only have the valid file
|
|
if len(db.Schemas[0].Scripts) != 1 {
|
|
t.Errorf("Expected 1 script (invalid files should be skipped), got %d", len(db.Schemas[0].Scripts))
|
|
}
|
|
|
|
if db.Schemas[0].Scripts[0].Name != "valid" {
|
|
t.Errorf("Expected script name 'valid', got '%s'", db.Schemas[0].Scripts[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadTable(t *testing.T) {
|
|
reader := NewReader(&readers.ReaderOptions{})
|
|
|
|
_, err := reader.ReadTable()
|
|
if err == nil {
|
|
t.Error("Expected error for ReadTable (not supported), got nil")
|
|
}
|
|
}
|
|
|
|
func TestReader_HyphenFormat(t *testing.T) {
|
|
// Create temporary test directory
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-hyphen-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
// Create test files with hyphen separators
|
|
testFiles := map[string]string{
|
|
"1-001-create-table.sql": "CREATE TABLE test (id INT);",
|
|
"1-002-insert-data.pgsql": "INSERT INTO test VALUES (1);",
|
|
"10-10-create-newid.pgsql": "CREATE TABLE newid (id SERIAL);",
|
|
"2-005-add-index.sql": "CREATE INDEX idx_test ON test(id);",
|
|
}
|
|
|
|
for filename, content := range testFiles {
|
|
filePath := filepath.Join(tempDir, filename)
|
|
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
|
}
|
|
}
|
|
|
|
// Create reader
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
})
|
|
|
|
// Read database
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase failed: %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
if len(schema.Scripts) != 4 {
|
|
t.Fatalf("Expected 4 scripts, got %d", len(schema.Scripts))
|
|
}
|
|
|
|
// Verify specific hyphen-formatted scripts
|
|
expectedScripts := map[string]struct {
|
|
priority int
|
|
sequence uint
|
|
}{
|
|
"create-table": {1, 1},
|
|
"insert-data": {1, 2},
|
|
"add-index": {2, 5},
|
|
"create-newid": {10, 10},
|
|
}
|
|
|
|
for _, script := range schema.Scripts {
|
|
expected, exists := expectedScripts[script.Name]
|
|
if !exists {
|
|
t.Errorf("Unexpected script: %s", script.Name)
|
|
continue
|
|
}
|
|
if script.Priority != expected.priority {
|
|
t.Errorf("Script '%s': expected priority %d, got %d",
|
|
script.Name, expected.priority, script.Priority)
|
|
}
|
|
if script.Sequence != expected.sequence {
|
|
t.Errorf("Script '%s': expected sequence %d, got %d",
|
|
script.Name, expected.sequence, script.Sequence)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReader_MixedFormat(t *testing.T) {
|
|
// Test that both underscore and hyphen formats can be mixed
|
|
tempDir, err := os.MkdirTemp("", "sqldir-test-mixed-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
testFiles := map[string]string{
|
|
"1_001_underscore.sql": "SELECT 1;",
|
|
"1-002-hyphen.sql": "SELECT 2;",
|
|
"2_003_underscore.sql": "SELECT 3;",
|
|
"2-004-hyphen.sql": "SELECT 4;",
|
|
}
|
|
|
|
for filename, content := range testFiles {
|
|
filePath := filepath.Join(tempDir, filename)
|
|
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
|
}
|
|
}
|
|
|
|
reader := NewReader(&readers.ReaderOptions{
|
|
FilePath: tempDir,
|
|
})
|
|
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase failed: %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
if len(schema.Scripts) != 4 {
|
|
t.Fatalf("Expected 4 scripts (mixed format), got %d", len(schema.Scripts))
|
|
}
|
|
|
|
// Verify both formats are parsed correctly
|
|
names := make(map[string]bool)
|
|
for _, script := range schema.Scripts {
|
|
names[script.Name] = true
|
|
}
|
|
|
|
expectedNames := []string{"underscore", "hyphen", "underscore", "hyphen"}
|
|
for _, name := range expectedNames {
|
|
if !names[name] {
|
|
t.Errorf("Expected script name '%s' not found", name)
|
|
}
|
|
}
|
|
}
|