Files
relspecgo/pkg/writers/json/writer_test.go
Hein a427aa5537
Some checks are pending
CI / Test (1.23) (push) Waiting to run
CI / Test (1.24) (push) Waiting to run
CI / Test (1.25) (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Build (push) Waiting to run
More Roundtrip tests
2025-12-17 22:52:24 +02:00

449 lines
12 KiB
Go

package json
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"git.warky.dev/wdevs/relspecgo/pkg/models"
"git.warky.dev/wdevs/relspecgo/pkg/writers"
)
func TestWriter_WriteTable(t *testing.T) {
table := models.InitTable("users", "public")
table.Description = "User accounts table"
idCol := models.InitColumn("id", "users", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
idCol.AutoIncrement = true
idCol.NotNull = true
table.Columns["id"] = idCol
emailCol := models.InitColumn("email", "users", "public")
emailCol.Type = "varchar"
emailCol.Length = 255
emailCol.NotNull = true
emailCol.Comment = "User email address"
table.Columns["email"] = emailCol
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "test.json")
opts := &writers.WriterOptions{
OutputPath: outputPath,
}
writer := NewWriter(opts)
err := writer.WriteTable(table)
if err != nil {
t.Fatalf("WriteTable() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read output file: %v", err)
}
var result models.Table
if err := json.Unmarshal(content, &result); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
if result.Name != "users" {
t.Errorf("Expected table name 'users', got '%s'", result.Name)
}
if result.Description != "User accounts table" {
t.Errorf("Expected description 'User accounts table', got '%s'", result.Description)
}
if len(result.Columns) != 2 {
t.Errorf("Expected 2 columns, got %d", len(result.Columns))
}
// Verify id column
idColResult, exists := result.Columns["id"]
if !exists {
t.Fatal("Column 'id' not found")
}
if !idColResult.IsPrimaryKey {
t.Error("Column 'id' should be primary key")
}
if !idColResult.AutoIncrement {
t.Error("Column 'id' should be auto-increment")
}
// Verify email column
emailColResult, exists := result.Columns["email"]
if !exists {
t.Fatal("Column 'email' not found")
}
if emailColResult.Length != 255 {
t.Errorf("Expected email length 255, got %d", emailColResult.Length)
}
if emailColResult.Comment != "User email address" {
t.Errorf("Expected email comment 'User email address', got '%s'", emailColResult.Comment)
}
}
func TestWriter_WriteDatabase_WithRelationships(t *testing.T) {
db := models.InitDatabase("test_db")
db.Description = "Test database"
db.DatabaseType = models.PostgresqlDatabaseType
schema := models.InitSchema("public")
// Create users table
usersTable := models.InitTable("users", "public")
idCol := models.InitColumn("id", "users", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
idCol.AutoIncrement = true
idCol.NotNull = true
usersTable.Columns["id"] = idCol
emailCol := models.InitColumn("email", "users", "public")
emailCol.Type = "varchar"
emailCol.Length = 255
emailCol.NotNull = true
usersTable.Columns["email"] = emailCol
// Add index
emailIdx := models.InitIndex("idx_users_email", "users", "public")
emailIdx.Columns = []string{"email"}
emailIdx.Unique = true
emailIdx.Type = "btree"
emailIdx.Table = "users"
emailIdx.Schema = "public"
usersTable.Indexes["idx_users_email"] = emailIdx
// Create posts table
postsTable := models.InitTable("posts", "public")
postIdCol := models.InitColumn("id", "posts", "public")
postIdCol.Type = "bigint"
postIdCol.IsPrimaryKey = true
postIdCol.NotNull = true
postsTable.Columns["id"] = postIdCol
userIdCol := models.InitColumn("user_id", "posts", "public")
userIdCol.Type = "bigint"
userIdCol.NotNull = true
postsTable.Columns["user_id"] = userIdCol
titleCol := models.InitColumn("title", "posts", "public")
titleCol.Type = "varchar"
titleCol.Length = 200
titleCol.NotNull = true
postsTable.Columns["title"] = titleCol
// Add foreign key constraint
fk := models.InitConstraint("fk_posts_user", models.ForeignKeyConstraint)
fk.Table = "posts"
fk.Schema = "public"
fk.Columns = []string{"user_id"}
fk.ReferencedTable = "users"
fk.ReferencedSchema = "public"
fk.ReferencedColumns = []string{"id"}
fk.OnDelete = "CASCADE"
fk.OnUpdate = "CASCADE"
postsTable.Constraints["fk_posts_user"] = fk
schema.Tables = append(schema.Tables, usersTable, postsTable)
db.Schemas = append(db.Schemas, schema)
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "test.json")
opts := &writers.WriterOptions{
OutputPath: outputPath,
}
writer := NewWriter(opts)
err := writer.WriteDatabase(db)
if err != nil {
t.Fatalf("WriteDatabase() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read output file: %v", err)
}
var result models.Database
if err := json.Unmarshal(content, &result); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
if result.Name != "test_db" {
t.Errorf("Expected database name 'test_db', got '%s'", result.Name)
}
if result.DatabaseType != models.PostgresqlDatabaseType {
t.Errorf("Expected database type 'pgsql', got '%s'", result.DatabaseType)
}
if len(result.Schemas) != 1 {
t.Fatalf("Expected 1 schema, got %d", len(result.Schemas))
}
resultSchema := result.Schemas[0]
if len(resultSchema.Tables) != 2 {
t.Fatalf("Expected 2 tables, got %d", len(resultSchema.Tables))
}
// Find posts table and verify foreign key
var postsTableResult *models.Table
for _, table := range resultSchema.Tables {
if table.Name == "posts" {
postsTableResult = table
break
}
}
if postsTableResult == nil {
t.Fatal("Posts table not found")
}
if len(postsTableResult.Constraints) != 1 {
t.Errorf("Expected 1 constraint, got %d", len(postsTableResult.Constraints))
}
fkResult, exists := postsTableResult.Constraints["fk_posts_user"]
if !exists {
t.Fatal("Foreign key 'fk_posts_user' not found")
}
if fkResult.Type != models.ForeignKeyConstraint {
t.Error("Expected foreign key constraint type")
}
if fkResult.ReferencedTable != "users" {
t.Errorf("Expected referenced table 'users', got '%s'", fkResult.ReferencedTable)
}
if fkResult.OnDelete != "CASCADE" {
t.Errorf("Expected ON DELETE CASCADE, got '%s'", fkResult.OnDelete)
}
if fkResult.OnUpdate != "CASCADE" {
t.Errorf("Expected ON UPDATE CASCADE, got '%s'", fkResult.OnUpdate)
}
// Verify index
var usersTableResult *models.Table
for _, table := range resultSchema.Tables {
if table.Name == "users" {
usersTableResult = table
break
}
}
if usersTableResult == nil {
t.Fatal("Users table not found")
}
if len(usersTableResult.Indexes) != 1 {
t.Errorf("Expected 1 index, got %d", len(usersTableResult.Indexes))
}
idxResult, exists := usersTableResult.Indexes["idx_users_email"]
if !exists {
t.Fatal("Index 'idx_users_email' not found")
}
if !idxResult.Unique {
t.Error("Email index should be unique")
}
if idxResult.Type != "btree" {
t.Errorf("Expected index type 'btree', got '%s'", idxResult.Type)
}
}
func TestWriter_WriteSchema(t *testing.T) {
schema := models.InitSchema("public")
schema.Description = "Public schema"
table := models.InitTable("users", "public")
idCol := models.InitColumn("id", "users", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
table.Columns["id"] = idCol
usernameCol := models.InitColumn("username", "users", "public")
usernameCol.Type = "varchar"
usernameCol.Length = 50
usernameCol.NotNull = true
table.Columns["username"] = usernameCol
schema.Tables = append(schema.Tables, table)
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "test.json")
opts := &writers.WriterOptions{
OutputPath: outputPath,
}
writer := NewWriter(opts)
err := writer.WriteSchema(schema)
if err != nil {
t.Fatalf("WriteSchema() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read output file: %v", err)
}
var result models.Schema
if err := json.Unmarshal(content, &result); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
if result.Name != "public" {
t.Errorf("Expected schema name 'public', got '%s'", result.Name)
}
if result.Description != "Public schema" {
t.Errorf("Expected description 'Public schema', got '%s'", result.Description)
}
if len(result.Tables) != 1 {
t.Errorf("Expected 1 table, got %d", len(result.Tables))
}
}
func TestWriter_WriteTable_EmptyPath(t *testing.T) {
table := models.InitTable("users", "public")
idCol := models.InitColumn("id", "users", "public")
idCol.Type = "bigint"
table.Columns["id"] = idCol
// When OutputPath is empty, it should print to stdout (not error)
opts := &writers.WriterOptions{
OutputPath: "",
}
writer := NewWriter(opts)
err := writer.WriteTable(table)
if err != nil {
t.Fatalf("WriteTable() with empty path should not error, got: %v", err)
}
}
func TestWriter_WriteDatabase_WithDefaults(t *testing.T) {
db := models.InitDatabase("test_db")
schema := models.InitSchema("public")
table := models.InitTable("products", "public")
idCol := models.InitColumn("id", "products", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
table.Columns["id"] = idCol
isActiveCol := models.InitColumn("is_active", "products", "public")
isActiveCol.Type = "boolean"
isActiveCol.Default = "true"
table.Columns["is_active"] = isActiveCol
createdCol := models.InitColumn("created_at", "products", "public")
createdCol.Type = "timestamp"
createdCol.Default = "CURRENT_TIMESTAMP"
table.Columns["created_at"] = createdCol
schema.Tables = append(schema.Tables, table)
db.Schemas = append(db.Schemas, schema)
tmpDir := t.TempDir()
outputPath := filepath.Join(tmpDir, "test.json")
opts := &writers.WriterOptions{
OutputPath: outputPath,
}
writer := NewWriter(opts)
err := writer.WriteDatabase(db)
if err != nil {
t.Fatalf("WriteDatabase() error = %v", err)
}
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read output file: %v", err)
}
var result models.Database
if err := json.Unmarshal(content, &result); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
tableResult := result.Schemas[0].Tables[0]
// Verify default values
isActiveColResult, exists := tableResult.Columns["is_active"]
if !exists {
t.Fatal("Column 'is_active' not found")
}
if isActiveColResult.Default != "true" {
t.Errorf("Expected is_active default 'true', got '%v'", isActiveColResult.Default)
}
createdColResult, exists := tableResult.Columns["created_at"]
if !exists {
t.Fatal("Column 'created_at' not found")
}
if createdColResult.Default != "CURRENT_TIMESTAMP" {
t.Errorf("Expected created_at default 'CURRENT_TIMESTAMP', got '%v'", createdColResult.Default)
}
}
func TestGetPrimaryKey(t *testing.T) {
table := models.InitTable("users", "public")
idCol := models.InitColumn("id", "users", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
table.Columns["id"] = idCol
emailCol := models.InitColumn("email", "users", "public")
emailCol.Type = "varchar"
table.Columns["email"] = emailCol
pk := table.GetPrimaryKey()
if pk == nil {
t.Fatal("Expected primary key, got nil")
}
if pk.Name != "id" {
t.Errorf("Expected primary key name 'id', got '%s'", pk.Name)
}
}
func TestGetForeignKeys(t *testing.T) {
table := models.InitTable("posts", "public")
idCol := models.InitColumn("id", "posts", "public")
idCol.Type = "bigint"
idCol.IsPrimaryKey = true
table.Columns["id"] = idCol
userIdCol := models.InitColumn("user_id", "posts", "public")
userIdCol.Type = "bigint"
table.Columns["user_id"] = userIdCol
// Add foreign key constraint
fk := models.InitConstraint("fk_posts_user", models.ForeignKeyConstraint)
fk.Columns = []string{"user_id"}
fk.ReferencedTable = "users"
fk.ReferencedColumns = []string{"id"}
table.Constraints["fk_posts_user"] = fk
fks := table.GetForeignKeys()
if len(fks) != 1 {
t.Errorf("Expected 1 foreign key, got %d", len(fks))
}
if fks[0].Type != models.ForeignKeyConstraint {
t.Error("Expected foreign key constraint type")
}
}