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
14// recipes.SAVE.3 recipes.SAVE.4 recipes.SAVE.9 tools.SAVE_RECIPE_TOOL.1
15func TestCallToolACIDRecipesSave3And4And9ImportsURLSavedRecipe(t *testing.T) {
16 backend := &fakeBackend{importRecipeURLResult: cooked.RecipeURLImport{RecipeID: testRecipeID}}
17 server := NewServer(backend, "test")
18
19 _, output, err := server.callSaveRecipeTool(
20 context.Background(),
21 nil,
22 SaveRecipeArguments{Source: " url ", URL: " https://example.invalid/recipe "},
23 )
24 if err != nil {
25 t.Fatalf("callSaveRecipeTool() error = %v", err)
26 }
27
28 if backend.importRecipeURLCalls != 1 {
29 t.Fatalf("import calls = %d, want 1", backend.importRecipeURLCalls)
30 }
31 if backend.importURL != "https://example.invalid/recipe" {
32 t.Fatalf("backend import URL = %q, want trimmed URL", backend.importURL)
33 }
34 if output.RecipeID != testRecipeID || output.DraftID != "" {
35 t.Fatalf("save output = %#v, want recipe_id only", output)
36 }
37 if backend.metadataCalls != 0 || backend.contentCalls != 0 {
38 t.Fatalf("draft read calls = metadata %d content %d, want none", backend.metadataCalls, backend.contentCalls)
39 }
40 if backend.saveCalls != 0 || backend.updateCalls != 0 {
41 t.Fatalf("save/update calls = %d/%d, want none", backend.saveCalls, backend.updateCalls)
42 }
43}
44
45// recipes.SAVE.3-1 tools.SAVE_RECIPE_TOOL.4
46func TestCallToolACIDRecipesSave3_1AndToolsSaveRecipeTool4RequiresURL(t *testing.T) {
47 backend := &fakeBackend{}
48 server := NewServer(backend, "test")
49
50 _, _, err := server.callSaveRecipeTool(context.Background(), nil, SaveRecipeArguments{Source: "url", URL: " "})
51 if err == nil {
52 t.Fatal("callSaveRecipeTool() error = nil, want missing URL error")
53 }
54 if backend.importRecipeURLCalls != 0 {
55 t.Fatalf("import calls = %d, want none", backend.importRecipeURLCalls)
56 }
57}
58
59// recipes.SAVE.5 recipes.SAVE.6 recipes.SAVE.12 recipes.SAVE.14 recipes.SAVE.15 recipes.SAVE.16
60func TestCallToolACIDRecipesSave5And12And14And15ReturnsURLImportDraft(t *testing.T) {
61 draftID := "draft-1"
62 backend := &fakeBackend{
63 importRecipeURLResult: cooked.RecipeURLImport{DraftID: draftID},
64 recipeMetadata: cooked.RecipeMetadata{Title: "Pasta"},
65 recipeContent: cooked.RecipeContent{Content: "# Pasta\n\n1. Boil pasta.", Portions: 2},
66 }
67 server := NewServer(backend, "test")
68
69 _, output, err := server.callSaveRecipeTool(
70 context.Background(),
71 nil,
72 SaveRecipeArguments{Source: "url", URL: " https://example.invalid/pasta "},
73 )
74 if err != nil {
75 t.Fatalf("callSaveRecipeTool() error = %v", err)
76 }
77
78 if backend.importRecipeURLCalls != 1 {
79 t.Fatalf("import calls = %d, want 1", backend.importRecipeURLCalls)
80 }
81 if backend.importURL != "https://example.invalid/pasta" {
82 t.Fatalf("backend import URL = %q, want trimmed URL", backend.importURL)
83 }
84 if backend.metadataRecipeID != draftID || backend.contentRecipeID != draftID {
85 t.Fatalf(
86 "draft read IDs = metadata %q content %q, want draft ID",
87 backend.metadataRecipeID,
88 backend.contentRecipeID,
89 )
90 }
91 if backend.metadataCalls != 1 || backend.contentCalls != 1 {
92 t.Fatalf("draft read calls = metadata %d content %d, want 1/1", backend.metadataCalls, backend.contentCalls)
93 }
94 if output.RecipeID != "" || output.DraftID != draftID || output.Title != "Pasta" {
95 t.Fatalf("draft output identity = %#v, want draft ID Pasta with no recipe ID", output)
96 }
97 if output.Markdown != "# Pasta\n\n1. Boil pasta." || output.Portions != 2 {
98 t.Fatalf("draft output content = %q/%g, want markdown/2", output.Markdown, output.Portions)
99 }
100 if backend.saveCalls != 0 || backend.updateCalls != 0 {
101 t.Fatalf("save/update calls = %d/%d, want none", backend.saveCalls, backend.updateCalls)
102 }
103}