Skip to content

Commit c893629

Browse files
alxkmsobychacko
authored andcommitted
test: Testing improvements in various classes
Add comprehensive test coverage for the following components: - KeywordMetadataEnricher, ToolRuntimeHints, and Usage classes - ModelObservationContext and ModelUsageMetricsGenerator - SystemMessage, UserMessage, and MessageUtils Add comprehensive test coverage for tool execution classes Add comprehensive test coverage for Prompt and ChatOptions builders Enhance Document and DocumentBuilder test coverage with edge cases and validation tests Signed-off-by: Alex Klimenko <[email protected]>
1 parent e0ccc13 commit c893629

15 files changed

+1209
-0
lines changed

spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentBuilderTests.java

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,120 @@ void testBuilderReuse() {
290290
assertThat(doc2.getMetadata()).containsEntry("key", "value2");
291291
}
292292

293+
@Test
294+
void testMediaDocumentWithoutText() {
295+
Media media = getMedia();
296+
Document document = this.builder.media(media).build();
297+
298+
assertThat(document.getMedia()).isEqualTo(media);
299+
assertThat(document.getText()).isNull();
300+
}
301+
302+
@Test
303+
void testTextDocumentWithoutMedia() {
304+
Document document = this.builder.text("test content").build();
305+
306+
assertThat(document.getText()).isEqualTo("test content");
307+
assertThat(document.getMedia()).isNull();
308+
}
309+
310+
@Test
311+
void testOverwritingMediaWithNull() {
312+
Media media = getMedia();
313+
Document document = this.builder.media(media).media(null).text("fallback").build();
314+
315+
assertThat(document.getMedia()).isNull();
316+
}
317+
318+
@Test
319+
void testMetadataWithSpecialCharacterKeys() {
320+
Document document = this.builder.text("test")
321+
.metadata("key-with-dashes", "value1")
322+
.metadata("key.with.dots", "value2")
323+
.metadata("key_with_underscores", "value3")
324+
.metadata("key with spaces", "value4")
325+
.build();
326+
327+
assertThat(document.getMetadata()).containsEntry("key-with-dashes", "value1")
328+
.containsEntry("key.with.dots", "value2")
329+
.containsEntry("key_with_underscores", "value3")
330+
.containsEntry("key with spaces", "value4");
331+
}
332+
333+
@Test
334+
void testBuilderStateIsolation() {
335+
// Configure first builder state
336+
this.builder.text("first").metadata("shared", "first");
337+
338+
// Create first document
339+
Document doc1 = this.builder.build();
340+
341+
// Modify builder for second document
342+
this.builder.text("second").metadata("shared", "second");
343+
344+
// Create second document
345+
Document doc2 = this.builder.build();
346+
347+
// Verify first document wasn't affected by subsequent changes
348+
assertThat(doc1.getText()).isEqualTo("first");
349+
assertThat(doc1.getMetadata()).containsEntry("shared", "first");
350+
351+
assertThat(doc2.getText()).isEqualTo("second");
352+
assertThat(doc2.getMetadata()).containsEntry("shared", "second");
353+
}
354+
355+
@Test
356+
void testBuilderMethodChaining() {
357+
Document document = this.builder.text("chained")
358+
.id("chain-id")
359+
.metadata("key1", "value1")
360+
.metadata("key2", "value2")
361+
.score(0.75)
362+
.build();
363+
364+
assertThat(document.getText()).isEqualTo("chained");
365+
assertThat(document.getId()).isEqualTo("chain-id");
366+
assertThat(document.getMetadata()).hasSize(2);
367+
assertThat(document.getScore()).isEqualTo(0.75);
368+
}
369+
370+
@Test
371+
void testTextWithNewlinesAndTabs() {
372+
String textWithFormatting = "Line 1\nLine 2\n\tTabbed line\r\nWindows line ending";
373+
Document document = this.builder.text(textWithFormatting).build();
374+
375+
assertThat(document.getText()).isEqualTo(textWithFormatting);
376+
}
377+
378+
@Test
379+
void testMetadataOverwritingWithMapAfterKeyValue() {
380+
Map<String, Object> newMetadata = new HashMap<>();
381+
newMetadata.put("map-key", "map-value");
382+
383+
Document document = this.builder.text("test")
384+
.metadata("old-key", "old-value")
385+
.metadata("another-key", "another-value")
386+
.metadata(newMetadata) // This should replace all previous metadata
387+
.build();
388+
389+
assertThat(document.getMetadata()).hasSize(1);
390+
assertThat(document.getMetadata()).containsEntry("map-key", "map-value");
391+
assertThat(document.getMetadata()).doesNotContainKey("old-key");
392+
assertThat(document.getMetadata()).doesNotContainKey("another-key");
393+
}
394+
395+
@Test
396+
void testMetadataKeyValuePairsAccumulation() {
397+
Document document = this.builder.text("test")
398+
.metadata("a", "1")
399+
.metadata("b", "2")
400+
.metadata("c", "3")
401+
.metadata("d", "4")
402+
.metadata("e", "5")
403+
.build();
404+
405+
assertThat(document.getMetadata()).hasSize(5);
406+
assertThat(document.getMetadata().keySet()).containsExactlyInAnyOrder("a", "b", "c", "d", "e");
407+
}
408+
293409
}

