ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

get some generated tests in the user space

+305
+35
internal/users/normalize_test.go
··· 1 + package users 2 + 3 + import "testing" 4 + 5 + func TestNormalizeEmail(t *testing.T) { 6 + tests := []struct { 7 + name string 8 + input string 9 + want string 10 + }{ 11 + { 12 + name: "trim and lower", 13 + input: " Alice@Example.COM ", 14 + want: "alice@example.com", 15 + }, 16 + { 17 + name: "newline trimmed", 18 + input: "bob@example.com\n", 19 + want: "bob@example.com", 20 + }, 21 + { 22 + name: "already normalized", 23 + input: "carol@example.com", 24 + want: "carol@example.com", 25 + }, 26 + } 27 + 28 + for _, tt := range tests { 29 + t.Run(tt.name, func(t *testing.T) { 30 + if got := normalizeEmail(tt.input); got != tt.want { 31 + t.Fatalf("normalizeEmail(%q) = %q, want %q", tt.input, got, tt.want) 32 + } 33 + }) 34 + } 35 + }
+215
internal/users/storage_more_test.go
··· 1 + package users 2 + 3 + import ( 4 + "context" 5 + "net/http" 6 + "net/http/httptest" 7 + "testing" 8 + "time" 9 + 10 + "careme/internal/auth" 11 + "careme/internal/cache" 12 + "careme/internal/config" 13 + utypes "careme/internal/users/types" 14 + ) 15 + 16 + type stubEmailFetcher struct { 17 + email string 18 + err error 19 + calls int 20 + } 21 + 22 + func (s *stubEmailFetcher) GetUserEmail(_ context.Context, _ string) (string, error) { 23 + s.calls++ 24 + return s.email, s.err 25 + } 26 + 27 + func TestStorageUpdateAndGetByID(t *testing.T) { 28 + fc := cache.NewFileCache(t.TempDir()) 29 + storage := NewStorage(fc) 30 + 31 + user := &utypes.User{ 32 + ID: "user-1", 33 + Email: []string{"Alice@Example.com"}, 34 + ShoppingDay: time.Monday.String(), 35 + } 36 + 37 + if err := storage.Update(user); err != nil { 38 + t.Fatalf("Update() error: %v", err) 39 + } 40 + 41 + got, err := storage.GetByID("user-1") 42 + if err != nil { 43 + t.Fatalf("GetByID() error: %v", err) 44 + } 45 + if got.ID != user.ID { 46 + t.Fatalf("GetByID() ID = %q, want %q", got.ID, user.ID) 47 + } 48 + if got.ShoppingDay != user.ShoppingDay { 49 + t.Fatalf("GetByID() ShoppingDay = %q, want %q", got.ShoppingDay, user.ShoppingDay) 50 + } 51 + if len(got.Email) != 1 || got.Email[0] != user.Email[0] { 52 + t.Fatalf("GetByID() Email = %v, want %v", got.Email, user.Email) 53 + } 54 + } 55 + 56 + func TestStorageGetByIDNotFound(t *testing.T) { 57 + fc := cache.NewFileCache(t.TempDir()) 58 + storage := NewStorage(fc) 59 + 60 + _, err := storage.GetByID("missing") 61 + if err == nil || err != ErrNotFound { 62 + t.Fatalf("GetByID() error = %v, want %v", err, ErrNotFound) 63 + } 64 + } 65 + 66 + func TestStorageGetByEmailNotFound(t *testing.T) { 67 + fc := cache.NewFileCache(t.TempDir()) 68 + storage := NewStorage(fc) 69 + 70 + _, err := storage.GetByEmail("missing@example.com") 71 + if err == nil || err != ErrNotFound { 72 + t.Fatalf("GetByEmail() error = %v, want %v", err, ErrNotFound) 73 + } 74 + } 75 + 76 + func TestStorageGetByEmail(t *testing.T) { 77 + fc := cache.NewFileCache(t.TempDir()) 78 + storage := NewStorage(fc) 79 + 80 + user := &utypes.User{ 81 + ID: "user-2", 82 + Email: []string{"Alice@Example.com"}, 83 + ShoppingDay: time.Tuesday.String(), 84 + } 85 + 86 + if err := storage.Update(user); err != nil { 87 + t.Fatalf("Update() error: %v", err) 88 + } 89 + if err := fc.Put(context.Background(), emailPrefix+normalizeEmail(user.Email[0]), user.ID, cache.Unconditional()); err != nil { 90 + t.Fatalf("failed to index email: %v", err) 91 + } 92 + 93 + got, err := storage.GetByEmail("ALICE@EXAMPLE.COM") 94 + if err != nil { 95 + t.Fatalf("GetByEmail() error: %v", err) 96 + } 97 + if got.ID != user.ID { 98 + t.Fatalf("GetByEmail() ID = %q, want %q", got.ID, user.ID) 99 + } 100 + } 101 + 102 + func TestFindOrCreateFromClerkExistingUser(t *testing.T) { 103 + fc := cache.NewFileCache(t.TempDir()) 104 + storage := NewStorage(fc) 105 + 106 + user := &utypes.User{ 107 + ID: "user-3", 108 + Email: []string{"dana@example.com"}, 109 + ShoppingDay: time.Wednesday.String(), 110 + } 111 + if err := storage.Update(user); err != nil { 112 + t.Fatalf("Update() error: %v", err) 113 + } 114 + 115 + fetcher := &stubEmailFetcher{email: "should-not-call@example.com"} 116 + got, err := storage.FindOrCreateFromClerk(context.Background(), "user-3", fetcher) 117 + if err != nil { 118 + t.Fatalf("FindOrCreateFromClerk() error: %v", err) 119 + } 120 + if fetcher.calls != 0 { 121 + t.Fatalf("expected email fetcher to not be called, calls=%d", fetcher.calls) 122 + } 123 + if got.ID != user.ID { 124 + t.Fatalf("FindOrCreateFromClerk() ID = %q, want %q", got.ID, user.ID) 125 + } 126 + } 127 + 128 + func TestFindOrCreateFromClerkCreatesUser(t *testing.T) { 129 + fc := cache.NewFileCache(t.TempDir()) 130 + storage := NewStorage(fc) 131 + 132 + fetcher := &stubEmailFetcher{email: "NewUser@Example.com"} 133 + start := time.Now() 134 + got, err := storage.FindOrCreateFromClerk(context.Background(), "user-4", fetcher) 135 + end := time.Now() 136 + if err != nil { 137 + t.Fatalf("FindOrCreateFromClerk() error: %v", err) 138 + } 139 + if fetcher.calls != 1 { 140 + t.Fatalf("expected email fetcher to be called once, calls=%d", fetcher.calls) 141 + } 142 + if got.ID != "user-4" { 143 + t.Fatalf("FindOrCreateFromClerk() ID = %q, want %q", got.ID, "user-4") 144 + } 145 + if len(got.Email) != 1 || got.Email[0] != "newuser@example.com" { 146 + t.Fatalf("FindOrCreateFromClerk() Email = %v, want [newuser@example.com]", got.Email) 147 + } 148 + if got.ShoppingDay != time.Saturday.String() { 149 + t.Fatalf("FindOrCreateFromClerk() ShoppingDay = %q, want %q", got.ShoppingDay, time.Saturday.String()) 150 + } 151 + if got.CreatedAt.Before(start) || got.CreatedAt.After(end) { 152 + t.Fatalf("FindOrCreateFromClerk() CreatedAt = %v, expected between %v and %v", got.CreatedAt, start, end) 153 + } 154 + 155 + stored, err := storage.GetByID("user-4") 156 + if err != nil { 157 + t.Fatalf("GetByID() error: %v", err) 158 + } 159 + if stored.ID != got.ID { 160 + t.Fatalf("stored ID = %q, want %q", stored.ID, got.ID) 161 + } 162 + } 163 + 164 + func TestFromRequestCreatesUserWithMockAuth(t *testing.T) { 165 + fc := cache.NewFileCache(t.TempDir()) 166 + storage := NewStorage(fc) 167 + 168 + cfg := &config.Config{ 169 + Mocks: config.MockConfig{Email: "NewUser@Example.com"}, 170 + } 171 + client := auth.Mock(cfg) 172 + 173 + req := httptest.NewRequest(http.MethodGet, "/", nil) 174 + got, err := storage.FromRequest(context.Background(), req, client) 175 + if err != nil { 176 + t.Fatalf("FromRequest() error: %v", err) 177 + } 178 + if got.ID != "mock-clerk-user-id" { 179 + t.Fatalf("FromRequest() ID = %q, want %q", got.ID, "mock-clerk-user-id") 180 + } 181 + if len(got.Email) != 1 || got.Email[0] != "newuser@example.com" { 182 + t.Fatalf("FromRequest() Email = %v, want [newuser@example.com]", got.Email) 183 + } 184 + } 185 + 186 + func TestFromRequestReturnsExistingUser(t *testing.T) { 187 + fc := cache.NewFileCache(t.TempDir()) 188 + storage := NewStorage(fc) 189 + 190 + existing := &utypes.User{ 191 + ID: "mock-clerk-user-id", 192 + Email: []string{"existing@example.com"}, 193 + ShoppingDay: time.Thursday.String(), 194 + } 195 + if err := storage.Update(existing); err != nil { 196 + t.Fatalf("Update() error: %v", err) 197 + } 198 + 199 + cfg := &config.Config{ 200 + Mocks: config.MockConfig{Email: "ignored@example.com"}, 201 + } 202 + client := auth.Mock(cfg) 203 + 204 + req := httptest.NewRequest(http.MethodGet, "/", nil) 205 + got, err := storage.FromRequest(context.Background(), req, client) 206 + if err != nil { 207 + t.Fatalf("FromRequest() error: %v", err) 208 + } 209 + if got.ID != existing.ID { 210 + t.Fatalf("FromRequest() ID = %q, want %q", got.ID, existing.ID) 211 + } 212 + if len(got.Email) != 1 || got.Email[0] != "existing@example.com" { 213 + t.Fatalf("FromRequest() Email = %v, want [existing@example.com]", got.Email) 214 + } 215 + }
+55
internal/users/types/types_test.go
··· 1 + package types 2 + 3 + import ( 4 + "testing" 5 + "time" 6 + ) 7 + 8 + func TestParseWeekday(t *testing.T) { 9 + tests := []struct { 10 + name string 11 + input string 12 + want time.Weekday 13 + wantErr bool 14 + }{ 15 + { 16 + name: "sunday", 17 + input: "Sunday", 18 + want: time.Sunday, 19 + }, 20 + { 21 + name: "case insensitive", 22 + input: "mOnDaY", 23 + want: time.Monday, 24 + }, 25 + { 26 + name: "lowercase", 27 + input: "tuesday", 28 + want: time.Tuesday, 29 + }, 30 + { 31 + name: "invalid", 32 + input: "Caturday", 33 + want: time.Sunday, 34 + wantErr: true, 35 + }, 36 + } 37 + 38 + for _, tt := range tests { 39 + t.Run(tt.name, func(t *testing.T) { 40 + got, err := parseWeekday(tt.input) 41 + if tt.wantErr { 42 + if err == nil { 43 + t.Fatalf("parseWeekday(%q) expected error", tt.input) 44 + } 45 + return 46 + } 47 + if err != nil { 48 + t.Fatalf("parseWeekday(%q) unexpected error: %v", tt.input, err) 49 + } 50 + if got != tt.want { 51 + t.Fatalf("parseWeekday(%q) = %v, want %v", tt.input, got, tt.want) 52 + } 53 + }) 54 + } 55 + }