Skip to content

Commit 5caf108

Browse files
committed
Add tests for DefaultFunctionCallingOptions
1 parent 1c72f14 commit 5caf108

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
* Copyright 2024-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.function;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.BeforeEach;
21+
22+
import java.util.HashMap;
23+
import java.util.HashSet;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Set;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
30+
31+
/**
32+
* Unit tests for {@link DefaultFunctionCallingOptionsBuilder}.
33+
*
34+
*/
35+
class DefaultFunctionCallingOptionsBuilderTests {
36+
37+
private DefaultFunctionCallingOptionsBuilder builder;
38+
39+
@BeforeEach
40+
void setUp() {
41+
builder = new DefaultFunctionCallingOptionsBuilder();
42+
}
43+
44+
@Test
45+
void shouldBuildWithFunctionCallbacksList() {
46+
// Given
47+
FunctionCallback callback1 = FunctionCallback.builder()
48+
.function("test1", (String input) -> "result1")
49+
.description("Test function 1")
50+
.inputType(String.class)
51+
.build();
52+
FunctionCallback callback2 = FunctionCallback.builder()
53+
.function("test2", (String input) -> "result2")
54+
.description("Test function 2")
55+
.inputType(String.class)
56+
.build();
57+
List<FunctionCallback> callbacks = List.of(callback1, callback2);
58+
59+
// When
60+
FunctionCallingOptions options = builder.functionCallbacks(callbacks).build();
61+
62+
// Then
63+
assertThat(options.getFunctionCallbacks()).hasSize(2).containsExactlyElementsOf(callbacks);
64+
}
65+
66+
@Test
67+
void shouldBuildWithFunctionCallbacksVarargs() {
68+
// Given
69+
FunctionCallback callback1 = FunctionCallback.builder()
70+
.function("test1", (String input) -> "result1")
71+
.description("Test function 1")
72+
.inputType(String.class)
73+
.build();
74+
FunctionCallback callback2 = FunctionCallback.builder()
75+
.function("test2", (String input) -> "result2")
76+
.description("Test function 2")
77+
.inputType(String.class)
78+
.build();
79+
80+
// When
81+
FunctionCallingOptions options = builder.functionCallbacks(callback1, callback2).build();
82+
83+
// Then
84+
assertThat(options.getFunctionCallbacks()).hasSize(2).containsExactly(callback1, callback2);
85+
}
86+
87+
@Test
88+
void shouldThrowExceptionWhenFunctionCallbacksVarargsIsNull() {
89+
assertThatThrownBy(() -> builder.functionCallbacks((FunctionCallback[]) null))
90+
.isInstanceOf(IllegalArgumentException.class)
91+
.hasMessage("FunctionCallbacks must not be null");
92+
}
93+
94+
@Test
95+
void shouldBuildWithFunctionsSet() {
96+
// Given
97+
Set<String> functions = Set.of("function1", "function2");
98+
99+
// When
100+
FunctionCallingOptions options = builder.functions(functions).build();
101+
102+
// Then
103+
assertThat(options.getFunctions()).hasSize(2).containsExactlyInAnyOrderElementsOf(functions);
104+
}
105+
106+
@Test
107+
void shouldBuildWithSingleFunction() {
108+
// When
109+
FunctionCallingOptions options = builder.function("function1").function("function2").build();
110+
111+
// Then
112+
assertThat(options.getFunctions()).hasSize(2).containsExactlyInAnyOrder("function1", "function2");
113+
}
114+
115+
@Test
116+
void shouldThrowExceptionWhenFunctionIsNull() {
117+
assertThatThrownBy(() -> builder.function(null)).isInstanceOf(IllegalArgumentException.class)
118+
.hasMessage("Function must not be null");
119+
}
120+
121+
@Test
122+
void shouldBuildWithProxyToolCalls() {
123+
// When
124+
FunctionCallingOptions options = builder.proxyToolCalls(true).build();
125+
126+
// Then
127+
assertThat(options.getProxyToolCalls()).isTrue();
128+
}
129+
130+
@Test
131+
void shouldBuildWithToolContextMap() {
132+
// Given
133+
Map<String, Object> context = Map.of("key1", "value1", "key2", 42);
134+
135+
// When
136+
FunctionCallingOptions options = builder.toolContext(context).build();
137+
138+
// Then
139+
assertThat(options.getToolContext()).hasSize(2).containsAllEntriesOf(context);
140+
}
141+
142+
@Test
143+
void shouldThrowExceptionWhenToolContextMapIsNull() {
144+
assertThatThrownBy(() -> builder.toolContext((Map<String, Object>) null))
145+
.isInstanceOf(IllegalArgumentException.class)
146+
.hasMessage("Tool context must not be null");
147+
}
148+
149+
@Test
150+
void shouldBuildWithToolContextKeyValue() {
151+
// When
152+
FunctionCallingOptions options = builder.toolContext("key1", "value1").toolContext("key2", 42).build();
153+
154+
// Then
155+
assertThat(options.getToolContext()).hasSize(2).containsEntry("key1", "value1").containsEntry("key2", 42);
156+
}
157+
158+
@Test
159+
void shouldThrowExceptionWhenToolContextKeyIsNull() {
160+
assertThatThrownBy(() -> builder.toolContext(null, "value")).isInstanceOf(IllegalArgumentException.class)
161+
.hasMessage("Key must not be null");
162+
}
163+
164+
@Test
165+
void shouldThrowExceptionWhenToolContextValueIsNull() {
166+
assertThatThrownBy(() -> builder.toolContext("key", null)).isInstanceOf(IllegalArgumentException.class)
167+
.hasMessage("Value must not be null");
168+
}
169+
170+
@Test
171+
void shouldMergeToolContextMaps() {
172+
// Given
173+
Map<String, Object> context1 = Map.of("key1", "value1", "key2", 42);
174+
Map<String, Object> context2 = Map.of("key2", "updated", "key3", true);
175+
176+
// When
177+
FunctionCallingOptions options = builder.toolContext(context1).toolContext(context2).build();
178+
179+
// Then
180+
assertThat(options.getToolContext()).hasSize(3)
181+
.containsEntry("key1", "value1")
182+
.containsEntry("key2", "updated")
183+
.containsEntry("key3", true);
184+
}
185+
186+
@Test
187+
void shouldBuildWithAllOptions() {
188+
// Given
189+
FunctionCallback callback = FunctionCallback.builder()
190+
.function("test", (String input) -> "result")
191+
.description("Test function")
192+
.inputType(String.class)
193+
.build();
194+
Set<String> functions = Set.of("function1");
195+
Map<String, Object> context = Map.of("key1", "value1");
196+
197+
// When
198+
FunctionCallingOptions options = builder.functionCallbacks(callback)
199+
.functions(functions)
200+
.proxyToolCalls(true)
201+
.toolContext(context)
202+
.build();
203+
204+
// Then
205+
assertThat(options.getFunctionCallbacks()).hasSize(1).containsExactly(callback);
206+
assertThat(options.getFunctions()).hasSize(1).containsExactlyElementsOf(functions);
207+
assertThat(options.getProxyToolCalls()).isTrue();
208+
assertThat(options.getToolContext()).hasSize(1).containsAllEntriesOf(context);
209+
}
210+
211+
}

0 commit comments

Comments
 (0)