spring-ai-commons/src/test/java/org/springframework/ai/document/DocumentTests.java

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,150 @@ private static Media getMedia() {
213213
return Media.builder().mimeType(MimeTypeUtils.IMAGE_JPEG).data(URI.create("http://type1")).build();
214214
}
215215

216+
@Test
217+
void testMetadataModeNone() {
218+
Map<String, Object> metadata = new HashMap<>();
219+
metadata.put("secret", "hidden");
220+
221+
Document document = Document.builder().text("Visible content").metadata(metadata).build();
222+
223+
String formattedContent = document.getFormattedContent(MetadataMode.NONE);
224+
assertThat(formattedContent).contains("Visible content");
225+
assertThat(formattedContent).doesNotContain("secret");
226+
assertThat(formattedContent).doesNotContain("hidden");
227+
}
228+
229+
@Test
230+
void testMetadataModeEmbed() {
231+
Map<String, Object> metadata = new HashMap<>();
232+
metadata.put("embedKey", "embedValue");
233+
metadata.put("filterKey", "filterValue");
234+
235+
Document document = Document.builder().text("Test content").metadata(metadata).build();
236+
237+
String formattedContent = document.getFormattedContent(MetadataMode.EMBED);
238+
// This test assumes EMBED mode includes all metadata - adjust based on actual
239+
// implementation
240+
assertThat(formattedContent).contains("Test content");
241+
}
242+
243+
@Test
244+
void testDocumentBuilderChaining() {
245+
Map<String, Object> metadata = new HashMap<>();
246+
metadata.put("chain", "test");
247+
248+
Document document = Document.builder()
249+
.text("Chain test")
250+
.metadata(metadata)
251+
.metadata("additional", "value")
252+
.score(0.85)
253+
.build();
254+
255+
assertThat(document.getText()).isEqualTo("Chain test");
256+
assertThat(document.getMetadata()).containsEntry("chain", "test");
257+
assertThat(document.getMetadata()).containsEntry("additional", "value");
258+
assertThat(document.getScore()).isEqualTo(0.85);
259+
}
260+
261+
@Test
262+
void testDocumentWithScoreGreaterThanOne() {
263+
Document document = Document.builder().text("High score test").score(1.5).build();
264+
265+
assertThat(document.getScore()).isEqualTo(1.5);
266+
}
267+
268+
@Test
269+
void testMutateWithChanges() {
270+
Document original = Document.builder().text("Original text").score(0.5).metadata("original", "value").build();
271+
272+
Document mutated = original.mutate().text("Mutated text").score(0.8).metadata("new", "metadata").build();
273+
274+
assertThat(mutated.getText()).isEqualTo("Mutated text");
275+
assertThat(mutated.getScore()).isEqualTo(0.8);
276+
assertThat(mutated.getMetadata()).containsEntry("new", "metadata");
277+
assertThat(original.getText()).isEqualTo("Original text"); // Original unchanged
278+
}
279+
280+
@Test
281+
void testDocumentEqualityWithDifferentScores() {
282+
Document doc1 = Document.builder().id("sameId").text("Same text").score(0.5).build();
283+
284+
Document doc2 = Document.builder().id("sameId").text("Same text").score(0.8).build();
285+
286+
// Assuming score affects equality - adjust if it doesn't
287+
assertThat(doc1).isNotEqualTo(doc2);
288+
}
289+
290+
@Test
291+
void testDocumentWithComplexMetadata() {
292+
Map<String, Object> nestedMap = new HashMap<>();
293+
nestedMap.put("nested", "value");
294+
295+
Map<String, Object> metadata = new HashMap<>();
296+
metadata.put("string", "value");
297+
metadata.put("number", 1);
298+
metadata.put("boolean", true);
299+
metadata.put("map", nestedMap);
300+
301+
Document document = Document.builder().text("Complex metadata test").metadata(metadata).build();
302+
303+
assertThat(document.getMetadata()).containsEntry("string", "value");
304+
assertThat(document.getMetadata()).containsEntry("number", 1);
305+
assertThat(document.getMetadata()).containsEntry("boolean", true);
306+
assertThat(document.getMetadata()).containsEntry("map", nestedMap);
307+
}
308+
309+
@Test
310+
void testMetadataImmutability() {
311+
Map<String, Object> originalMetadata = new HashMap<>();
312+
originalMetadata.put("key", "value");
313+
314+
Document document = Document.builder().text("Immutability test").metadata(originalMetadata).build();
315+
316+
// Modify original map
317+
originalMetadata.put("key", "modified");
318+
originalMetadata.put("newKey", "newValue");
319+
320+
// Document's metadata should be unaffected (if properly copied)
321+
assertThat(document.getMetadata()).containsEntry("key", "value");
322+
assertThat(document.getMetadata()).doesNotContainKey("newKey");
323+
}
324+
325+
@Test
326+
void testDocumentWithEmptyMetadata() {
327+
Document document = Document.builder().text("Empty metadata test").metadata(new HashMap<>()).build();
328+
329+
assertThat(document.getMetadata()).isEmpty();
330+
}
331+
332+
@Test
333+
void testMetadataWithNullValueInMap() {
334+
Map<String, Object> metadata = new HashMap<>();
335+
metadata.put("validKey", "validValue");
336+
metadata.put("nullKey", null);
337+
338+
assertThrows(IllegalArgumentException.class, () -> {
339+
Document.builder().text("test").metadata(metadata).build();
340+
});
341+
}
342+
343+
@Test
344+
void testDocumentWithWhitespaceOnlyText() {
345+
String whitespaceText = " \n\t\r ";
346+
Document document = Document.builder().text(whitespaceText).build();
347+
348+
assertThat(document.getText()).isEqualTo(whitespaceText);
349+
assertThat(document.isText()).isTrue();
350+
}
351+
352+
@Test
353+
void testDocumentHashCodeConsistency() {
354+
Document document = Document.builder().text("Hash test").metadata("key", "value").score(0.1).build();
355+
356+
int hashCode1 = document.hashCode();
357+
int hashCode2 = document.hashCode();
358+
359+
assertThat(hashCode1).isEqualTo(hashCode2);
360+
}
361+
216362
}

