server_test.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: LicenseRef-MutuaL-1.2
 4
 5package mcp
 6
 7import (
 8	"context"
 9	"testing"
10
11	"git.secluded.site/cooked-mcp/internal/cooked"
12)
13
14func TestCallToolACIDToolsSurface1ReadsShoppingList(t *testing.T) {
15	backend := &fakeBackend{shoppingList: cooked.ShoppingList{
16		Aisles: []cooked.Aisle{{
17			ID:   "pantry",
18			Name: "Pantry",
19			ProductGroups: []cooked.ProductGroup{{
20				ID:       "pasta",
21				Name:     "Pasta",
22				Quantity: "200g",
23			}},
24		}},
25	}}
26	server := NewServer(backend, "test")
27
28	output, err := server.CallReadTool(context.Background(), ReadArguments{Target: "shopping_list"})
29	if err != nil {
30		t.Fatalf("CallReadTool() error = %v", err)
31	}
32
33	if len(output.Aisles) != 1 {
34		t.Fatalf("structured aisles = %d, want 1", len(output.Aisles))
35	}
36	if output.Aisles[0].ProductGroups[0].Name != "Pasta" {
37		t.Fatalf("first item = %q, want Pasta", output.Aisles[0].ProductGroups[0].Name)
38	}
39}
40
41func TestCallToolACIDRecipesRead1ListsRecipes(t *testing.T) {
42	backend := &fakeBackend{recipes: []cooked.RecipeCard{{ID: "recipe-1", Title: "Pasta", ThumbnailURL: "https://example.invalid/thumb.jpg"}}}
43	server := NewServer(backend, "test")
44
45	output, err := server.CallReadTool(context.Background(), ReadArguments{Target: "recipes", Page: 2, Limit: 5})
46	if err != nil {
47		t.Fatalf("CallReadTool() error = %v", err)
48	}
49
50	if backend.page != 2 {
51		t.Fatalf("backend page = %d, want 2", backend.page)
52	}
53	if backend.limit != 5 {
54		t.Fatalf("backend limit = %d, want 5", backend.limit)
55	}
56	if len(output.Recipes) != 1 {
57		t.Fatalf("structured recipes = %d, want 1", len(output.Recipes))
58	}
59	if output.Recipes[0].ID != "recipe-1" || output.Recipes[0].Title != "Pasta" {
60		t.Fatalf("first recipe = %#v, want recipe-1 Pasta", output.Recipes[0])
61	}
62}
63
64func TestCallToolACIDRecipesPagination4DefaultsAndCapsRecipeLimit(t *testing.T) {
65	backend := &fakeBackend{}
66	server := NewServer(backend, "test")
67
68	_, err := server.CallReadTool(context.Background(), ReadArguments{Target: "recipes", Limit: 99})
69	if err != nil {
70		t.Fatalf("CallReadTool() error = %v", err)
71	}
72
73	if backend.page != 1 {
74		t.Fatalf("backend page = %d, want default page 1", backend.page)
75	}
76	if backend.limit != 30 {
77		t.Fatalf("backend limit = %d, want capped limit 30", backend.limit)
78	}
79}
80
81type fakeBackend struct {
82	shoppingList cooked.ShoppingList
83	recipes      []cooked.RecipeCard
84	page         int
85	limit        int
86}
87
88func (f *fakeBackend) ReadShoppingList(context.Context) (cooked.ShoppingList, error) {
89	return f.shoppingList, nil
90}
91
92func (f *fakeBackend) ListRecipes(_ context.Context, page, limit int) ([]cooked.RecipeCard, error) {
93	f.page = page
94	f.limit = limit
95
96	return f.recipes, nil
97}