package pgsql import ( "bytes" "strings" "testing" "git.warky.dev/wdevs/relspecgo/pkg/models" "git.warky.dev/wdevs/relspecgo/pkg/writers" ) func TestWriteDatabase(t *testing.T) { // Create a test database db := models.InitDatabase("testdb") schema := models.InitSchema("public") // Create a test table table := models.InitTable("users", "public") table.Description = "User accounts table" // Add columns idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" idCol.Description = "Primary key" idCol.Default = "nextval('public.identity_users_id'::regclass)" table.Columns["id"] = idCol nameCol := models.InitColumn("name", "users", "public") nameCol.Type = "text" nameCol.Description = "User name" table.Columns["name"] = nameCol emailCol := models.InitColumn("email", "users", "public") emailCol.Type = "text" emailCol.Description = "Email address" table.Columns["email"] = emailCol // Add primary key constraint pkConstraint := &models.Constraint{ Name: "pk_users", Type: models.PrimaryKeyConstraint, Columns: []string{"id"}, } table.Constraints["pk_users"] = pkConstraint // Add unique index uniqueEmailIndex := &models.Index{ Name: "uk_users_email", Unique: true, Columns: []string{"email"}, } table.Indexes["uk_users_email"] = uniqueEmailIndex schema.Tables = append(schema.Tables, table) db.Schemas = append(db.Schemas, schema) // Create writer with output to buffer var buf bytes.Buffer options := &writers.WriterOptions{} writer := NewWriter(options) writer.writer = &buf // Write the database err := writer.WriteDatabase(db) if err != nil { t.Fatalf("WriteDatabase failed: %v", err) } output := buf.String() // Print output for debugging t.Logf("Generated SQL:\n%s", output) // Verify output contains expected elements expectedStrings := []string{ "CREATE TABLE", "PRIMARY KEY", "UNIQUE INDEX", "COMMENT ON TABLE", "COMMENT ON COLUMN", } for _, expected := range expectedStrings { if !strings.Contains(output, expected) { t.Errorf("Output missing expected string: %s\nFull output:\n%s", expected, output) } } } func TestWriteForeignKeys(t *testing.T) { // Create a test database with two related tables db := models.InitDatabase("testdb") schema := models.InitSchema("public") // Create parent table (users) usersTable := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" usersTable.Columns["id"] = idCol // Create child table (posts) postsTable := models.InitTable("posts", "public") postIdCol := models.InitColumn("id", "posts", "public") postIdCol.Type = "integer" postsTable.Columns["id"] = postIdCol userIdCol := models.InitColumn("user_id", "posts", "public") userIdCol.Type = "integer" postsTable.Columns["user_id"] = userIdCol // Add foreign key constraint fkConstraint := &models.Constraint{ Name: "fk_posts_users", Type: models.ForeignKeyConstraint, Columns: []string{"user_id"}, ReferencedTable: "users", ReferencedSchema: "public", ReferencedColumns: []string{"id"}, OnDelete: "CASCADE", OnUpdate: "CASCADE", } postsTable.Constraints["fk_posts_users"] = fkConstraint // Add relationship relationship := &models.Relationship{ Name: "fk_posts_users", FromTable: "posts", FromSchema: "public", ToTable: "users", ToSchema: "public", ForeignKey: "fk_posts_users", } postsTable.Relationships["fk_posts_users"] = relationship schema.Tables = append(schema.Tables, usersTable, postsTable) db.Schemas = append(db.Schemas, schema) // Create writer with output to buffer var buf bytes.Buffer options := &writers.WriterOptions{} writer := NewWriter(options) writer.writer = &buf // Write the database err := writer.WriteDatabase(db) if err != nil { t.Fatalf("WriteDatabase failed: %v", err) } output := buf.String() // Print output for debugging t.Logf("Generated SQL:\n%s", output) // Verify foreign key is present if !strings.Contains(output, "FOREIGN KEY") { t.Errorf("Output missing FOREIGN KEY statement\nFull output:\n%s", output) } if !strings.Contains(output, "ON DELETE CASCADE") { t.Errorf("Output missing ON DELETE CASCADE\nFull output:\n%s", output) } if !strings.Contains(output, "ON UPDATE CASCADE") { t.Errorf("Output missing ON UPDATE CASCADE\nFull output:\n%s", output) } } func TestWriteTable(t *testing.T) { // Create a single table table := models.InitTable("products", "public") idCol := models.InitColumn("id", "products", "public") idCol.Type = "integer" table.Columns["id"] = idCol nameCol := models.InitColumn("name", "products", "public") nameCol.Type = "text" table.Columns["name"] = nameCol // Create writer with output to buffer var buf bytes.Buffer options := &writers.WriterOptions{} writer := NewWriter(options) writer.writer = &buf // Write the table err := writer.WriteTable(table) if err != nil { t.Fatalf("WriteTable failed: %v", err) } output := buf.String() // Verify output contains table creation if !strings.Contains(output, "CREATE TABLE") { t.Error("Output missing CREATE TABLE statement") } if !strings.Contains(output, "products") { t.Error("Output missing table name 'products'") } } func TestEscapeQuote(t *testing.T) { tests := []struct { input string expected string }{ {"simple text", "simple text"}, {"text with 'quote'", "text with ''quote''"}, {"multiple 'quotes' here", "multiple ''quotes'' here"}, {"", ""}, } for _, tt := range tests { result := escapeQuote(tt.input) if result != tt.expected { t.Errorf("escapeQuote(%q) = %q, want %q", tt.input, result, tt.expected) } } } func TestIsIntegerType(t *testing.T) { tests := []struct { input string expected bool }{ {"integer", true}, {"INTEGER", true}, {"bigint", true}, {"smallint", true}, {"serial", true}, {"bigserial", true}, {"text", false}, {"varchar", false}, {"uuid", false}, } for _, tt := range tests { result := isIntegerType(tt.input) if result != tt.expected { t.Errorf("isIntegerType(%q) = %v, want %v", tt.input, result, tt.expected) } } }