package domain import ( "strings" "testing" "github.com/shopspring/decimal" ) func TestNewCurrency(t *testing.T) { tests := []struct { name string code string currName string precision int wantErr bool }{ { name: "valid currency", code: "USD", currName: "US Dollar", precision: 2, wantErr: false, }, { name: "empty code", code: "", currName: "Test", precision: 2, wantErr: true, }, { name: "whitespace code", code: " ", currName: "Test", precision: 2, wantErr: true, }, { name: "negative precision", code: "BTC", currName: "Bitcoin", precision: -1, wantErr: true, }, { name: "lowercase code gets uppercase", code: "btc", currName: "Bitcoin", precision: 8, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { currency, err := NewCurrency(tt.code, tt.currName, tt.precision) if tt.wantErr { if err == nil { t.Errorf("NewCurrency() expected error but got none") } return } if err != nil { t.Errorf("NewCurrency() unexpected error: %v", err) return } expectedCode := strings.ToUpper(strings.TrimSpace(tt.code)) if currency.Code != expectedCode { t.Errorf("NewCurrency() code = %s, want %s", currency.Code, expectedCode) } if currency.Precision != tt.precision { t.Errorf("NewCurrency() precision = %d, want %d", currency.Precision, tt.precision) } }) } } func TestNewMoney(t *testing.T) { currency, _ := NewCurrency("USD", "US Dollar", 2) tests := []struct { name string amount string currency Currency wantErr bool }{ { name: "valid amount", amount: "123.45", currency: currency, wantErr: false, }, { name: "zero amount", amount: "0", currency: currency, wantErr: false, }, { name: "empty amount", amount: "", currency: currency, wantErr: true, }, { name: "invalid amount format", amount: "abc", currency: currency, wantErr: true, }, { name: "negative amount", amount: "-123.45", currency: currency, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { money, err := NewMoney(tt.amount, tt.currency) if tt.wantErr { if err == nil { t.Errorf("NewMoney() expected error but got none") } return } if err != nil { t.Errorf("NewMoney() unexpected error: %v", err) return } if money.Currency.Code != tt.currency.Code { t.Errorf("NewMoney() currency = %s, want %s", money.Currency.Code, tt.currency.Code) } }) } } func TestNewRate(t *testing.T) { usd, _ := NewCurrency("USD", "US Dollar", 2) btc, _ := NewCurrency("BTC", "Bitcoin", 8) tests := []struct { name string from Currency to Currency value string source string wantErr bool }{ { name: "valid rate", from: usd, to: btc, value: "0.00001234", source: "test", wantErr: false, }, { name: "same currencies", from: usd, to: usd, value: "1.0", source: "test", wantErr: true, }, { name: "negative rate", from: usd, to: btc, value: "-0.00001234", source: "test", wantErr: true, }, { name: "zero rate", from: usd, to: btc, value: "0", source: "test", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { value, _ := decimal.NewFromString(tt.value) rate, err := NewRate(tt.from, tt.to, value, tt.source) if tt.wantErr { if err == nil { t.Errorf("NewRate() expected error but got none") } return } if err != nil { t.Errorf("NewRate() unexpected error: %v", err) return } if rate.From.Code != tt.from.Code { t.Errorf("NewRate() from = %s, want %s", rate.From.Code, tt.from.Code) } if rate.To.Code != tt.to.Code { t.Errorf("NewRate() to = %s, want %s", rate.To.Code, tt.to.Code) } }) } }