@@ -280,4 +280,173 @@ void testFromOptions_webSearchOptions() {
280
280
assertThat (target .getWebSearchOptions ().userLocation ().approximate ().timezone ()).isEqualTo ("UTC+8" );
281
281
}
282
282
283
+ @ Test
284
+ void testEqualsAndHashCode () {
285
+ OpenAiChatOptions options1 = OpenAiChatOptions .builder ()
286
+ .model ("test-model" )
287
+ .temperature (0.7 )
288
+ .maxTokens (100 )
289
+ .build ();
290
+
291
+ OpenAiChatOptions options2 = OpenAiChatOptions .builder ()
292
+ .model ("test-model" )
293
+ .temperature (0.7 )
294
+ .maxTokens (100 )
295
+ .build ();
296
+
297
+ OpenAiChatOptions options3 = OpenAiChatOptions .builder ()
298
+ .model ("different-model" )
299
+ .temperature (0.7 )
300
+ .maxTokens (100 )
301
+ .build ();
302
+
303
+ // Test equals
304
+ assertThat (options1 ).isEqualTo (options2 );
305
+ assertThat (options1 ).isNotEqualTo (options3 );
306
+ assertThat (options1 ).isNotEqualTo (null );
307
+ assertThat (options1 ).isEqualTo (options1 );
308
+
309
+ // Test hashCode
310
+ assertThat (options1 .hashCode ()).isEqualTo (options2 .hashCode ());
311
+ assertThat (options1 .hashCode ()).isNotEqualTo (options3 .hashCode ());
312
+ }
313
+
314
+ @ Test
315
+ void testBuilderWithNullValues () {
316
+ OpenAiChatOptions options = OpenAiChatOptions .builder ()
317
+ .temperature (null )
318
+ .logitBias (null )
319
+ .stop (null )
320
+ .tools (null )
321
+ .metadata (null )
322
+ .build ();
323
+
324
+ assertThat (options .getModel ()).isNull ();
325
+ assertThat (options .getTemperature ()).isNull ();
326
+ assertThat (options .getLogitBias ()).isNull ();
327
+ assertThat (options .getStop ()).isNull ();
328
+ assertThat (options .getTools ()).isNull ();
329
+ assertThat (options .getMetadata ()).isNull ();
330
+ }
331
+
332
+ @ Test
333
+ void testBuilderChaining () {
334
+ OpenAiChatOptions .Builder builder = OpenAiChatOptions .builder ();
335
+
336
+ OpenAiChatOptions .Builder result = builder .model ("test-model" ).temperature (0.7 ).maxTokens (100 );
337
+
338
+ assertThat (result ).isSameAs (builder );
339
+
340
+ OpenAiChatOptions options = result .build ();
341
+ assertThat (options .getModel ()).isEqualTo ("test-model" );
342
+ assertThat (options .getTemperature ()).isEqualTo (0.7 );
343
+ assertThat (options .getMaxTokens ()).isEqualTo (100 );
344
+ }
345
+
346
+ @ Test
347
+ void testNullAndEmptyCollections () {
348
+ OpenAiChatOptions options = new OpenAiChatOptions ();
349
+
350
+ // Test setting null collections
351
+ options .setLogitBias (null );
352
+ options .setStop (null );
353
+ options .setTools (null );
354
+ options .setMetadata (null );
355
+ options .setOutputModalities (null );
356
+
357
+ assertThat (options .getLogitBias ()).isNull ();
358
+ assertThat (options .getStop ()).isNull ();
359
+ assertThat (options .getTools ()).isNull ();
360
+ assertThat (options .getMetadata ()).isNull ();
361
+ assertThat (options .getOutputModalities ()).isNull ();
362
+
363
+ // Test setting empty collections
364
+ options .setLogitBias (new HashMap <>());
365
+ options .setStop (new ArrayList <>());
366
+ options .setTools (new ArrayList <>());
367
+ options .setMetadata (new HashMap <>());
368
+ options .setOutputModalities (new ArrayList <>());
369
+
370
+ assertThat (options .getLogitBias ()).isEmpty ();
371
+ assertThat (options .getStop ()).isEmpty ();
372
+ assertThat (options .getTools ()).isEmpty ();
373
+ assertThat (options .getMetadata ()).isEmpty ();
374
+ assertThat (options .getOutputModalities ()).isEmpty ();
375
+ }
376
+
377
+ @ Test
378
+ void testStreamUsageStreamOptionsInteraction () {
379
+ OpenAiChatOptions options = new OpenAiChatOptions ();
380
+
381
+ // Initially false
382
+ assertThat (options .getStreamUsage ()).isFalse ();
383
+ assertThat (options .getStreamOptions ()).isNull ();
384
+
385
+ // Setting streamUsage to true should set streamOptions
386
+ options .setStreamUsage (true );
387
+ assertThat (options .getStreamUsage ()).isTrue ();
388
+ assertThat (options .getStreamOptions ()).isEqualTo (StreamOptions .INCLUDE_USAGE );
389
+
390
+ // Setting streamUsage to false should clear streamOptions
391
+ options .setStreamUsage (false );
392
+ assertThat (options .getStreamUsage ()).isFalse ();
393
+ assertThat (options .getStreamOptions ()).isNull ();
394
+
395
+ // Setting streamOptions directly should update streamUsage
396
+ options .setStreamOptions (StreamOptions .INCLUDE_USAGE );
397
+ assertThat (options .getStreamUsage ()).isTrue ();
398
+ assertThat (options .getStreamOptions ()).isEqualTo (StreamOptions .INCLUDE_USAGE );
399
+
400
+ // Setting streamOptions to null should set streamUsage to false
401
+ options .setStreamOptions (null );
402
+ assertThat (options .getStreamUsage ()).isFalse ();
403
+ assertThat (options .getStreamOptions ()).isNull ();
404
+ }
405
+
406
+ @ Test
407
+ void testStopSequencesAlias () {
408
+ OpenAiChatOptions options = new OpenAiChatOptions ();
409
+ List <String > stopSequences = List .of ("stop1" , "stop2" );
410
+
411
+ // Setting stopSequences should also set stop
412
+ options .setStopSequences (stopSequences );
413
+ assertThat (options .getStopSequences ()).isEqualTo (stopSequences );
414
+ assertThat (options .getStop ()).isEqualTo (stopSequences );
415
+
416
+ // Setting stop should also update stopSequences
417
+ List <String > newStop = List .of ("stop3" , "stop4" );
418
+ options .setStop (newStop );
419
+ assertThat (options .getStop ()).isEqualTo (newStop );
420
+ assertThat (options .getStopSequences ()).isEqualTo (newStop );
421
+ }
422
+
423
+ @ Test
424
+ void testFromOptionsWithWebSearchOptionsNull () {
425
+ OpenAiChatOptions source = OpenAiChatOptions .builder ()
426
+ .model ("test-model" )
427
+ .temperature (0.7 )
428
+ .webSearchOptions (null )
429
+ .build ();
430
+
431
+ OpenAiChatOptions result = OpenAiChatOptions .fromOptions (source );
432
+ assertThat (result .getModel ()).isEqualTo ("test-model" );
433
+ assertThat (result .getTemperature ()).isEqualTo (0.7 );
434
+ assertThat (result .getWebSearchOptions ()).isNull ();
435
+ }
436
+
437
+ @ Test
438
+ void testCopyChangeIndependence () {
439
+ OpenAiChatOptions original = OpenAiChatOptions .builder ().model ("original-model" ).temperature (0.5 ).build ();
440
+
441
+ OpenAiChatOptions copied = original .copy ();
442
+
443
+ // Modify original
444
+ original .setModel ("modified-model" );
445
+ original .setTemperature (0.9 );
446
+
447
+ // Verify copy is unchanged
448
+ assertThat (copied .getModel ()).isEqualTo ("original-model" );
449
+ assertThat (copied .getTemperature ()).isEqualTo (0.5 );
450
+ }
451
+
283
452
}
0 commit comments