1+
2+ /*
3+ * Copyright 2023-2025 the original author or authors.
4+ *
5+ * Licensed under the Apache License, Version 2.0 (the "License");
6+ * you may not use this file except in compliance with the License.
7+ * You may obtain a copy of the License at
8+ *
9+ * https://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS,
13+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ * See the License for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+
18+ package org .springframework .ai .tool .method ;
19+
20+ import java .lang .reflect .Method ;
21+
22+ import org .junit .jupiter .api .Test ;
23+
24+ import org .springframework .ai .tool .annotation .Tool ;
25+ import org .springframework .ai .tool .definition .DefaultToolDefinition ;
26+ import org .springframework .ai .tool .definition .ToolDefinition ;
27+ import org .springframework .ai .tool .execution .ToolExecutionException ;
28+
29+ import static org .assertj .core .api .Assertions .assertThat ;
30+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
31+
32+ /**
33+ * Unit tests for {@link MethodToolCallback}.
34+ *
35+ * @author Thomas Vitale
36+ */
37+ class MethodToolCallbackTests {
38+
39+ @ Test
40+ void shouldThrowToolExecutionExceptionForInvalidEnumArgument () throws Exception {
41+ // Given
42+ TestToolClass testTool = new TestToolClass ();
43+ Method method = TestToolClass .class .getDeclaredMethod ("processOrder" , OrderType .class );
44+ ToolDefinition toolDefinition = DefaultToolDefinition .builder ()
45+ .name ("processOrder" )
46+ .description ("Process an order" )
47+ .inputSchema ("{}" )
48+ .build ();
49+
50+ MethodToolCallback callback = new MethodToolCallback (toolDefinition , null , method , testTool , null );
51+
52+ // When/Then - Invalid enum value should throw ToolExecutionException
53+ assertThatThrownBy (() -> callback .call ("{\" orderType\" : \" INVALID_TYPE\" }" ))
54+ .isInstanceOf (ToolExecutionException .class )
55+ .hasCauseInstanceOf (IllegalArgumentException .class )
56+ .hasMessageContaining ("No enum constant" );
57+
58+ // Verify the ToolExecutionException contains the correct tool definition
59+ try {
60+ callback .call ("{\" orderType\" : \" INVALID_TYPE\" }" );
61+ }
62+ catch (ToolExecutionException ex ) {
63+ assertThat (ex .getToolDefinition ()).isEqualTo (toolDefinition );
64+ assertThat (ex .getCause ()).isInstanceOf (IllegalArgumentException .class );
65+ }
66+ }
67+
68+ @ Test
69+ void shouldSucceedWithValidEnumArgument () throws Exception {
70+ // Given
71+ TestToolClass testTool = new TestToolClass ();
72+ Method method = TestToolClass .class .getDeclaredMethod ("processOrder" , OrderType .class );
73+ ToolDefinition toolDefinition = DefaultToolDefinition .builder ()
74+ .name ("processOrder" )
75+ .description ("Process an order" )
76+ .inputSchema ("{}" )
77+ .build ();
78+
79+ MethodToolCallback callback = new MethodToolCallback (toolDefinition , null , method , testTool , null );
80+
81+ // When
82+ String result = callback .call ("{\" orderType\" : \" ONE_DAY\" }" );
83+
84+ // Then
85+ assertThat (result ).isEqualTo ("\" Processing ONE_DAY order\" " );
86+ }
87+
88+ // Test classes
89+ static class TestToolClass {
90+
91+ @ Tool (description = "Process an order with the specified delivery type" )
92+ public String processOrder (OrderType orderType ) {
93+ return "Processing " + orderType + " order" ;
94+ }
95+
96+ }
97+
98+ enum OrderType {
99+
100+ ONE_DAY , TWO_DAY , THREE_DAY
101+
102+ }
103+
104+ }
0 commit comments