1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: LicenseRef-MutuaL-1.2
4
5package cooked
6
7import (
8 "context"
9 "encoding/json"
10 "net/http"
11 "net/http/httptest"
12 "net/url"
13 "testing"
14)
15
16func TestReadShoppingListACIDAuthenticationLogin3StoresCookies(t *testing.T) {
17 var sawSessionCookie bool
18
19 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 switch r.URL.Path {
21 case "/api/public/login":
22 if r.Method != http.MethodPost {
23 t.Fatalf("login method = %s, want POST", r.Method)
24 }
25
26 var request loginRequest
27 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
28 t.Fatalf("decode login request: %v", err)
29 }
30 if request.Username != "configured-user" || request.Password != "configured-password" {
31 t.Fatalf("login request = %#v, want configured credentials", request)
32 }
33
34 http.SetCookie(w, &http.Cookie{Name: "cooked_session", Value: "session-value", Path: "/"})
35 writeJSON(t, w, loginResponse{Username: "returned-user"})
36 case "/api/user/returned-user/shopping-list":
37 cookie, err := r.Cookie("cooked_session")
38 if err != nil {
39 t.Fatalf("missing session cookie: %v", err)
40 }
41 if cookie.Value != "session-value" {
42 t.Fatalf("session cookie = %q, want session-value", cookie.Value)
43 }
44 sawSessionCookie = true
45 writeJSON(t, w, shoppingListResponse{
46 ShoppingList: ShoppingList{
47 Aisles: []Aisle{{
48 ID: "pantry",
49 Name: "Pantry",
50 ProductGroups: []ProductGroup{{
51 ID: "pasta",
52 Name: "Pasta",
53 Quantity: "200g",
54 }},
55 }},
56 },
57 Recipes: []string{"recipe-id"},
58 })
59 default:
60 t.Fatalf("unexpected path %s", r.URL.Path)
61 }
62 }))
63 defer server.Close()
64
65 baseURL, err := url.Parse(server.URL)
66 if err != nil {
67 t.Fatalf("parse server URL: %v", err)
68 }
69 client, err := NewClient(baseURL, "configured-user", "configured-password")
70 if err != nil {
71 t.Fatalf("NewClient() error = %v", err)
72 }
73
74 shoppingList, err := client.ReadShoppingList(context.Background())
75 if err != nil {
76 t.Fatalf("ReadShoppingList() error = %v", err)
77 }
78
79 if !sawSessionCookie {
80 t.Fatal("shopping-list request did not receive session cookie")
81 }
82 if len(shoppingList.Aisles) != 1 || shoppingList.Aisles[0].ProductGroups[0].Name != "Pasta" {
83 t.Fatalf("shopping list = %#v, want one Pasta item", shoppingList)
84 }
85}
86
87func TestUserPathEscapesAuthenticatedUsername(t *testing.T) {
88 client := &Client{authenticatedUsername: "user/name"}
89
90 got := client.userPath("/api/user/{username}/shopping-list")
91 if got != "/api/user/user%2Fname/shopping-list" {
92 t.Fatalf("userPath() = %q, want escaped username", got)
93 }
94}
95
96func writeJSON[T loginResponse | shoppingListResponse](t *testing.T, w http.ResponseWriter, value T) {
97 t.Helper()
98
99 w.Header().Set("Content-Type", "application/json")
100 if err := json.NewEncoder(w).Encode(value); err != nil {
101 t.Fatalf("write JSON: %v", err)
102 }
103}