test(pgsql, reflectutil): ✨ add comprehensive test coverage
All checks were successful
All checks were successful
* Introduce tests for PostgreSQL data types and keywords. * Implement tests for reflect utility functions. * Ensure consistency and correctness of type conversions and keyword mappings. * Validate behavior for various edge cases and input types.
This commit is contained in:
249
pkg/inspector/rules_test.go
Normal file
249
pkg/inspector/rules_test.go
Normal file
@@ -0,0 +1,249 @@
|
||||
package inspector
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDefaultConfig(t *testing.T) {
|
||||
config := GetDefaultConfig()
|
||||
|
||||
if config == nil {
|
||||
t.Fatal("GetDefaultConfig() returned nil")
|
||||
}
|
||||
|
||||
if config.Version != "1.0" {
|
||||
t.Errorf("GetDefaultConfig() Version = %q, want \"1.0\"", config.Version)
|
||||
}
|
||||
|
||||
if len(config.Rules) == 0 {
|
||||
t.Error("GetDefaultConfig() returned no rules")
|
||||
}
|
||||
|
||||
// Check that all expected rules are present
|
||||
expectedRules := []string{
|
||||
"primary_key_naming",
|
||||
"primary_key_datatype",
|
||||
"primary_key_auto_increment",
|
||||
"foreign_key_column_naming",
|
||||
"foreign_key_constraint_naming",
|
||||
"foreign_key_index",
|
||||
"table_naming_case",
|
||||
"column_naming_case",
|
||||
"table_name_length",
|
||||
"column_name_length",
|
||||
"reserved_keywords",
|
||||
"missing_primary_key",
|
||||
"orphaned_foreign_key",
|
||||
"circular_dependency",
|
||||
}
|
||||
|
||||
for _, ruleName := range expectedRules {
|
||||
if _, exists := config.Rules[ruleName]; !exists {
|
||||
t.Errorf("GetDefaultConfig() missing rule: %q", ruleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_NonExistentFile(t *testing.T) {
|
||||
// Try to load a non-existent file
|
||||
config, err := LoadConfig("/path/to/nonexistent/file.yaml")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() with non-existent file returned error: %v", err)
|
||||
}
|
||||
|
||||
// Should return default config
|
||||
if config == nil {
|
||||
t.Fatal("LoadConfig() returned nil config for non-existent file")
|
||||
}
|
||||
|
||||
if len(config.Rules) == 0 {
|
||||
t.Error("LoadConfig() returned config with no rules")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_ValidFile(t *testing.T) {
|
||||
// Create a temporary config file
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "test-config.yaml")
|
||||
|
||||
configContent := `version: "1.0"
|
||||
rules:
|
||||
primary_key_naming:
|
||||
enabled: "enforce"
|
||||
function: "primary_key_naming"
|
||||
pattern: "^pk_"
|
||||
message: "Primary keys must start with pk_"
|
||||
table_name_length:
|
||||
enabled: "warn"
|
||||
function: "table_name_length"
|
||||
max_length: 50
|
||||
message: "Table name too long"
|
||||
`
|
||||
|
||||
err := os.WriteFile(configPath, []byte(configContent), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test config file: %v", err)
|
||||
}
|
||||
|
||||
config, err := LoadConfig(configPath)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() returned error: %v", err)
|
||||
}
|
||||
|
||||
if config.Version != "1.0" {
|
||||
t.Errorf("LoadConfig() Version = %q, want \"1.0\"", config.Version)
|
||||
}
|
||||
|
||||
if len(config.Rules) != 2 {
|
||||
t.Errorf("LoadConfig() loaded %d rules, want 2", len(config.Rules))
|
||||
}
|
||||
|
||||
// Check primary_key_naming rule
|
||||
pkRule, exists := config.Rules["primary_key_naming"]
|
||||
if !exists {
|
||||
t.Fatal("LoadConfig() missing primary_key_naming rule")
|
||||
}
|
||||
|
||||
if pkRule.Enabled != "enforce" {
|
||||
t.Errorf("primary_key_naming.Enabled = %q, want \"enforce\"", pkRule.Enabled)
|
||||
}
|
||||
|
||||
if pkRule.Pattern != "^pk_" {
|
||||
t.Errorf("primary_key_naming.Pattern = %q, want \"^pk_\"", pkRule.Pattern)
|
||||
}
|
||||
|
||||
// Check table_name_length rule
|
||||
lengthRule, exists := config.Rules["table_name_length"]
|
||||
if !exists {
|
||||
t.Fatal("LoadConfig() missing table_name_length rule")
|
||||
}
|
||||
|
||||
if lengthRule.MaxLength != 50 {
|
||||
t.Errorf("table_name_length.MaxLength = %d, want 50", lengthRule.MaxLength)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_InvalidYAML(t *testing.T) {
|
||||
// Create a temporary invalid config file
|
||||
tmpDir := t.TempDir()
|
||||
configPath := filepath.Join(tmpDir, "invalid-config.yaml")
|
||||
|
||||
invalidContent := `invalid: yaml: content: {[}]`
|
||||
|
||||
err := os.WriteFile(configPath, []byte(invalidContent), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test config file: %v", err)
|
||||
}
|
||||
|
||||
_, err = LoadConfig(configPath)
|
||||
if err == nil {
|
||||
t.Error("LoadConfig() with invalid YAML did not return error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuleIsEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rule Rule
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "enforce is enabled",
|
||||
rule: Rule{Enabled: "enforce"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "warn is enabled",
|
||||
rule: Rule{Enabled: "warn"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "off is not enabled",
|
||||
rule: Rule{Enabled: "off"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "empty is not enabled",
|
||||
rule: Rule{Enabled: ""},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.rule.IsEnabled(); got != tt.want {
|
||||
t.Errorf("Rule.IsEnabled() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuleIsEnforced(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rule Rule
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "enforce is enforced",
|
||||
rule: Rule{Enabled: "enforce"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "warn is not enforced",
|
||||
rule: Rule{Enabled: "warn"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "off is not enforced",
|
||||
rule: Rule{Enabled: "off"},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.rule.IsEnforced(); got != tt.want {
|
||||
t.Errorf("Rule.IsEnforced() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultConfigRuleSettings(t *testing.T) {
|
||||
config := GetDefaultConfig()
|
||||
|
||||
// Test specific rule settings
|
||||
pkNamingRule := config.Rules["primary_key_naming"]
|
||||
if pkNamingRule.Function != "primary_key_naming" {
|
||||
t.Errorf("primary_key_naming.Function = %q, want \"primary_key_naming\"", pkNamingRule.Function)
|
||||
}
|
||||
|
||||
if pkNamingRule.Pattern != "^id_" {
|
||||
t.Errorf("primary_key_naming.Pattern = %q, want \"^id_\"", pkNamingRule.Pattern)
|
||||
}
|
||||
|
||||
// Test datatype rule
|
||||
pkDatatypeRule := config.Rules["primary_key_datatype"]
|
||||
if len(pkDatatypeRule.AllowedTypes) == 0 {
|
||||
t.Error("primary_key_datatype has no allowed types")
|
||||
}
|
||||
|
||||
// Test length rule
|
||||
tableLengthRule := config.Rules["table_name_length"]
|
||||
if tableLengthRule.MaxLength != 64 {
|
||||
t.Errorf("table_name_length.MaxLength = %d, want 64", tableLengthRule.MaxLength)
|
||||
}
|
||||
|
||||
// Test reserved keywords rule
|
||||
reservedRule := config.Rules["reserved_keywords"]
|
||||
if !reservedRule.CheckTables {
|
||||
t.Error("reserved_keywords.CheckTables should be true")
|
||||
}
|
||||
if !reservedRule.CheckColumns {
|
||||
t.Error("reserved_keywords.CheckColumns should be true")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user