|
25 | 25 | import org.mockito.Mockito; |
26 | 26 |
|
27 | 27 | import static org.assertj.core.api.Assertions.assertThat; |
| 28 | +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; |
28 | 29 |
|
29 | 30 | /** |
30 | 31 | * Unit tests for {@link OpenAiStreamFunctionCallingHelper} |
@@ -206,4 +207,131 @@ public void isStreamingToolFunctionCallFinishDetectsToolCallsFinishReason() { |
206 | 207 | assertThat(this.helper.isStreamingToolFunctionCallFinish(chunk)).isTrue(); |
207 | 208 | } |
208 | 209 |
|
| 210 | + @Test |
| 211 | + public void merge_whenBothChunksAreNull() { |
| 212 | + var result = this.helper.merge(null, null); |
| 213 | + assertThat(result).isNull(); |
| 214 | + } |
| 215 | + |
| 216 | + @Test |
| 217 | + public void merge_whenPreviousIsNull() { |
| 218 | + var current = new OpenAiApi.ChatCompletionChunk("id", Collections.emptyList(), System.currentTimeMillis(), |
| 219 | + "model", "default", "fingerprint", "object", null); |
| 220 | + |
| 221 | + var result = this.helper.merge(null, current); |
| 222 | + assertThat(result).isEqualTo(current); |
| 223 | + } |
| 224 | + |
| 225 | + @Test |
| 226 | + public void merge_whenCurrentIsNull() { |
| 227 | + var previous = new OpenAiApi.ChatCompletionChunk("id", Collections.emptyList(), System.currentTimeMillis(), |
| 228 | + "model", "default", "fingerprint", "object", null); |
| 229 | + |
| 230 | + var result = this.helper.merge(previous, null); |
| 231 | + assertThat(result).isEqualTo(previous); |
| 232 | + } |
| 233 | + |
| 234 | + @Test |
| 235 | + public void merge_partialFieldsFromEachChunk() { |
| 236 | + var choices = List.of(Mockito.mock(OpenAiApi.ChatCompletionChunk.ChunkChoice.class)); |
| 237 | + var usage = Mockito.mock(OpenAiApi.Usage.class); |
| 238 | + |
| 239 | + var previous = new OpenAiApi.ChatCompletionChunk(null, choices, 1L, "model1", null, "fp1", null, null); |
| 240 | + var current = new OpenAiApi.ChatCompletionChunk("id2", null, null, null, "tier2", null, "object2", usage); |
| 241 | + |
| 242 | + var result = this.helper.merge(previous, current); |
| 243 | + |
| 244 | + assertThat(result.id()).isEqualTo("id2"); |
| 245 | + assertThat(result.choices()).isEqualTo(choices); |
| 246 | + assertThat(result.created()).isEqualTo(1L); |
| 247 | + assertThat(result.model()).isEqualTo("model1"); |
| 248 | + assertThat(result.serviceTier()).isEqualTo("tier2"); |
| 249 | + assertThat(result.systemFingerprint()).isEqualTo("fp1"); |
| 250 | + assertThat(result.object()).isEqualTo("object2"); |
| 251 | + assertThat(result.usage()).isEqualTo(usage); |
| 252 | + } |
| 253 | + |
| 254 | + @Test |
| 255 | + public void isStreamingToolFunctionCall_withMultipleChoicesAndOnlyFirstHasToolCalls() { |
| 256 | + var toolCall = Mockito.mock(OpenAiApi.ChatCompletionMessage.ToolCall.class); |
| 257 | + var deltaWithToolCalls = new OpenAiApi.ChatCompletionMessage(null, null, null, null, List.of(toolCall), null, |
| 258 | + null, null); |
| 259 | + var deltaWithoutToolCalls = new OpenAiApi.ChatCompletionMessage(null, null); |
| 260 | + |
| 261 | + var choice1 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(null, null, deltaWithToolCalls, null); |
| 262 | + var choice2 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(null, null, deltaWithoutToolCalls, null); |
| 263 | + |
| 264 | + var chunk = new OpenAiApi.ChatCompletionChunk(null, List.of(choice1, choice2), null, null, null, null, null, |
| 265 | + null); |
| 266 | + |
| 267 | + assertThat(this.helper.isStreamingToolFunctionCall(chunk)).isTrue(); |
| 268 | + } |
| 269 | + |
| 270 | + @Test |
| 271 | + public void isStreamingToolFunctionCall_withMultipleChoicesAndNoneHaveToolCalls() { |
| 272 | + var deltaWithoutToolCalls = new OpenAiApi.ChatCompletionMessage(null, null); |
| 273 | + |
| 274 | + var choice1 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(null, null, deltaWithoutToolCalls, null); |
| 275 | + var choice2 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(null, null, deltaWithoutToolCalls, null); |
| 276 | + |
| 277 | + var chunk = new OpenAiApi.ChatCompletionChunk(null, List.of(choice1, choice2), null, null, null, null, null, |
| 278 | + null); |
| 279 | + |
| 280 | + assertThat(this.helper.isStreamingToolFunctionCall(chunk)).isFalse(); |
| 281 | + } |
| 282 | + |
| 283 | + @Test |
| 284 | + public void isStreamingToolFunctionCallFinish_withMultipleChoicesAndOnlyFirstIsToolCallsFinish() { |
| 285 | + var choice1 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(OpenAiApi.ChatCompletionFinishReason.TOOL_CALLS, |
| 286 | + null, new OpenAiApi.ChatCompletionMessage(null, null), null); |
| 287 | + var choice2 = new OpenAiApi.ChatCompletionChunk.ChunkChoice(OpenAiApi.ChatCompletionFinishReason.STOP, null, |
| 288 | + new OpenAiApi.ChatCompletionMessage(null, null), null); |
| 289 | + |
| 290 | + var chunk = new OpenAiApi.ChatCompletionChunk(null, List.of(choice1, choice2), null, null, null, null, null, |
| 291 | + null); |
| 292 | + |
| 293 | + assertThat(this.helper.isStreamingToolFunctionCallFinish(chunk)).isTrue(); |
| 294 | + } |
| 295 | + |
| 296 | + @Test |
| 297 | + public void chunkToChatCompletion_whenChunkIsNull() { |
| 298 | + assertThatThrownBy(() -> this.helper.chunkToChatCompletion(null)).isInstanceOf(NullPointerException.class); |
| 299 | + } |
| 300 | + |
| 301 | + @Test |
| 302 | + public void chunkToChatCompletion_withEmptyChoices() { |
| 303 | + var chunk = new OpenAiApi.ChatCompletionChunk("id", Collections.emptyList(), 1L, "model", "tier", "fp", |
| 304 | + "object", null); |
| 305 | + |
| 306 | + var result = this.helper.chunkToChatCompletion(chunk); |
| 307 | + |
| 308 | + assertThat(result.object()).isEqualTo("chat.completion"); |
| 309 | + assertThat(result.choices()).isEmpty(); |
| 310 | + assertThat(result.id()).isEqualTo("id"); |
| 311 | + assertThat(result.created()).isEqualTo(1L); |
| 312 | + assertThat(result.model()).isEqualTo("model"); |
| 313 | + } |
| 314 | + |
| 315 | + @Test |
| 316 | + public void edgeCases_emptyStringFields() { |
| 317 | + var chunk = new OpenAiApi.ChatCompletionChunk("", Collections.emptyList(), 0L, "", "", "", "", null); |
| 318 | + |
| 319 | + var result = this.helper.chunkToChatCompletion(chunk); |
| 320 | + |
| 321 | + assertThat(result.id()).isEmpty(); |
| 322 | + assertThat(result.model()).isEmpty(); |
| 323 | + assertThat(result.serviceTier()).isEmpty(); |
| 324 | + assertThat(result.systemFingerprint()).isEmpty(); |
| 325 | + assertThat(result.created()).isEqualTo(0L); |
| 326 | + } |
| 327 | + |
| 328 | + @Test |
| 329 | + public void isStreamingToolFunctionCall_withNullToolCallsList() { |
| 330 | + var delta = new OpenAiApi.ChatCompletionMessage(null, null, null, null, null, null, null, null); |
| 331 | + var choice = new OpenAiApi.ChatCompletionChunk.ChunkChoice(null, null, delta, null); |
| 332 | + var chunk = new OpenAiApi.ChatCompletionChunk(null, List.of(choice), null, null, null, null, null, null); |
| 333 | + |
| 334 | + assertThat(this.helper.isStreamingToolFunctionCall(chunk)).isFalse(); |
| 335 | + } |
| 336 | + |
209 | 337 | } |
0 commit comments