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) }