1+ import { validateToolName , validateAndWarnToolName , issueToolNameWarning } from './toolNameValidation.js' ;
2+
3+ // Spy on console.warn to capture output
4+ let warnSpy : jest . SpyInstance ;
5+
6+ beforeEach ( ( ) => {
7+ warnSpy = jest . spyOn ( console , 'warn' ) . mockImplementation ( ) ;
8+ } ) ;
9+
10+ afterEach ( ( ) => {
11+ jest . restoreAllMocks ( ) ;
12+ } ) ;
13+
14+ describe ( 'validateToolName' , ( ) => {
15+ describe ( 'valid tool names' , ( ) => {
16+ test ( 'should accept simple alphanumeric names' , ( ) => {
17+ const result = validateToolName ( 'getUser' ) ;
18+ expect ( result . isValid ) . toBe ( true ) ;
19+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
20+ } ) ;
21+
22+ test ( 'should accept names with underscores' , ( ) => {
23+ const result = validateToolName ( 'get_user_profile' ) ;
24+ expect ( result . isValid ) . toBe ( true ) ;
25+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
26+ } ) ;
27+
28+ test ( 'should accept names with dashes' , ( ) => {
29+ const result = validateToolName ( 'user-profile-update' ) ;
30+ expect ( result . isValid ) . toBe ( true ) ;
31+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
32+ } ) ;
33+
34+ test ( 'should accept names with dots' , ( ) => {
35+ const result = validateToolName ( 'admin.tools.list' ) ;
36+ expect ( result . isValid ) . toBe ( true ) ;
37+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
38+ } ) ;
39+
40+ test ( 'should accept names with forward slashes' , ( ) => {
41+ const result = validateToolName ( 'user/profile/update' ) ;
42+ expect ( result . isValid ) . toBe ( true ) ;
43+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
44+ } ) ;
45+
46+ test ( 'should accept mixed character names' , ( ) => {
47+ const result = validateToolName ( 'DATA_EXPORT_v2.1' ) ;
48+ expect ( result . isValid ) . toBe ( true ) ;
49+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
50+ } ) ;
51+
52+ test ( 'should accept single character names' , ( ) => {
53+ const result = validateToolName ( 'a' ) ;
54+ expect ( result . isValid ) . toBe ( true ) ;
55+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
56+ } ) ;
57+
58+ test ( 'should accept 128 character names' , ( ) => {
59+ const name = 'a' . repeat ( 128 ) ;
60+ const result = validateToolName ( name ) ;
61+ expect ( result . isValid ) . toBe ( true ) ;
62+ expect ( result . warnings ) . toHaveLength ( 0 ) ;
63+ } ) ;
64+ } ) ;
65+
66+ describe ( 'invalid tool names' , ( ) => {
67+ test ( 'should reject empty names' , ( ) => {
68+ const result = validateToolName ( '' ) ;
69+ expect ( result . isValid ) . toBe ( false ) ;
70+ expect ( result . warnings ) . toContain ( 'Tool name cannot be empty' ) ;
71+ } ) ;
72+
73+ test ( 'should reject names longer than 128 characters' , ( ) => {
74+ const name = 'a' . repeat ( 129 ) ;
75+ const result = validateToolName ( name ) ;
76+ expect ( result . isValid ) . toBe ( false ) ;
77+ expect ( result . warnings ) . toContain ( 'Tool name exceeds maximum length of 128 characters (current: 129)' ) ;
78+ } ) ;
79+
80+ test ( 'should reject names with spaces' , ( ) => {
81+ const result = validateToolName ( 'get user profile' ) ;
82+ expect ( result . isValid ) . toBe ( false ) ;
83+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: " "' ) ;
84+ } ) ;
85+
86+ test ( 'should reject names with commas' , ( ) => {
87+ const result = validateToolName ( 'get,user,profile' ) ;
88+ expect ( result . isValid ) . toBe ( false ) ;
89+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: ","' ) ;
90+ } ) ;
91+
92+ test ( 'should reject names with other special characters' , ( ) => {
93+ const result = validateToolName ( 'user@domain.com' ) ;
94+ expect ( result . isValid ) . toBe ( false ) ;
95+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: "@"' ) ;
96+ } ) ;
97+
98+ test ( 'should reject names with multiple invalid characters' , ( ) => {
99+ const result = validateToolName ( 'user name@domain,com' ) ;
100+ expect ( result . isValid ) . toBe ( false ) ;
101+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: " ", "@", ","' ) ;
102+ } ) ;
103+
104+ test ( 'should reject names with unicode characters' , ( ) => {
105+ const result = validateToolName ( 'user-ñame' ) ;
106+ expect ( result . isValid ) . toBe ( false ) ;
107+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: "ñ"' ) ;
108+ } ) ;
109+ } ) ;
110+
111+ describe ( 'warnings for potentially problematic patterns' , ( ) => {
112+ test ( 'should warn about names with spaces' , ( ) => {
113+ const result = validateToolName ( 'get user profile' ) ;
114+ expect ( result . isValid ) . toBe ( false ) ;
115+ expect ( result . warnings ) . toContain ( 'Tool name contains spaces, which may cause parsing issues' ) ;
116+ } ) ;
117+
118+ test ( 'should warn about names with commas' , ( ) => {
119+ const result = validateToolName ( 'get,user,profile' ) ;
120+ expect ( result . isValid ) . toBe ( false ) ;
121+ expect ( result . warnings ) . toContain ( 'Tool name contains commas, which may cause parsing issues' ) ;
122+ } ) ;
123+
124+ test ( 'should warn about names starting with dash' , ( ) => {
125+ const result = validateToolName ( '-get-user' ) ;
126+ expect ( result . isValid ) . toBe ( true ) ;
127+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dash, which may cause parsing issues in some contexts' ) ;
128+ } ) ;
129+
130+ test ( 'should warn about names ending with dash' , ( ) => {
131+ const result = validateToolName ( 'get-user-' ) ;
132+ expect ( result . isValid ) . toBe ( true ) ;
133+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dash, which may cause parsing issues in some contexts' ) ;
134+ } ) ;
135+
136+ test ( 'should warn about names starting with dot' , ( ) => {
137+ const result = validateToolName ( '.get.user' ) ;
138+ expect ( result . isValid ) . toBe ( true ) ;
139+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dot, which may cause parsing issues in some contexts' ) ;
140+ } ) ;
141+
142+ test ( 'should warn about names ending with dot' , ( ) => {
143+ const result = validateToolName ( 'get.user.' ) ;
144+ expect ( result . isValid ) . toBe ( true ) ;
145+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dot, which may cause parsing issues in some contexts' ) ;
146+ } ) ;
147+
148+ test ( 'should warn about names with both leading and trailing dots' , ( ) => {
149+ const result = validateToolName ( '.get.user.' ) ;
150+ expect ( result . isValid ) . toBe ( true ) ;
151+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dot, which may cause parsing issues in some contexts' ) ;
152+ } ) ;
153+ } ) ;
154+ } ) ;
155+
156+ describe ( 'issueToolNameWarning' , ( ) => {
157+ test ( 'should output warnings to console.warn' , ( ) => {
158+ const warnings = [ 'Warning 1' , 'Warning 2' ] ;
159+ issueToolNameWarning ( 'test-tool' , warnings ) ;
160+
161+ expect ( warnSpy ) . toHaveBeenCalledTimes ( 6 ) ; // Header + 2 warnings + 3 guidance lines
162+ const calls = warnSpy . mock . calls . map ( call => call . join ( ' ' ) ) ;
163+ expect ( calls [ 0 ] ) . toContain ( 'Tool name validation warning for "test-tool"' ) ;
164+ expect ( calls [ 1 ] ) . toContain ( '- Warning 1' ) ;
165+ expect ( calls [ 2 ] ) . toContain ( '- Warning 2' ) ;
166+ expect ( calls [ 3 ] ) . toContain ( 'Tool registration will proceed, but this may cause compatibility issues.' ) ;
167+ expect ( calls [ 4 ] ) . toContain ( 'Consider updating the tool name' ) ;
168+ expect ( calls [ 5 ] ) . toContain ( 'See SEP: Specify Format for Tool Names' ) ;
169+ } ) ;
170+
171+ test ( 'should handle empty warnings array' , ( ) => {
172+ issueToolNameWarning ( 'test-tool' , [ ] ) ;
173+ expect ( warnSpy ) . toHaveBeenCalledTimes ( 0 ) ;
174+ } ) ;
175+ } ) ;
176+
177+ describe ( 'validateAndWarnToolName' , ( ) => {
178+ test ( 'should return true and issue warnings for valid names with warnings' , ( ) => {
179+ const result = validateAndWarnToolName ( '-get-user-' ) ;
180+ expect ( result ) . toBe ( true ) ;
181+ expect ( warnSpy ) . toHaveBeenCalled ( ) ;
182+ } ) ;
183+
184+ test ( 'should return true and not issue warnings for completely valid names' , ( ) => {
185+ const result = validateAndWarnToolName ( 'get-user-profile' ) ;
186+ expect ( result ) . toBe ( true ) ;
187+ expect ( warnSpy ) . not . toHaveBeenCalled ( ) ;
188+ } ) ;
189+
190+ test ( 'should return false and issue warnings for invalid names' , ( ) => {
191+ const result = validateAndWarnToolName ( 'get user profile' ) ;
192+ expect ( result ) . toBe ( false ) ;
193+ expect ( warnSpy ) . toHaveBeenCalled ( ) ; // Now issues warnings instead of errors
194+ const warningCalls = warnSpy . mock . calls . map ( call => call . join ( ' ' ) ) ;
195+ expect ( warningCalls . some ( call => call . includes ( 'Tool name contains spaces' ) ) ) . toBe ( true ) ;
196+ } ) ;
197+
198+ test ( 'should return false for empty names' , ( ) => {
199+ const result = validateAndWarnToolName ( '' ) ;
200+ expect ( result ) . toBe ( false ) ;
201+ expect ( warnSpy ) . toHaveBeenCalled ( ) ; // Now issues warnings instead of errors
202+ } ) ;
203+
204+ test ( 'should return false for names exceeding length limit' , ( ) => {
205+ const longName = 'a' . repeat ( 129 ) ;
206+ const result = validateAndWarnToolName ( longName ) ;
207+ expect ( result ) . toBe ( false ) ;
208+ expect ( warnSpy ) . toHaveBeenCalled ( ) ; // Now issues warnings instead of errors
209+ } ) ;
210+ } ) ;
211+
212+ describe ( 'edge cases and robustness' , ( ) => {
213+ test ( 'should warn about names with only dots' , ( ) => {
214+ const result = validateToolName ( '...' ) ;
215+ expect ( result . isValid ) . toBe ( true ) ;
216+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dot, which may cause parsing issues in some contexts' ) ;
217+ } ) ;
218+
219+ test ( 'should handle names with only dashes' , ( ) => {
220+ const result = validateToolName ( '---' ) ;
221+ expect ( result . isValid ) . toBe ( true ) ;
222+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a dash, which may cause parsing issues in some contexts' ) ;
223+ } ) ;
224+
225+ test ( 'should warn about names with only forward slashes' , ( ) => {
226+ const result = validateToolName ( '///' ) ;
227+ expect ( result . isValid ) . toBe ( true ) ;
228+ expect ( result . warnings ) . toContain ( 'Tool name starts or ends with a slash, which may cause parsing issues in some contexts' ) ;
229+ } ) ;
230+
231+ test ( 'should handle names with mixed valid and invalid characters' , ( ) => {
232+ const result = validateToolName ( 'user@name123' ) ;
233+ expect ( result . isValid ) . toBe ( false ) ;
234+ expect ( result . warnings ) . toContain ( 'Tool name contains invalid characters: "@"' ) ;
235+ } ) ;
236+ } ) ;
0 commit comments