package engine_test import ( "testing" "time" "git.fsdpf.net/go/db/engine" _ "github.com/denisenkom/go-mssqldb" _ "github.com/go-sql-driver/mysql" _ "github.com/mattn/go-sqlite3" ) // TestMySQLConfig 测试 MySQL 驱动的配置 func TestMySQLConfig(t *testing.T) { tests := []struct { name string options []engine.Option wantErr bool errMsg string }{ { name: "Valid Config", options: []engine.Option{ engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithUsername("root"), engine.WithPassword("password"), engine.WithMySQLCollation("utf8mb4_unicode_ci"), }, wantErr: false, }, { name: "Missing Host", options: []engine.Option{ engine.WithDatabase("testdb"), engine.WithUsername("root"), engine.WithPassword("password"), }, wantErr: true, errMsg: "Host, ReadHosts, or WriteHosts is required for mysql driver", }, { name: "Missing Database", options: []engine.Option{ engine.WithHost("localhost"), engine.WithUsername("root"), engine.WithPassword("password"), }, wantErr: true, errMsg: "Database is required for mysql driver", }, { name: "engine.engine.With SQL Server engine.Option", options: []engine.Option{ engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithUsername("root"), engine.WithPassword("password"), engine.WithSQLServerInstance("SQLEXPRESS"), }, wantErr: true, errMsg: "engine.WithSQLServerInstance is only valid for sqlserver driver", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { if r := recover(); r != nil { if !tt.wantErr { t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r) } else if tt.errMsg != "" && r != tt.errMsg { t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg) } } else if tt.wantErr { t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg) } }() config := engine.NewDBConfig("mysql", tt.options...) if !tt.wantErr && (config.Driver != "mysql" || config.MySQL.Collation != "utf8mb4_unicode_ci") { t.Errorf("MySQL config not set correctly: %+v", config) } }) } } // TestPostgreSQLConfig 测试 PostgreSQL 驱动的配置 func TestPostgreSQLConfig(t *testing.T) { tests := []struct { name string options []engine.Option wantErr bool errMsg string }{ { name: "Valid Config", options: []engine.Option{ engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithUsername("postgres"), engine.WithPassword("password"), engine.WithPgSslmode("disable"), }, wantErr: false, }, { name: "Missing Username", options: []engine.Option{ engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithPassword("password"), }, wantErr: true, errMsg: "Username is required for pgsql driver", }, { name: "engine.engine.With MySQL engine.Option", options: []engine.Option{ engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithUsername("postgres"), engine.WithPassword("password"), engine.WithMySQLCollation("utf8mb4_unicode_ci"), }, wantErr: true, errMsg: "engine.WithMySQLCollation is only valid for mysql driver", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { if r := recover(); r != nil { if !tt.wantErr { t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r) } else if tt.errMsg != "" && r != tt.errMsg { t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg) } } else if tt.wantErr { t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg) } }() config := engine.NewDBConfig("pgsql", tt.options...) if !tt.wantErr && (config.Driver != "pgsql" || config.PostgreSQL.Sslmode != "disable") { t.Errorf("PostgreSQL config not set correctly: %+v", config) } }) } } // TestSQLiteConfig 测试 SQLite 驱动的配置 func TestSQLiteConfig(t *testing.T) { tests := []struct { name string options []engine.Option wantErr bool errMsg string }{ { name: "Valid Config", options: []engine.Option{ engine.WithSQLiteFile("test.db"), engine.WithSQLiteJournal("WAL"), }, wantErr: false, }, { name: "Missing File", options: []engine.Option{}, wantErr: true, errMsg: "File is required for sqlite3 driver", }, { name: "engine.engine.With PostgreSQL engine.Option", options: []engine.Option{ engine.WithSQLiteFile("test.db"), engine.WithPgSslmode("disable"), }, wantErr: true, errMsg: "engine.WithPgSslmode is only valid for pgsql driver", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { if r := recover(); r != nil { if !tt.wantErr { t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r) } else if tt.errMsg != "" && r != tt.errMsg { t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg) } } else if tt.wantErr { t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg) } }() config := engine.NewDBConfig("sqlite3", tt.options...) if !tt.wantErr && (config.Driver != "sqlite3" || config.SQLite.File != "test.db") { t.Errorf("SQLite config not set correctly: %+v", config) } }) } } // TestSQLServerConfig 测试 SQL Server 驱动的配置 func TestSQLServerConfig(t *testing.T) { tests := []struct { name string options []engine.Option wantErr bool errMsg string }{ { name: "Valid Config", options: []engine.Option{ engine.WithHost("sqlserver.example.com"), engine.WithDatabase("master"), engine.WithUsername("sa"), engine.WithPassword("password"), engine.WithSQLServerInstance("SQLEXPRESS"), }, wantErr: false, }, { name: "Missing Password", options: []engine.Option{ engine.WithHost("sqlserver.example.com"), engine.WithDatabase("master"), engine.WithUsername("sa"), }, wantErr: true, errMsg: "Password is required for sqlserver driver", }, { name: "engine.engine.With SQLite engine.Option", options: []engine.Option{ engine.WithHost("sqlserver.example.com"), engine.WithDatabase("master"), engine.WithUsername("sa"), engine.WithPassword("password"), engine.WithSQLiteFile("test.db"), }, wantErr: true, errMsg: "engine.WithSQLiteFile is only valid for sqlite3 driver", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { if r := recover(); r != nil { if !tt.wantErr { t.Errorf("engine.NewDBConfig() panicked unexpectedly: %v", r) } else if tt.errMsg != "" && r != tt.errMsg { t.Errorf("engine.NewDBConfig() panic = %v, want %v", r, tt.errMsg) } } else if tt.wantErr { t.Errorf("engine.NewDBConfig() did not panic, expected panic with: %v", tt.errMsg) } }() config := engine.NewDBConfig("sqlserver", tt.options...) if !tt.wantErr && (config.Driver != "sqlserver" || config.SQLServer.Instance != "SQLEXPRESS") { t.Errorf("SQL Server config not set correctly: %+v", config) } }) } } // TestInvalidDriver 测试不支持的驱动 func TestInvalidDriver(t *testing.T) { defer func() { if r := recover(); r != nil { if r != "Unsupported driver: oracle" { t.Errorf("engine.NewDBConfig() panic = %v, want 'Unsupported driver: oracle'", r) } } else { t.Errorf("engine.NewDBConfig() did not panic for invalid driver") } }() engine.NewDBConfig("oracle") } // TestDefaultValues 测试默认值 func TestDefaultValues(t *testing.T) { config := engine.NewDBConfig("mysql", engine.WithHost("localhost"), engine.WithDatabase("testdb"), engine.WithUsername("root"), engine.WithPassword("password"), ) if config.Charset != "utf8mb4" { t.Errorf("Default Charset = %v, want utf8mb4", config.Charset) } if config.ConnMaxLifetime != 2*time.Hour { t.Errorf("Default ConnMaxLifetime = %v, want 2h", config.ConnMaxLifetime) } if config.MaxOpenConns != 100 { t.Errorf("Default MaxOpenConns = %v, want 100", config.MaxOpenConns) } } func TestToDSN(t *testing.T) { tests := []struct { name string config engine.DBConfig wantDSN string wantErr bool errMsg string }{ { name: "MySQL DSN", config: engine.NewDBConfig("mysql", engine.WithHost("localhost"), engine.WithPort("3306"), engine.WithDatabase("testdb"), engine.WithUsername("root"), engine.WithPassword("password"), engine.WithMySQLCollation("utf8mb4_unicode_ci"), ), wantDSN: "root:password@tcp(localhost:3306)/testdb?charset=utf8mb4&collation=utf8mb4_unicode_ci", wantErr: false, }, { name: "PostgreSQL DSN", config: engine.NewDBConfig("pgsql", engine.WithHost("localhost"), engine.WithPort("5432"), engine.WithDatabase("testdb"), engine.WithUsername("postgres"), engine.WithPassword("password"), engine.WithPgSslmode("disable"), ), wantDSN: "host=localhost port=5432 user=postgres password=password dbname=testdb sslmode=disable", wantErr: false, }, { name: "SQLite DSN", config: engine.NewDBConfig("sqlite3", engine.WithSQLiteFile("test.db"), engine.WithSQLiteJournal("WAL"), ), wantDSN: "test.db?_journal=WAL", wantErr: false, }, { name: "SQL Server DSN", config: engine.NewDBConfig("sqlserver", engine.WithHost("sqlserver.example.com"), engine.WithPort("1433"), engine.WithDatabase("master"), engine.WithUsername("sa"), engine.WithPassword("password"), engine.WithSQLServerInstance("SQLEXPRESS"), ), wantDSN: "sqlserver://sa:password@sqlserver.example.com\\SQLEXPRESS:1433?server=sqlserver.example.com\\SQLEXPRESS&database=master", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { if r := recover(); r != nil { if !tt.wantErr { t.Errorf("ToDSN() panicked unexpectedly: %v", r) } else if tt.errMsg != "" && r != tt.errMsg { t.Errorf("ToDSN() panic = %v, want %v", r, tt.errMsg) } } else if tt.wantErr { t.Errorf("ToDSN() did not panic, expected panic with: %v", tt.errMsg) } }() dsn := tt.config.ToDSN() if !tt.wantErr && dsn != tt.wantDSN { t.Errorf("ToDSN() = %v, want %v", dsn, tt.wantDSN) } }) } }