better tests
This commit is contained in:
612
tests/assets/yaml/complex_database.yaml
Normal file
612
tests/assets/yaml/complex_database.yaml
Normal file
@@ -0,0 +1,612 @@
|
||||
name: complex_test_db
|
||||
description: Complex test database with relationships and indexes
|
||||
database_type: pgsql
|
||||
schemas:
|
||||
- name: public
|
||||
tables:
|
||||
- name: users
|
||||
schema: public
|
||||
description: User accounts table
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: users
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
email:
|
||||
name: email
|
||||
table: users
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 255
|
||||
not_null: true
|
||||
comment: User email address
|
||||
sequence: 2
|
||||
username:
|
||||
name: username
|
||||
table: users
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 100
|
||||
not_null: true
|
||||
sequence: 3
|
||||
name:
|
||||
name: name
|
||||
table: users
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 100
|
||||
not_null: false
|
||||
sequence: 4
|
||||
bio:
|
||||
name: bio
|
||||
table: users
|
||||
schema: public
|
||||
type: text
|
||||
not_null: false
|
||||
sequence: 5
|
||||
avatar_url:
|
||||
name: avatar_url
|
||||
table: users
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 500
|
||||
not_null: false
|
||||
sequence: 6
|
||||
is_active:
|
||||
name: is_active
|
||||
table: users
|
||||
schema: public
|
||||
type: boolean
|
||||
not_null: true
|
||||
default: true
|
||||
sequence: 7
|
||||
created_at:
|
||||
name: created_at
|
||||
table: users
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: true
|
||||
default: CURRENT_TIMESTAMP
|
||||
sequence: 8
|
||||
updated_at:
|
||||
name: updated_at
|
||||
table: users
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: false
|
||||
sequence: 9
|
||||
indexes:
|
||||
idx_users_email:
|
||||
name: idx_users_email
|
||||
table: users
|
||||
schema: public
|
||||
columns:
|
||||
- email
|
||||
unique: true
|
||||
type: btree
|
||||
idx_users_username:
|
||||
name: idx_users_username
|
||||
table: users
|
||||
schema: public
|
||||
columns:
|
||||
- username
|
||||
unique: true
|
||||
type: btree
|
||||
idx_users_created_at:
|
||||
name: idx_users_created_at
|
||||
table: users
|
||||
schema: public
|
||||
columns:
|
||||
- created_at
|
||||
unique: false
|
||||
type: btree
|
||||
constraints: {}
|
||||
relationships: {}
|
||||
|
||||
- name: categories
|
||||
schema: public
|
||||
description: Post categories
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: categories
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
name:
|
||||
name: name
|
||||
table: categories
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 100
|
||||
not_null: true
|
||||
sequence: 2
|
||||
slug:
|
||||
name: slug
|
||||
table: categories
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 100
|
||||
not_null: true
|
||||
sequence: 3
|
||||
description:
|
||||
name: description
|
||||
table: categories
|
||||
schema: public
|
||||
type: text
|
||||
not_null: false
|
||||
sequence: 4
|
||||
indexes:
|
||||
idx_categories_slug:
|
||||
name: idx_categories_slug
|
||||
table: categories
|
||||
schema: public
|
||||
columns:
|
||||
- slug
|
||||
unique: true
|
||||
type: btree
|
||||
constraints: {}
|
||||
relationships: {}
|
||||
|
||||
- name: posts
|
||||
schema: public
|
||||
description: Blog posts
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: posts
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
user_id:
|
||||
name: user_id
|
||||
table: posts
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
comment: Foreign key to users table
|
||||
sequence: 2
|
||||
title:
|
||||
name: title
|
||||
table: posts
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 200
|
||||
not_null: true
|
||||
sequence: 3
|
||||
slug:
|
||||
name: slug
|
||||
table: posts
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 200
|
||||
not_null: true
|
||||
sequence: 4
|
||||
content:
|
||||
name: content
|
||||
table: posts
|
||||
schema: public
|
||||
type: text
|
||||
not_null: false
|
||||
sequence: 5
|
||||
excerpt:
|
||||
name: excerpt
|
||||
table: posts
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 500
|
||||
not_null: false
|
||||
sequence: 6
|
||||
status:
|
||||
name: status
|
||||
table: posts
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 20
|
||||
not_null: true
|
||||
default: draft
|
||||
sequence: 7
|
||||
view_count:
|
||||
name: view_count
|
||||
table: posts
|
||||
schema: public
|
||||
type: integer
|
||||
not_null: true
|
||||
default: 0
|
||||
sequence: 8
|
||||
published_at:
|
||||
name: published_at
|
||||
table: posts
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: false
|
||||
sequence: 9
|
||||
created_at:
|
||||
name: created_at
|
||||
table: posts
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: true
|
||||
default: CURRENT_TIMESTAMP
|
||||
sequence: 10
|
||||
updated_at:
|
||||
name: updated_at
|
||||
table: posts
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: false
|
||||
sequence: 11
|
||||
indexes:
|
||||
idx_posts_user_id:
|
||||
name: idx_posts_user_id
|
||||
table: posts
|
||||
schema: public
|
||||
columns:
|
||||
- user_id
|
||||
unique: false
|
||||
type: btree
|
||||
idx_posts_slug:
|
||||
name: idx_posts_slug
|
||||
table: posts
|
||||
schema: public
|
||||
columns:
|
||||
- slug
|
||||
unique: true
|
||||
type: btree
|
||||
idx_posts_status:
|
||||
name: idx_posts_status
|
||||
table: posts
|
||||
schema: public
|
||||
columns:
|
||||
- status
|
||||
unique: false
|
||||
type: btree
|
||||
idx_posts_published_at:
|
||||
name: idx_posts_published_at
|
||||
table: posts
|
||||
schema: public
|
||||
columns:
|
||||
- published_at
|
||||
unique: false
|
||||
type: btree
|
||||
constraints:
|
||||
fk_posts_user:
|
||||
name: fk_posts_user
|
||||
type: foreign_key
|
||||
table: posts
|
||||
schema: public
|
||||
columns:
|
||||
- user_id
|
||||
referenced_table: users
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
relationships: {}
|
||||
|
||||
- name: comments
|
||||
schema: public
|
||||
description: Post comments
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: comments
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
post_id:
|
||||
name: post_id
|
||||
table: comments
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
comment: Foreign key to posts table
|
||||
sequence: 2
|
||||
user_id:
|
||||
name: user_id
|
||||
table: comments
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
comment: Foreign key to users table
|
||||
sequence: 3
|
||||
parent_id:
|
||||
name: parent_id
|
||||
table: comments
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: false
|
||||
comment: Self-referencing foreign key for nested comments
|
||||
sequence: 4
|
||||
content:
|
||||
name: content
|
||||
table: comments
|
||||
schema: public
|
||||
type: text
|
||||
not_null: true
|
||||
sequence: 5
|
||||
is_approved:
|
||||
name: is_approved
|
||||
table: comments
|
||||
schema: public
|
||||
type: boolean
|
||||
not_null: true
|
||||
default: false
|
||||
sequence: 6
|
||||
created_at:
|
||||
name: created_at
|
||||
table: comments
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: true
|
||||
default: CURRENT_TIMESTAMP
|
||||
sequence: 7
|
||||
updated_at:
|
||||
name: updated_at
|
||||
table: comments
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: false
|
||||
sequence: 8
|
||||
indexes:
|
||||
idx_comments_post_id:
|
||||
name: idx_comments_post_id
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- post_id
|
||||
unique: false
|
||||
type: btree
|
||||
idx_comments_user_id:
|
||||
name: idx_comments_user_id
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- user_id
|
||||
unique: false
|
||||
type: btree
|
||||
idx_comments_parent_id:
|
||||
name: idx_comments_parent_id
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- parent_id
|
||||
unique: false
|
||||
type: btree
|
||||
constraints:
|
||||
fk_comments_post:
|
||||
name: fk_comments_post
|
||||
type: foreign_key
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- post_id
|
||||
referenced_table: posts
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
fk_comments_user:
|
||||
name: fk_comments_user
|
||||
type: foreign_key
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- user_id
|
||||
referenced_table: users
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
fk_comments_parent:
|
||||
name: fk_comments_parent
|
||||
type: foreign_key
|
||||
table: comments
|
||||
schema: public
|
||||
columns:
|
||||
- parent_id
|
||||
referenced_table: comments
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
relationships: {}
|
||||
|
||||
- name: post_categories
|
||||
schema: public
|
||||
description: Many-to-many relationship between posts and categories
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: post_categories
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
post_id:
|
||||
name: post_id
|
||||
table: post_categories
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
sequence: 2
|
||||
category_id:
|
||||
name: category_id
|
||||
table: post_categories
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
sequence: 3
|
||||
created_at:
|
||||
name: created_at
|
||||
table: post_categories
|
||||
schema: public
|
||||
type: timestamp
|
||||
not_null: true
|
||||
default: CURRENT_TIMESTAMP
|
||||
sequence: 4
|
||||
indexes:
|
||||
idx_post_categories_unique:
|
||||
name: idx_post_categories_unique
|
||||
table: post_categories
|
||||
schema: public
|
||||
columns:
|
||||
- post_id
|
||||
- category_id
|
||||
unique: true
|
||||
type: btree
|
||||
idx_post_categories_category:
|
||||
name: idx_post_categories_category
|
||||
table: post_categories
|
||||
schema: public
|
||||
columns:
|
||||
- category_id
|
||||
unique: false
|
||||
type: btree
|
||||
constraints:
|
||||
fk_post_categories_post:
|
||||
name: fk_post_categories_post
|
||||
type: foreign_key
|
||||
table: post_categories
|
||||
schema: public
|
||||
columns:
|
||||
- post_id
|
||||
referenced_table: posts
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
fk_post_categories_category:
|
||||
name: fk_post_categories_category
|
||||
type: foreign_key
|
||||
table: post_categories
|
||||
schema: public
|
||||
columns:
|
||||
- category_id
|
||||
referenced_table: categories
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
relationships: {}
|
||||
|
||||
- name: tags
|
||||
schema: public
|
||||
description: Tags for posts
|
||||
columns:
|
||||
id:
|
||||
name: id
|
||||
table: tags
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
auto_increment: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
name:
|
||||
name: name
|
||||
table: tags
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 50
|
||||
not_null: true
|
||||
sequence: 2
|
||||
slug:
|
||||
name: slug
|
||||
table: tags
|
||||
schema: public
|
||||
type: varchar
|
||||
length: 50
|
||||
not_null: true
|
||||
sequence: 3
|
||||
indexes:
|
||||
idx_tags_slug:
|
||||
name: idx_tags_slug
|
||||
table: tags
|
||||
schema: public
|
||||
columns:
|
||||
- slug
|
||||
unique: true
|
||||
type: btree
|
||||
constraints: {}
|
||||
relationships: {}
|
||||
|
||||
- name: post_tags
|
||||
schema: public
|
||||
description: Many-to-many relationship between posts and tags
|
||||
columns:
|
||||
post_id:
|
||||
name: post_id
|
||||
table: post_tags
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
is_primary_key: true
|
||||
sequence: 1
|
||||
tag_id:
|
||||
name: tag_id
|
||||
table: post_tags
|
||||
schema: public
|
||||
type: bigint
|
||||
not_null: true
|
||||
is_primary_key: true
|
||||
sequence: 2
|
||||
indexes:
|
||||
idx_post_tags_tag:
|
||||
name: idx_post_tags_tag
|
||||
table: post_tags
|
||||
schema: public
|
||||
columns:
|
||||
- tag_id
|
||||
unique: false
|
||||
type: btree
|
||||
constraints:
|
||||
fk_post_tags_post:
|
||||
name: fk_post_tags_post
|
||||
type: foreign_key
|
||||
table: post_tags
|
||||
schema: public
|
||||
columns:
|
||||
- post_id
|
||||
referenced_table: posts
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
fk_post_tags_tag:
|
||||
name: fk_post_tags_tag
|
||||
type: foreign_key
|
||||
table: post_tags
|
||||
schema: public
|
||||
columns:
|
||||
- tag_id
|
||||
referenced_table: tags
|
||||
referenced_schema: public
|
||||
referenced_columns:
|
||||
- id
|
||||
on_delete: CASCADE
|
||||
on_update: CASCADE
|
||||
relationships: {}
|
||||
314
tests/integration/orm_roundtrip_test.go
Normal file
314
tests/integration/orm_roundtrip_test.go
Normal file
@@ -0,0 +1,314 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
bunreader "git.warky.dev/wdevs/relspecgo/pkg/readers/bun"
|
||||
gormreader "git.warky.dev/wdevs/relspecgo/pkg/readers/gorm"
|
||||
yamlreader "git.warky.dev/wdevs/relspecgo/pkg/readers/yaml"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
bunwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/bun"
|
||||
gormwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/gorm"
|
||||
yamlwriter "git.warky.dev/wdevs/relspecgo/pkg/writers/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// TestYAMLToBunRoundTrip tests YAML → Bun Go → YAML roundtrip
|
||||
func TestYAMLToBunRoundTrip(t *testing.T) {
|
||||
testDir := t.TempDir()
|
||||
|
||||
// Step 1: Read YAML file
|
||||
t.Log("Step 1: Reading YAML file...")
|
||||
yamlPath := filepath.Join("..", "assets", "yaml", "database.yaml")
|
||||
yamlReaderOpts := &readers.ReaderOptions{
|
||||
FilePath: yamlPath,
|
||||
}
|
||||
yamlReader := yamlreader.NewReader(yamlReaderOpts)
|
||||
|
||||
dbFromYAML, err := yamlReader.ReadDatabase()
|
||||
require.NoError(t, err, "Failed to read YAML file")
|
||||
require.NotNil(t, dbFromYAML, "Database from YAML should not be nil")
|
||||
t.Logf(" ✓ Read database '%s' with %d schemas", dbFromYAML.Name, len(dbFromYAML.Schemas))
|
||||
|
||||
// Step 2: Write to Bun Go code
|
||||
t.Log("Step 2: Writing to Bun Go code...")
|
||||
bunGoPath := filepath.Join(testDir, "models_bun.go")
|
||||
bunWriterOpts := &writers.WriterOptions{
|
||||
OutputPath: bunGoPath,
|
||||
PackageName: "models",
|
||||
Metadata: map[string]interface{}{
|
||||
"generate_table_name": true,
|
||||
"generate_get_id": false,
|
||||
},
|
||||
}
|
||||
bunWriter := bunwriter.NewWriter(bunWriterOpts)
|
||||
|
||||
err = bunWriter.WriteDatabase(dbFromYAML)
|
||||
require.NoError(t, err, "Failed to write Bun Go code")
|
||||
|
||||
bunStat, err := os.Stat(bunGoPath)
|
||||
require.NoError(t, err, "Bun Go file should exist")
|
||||
require.Greater(t, bunStat.Size(), int64(0), "Bun Go file should not be empty")
|
||||
t.Logf(" ✓ Wrote Bun Go file (%d bytes)", bunStat.Size())
|
||||
|
||||
// Step 3: Read Bun Go code back
|
||||
t.Log("Step 3: Reading Bun Go code back...")
|
||||
bunReaderOpts := &readers.ReaderOptions{
|
||||
FilePath: bunGoPath,
|
||||
}
|
||||
bunReader := bunreader.NewReader(bunReaderOpts)
|
||||
|
||||
dbFromBun, err := bunReader.ReadDatabase()
|
||||
require.NoError(t, err, "Failed to read Bun Go code")
|
||||
require.NotNil(t, dbFromBun, "Database from Bun should not be nil")
|
||||
t.Logf(" ✓ Read database from Bun with %d schemas", len(dbFromBun.Schemas))
|
||||
|
||||
// Step 4: Write back to YAML
|
||||
t.Log("Step 4: Writing back to YAML...")
|
||||
yaml2Path := filepath.Join(testDir, "roundtrip.yaml")
|
||||
yamlWriter2Opts := &writers.WriterOptions{
|
||||
OutputPath: yaml2Path,
|
||||
}
|
||||
yamlWriter2 := yamlwriter.NewWriter(yamlWriter2Opts)
|
||||
|
||||
err = yamlWriter2.WriteDatabase(dbFromBun)
|
||||
require.NoError(t, err, "Failed to write YAML")
|
||||
|
||||
yaml2Stat, err := os.Stat(yaml2Path)
|
||||
require.NoError(t, err, "Second YAML file should exist")
|
||||
require.Greater(t, yaml2Stat.Size(), int64(0), "Second YAML file should not be empty")
|
||||
t.Logf(" ✓ Wrote second YAML file (%d bytes)", yaml2Stat.Size())
|
||||
|
||||
// Step 5: Compare YAML files
|
||||
t.Log("Step 5: Comparing YAML outputs...")
|
||||
|
||||
// Read both YAML files
|
||||
yaml1Data, err := os.ReadFile(yamlPath)
|
||||
require.NoError(t, err, "Failed to read first YAML")
|
||||
|
||||
yaml2Data, err := os.ReadFile(yaml2Path)
|
||||
require.NoError(t, err, "Failed to read second YAML")
|
||||
|
||||
// Parse into Database models for comparison
|
||||
var db1, db2 models.Database
|
||||
err = yaml.Unmarshal(yaml1Data, &db1)
|
||||
require.NoError(t, err, "Failed to parse first YAML")
|
||||
|
||||
err = yaml.Unmarshal(yaml2Data, &db2)
|
||||
require.NoError(t, err, "Failed to parse second YAML")
|
||||
|
||||
// Compare high-level structure
|
||||
t.Log(" Comparing high-level structure...")
|
||||
assert.Equal(t, len(db1.Schemas), len(db2.Schemas), "Schema count should match")
|
||||
|
||||
// Compare schemas and tables
|
||||
for i, schema1 := range db1.Schemas {
|
||||
if i >= len(db2.Schemas) {
|
||||
t.Errorf("Schema index %d out of bounds in second database", i)
|
||||
continue
|
||||
}
|
||||
schema2 := db2.Schemas[i]
|
||||
|
||||
assert.Equal(t, schema1.Name, schema2.Name, "Schema names should match")
|
||||
assert.Equal(t, len(schema1.Tables), len(schema2.Tables),
|
||||
"Table count in schema '%s' should match", schema1.Name)
|
||||
|
||||
// Compare tables
|
||||
for j, table1 := range schema1.Tables {
|
||||
if j >= len(schema2.Tables) {
|
||||
t.Errorf("Table index %d out of bounds in schema '%s'", j, schema1.Name)
|
||||
continue
|
||||
}
|
||||
table2 := schema2.Tables[j]
|
||||
|
||||
assert.Equal(t, table1.Name, table2.Name,
|
||||
"Table names should match in schema '%s'", schema1.Name)
|
||||
|
||||
// Compare column count
|
||||
assert.Equal(t, len(table1.Columns), len(table2.Columns),
|
||||
"Column count in table '%s.%s' should match", schema1.Name, table1.Name)
|
||||
|
||||
// Compare each column
|
||||
for colName, col1 := range table1.Columns {
|
||||
col2, ok := table2.Columns[colName]
|
||||
if !ok {
|
||||
t.Errorf("Column '%s' missing from roundtrip table '%s.%s'",
|
||||
colName, schema1.Name, table1.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Compare key column properties
|
||||
assert.Equal(t, col1.Name, col2.Name,
|
||||
"Column name mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
assert.Equal(t, col1.Type, col2.Type,
|
||||
"Column type mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
assert.Equal(t, col1.IsPrimaryKey, col2.IsPrimaryKey,
|
||||
"Primary key mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Summary
|
||||
t.Log("Summary:")
|
||||
t.Logf(" ✓ Round-trip completed: YAML → Bun → YAML")
|
||||
t.Logf(" ✓ Schemas match: %d", len(db1.Schemas))
|
||||
|
||||
totalTables := 0
|
||||
for _, schema := range db1.Schemas {
|
||||
totalTables += len(schema.Tables)
|
||||
}
|
||||
t.Logf(" ✓ Total tables: %d", totalTables)
|
||||
}
|
||||
|
||||
// TestYAMLToGORMRoundTrip tests YAML → GORM Go → YAML roundtrip
|
||||
func TestYAMLToGORMRoundTrip(t *testing.T) {
|
||||
testDir := t.TempDir()
|
||||
|
||||
// Step 1: Read YAML file
|
||||
t.Log("Step 1: Reading YAML file...")
|
||||
yamlPath := filepath.Join("..", "assets", "yaml", "database.yaml")
|
||||
yamlReaderOpts := &readers.ReaderOptions{
|
||||
FilePath: yamlPath,
|
||||
}
|
||||
yamlReader := yamlreader.NewReader(yamlReaderOpts)
|
||||
|
||||
dbFromYAML, err := yamlReader.ReadDatabase()
|
||||
require.NoError(t, err, "Failed to read YAML file")
|
||||
require.NotNil(t, dbFromYAML, "Database from YAML should not be nil")
|
||||
t.Logf(" ✓ Read database '%s' with %d schemas", dbFromYAML.Name, len(dbFromYAML.Schemas))
|
||||
|
||||
// Step 2: Write to GORM Go code
|
||||
t.Log("Step 2: Writing to GORM Go code...")
|
||||
gormGoPath := filepath.Join(testDir, "models_gorm.go")
|
||||
gormWriterOpts := &writers.WriterOptions{
|
||||
OutputPath: gormGoPath,
|
||||
PackageName: "models",
|
||||
Metadata: map[string]interface{}{
|
||||
"generate_table_name": true,
|
||||
"generate_get_id": false,
|
||||
},
|
||||
}
|
||||
gormWriter := gormwriter.NewWriter(gormWriterOpts)
|
||||
|
||||
err = gormWriter.WriteDatabase(dbFromYAML)
|
||||
require.NoError(t, err, "Failed to write GORM Go code")
|
||||
|
||||
gormStat, err := os.Stat(gormGoPath)
|
||||
require.NoError(t, err, "GORM Go file should exist")
|
||||
require.Greater(t, gormStat.Size(), int64(0), "GORM Go file should not be empty")
|
||||
t.Logf(" ✓ Wrote GORM Go file (%d bytes)", gormStat.Size())
|
||||
|
||||
// Step 3: Read GORM Go code back
|
||||
t.Log("Step 3: Reading GORM Go code back...")
|
||||
gormReaderOpts := &readers.ReaderOptions{
|
||||
FilePath: gormGoPath,
|
||||
}
|
||||
gormReader := gormreader.NewReader(gormReaderOpts)
|
||||
|
||||
dbFromGORM, err := gormReader.ReadDatabase()
|
||||
require.NoError(t, err, "Failed to read GORM Go code")
|
||||
require.NotNil(t, dbFromGORM, "Database from GORM should not be nil")
|
||||
t.Logf(" ✓ Read database from GORM with %d schemas", len(dbFromGORM.Schemas))
|
||||
|
||||
// Step 4: Write back to YAML
|
||||
t.Log("Step 4: Writing back to YAML...")
|
||||
yaml2Path := filepath.Join(testDir, "roundtrip.yaml")
|
||||
yamlWriter2Opts := &writers.WriterOptions{
|
||||
OutputPath: yaml2Path,
|
||||
}
|
||||
yamlWriter2 := yamlwriter.NewWriter(yamlWriter2Opts)
|
||||
|
||||
err = yamlWriter2.WriteDatabase(dbFromGORM)
|
||||
require.NoError(t, err, "Failed to write YAML")
|
||||
|
||||
yaml2Stat, err := os.Stat(yaml2Path)
|
||||
require.NoError(t, err, "Second YAML file should exist")
|
||||
require.Greater(t, yaml2Stat.Size(), int64(0), "Second YAML file should not be empty")
|
||||
t.Logf(" ✓ Wrote second YAML file (%d bytes)", yaml2Stat.Size())
|
||||
|
||||
// Step 5: Compare YAML files
|
||||
t.Log("Step 5: Comparing YAML outputs...")
|
||||
|
||||
// Read both YAML files
|
||||
yaml1Data, err := os.ReadFile(yamlPath)
|
||||
require.NoError(t, err, "Failed to read first YAML")
|
||||
|
||||
yaml2Data, err := os.ReadFile(yaml2Path)
|
||||
require.NoError(t, err, "Failed to read second YAML")
|
||||
|
||||
// Parse into Database models for comparison
|
||||
var db1, db2 models.Database
|
||||
err = yaml.Unmarshal(yaml1Data, &db1)
|
||||
require.NoError(t, err, "Failed to parse first YAML")
|
||||
|
||||
err = yaml.Unmarshal(yaml2Data, &db2)
|
||||
require.NoError(t, err, "Failed to parse second YAML")
|
||||
|
||||
// Compare high-level structure
|
||||
t.Log(" Comparing high-level structure...")
|
||||
assert.Equal(t, len(db1.Schemas), len(db2.Schemas), "Schema count should match")
|
||||
|
||||
// Compare schemas and tables
|
||||
for i, schema1 := range db1.Schemas {
|
||||
if i >= len(db2.Schemas) {
|
||||
t.Errorf("Schema index %d out of bounds in second database", i)
|
||||
continue
|
||||
}
|
||||
schema2 := db2.Schemas[i]
|
||||
|
||||
assert.Equal(t, schema1.Name, schema2.Name, "Schema names should match")
|
||||
assert.Equal(t, len(schema1.Tables), len(schema2.Tables),
|
||||
"Table count in schema '%s' should match", schema1.Name)
|
||||
|
||||
// Compare tables
|
||||
for j, table1 := range schema1.Tables {
|
||||
if j >= len(schema2.Tables) {
|
||||
t.Errorf("Table index %d out of bounds in schema '%s'", j, schema1.Name)
|
||||
continue
|
||||
}
|
||||
table2 := schema2.Tables[j]
|
||||
|
||||
assert.Equal(t, table1.Name, table2.Name,
|
||||
"Table names should match in schema '%s'", schema1.Name)
|
||||
|
||||
// Compare column count
|
||||
assert.Equal(t, len(table1.Columns), len(table2.Columns),
|
||||
"Column count in table '%s.%s' should match", schema1.Name, table1.Name)
|
||||
|
||||
// Compare each column
|
||||
for colName, col1 := range table1.Columns {
|
||||
col2, ok := table2.Columns[colName]
|
||||
if !ok {
|
||||
t.Errorf("Column '%s' missing from roundtrip table '%s.%s'",
|
||||
colName, schema1.Name, table1.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Compare key column properties
|
||||
assert.Equal(t, col1.Name, col2.Name,
|
||||
"Column name mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
assert.Equal(t, col1.Type, col2.Type,
|
||||
"Column type mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
assert.Equal(t, col1.IsPrimaryKey, col2.IsPrimaryKey,
|
||||
"Primary key mismatch in '%s.%s.%s'", schema1.Name, table1.Name, colName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Summary
|
||||
t.Log("Summary:")
|
||||
t.Logf(" ✓ Round-trip completed: YAML → GORM → YAML")
|
||||
t.Logf(" ✓ Schemas match: %d", len(db1.Schemas))
|
||||
|
||||
totalTables := 0
|
||||
for _, schema := range db1.Schemas {
|
||||
totalTables += len(schema.Tables)
|
||||
}
|
||||
t.Logf(" ✓ Total tables: %d", totalTables)
|
||||
}
|
||||
Reference in New Issue
Block a user