Bugs Fixed
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
This commit is contained in:
447
pkg/readers/dctx/reader_test.go
Normal file
447
pkg/readers/dctx/reader_test.go
Normal file
@@ -0,0 +1,447 @@
|
||||
package dctx
|
||||
|
||||
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("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
t.Error("Expected non-empty database name")
|
||||
}
|
||||
|
||||
if len(db.Schemas) == 0 {
|
||||
t.Fatal("Expected at least one schema")
|
||||
}
|
||||
|
||||
schema := db.Schemas[0]
|
||||
if schema.Name == "" {
|
||||
t.Error("Expected non-empty schema name")
|
||||
}
|
||||
|
||||
if len(schema.Tables) == 0 {
|
||||
t.Fatal("Expected at least one table")
|
||||
}
|
||||
|
||||
// Verify at least one table has columns
|
||||
hasColumns := false
|
||||
for _, table := range schema.Tables {
|
||||
if len(table.Columns) > 0 {
|
||||
hasColumns = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasColumns {
|
||||
t.Error("Expected at least one table with columns")
|
||||
}
|
||||
|
||||
// Verify at least one table has a primary key
|
||||
hasPK := false
|
||||
for _, table := range schema.Tables {
|
||||
pk := table.GetPrimaryKey()
|
||||
if pk != nil {
|
||||
hasPK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasPK {
|
||||
t.Error("Expected at least one table with a primary key")
|
||||
}
|
||||
|
||||
// Verify at least one foreign key relationship exists
|
||||
hasFKs := false
|
||||
for _, table := range schema.Tables {
|
||||
fks := table.GetForeignKeys()
|
||||
if len(fks) > 0 {
|
||||
hasFKs = true
|
||||
// Verify foreign key properties
|
||||
for _, fk := range fks {
|
||||
if fk.Type != models.ForeignKeyConstraint {
|
||||
t.Error("Expected foreign key constraint type")
|
||||
}
|
||||
if len(fk.Columns) == 0 {
|
||||
t.Error("Foreign key should have at least one column")
|
||||
}
|
||||
if fk.ReferencedTable == "" {
|
||||
t.Error("Foreign key should have referenced table")
|
||||
}
|
||||
if len(fk.ReferencedColumns) == 0 {
|
||||
t.Error("Foreign key should have at least one referenced column")
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasFKs {
|
||||
t.Error("Expected at least one foreign key relationship")
|
||||
}
|
||||
|
||||
// Verify indexes exist on some tables
|
||||
hasIndexes := false
|
||||
for _, table := range schema.Tables {
|
||||
if len(table.Indexes) > 0 {
|
||||
hasIndexes = true
|
||||
// Verify index properties
|
||||
for _, idx := range table.Indexes {
|
||||
if idx.Name == "" {
|
||||
t.Error("Index should have a name")
|
||||
}
|
||||
if len(idx.Columns) == 0 {
|
||||
t.Error("Index should have at least one column")
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasIndexes {
|
||||
t.Error("Expected at least one table with indexes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReader_ReadSchema(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: filepath.Join("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
t.Error("Expected non-empty schema name")
|
||||
}
|
||||
|
||||
if len(schema.Tables) == 0 {
|
||||
t.Fatal("Expected at least one table")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReader_ReadTable(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: filepath.Join("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
t.Error("Expected non-empty table name")
|
||||
}
|
||||
|
||||
if table.Schema == "" {
|
||||
t.Error("Expected non-empty schema name")
|
||||
}
|
||||
|
||||
if len(table.Columns) == 0 {
|
||||
t.Error("Expected at least one column")
|
||||
}
|
||||
|
||||
// Verify column properties
|
||||
for _, col := range table.Columns {
|
||||
if col.Name == "" {
|
||||
t.Error("Column should have a name")
|
||||
}
|
||||
if col.Type == "" {
|
||||
t.Error("Column should have a type")
|
||||
}
|
||||
if col.Table != table.Name {
|
||||
t.Errorf("Column table '%s' should match table name '%s'", col.Table, table.Name)
|
||||
}
|
||||
if col.Schema != table.Schema {
|
||||
t.Errorf("Column schema '%s' should match table schema '%s'", col.Schema, table.Schema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReader_ReadDatabase_InvalidPath(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: "/nonexistent/file.dctx",
|
||||
}
|
||||
|
||||
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("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
reader := NewReader(opts)
|
||||
db, err := reader.ReadDatabase()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDatabase() error = %v", err)
|
||||
}
|
||||
|
||||
// Find a table with a primary key
|
||||
var tableName string
|
||||
var pk *models.Column
|
||||
for _, schema := range db.Schemas {
|
||||
for _, table := range schema.Tables {
|
||||
pk = table.GetPrimaryKey()
|
||||
if pk != nil {
|
||||
tableName = table.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
if pk != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if pk == nil {
|
||||
t.Fatal("Expected to find at least one table with a primary key")
|
||||
}
|
||||
|
||||
if pk.Name == "" {
|
||||
t.Error("Primary key should have a name")
|
||||
}
|
||||
|
||||
if !pk.IsPrimaryKey {
|
||||
t.Error("Primary key column should have IsPrimaryKey set to true")
|
||||
}
|
||||
|
||||
t.Logf("Found primary key '%s' in table '%s'", pk.Name, tableName)
|
||||
}
|
||||
|
||||
func TestGetForeignKeys(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: filepath.Join("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
reader := NewReader(opts)
|
||||
db, err := reader.ReadDatabase()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDatabase() error = %v", err)
|
||||
}
|
||||
|
||||
// Find a table with foreign keys
|
||||
var tableName string
|
||||
var fks []*models.Constraint
|
||||
for _, schema := range db.Schemas {
|
||||
for _, table := range schema.Tables {
|
||||
fks = table.GetForeignKeys()
|
||||
if len(fks) > 0 {
|
||||
tableName = table.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(fks) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(fks) == 0 {
|
||||
t.Fatal("Expected to find at least one table with foreign keys")
|
||||
}
|
||||
|
||||
t.Logf("Found %d foreign keys in table '%s'", len(fks), tableName)
|
||||
|
||||
// Verify foreign key structure
|
||||
for i, fk := range fks {
|
||||
if fk.Type != models.ForeignKeyConstraint {
|
||||
t.Errorf("FK %d: Expected foreign key constraint type", i)
|
||||
}
|
||||
if fk.Name == "" {
|
||||
t.Errorf("FK %d: Expected foreign key to have a name", i)
|
||||
}
|
||||
if len(fk.Columns) == 0 {
|
||||
t.Errorf("FK %d: Expected foreign key to have at least one column", i)
|
||||
}
|
||||
if fk.ReferencedTable == "" {
|
||||
t.Errorf("FK %d: Expected foreign key to have a referenced table", i)
|
||||
}
|
||||
if len(fk.ReferencedColumns) == 0 {
|
||||
t.Errorf("FK %d: Expected foreign key to have at least one referenced column", i)
|
||||
}
|
||||
|
||||
t.Logf("FK %d: %s.%s -> %s.%s",
|
||||
i,
|
||||
tableName,
|
||||
fk.Columns,
|
||||
fk.ReferencedTable,
|
||||
fk.ReferencedColumns,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabaseStructure(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: filepath.Join("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
reader := NewReader(opts)
|
||||
db, err := reader.ReadDatabase()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDatabase() error = %v", err)
|
||||
}
|
||||
|
||||
// Comprehensive structure validation
|
||||
for _, schema := range db.Schemas {
|
||||
if schema.Name == "" {
|
||||
t.Error("Schema should have a name")
|
||||
}
|
||||
|
||||
for _, table := range schema.Tables {
|
||||
if table.Name == "" {
|
||||
t.Error("Table should have a name")
|
||||
}
|
||||
if table.Schema == "" {
|
||||
t.Error("Table should have a schema")
|
||||
}
|
||||
|
||||
// Verify columns
|
||||
for _, col := range table.Columns {
|
||||
if col.Name == "" {
|
||||
t.Errorf("Column in table '%s' should have a name", table.Name)
|
||||
}
|
||||
if col.Type == "" {
|
||||
t.Errorf("Column '%s' in table '%s' should have a type", col.Name, table.Name)
|
||||
}
|
||||
if col.Table != table.Name {
|
||||
t.Errorf("Column '%s' table reference should match table name", col.Name)
|
||||
}
|
||||
if col.Schema != table.Schema {
|
||||
t.Errorf("Column '%s' schema reference should match table schema", col.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify constraints
|
||||
for _, constraint := range table.Constraints {
|
||||
if constraint.Name == "" {
|
||||
t.Errorf("Constraint in table '%s' should have a name", table.Name)
|
||||
}
|
||||
if constraint.Type == "" {
|
||||
t.Errorf("Constraint '%s' should have a type", constraint.Name)
|
||||
}
|
||||
if constraint.Table != table.Name {
|
||||
t.Errorf("Constraint '%s' table reference should match table name", constraint.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify indexes
|
||||
for _, index := range table.Indexes {
|
||||
if index.Name == "" {
|
||||
t.Errorf("Index in table '%s' should have a name", table.Name)
|
||||
}
|
||||
if len(index.Columns) == 0 {
|
||||
t.Errorf("Index '%s' should have at least one column", index.Name)
|
||||
}
|
||||
if index.Table != table.Name {
|
||||
t.Errorf("Index '%s' table reference should match table name", index.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestColumnProperties(t *testing.T) {
|
||||
opts := &readers.ReaderOptions{
|
||||
FilePath: filepath.Join("..", "..", "..", "examples", "dctx", "example.dctx"),
|
||||
}
|
||||
|
||||
reader := NewReader(opts)
|
||||
db, err := reader.ReadDatabase()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDatabase() error = %v", err)
|
||||
}
|
||||
|
||||
// Find various column types
|
||||
hasNotNullColumn := false
|
||||
hasNullableColumn := false
|
||||
hasDefaultValue := false
|
||||
|
||||
for _, schema := range db.Schemas {
|
||||
for _, table := range schema.Tables {
|
||||
for _, col := range table.Columns {
|
||||
if col.NotNull {
|
||||
hasNotNullColumn = true
|
||||
} else {
|
||||
hasNullableColumn = true
|
||||
}
|
||||
if col.Default != nil {
|
||||
hasDefaultValue = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hasNotNullColumn {
|
||||
t.Log("Note: No NOT NULL columns found (this may be valid for the test data)")
|
||||
}
|
||||
if !hasNullableColumn {
|
||||
t.Log("Note: No nullable columns found (this may be valid for the test data)")
|
||||
}
|
||||
if !hasDefaultValue {
|
||||
t.Log("Note: No columns with default values found (this may be valid for the test data)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user