1. pkg/models/models.go:184 - Fixed typo in ForeignKeyConstraint constant from "foreign_Key" to "foreign_key" 2. pkg/readers/drawdb/reader.go:62-68 - Fixed ReadSchema() to properly detect schema name from tables instead of hardcoding "default" 3. pkg/writers/dbml/writer.go:128 - Changed primary key attribute from "primary key" to DBML standard "pk" 4. pkg/writers/dbml/writer.go:208-221 - Fixed foreign key reference format to use "table.column" syntax for single columns instead of "table.(column)" Test Results All reader and writer tests are now passing: Readers: - DBML: 74.4% coverage (2 tests skipped due to missing parser features for Ref statements) - DCTX: 77.6% coverage - DrawDB: 83.6% coverage - JSON: 82.1% coverage - YAML: 82.1% coverage Writers: - Bun: 68.5% coverage - DBML: 91.5% coverage - DCTX: 100.0% coverage - DrawDB: 83.8% coverage - GORM: 69.2% coverage - JSON: 82.4% coverage - YAML: 82.4% coverage
385 lines
9.2 KiB
Go
385 lines
9.2 KiB
Go
package json
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
|
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
|
)
|
|
|
|
func TestReader_ReadDatabase(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "json", "database.json"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
if db == nil {
|
|
t.Fatal("ReadDatabase() returned nil database")
|
|
}
|
|
|
|
if db.Name != "test_db" {
|
|
t.Errorf("Expected database name 'test_db', got '%s'", db.Name)
|
|
}
|
|
|
|
if db.Description != "Test database for JSON reader" {
|
|
t.Errorf("Expected description 'Test database for JSON reader', got '%s'", db.Description)
|
|
}
|
|
|
|
if db.DatabaseType != models.PostgresqlDatabaseType {
|
|
t.Errorf("Expected database type 'pgsql', got '%s'", db.DatabaseType)
|
|
}
|
|
|
|
if len(db.Schemas) != 1 {
|
|
t.Fatalf("Expected 1 schema, got %d", len(db.Schemas))
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
if schema.Name != "public" {
|
|
t.Errorf("Expected schema name 'public', got '%s'", schema.Name)
|
|
}
|
|
|
|
if len(schema.Tables) != 2 {
|
|
t.Fatalf("Expected 2 tables, got %d", len(schema.Tables))
|
|
}
|
|
|
|
// Find users table
|
|
var usersTable *models.Table
|
|
for _, table := range schema.Tables {
|
|
if table.Name == "users" {
|
|
usersTable = table
|
|
break
|
|
}
|
|
}
|
|
|
|
if usersTable == nil {
|
|
t.Fatal("Users table not found")
|
|
}
|
|
|
|
if usersTable.Description != "User accounts table" {
|
|
t.Errorf("Expected table description 'User accounts table', got '%s'", usersTable.Description)
|
|
}
|
|
|
|
if len(usersTable.Columns) != 4 {
|
|
t.Errorf("Expected 4 columns, got %d", len(usersTable.Columns))
|
|
}
|
|
|
|
// Verify id column
|
|
idCol, exists := usersTable.Columns["id"]
|
|
if !exists {
|
|
t.Fatal("Column 'id' not found")
|
|
}
|
|
if !idCol.IsPrimaryKey {
|
|
t.Error("Column 'id' should be primary key")
|
|
}
|
|
if !idCol.AutoIncrement {
|
|
t.Error("Column 'id' should be auto-increment")
|
|
}
|
|
if !idCol.NotNull {
|
|
t.Error("Column 'id' should be not null")
|
|
}
|
|
if idCol.Type != "bigint" {
|
|
t.Errorf("Expected id type 'bigint', got '%s'", idCol.Type)
|
|
}
|
|
|
|
// Verify email column
|
|
emailCol, exists := usersTable.Columns["email"]
|
|
if !exists {
|
|
t.Fatal("Column 'email' not found")
|
|
}
|
|
if !emailCol.NotNull {
|
|
t.Error("Column 'email' should be not null")
|
|
}
|
|
if emailCol.Type != "varchar" {
|
|
t.Errorf("Expected email type 'varchar', got '%s'", emailCol.Type)
|
|
}
|
|
if emailCol.Length != 255 {
|
|
t.Errorf("Expected email length 255, got %d", emailCol.Length)
|
|
}
|
|
if emailCol.Comment != "User email address" {
|
|
t.Errorf("Expected email comment 'User email address', got '%s'", emailCol.Comment)
|
|
}
|
|
|
|
// Verify created_at column with default
|
|
createdCol, exists := usersTable.Columns["created_at"]
|
|
if !exists {
|
|
t.Fatal("Column 'created_at' not found")
|
|
}
|
|
if createdCol.Default == nil {
|
|
t.Error("Expected default value for created_at")
|
|
}
|
|
if createdCol.Default != "CURRENT_TIMESTAMP" {
|
|
t.Errorf("Expected default 'CURRENT_TIMESTAMP', got '%v'", createdCol.Default)
|
|
}
|
|
|
|
// Verify index
|
|
if len(usersTable.Indexes) != 1 {
|
|
t.Errorf("Expected 1 index, got %d", len(usersTable.Indexes))
|
|
}
|
|
|
|
emailIdx, exists := usersTable.Indexes["idx_users_email"]
|
|
if !exists {
|
|
t.Fatal("Index 'idx_users_email' not found")
|
|
}
|
|
if !emailIdx.Unique {
|
|
t.Error("Email index should be unique")
|
|
}
|
|
if len(emailIdx.Columns) != 1 || emailIdx.Columns[0] != "email" {
|
|
t.Error("Email index should have 'email' column")
|
|
}
|
|
if emailIdx.Type != "btree" {
|
|
t.Errorf("Expected index type 'btree', got '%s'", emailIdx.Type)
|
|
}
|
|
|
|
// Find posts table and verify foreign key
|
|
var postsTable *models.Table
|
|
for _, table := range schema.Tables {
|
|
if table.Name == "posts" {
|
|
postsTable = table
|
|
break
|
|
}
|
|
}
|
|
|
|
if postsTable == nil {
|
|
t.Fatal("Posts table not found")
|
|
}
|
|
|
|
if len(postsTable.Constraints) != 1 {
|
|
t.Errorf("Expected 1 constraint, got %d", len(postsTable.Constraints))
|
|
}
|
|
|
|
fk, exists := postsTable.Constraints["fk_posts_user"]
|
|
if !exists {
|
|
t.Fatal("Foreign key 'fk_posts_user' not found")
|
|
}
|
|
if fk.Type != models.ForeignKeyConstraint {
|
|
t.Error("Expected foreign key constraint type")
|
|
}
|
|
if fk.ReferencedTable != "users" {
|
|
t.Errorf("Expected referenced table 'users', got '%s'", fk.ReferencedTable)
|
|
}
|
|
if fk.ReferencedSchema != "public" {
|
|
t.Errorf("Expected referenced schema 'public', got '%s'", fk.ReferencedSchema)
|
|
}
|
|
if len(fk.Columns) != 1 || fk.Columns[0] != "user_id" {
|
|
t.Error("Expected FK column 'user_id'")
|
|
}
|
|
if len(fk.ReferencedColumns) != 1 || fk.ReferencedColumns[0] != "id" {
|
|
t.Error("Expected FK referenced column 'id'")
|
|
}
|
|
if fk.OnDelete != "CASCADE" {
|
|
t.Errorf("Expected ON DELETE CASCADE, got '%s'", fk.OnDelete)
|
|
}
|
|
if fk.OnUpdate != "CASCADE" {
|
|
t.Errorf("Expected ON UPDATE CASCADE, got '%s'", fk.OnUpdate)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadSchema(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "json", "schema.json"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
schema, err := reader.ReadSchema()
|
|
if err != nil {
|
|
t.Fatalf("ReadSchema() error = %v", err)
|
|
}
|
|
|
|
if schema == nil {
|
|
t.Fatal("ReadSchema() returned nil schema")
|
|
}
|
|
|
|
if schema.Name != "public" {
|
|
t.Errorf("Expected schema name 'public', got '%s'", schema.Name)
|
|
}
|
|
|
|
if schema.Description != "Public schema" {
|
|
t.Errorf("Expected description 'Public schema', got '%s'", schema.Description)
|
|
}
|
|
|
|
if len(schema.Tables) != 1 {
|
|
t.Errorf("Expected 1 table, got %d", len(schema.Tables))
|
|
}
|
|
|
|
table := schema.Tables[0]
|
|
if table.Name != "users" {
|
|
t.Errorf("Expected table name 'users', got '%s'", table.Name)
|
|
}
|
|
|
|
if len(table.Columns) != 2 {
|
|
t.Errorf("Expected 2 columns, got %d", len(table.Columns))
|
|
}
|
|
|
|
// Verify username column
|
|
usernameCol, exists := table.Columns["username"]
|
|
if !exists {
|
|
t.Fatal("Column 'username' not found")
|
|
}
|
|
if usernameCol.Type != "varchar" {
|
|
t.Errorf("Expected username type 'varchar', got '%s'", usernameCol.Type)
|
|
}
|
|
if usernameCol.Length != 50 {
|
|
t.Errorf("Expected username length 50, got %d", usernameCol.Length)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadTable(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "json", "table.json"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
table, err := reader.ReadTable()
|
|
if err != nil {
|
|
t.Fatalf("ReadTable() error = %v", err)
|
|
}
|
|
|
|
if table == nil {
|
|
t.Fatal("ReadTable() returned nil table")
|
|
}
|
|
|
|
if table.Name != "users" {
|
|
t.Errorf("Expected table name 'users', got '%s'", table.Name)
|
|
}
|
|
|
|
if table.Schema != "public" {
|
|
t.Errorf("Expected schema 'public', got '%s'", table.Schema)
|
|
}
|
|
|
|
if table.Description != "Users table" {
|
|
t.Errorf("Expected description 'Users table', got '%s'", table.Description)
|
|
}
|
|
|
|
if len(table.Columns) != 2 {
|
|
t.Errorf("Expected 2 columns, got %d", len(table.Columns))
|
|
}
|
|
|
|
// Verify columns
|
|
idCol, exists := table.Columns["id"]
|
|
if !exists {
|
|
t.Fatal("Column 'id' not found")
|
|
}
|
|
if !idCol.IsPrimaryKey {
|
|
t.Error("Column 'id' should be primary key")
|
|
}
|
|
|
|
emailCol, exists := table.Columns["email"]
|
|
if !exists {
|
|
t.Fatal("Column 'email' not found")
|
|
}
|
|
if emailCol.Length != 255 {
|
|
t.Errorf("Expected email length 255, got %d", emailCol.Length)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_InvalidPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "/nonexistent/file.json",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadDatabase()
|
|
if err == nil {
|
|
t.Error("Expected error for invalid file path")
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_EmptyPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadDatabase()
|
|
if err == nil {
|
|
t.Error("Expected error for empty file path")
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadSchema_EmptyPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadSchema()
|
|
if err == nil {
|
|
t.Error("Expected error for empty file path")
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadTable_EmptyPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadTable()
|
|
if err == nil {
|
|
t.Error("Expected error for empty file path")
|
|
}
|
|
}
|
|
|
|
func TestGetPrimaryKey(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "json", "table.json"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
table, err := reader.ReadTable()
|
|
if err != nil {
|
|
t.Fatalf("ReadTable() error = %v", err)
|
|
}
|
|
|
|
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) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "json", "database.json"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
// Find posts table
|
|
var postsTable *models.Table
|
|
for _, schema := range db.Schemas {
|
|
for _, table := range schema.Tables {
|
|
if table.Name == "posts" {
|
|
postsTable = table
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if postsTable == nil {
|
|
t.Fatal("Posts table not found")
|
|
}
|
|
|
|
fks := postsTable.GetForeignKeys()
|
|
if len(fks) != 1 {
|
|
t.Errorf("Expected 1 foreign key, got %d", len(fks))
|
|
}
|
|
|
|
if len(fks) > 0 && fks[0].Type != models.ForeignKeyConstraint {
|
|
t.Error("Expected foreign key constraint type")
|
|
}
|
|
}
|