spring-ai-model/src/test/java/org/springframework/ai/aot/ToolRuntimeHintsTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,36 @@ void registerHintsWithNullClassLoader() {
4747
assertThatCode(() -> toolRuntimeHints.registerHints(runtimeHints, null)).doesNotThrowAnyException();
4848
}
4949

50+
@Test
51+
void registerHintsWithCustomClassLoader() {
52+
RuntimeHints runtimeHints = new RuntimeHints();
53+
ToolRuntimeHints toolRuntimeHints = new ToolRuntimeHints();
54+
ClassLoader customClassLoader = Thread.currentThread().getContextClassLoader();
55+
56+
toolRuntimeHints.registerHints(runtimeHints, customClassLoader);
57+
58+
assertThat(runtimeHints).matches(reflection().onType(DefaultToolCallResultConverter.class));
59+
}
60+
61+
@Test
62+
void registerHintsMultipleTimes() {
63+
RuntimeHints runtimeHints = new RuntimeHints();
64+
ToolRuntimeHints toolRuntimeHints = new ToolRuntimeHints();
65+
66+
toolRuntimeHints.registerHints(runtimeHints, null);
67+
toolRuntimeHints.registerHints(runtimeHints, null);
68+
69+
assertThat(runtimeHints).matches(reflection().onType(DefaultToolCallResultConverter.class));
70+
}
71+
72+
@Test
73+
void toolRuntimeHintsInstanceCreation() {
74+
assertThatCode(() -> new ToolRuntimeHints()).doesNotThrowAnyException();
75+
76+
ToolRuntimeHints hints1 = new ToolRuntimeHints();
77+
ToolRuntimeHints hints2 = new ToolRuntimeHints();
78+
79+
assertThat(hints1).isNotSameAs(hints2);
80+
}
81+
5082
}

spring-ai-model/src/test/java/org/springframework/ai/chat/messages/MessageUtilsTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,11 @@ void readResourceWithCharsetWhenNull() {
5757
.hasMessageContaining("charset cannot be null");
5858
}
5959

60+
@Test
61+
void readResourceWithCharsetWhenResourceNull() {
62+
assertThatThrownBy(() -> MessageUtils.readResource(null, StandardCharsets.UTF_8))
63+
.isInstanceOf(IllegalArgumentException.class)
64+
.hasMessageContaining("resource cannot be null");
65+
}
66+
6067
}

0 commit comments

Comments
 (0)