view_test.go

  1package tools
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6	"os"
  7	"path/filepath"
  8	"strings"
  9	"testing"
 10
 11	"github.com/stretchr/testify/require"
 12)
 13
 14func TestReadTextFileBoundaryCases(t *testing.T) {
 15	t.Parallel()
 16
 17	tmpDir := t.TempDir()
 18	filePath := filepath.Join(tmpDir, "sample.txt")
 19
 20	var allLines []string
 21	for i := range 5 {
 22		allLines = append(allLines, fmt.Sprintf("line %d", i+1))
 23	}
 24	require.NoError(t, os.WriteFile(filePath, []byte(strings.Join(allLines, "\n")), 0o644))
 25
 26	tests := []struct {
 27		name        string
 28		offset      int
 29		limit       int
 30		wantContent string
 31		wantHasMore bool
 32	}{
 33		{
 34			name:        "exactly limit lines remaining",
 35			offset:      0,
 36			limit:       5,
 37			wantContent: "line 1\nline 2\nline 3\nline 4\nline 5",
 38			wantHasMore: false,
 39		},
 40		{
 41			name:        "limit plus one line remaining",
 42			offset:      0,
 43			limit:       4,
 44			wantContent: "line 1\nline 2\nline 3\nline 4",
 45			wantHasMore: true,
 46		},
 47		{
 48			name:        "offset at last line",
 49			offset:      4,
 50			limit:       3,
 51			wantContent: "line 5",
 52			wantHasMore: false,
 53		},
 54		{
 55			name:        "offset beyond eof",
 56			offset:      10,
 57			limit:       3,
 58			wantContent: "",
 59			wantHasMore: false,
 60		},
 61	}
 62
 63	for _, tt := range tests {
 64		t.Run(tt.name, func(t *testing.T) {
 65			t.Parallel()
 66
 67			gotContent, gotHasMore, err := readTextFile(filePath, tt.offset, tt.limit)
 68			require.NoError(t, err)
 69			require.Equal(t, tt.wantContent, gotContent)
 70			require.Equal(t, tt.wantHasMore, gotHasMore)
 71		})
 72	}
 73}
 74
 75func TestReadTextFileTruncatesLongLines(t *testing.T) {
 76	t.Parallel()
 77
 78	tmpDir := t.TempDir()
 79	filePath := filepath.Join(tmpDir, "longline.txt")
 80
 81	longLine := strings.Repeat("a", MaxLineLength+10)
 82	require.NoError(t, os.WriteFile(filePath, []byte(longLine), 0o644))
 83
 84	content, hasMore, err := readTextFile(filePath, 0, 1)
 85	require.NoError(t, err)
 86	require.False(t, hasMore)
 87	require.Equal(t, strings.Repeat("a", MaxLineLength)+"...", content)
 88}
 89
 90func TestReadBuiltinFile(t *testing.T) {
 91	t.Parallel()
 92
 93	t.Run("reads crush-config skill", func(t *testing.T) {
 94		t.Parallel()
 95
 96		resp, err := readBuiltinFile(ViewParams{
 97			FilePath: "crush://skills/crush-config/SKILL.md",
 98		}, nil)
 99		require.NoError(t, err)
100		require.NotEmpty(t, resp.Content)
101		require.Contains(t, resp.Content, "Crush Configuration")
102	})
103
104	t.Run("not found", func(t *testing.T) {
105		t.Parallel()
106
107		resp, err := readBuiltinFile(ViewParams{
108			FilePath: "crush://skills/nonexistent/SKILL.md",
109		}, nil)
110		require.NoError(t, err)
111		require.True(t, resp.IsError)
112	})
113
114	t.Run("metadata has skill info", func(t *testing.T) {
115		t.Parallel()
116
117		resp, err := readBuiltinFile(ViewParams{
118			FilePath: "crush://skills/crush-config/SKILL.md",
119		}, nil)
120		require.NoError(t, err)
121
122		var meta ViewResponseMetadata
123		require.NoError(t, json.Unmarshal([]byte(resp.Metadata), &meta))
124		require.Equal(t, ViewResourceSkill, meta.ResourceType)
125		require.Equal(t, "crush-config", meta.ResourceName)
126		require.NotEmpty(t, meta.ResourceDescription)
127	})
128
129	t.Run("respects offset", func(t *testing.T) {
130		t.Parallel()
131
132		resp, err := readBuiltinFile(ViewParams{
133			FilePath: "crush://skills/crush-config/SKILL.md",
134			Offset:   5,
135		}, nil)
136		require.NoError(t, err)
137		require.NotContains(t, resp.Content, "     1|")
138	})
139}