139 lines
5.9 KiB
Go
139 lines
5.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"gorm.io/gorm/schema"
|
|
)
|
|
|
|
func validOnboarding() onboardClientRequest {
|
|
return onboardClientRequest{
|
|
Companyname: " Acme Foods ",
|
|
Contactname: "Priya Raman",
|
|
Email: " Ops@Acme.Example ",
|
|
Phone: "+91 98765-43210",
|
|
Password: "s3cure-pass",
|
|
Applocationid: 1,
|
|
}
|
|
}
|
|
|
|
func TestOnboardingValidateNormalises(t *testing.T) {
|
|
r := validOnboarding()
|
|
if msg := r.validate(); msg != "" {
|
|
t.Fatalf("valid request refused: %s", msg)
|
|
}
|
|
if r.Companyname != "Acme Foods" || r.Contactname != "Priya Raman" || r.Email != "ops@acme.example" || r.Phone != "9876543210" {
|
|
t.Fatalf("not normalised: %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestOnboardingValidateRefuses(t *testing.T) {
|
|
cases := map[string]func(*onboardClientRequest){
|
|
"company name is required": func(r *onboardClientRequest) { r.Companyname = " " },
|
|
"company name is too long": func(r *onboardClientRequest) { r.Companyname = strings.Repeat("a", 121) },
|
|
"contact person's name": func(r *onboardClientRequest) { r.Contactname = "" },
|
|
"valid email": func(r *onboardClientRequest) { r.Email = "not-an-email" },
|
|
"valid email ": func(r *onboardClientRequest) { r.Email = "Ops <ops@acme.example>" },
|
|
"valid email ": func(r *onboardClientRequest) { r.Email = "ops@localhost" },
|
|
"10-digit mobile": func(r *onboardClientRequest) { r.Phone = "12345" },
|
|
"10-digit mobile ": func(r *onboardClientRequest) { r.Phone = "5876543210" }, // must start 6-9
|
|
"at least 8 characters": func(r *onboardClientRequest) { r.Password = "short" },
|
|
"at most 72 characters": func(r *onboardClientRequest) { r.Password = strings.Repeat("x", 73) },
|
|
"must not be the email": func(r *onboardClientRequest) { r.Password = "OPS@acme.example" },
|
|
"must not be the email or the ": func(r *onboardClientRequest) { r.Password = "9876543210" },
|
|
"operating city": func(r *onboardClientRequest) { r.Applocationid = 0 },
|
|
}
|
|
for want, mutate := range cases {
|
|
r := validOnboarding()
|
|
mutate(&r)
|
|
if msg := r.validate(); !strings.Contains(msg, strings.TrimSpace(want)) {
|
|
t.Errorf("%q: got %q", want, msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalisePhone(t *testing.T) {
|
|
for in, want := range map[string]string{
|
|
"9876543210": "9876543210",
|
|
"+919876543210": "9876543210",
|
|
"919876543210": "9876543210",
|
|
"09876543210": "9876543210",
|
|
" 98765 43210 ": "9876543210",
|
|
"(987) 654-3210": "9876543210",
|
|
} {
|
|
if got := normalisePhone(in); got != want {
|
|
t.Errorf("normalisePhone(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The list query selects these column aliases; every one must land in a field.
|
|
// GORM maps silently — a field it cannot see stays empty with no error — so
|
|
// this parses the scan struct exactly as GORM does and checks each alias.
|
|
func TestOnboardedClientRowMapsEveryColumn(t *testing.T) {
|
|
s, err := schema.Parse(&onboardedClientRow{}, &sync.Map{}, schema.NamingStrategy{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, col := range []string{
|
|
"authid", "tenantid", "tenantname", "primaryemail", "primarycontact", "status",
|
|
"requiredeliveryotp", "contactname", "loginemail", "loginrole", "authcreatedat", "tenantcreatedat",
|
|
"address", "city", "state", "pincode", "latitude", "longitude",
|
|
} {
|
|
if s.LookUpField(col) == nil {
|
|
t.Errorf("column %q selected by the list query maps to no field", col)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOnboardedClientRowToClient(t *testing.T) {
|
|
zero := time.Time{}
|
|
// As the driver hands back a timestamp-without-zone column: IST digits tagged UTC.
|
|
tenant := time.Date(2026, 6, 24, 16, 14, 0, 0, time.UTC)
|
|
c := onboardedClientRow{Authid: 7, Tenantname: "Acme", Loginemail: "a@b.co", Authcreatedat: &zero, Tenantcreatedat: &tenant}.toClient()
|
|
if c.Authid != 7 || c.Tenantname != "Acme" || c.Loginemail != "a@b.co" {
|
|
t.Fatalf("fields lost: %+v", c)
|
|
}
|
|
// 16:14 IST, i.e. 10:44 UTC — not 16:14 UTC (which would show as 21:44 in India).
|
|
if c.Logincreatedat == nil || !c.Logincreatedat.Equal(time.Date(2026, 6, 24, 10, 44, 0, 0, time.UTC)) {
|
|
t.Fatalf("a zero login date must fall back to the tenant's, read as IST: %v", c.Logincreatedat)
|
|
}
|
|
if (onboardedClientRow{}).toClient().Logincreatedat != nil {
|
|
t.Fatal("no real date must give null, not year 1")
|
|
}
|
|
}
|
|
|
|
func TestClientAddressValidate(t *testing.T) {
|
|
ok := clientAddress{Address: " 14 DB Road, RS Puram ", City: " Coimbatore ", State: "Tamil Nadu",
|
|
Pincode: " 641 002", Latitude: 11.009, Longitude: 76.95}
|
|
if msg := ok.validate(); msg != "" {
|
|
t.Fatalf("valid address refused: %s", msg)
|
|
}
|
|
if ok.Address != "14 DB Road, RS Puram" || ok.City != "Coimbatore" || ok.State != "Tamil Nadu" || ok.Pincode != "641002" {
|
|
t.Fatalf("not normalised: %+v", ok)
|
|
}
|
|
cases := []struct {
|
|
name string
|
|
a clientAddress
|
|
want string
|
|
}{
|
|
{"empty", clientAddress{}, "enter the client's address"},
|
|
{"too short", clientAddress{Address: "abc", Pincode: "641002", Latitude: 11, Longitude: 77}, "enter the client's address"},
|
|
{"too long", clientAddress{Address: strings.Repeat("a", 301), Pincode: "641002", Latitude: 11, Longitude: 77}, "too long"},
|
|
{"pincode 5 digits", clientAddress{Address: "14 DB Road", Pincode: "64100", Latitude: 11, Longitude: 77}, "6-digit pincode"},
|
|
{"pincode starts 0", clientAddress{Address: "14 DB Road", Pincode: "041002", Latitude: 11, Longitude: 77}, "6-digit pincode"},
|
|
{"no map location", clientAddress{Address: "14 DB Road", Pincode: "641002"}, "pick the address"},
|
|
{"swapped lat/lon", clientAddress{Address: "14 DB Road", Pincode: "641002", Latitude: 76.95, Longitude: 11.0}, "pick the address"},
|
|
{"outside India", clientAddress{Address: "14 DB Road", Pincode: "641002", Latitude: 51.5, Longitude: -0.1}, "pick the address"},
|
|
}
|
|
for _, c := range cases {
|
|
a := c.a
|
|
if msg := a.validate(); !strings.Contains(msg, c.want) {
|
|
t.Errorf("%s: %q, want %q", c.name, msg, c.want)
|
|
}
|
|
}
|
|
}
|